Getting Started¶
Installation¶
consteig requires a C++17 compiler. No separate compilation step is needed.
Git submodule¶
Add the repository as a submodule:
Alternatively, the headers can be copied directly into your project.
With CMake, add the submodule to your build:
add_subdirectory(third_party/consteig)
target_link_libraries(your_target PRIVATE consteig::consteig)
CMake FetchContent¶
include(FetchContent)
FetchContent_Declare(
consteig
GIT_REPOSITORY https://github.com/mitchellthompkins/consteig.git
GIT_TAG 1.0.0
)
FetchContent_MakeAvailable(consteig)
target_link_libraries(your_target PRIVATE consteig::consteig)
vcpkg¶
Configure CMake with the vcpkg toolchain file so find_package can locate installed packages:
Alternatively, use vcpkg manifest mode with a vcpkg.json and a CMakePresets.json that sets the toolchain.
Conan¶
Add consteig to your conanfile.txt:
Or in a conanfile.py:
Then install and configure CMake:
conan install . --output-folder=build --build=missing
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
System install¶
To install consteig system-wide and use it via find_package:
Quick Reference Examples¶
- Working with matrices
- Finding eigenvalues
- DC motor control gain validation
- Population flow
- Butterworth filter design
Full Examples¶
Control Theory¶
When system parameters and controller gains are known at compile-time, consteig can verify that the closed-loop poles meet performance requirements, turning a runtime failure into a build failure. See the dc-motor example.
Population Flow¶
If a system's transition matrix is fixed at compile-time, its steady-state
behavior never needs to be recomputed at runtime. The
population.cpp example computes steady-state
population fractions as static constexpr values; at runtime, distributing any
total population is a single multiply with no matrix iteration. See the
population
example.
Digital Filter Design¶
IIR filter coefficients derived entirely at compile-time from a continuous-time transfer function. See the butterworth example.
Your First Eigenvalue Computation¶
#include <consteig/consteig.hpp>
// Define a matrix — all values must be known at compile time
static constexpr consteig::Matrix<double, 2, 2> A{{
{3.0, 1.0},
{1.0, 3.0}
}};
// Compute eigenvalues at compile time
static constexpr auto eigs = consteig::eigenvalues(A);
Sanity-Checking the Solver with checkEigenValues¶
checkEigenValues verifies that the computed eigenvalues are self-consistent
with the input matrix by checking two invariants: the sum of eigenvalues equals
the matrix trace, and (for matrices up to 4x4) the product equals the
determinant. This catches solver failures, but does not verify that the
eigenvalues match any user-defined expectation.
static constexpr auto eigs = consteig::eigenvalues(A);
static_assert(consteig::checkEigenValues(A, eigs, 1e-9),
"Eigenvalue invariants failed");
To assert something meaningful about your specific problem, write your own
static_assert against the computed values directly. For example, to confirm
all poles are stable:
Computing Eigenvectors¶
static constexpr auto eigs = consteig::eigenvalues(A);
static constexpr auto vecs = consteig::eigenvectors(A, eigs);
// vecs is a Matrix<Complex<double>, N, N>
// Column i of vecs is the eigenvector for eigs(i, 0)
Declaring Matrices¶
Matrix dimensions are template parameters. Values are provided as nested
initializer lists (alternatively there is a consteig::make_matrix function):
// 3x3 matrix
static constexpr consteig::Matrix<double, 3, 3> M{{
{1.0, 2.0, 3.0},
{4.0, 5.0, 6.0},
{7.0, 8.0, 9.0}
}};
// Access element at row 1, column 2 (zero-based)
static constexpr double val = M(1, 2); // 6.0
The double braces {{...}} are required: the outer pair initializes the
Matrix, the inner pairs initialize each row. See Matrix
Operations for more detail.