Skip to content

Setup for 1.0.0 release#6

Merged
MitchellThompkins merged 324 commits intomainfrom
develop
Mar 29, 2026
Merged

Setup for 1.0.0 release#6
MitchellThompkins merged 324 commits intomainfrom
develop

Conversation

@MitchellThompkins
Copy link
Copy Markdown
Owner

@MitchellThompkins MitchellThompkins commented Feb 17, 2026

Summary

I started working on this set of changes a number of years ago and have only gotten around to completing the implementation recently. This adds a numerically accurate eigenvalue and eigenvector solver, many more tests (compile-time and run-time against both Octave generated references and Eigen respectively), examples, and some theory discussion, along with the CI/CD, build system, and documentation infrastructure needed to support a proper public release.

CI/CD

  • Rewrote main.yml from a single job to a matrix pipeline: separate lint, build-and-test (GCC + Clang), cross-compile (ARM GCC + Clang), check-generated, and dc-motor-fail jobs.
  • Added docs.yml to build and deploy the MkDocs + Doxygen site to GitHub Pages on pushes to main.
  • Container images are now tagged by date (from .env) and SHA; a CI guard enforces that Dockerfile and .env change together.
  • Added a weekly scheduled run.

Build system

  • CMakeLists.txt: upgraded to C++17, renamed project to consteig, added strict consteig_warnings interface target (-Wall -Wextra -pedantic -Werror + extended set), CONSTEIG_BUILD_TESTS and CONSTEIG_COMPILE_ONLY options, consteig_raise_compiler_limits() helper, and FetchContent-compatible structure.
  • Makefile: added per-compiler targets (build.gcc, test.clang, etc.), cross-compile targets (cross.arm-gcc, cross.arm-clang), check-format, generate-test-cases, check-generated, test-dc-motor-fail, and profile.
  • Dockerfile: updated Alpine 3.14 -> 3.23, added ARM GNU toolchain (15.2), clang-extra-tools, octave, and uv.

Cross-compilation

  • Added cmake/toolchains/arm-none-eabi-gcc.cmake and arm-none-eabi-clang.cmake for bare-metal ARM targets.
  • CONSTEIG_COMPILE_ONLY mode compiles to .o files only (no linker step), exercising all static_assert checks without a C runtime.

Library

  • Expanded eigen value solver to route symmetric and non-symmetric matrices to different algorithms. The old solver used a simple explicit single-shift QR loop with a hardcoded convergence threshold and no preprocessing. The new implementation routes symmetric matrices through a single-shift QR path (sufficient since real eigenvalues are guaranteed) and non-symmetric matrices through the full Francis implicit double-shift QR algorithm (with both matrix balancing (Parlett & Reinsch 1969) and Hessenberg reduction as preprocessing. The double-shift path handles complex conjugate pairs simultaneously using real arithmetic, with Wilkinson shifts for quadratic convergence, LAPACK-style exceptional shifts every 10 iterations to prevent stalling, and a dual-mode deflation criterion (relative to matrix norm + absolute against machine epsilon). The deflation was critical for keeping compile times tractable across the expanded robustness test suite; otherwise compilation times exploded but with no real improvement on accuracy.

  • The old solver used a simple explicit single-shift QR loop with a hardcoded convergence threshold and no preprocessing. The new implementation uses the Francis implicit double-shift QR algorithm: the input is first balanced (Parlett & Reinsch 1969) and reduced to Hessenberg form, then a bulge-chasing step handles complex
    conjugate pairs simultaneously using real arithmetic, with Wilkinson shifts for quadratic convergence, LAPACK-style exceptional shifts every 10 iterations to prevent
    stalling, and a dual-mode deflation criterion (relative + absolute against machine epsilon) that was critical for keeping compile times tractable across the expanded
    robustness test suite.

  • New consteig_types.hpp introducing consteig::Size; replaced all size_t uses in library and test code.

  • consteig_options.hpp: expanded with Doxygen @defgroup config documentation; added CONSTEIG_MAX_ITER, CONSTEIG_BALANCE_CONVERGENCE_THRESHOLD, E_CONST, PI_CONST, CONSTEIG_TRIG_MAX_ITER, and CONSTEIG_USE_LONG_DOUBLE.

  • array/array.hpp: added const T* data() overload and full Doxygen comments.

  • eigen/eigen.hpp, matrix/, math/: reformatted to Microsoft/clang-format style; explicit casts for Eigen indexing; hardcoded tolerances replaced with named constants.

Tests

  • Significantly expanded generated test suite (eigen/tests/generated_*): adds robustness categories including defective, nearly defective, clustered eigenvalues, companion, and Hamiltonian matrices.
  • All tests updated for strict-warning builds.
  • dc-motor-fail test verifies that bad PID gains trigger a static_assert at build time.

Documentation

  • New MkDocs + Material site under docs/: getting-started guide, configuration reference, decompositions/eigensolvers/math-functions/matrix guides, example walkthroughs (Butterworth filter, DC motor control, population dynamics), verification and performance pages.
  • Doxygen API reference generated and co-deployed to GitHub Pages.

Legal / project

  • Added LICENSE (Apache 2.0) and NOTICE (attributing GCE-Math).
  • New README.md, AGENT.md (with CLAUDE.md/GEMINI.md symlinks), .clang-format, .coderabbit.yaml, .gitattributes (LFS for profiling/docs PNGs).

Octave

  • Reorganized development scripts into octave/development_scripts/.
  • generate_test_cases.m updated to produce the expanded robustness test cases.
  • New generate_profiling_cases.m for compile-time profiling.

Profiling

  • New profiling infrastructure: profiling/CMakeLists.txt, run_profiling.sh, analyze_results.py, GCC 15.2.0 baseline results.

@MitchellThompkins MitchellThompkins marked this pull request as draft February 17, 2026 01:32
Enable -Werror and Resolve Compiler Warnings
Build System Simplification and Enhanced Test Coverage
Only build and publish container on develop/main
Add clang support and testing (add but don't run clang format)
MitchellThompkins and others added 16 commits March 15, 2026 19:02
* inlude example outputs in CI

* address MR feedback

* add example

* split examples out into separate jobs

* update actions dep

* update CI deps to latest

* make a matrix

* be more agile to Dockerfile changes

* simple test

* try to force dockerfile changes to be honored in PR

* use concurrency grouping

* deconflict concurrency across event types

* Revert "simple test"

This reverts commit 7ddea1b.

* Reapply "simple test"

This reverts commit 7b67f87.

* Revert "Reapply "simple test""

This reverts commit 3a3c201.

* now with change

* Revert "now with change"

This reverts commit c4e04f4.

* be more robust to Dockerfile changes

* test with dockerfile change

* Revert "test with dockerfile change"

This reverts commit a6fe94b.

* KISS with just now allowing Actions on all push events

* force dockerfile change

* Revert "force dockerfile change"

This reverts commit e25eb87.

* forward make options

* use dev container as backing image

* update alpine image

* make git hooks setup non-fatal

* fix formatting error with update clange-format dependency

* don't let Eigen build for examples

* slimpify build into 1 step

* update docker dependency

* force set -3

* The container image was recently updated (commit da847dc update alpine
 image). A newer Alpine image means a newer clang, and newer clang added
 -Wcharacter-conversion which gets promoted to an error by -Werror. The
 googletest code hasn't changed — the compiler just got stricter.

* update google test dependency to avoid more agressive Werrors

* use more modern compiler catch

* fail dc-motor-build on static assert properly

* Localize all test code dependency

* do some serious CMakeLists.txt cleanup

* exlude examples from make build

* I removed the githooks dir anyway a while ago so I shouldn't need this

* address MR feedback
* inlude example outputs in CI

* address MR feedback

* add example

* split examples out into separate jobs

* update actions dep

* update CI deps to latest

* make a matrix

* be more agile to Dockerfile changes

* simple test

* try to force dockerfile changes to be honored in PR

* use concurrency grouping

* deconflict concurrency across event types

* Revert "simple test"

This reverts commit 7ddea1b.

* Reapply "simple test"

This reverts commit 7b67f87.

* Revert "Reapply "simple test""

This reverts commit 3a3c201.

* now with change

* Revert "now with change"

This reverts commit c4e04f4.

* be more robust to Dockerfile changes

* test with dockerfile change

* Revert "test with dockerfile change"

This reverts commit a6fe94b.

* KISS with just now allowing Actions on all push events

* force dockerfile change

* Revert "force dockerfile change"

This reverts commit e25eb87.

* forward make options

* use dev container as backing image

* update alpine image

* make git hooks setup non-fatal

* fix formatting error with update clange-format dependency

* don't let Eigen build for examples

* slimpify build into 1 step

* update docker dependency

* force set -3

* The container image was recently updated (commit da847dc update alpine
 image). A newer Alpine image means a newer clang, and newer clang added
 -Wcharacter-conversion which gets promoted to an error by -Werror. The
 googletest code hasn't changed — the compiler just got stricter.

* update google test dependency to avoid more agressive Werrors

* use more modern compiler catch

* fail dc-motor-build on static assert properly

* Localize all test code dependency

* do some serious CMakeLists.txt cleanup

* exlude examples from make build

* will this pass with no compiler limits raised

* forgot to comment these out

* did not mean to comment this out

* Remove compiler limit raises and add some documentation about why, also, explain why macos is still slow to run tests

* I tried to get macos to test faster but it seems not to matter

* update test with reason for slowdown

* Update readme wording. Add back in macro as an option. Update
documentation.

* slight wording update

* address MR feedback

* Minor feedback

* rename
* preserve container history

* address MR feedback
* add these options

* add ateict flags

* revert float tests

* enforce {} styling

* add whitespaces to generation script

* check in white-spaces

* use more generic comparison function name for floating point types

* don't use temporary tolerance variables

* make this match develop

* tell the compiler to treat Eigen's headers as system headers (like
/usr/include). GCC and Clang then suppress all warnings originating from
those files so strict flags like -Wduplicated-branches won't fire
on Eigen's own code, only on ours.

Without SYSTEM, the compiler treats Eigen headers the same as our own
source, and -Werror turns Eigen's internal warnings into build failures
I can't fix.

* GCC does warn about float to double promotion with -Wdouble-promotion,
but only when you actually use the default argument. Clang is stricter —
it evaluates and warns about the default argument expression at the
point of instantiation of the template signature, even before the
default is used in a call.

In the test code, nearlyEqual<double> is called without explicitly
passing epsilon/relth, so both compilers should in theory flag it. But
GCC's implementation of -Wdouble-promotion has known blind spots with
template default arguments — it doesn't consistently diagnose the
promotion when it happens inside a default argument
expression during template instantiation. Clang does.

* update naming to be consistent

* update comments to explain function

* be explicit about cast

* Correct missing braces

* address MR fedback

* use an interface library to apply compiler flags for the tests

* address MR feedback for matching parametr types

* update per MR feedback

* lint

* change zpproxEqual to better reflect function intent

* remove more kTol nonsense

* Remove more kTol references

* lint

* apply bugfix and more robust tests

* stop using hard-coded matrix size in template that was silly

* add better tests

* address MR feedback for magic numbers

* allow float symetric comparisions to actually work, but enforce the parameterized version to leverage floats. Also give coding guidelines.

* light code cleanup for early return version
* Start adding support for cross compilation tests

* cleaning up github ci files

* build?

* updated how dockerfile pulls cross compiler toolchain

* change hwo things get built

* let claude churn on trying to get these tests to compile

* try to get these tests to build

* try with this cross_compile_verify source

* try explictly setting compile options, and letting test TU's compile against stubs

* remove these cros compilation target tests since they're covered by main

* remove extra compiler tests, they're not very valuable

* make using local image a bit more ergonomic

* fix leaking test deps into matrix lib, check sha256 checksum of arm, make test executables private

* Let dockerfile manage arm dependency

* update comments

* break out tests into compile-time and run-time (for verification against eigen)

* address MR fb

* split out some of the eigen tests to constepxr variatns

* add comments and rename tests

* add dedicated makefile commands

* collapse all eigen tests into a single file

* add build dir first

* makefile clean-up and updates

* use modern cmake

* add commands to remove cached cross compiler builds

* remove other targets
* add explanation for trig iteration limit and update .gitignore

* add refernce

* add tan

* lint

* add comments explaining

* update comment
* co-locate test files

* I think updating the container changed octave and LAPACK gave me slightly different values for the generated test cases so I decided to pin deps in the container

* add explanation to test-case generator

* use true clustered eigenvalues

* use more robust randn to get normalized random distribution

* coderrabbitai is right that I'll probably end up breaking packages. There may be slight drift in re-generated test cases so leave it that way for now

* correct comments and error on unknown matrix type

* use normally distrbuted srandn

* regenerate and reformat but sparse matricies now fail

* lower sparsity and justify it

* regen slightly

* correct comment

* update comment
Co-authored-by: Mitchell Thompkins <mitchell.thompkins@pm.me>
Co-authored-by: Mitchell Thompkins <mitchell.thompkins@pm.me>
…mposition docs (#42)

* make this a definition and add reference

* readme update

* add comments for decompositions and update docker file and .env

* pull this in via shell

* comment to re-generate images

* comment update

* force rule to update container tag

* check against base branch

* address MR feedback

* just use ... syntax

* try something new

* try to get a deeper history to use ... syntax
* cleanup population example slightly and tighten up language

* update examples and co-locate butterworht example

* readme clean-up

* more language update

* update consteig usage

* tighten up language

* update constraints and fix references

* apply mr fixes, make why is this useful more apparent

* readme update

* tighten up lanauge and add comment in example

* improve bash rendering

* remove 2nd person voice

* tighten up first 2 paragraphs

* clean up language here

* light clean-up

* slight updates

* align consteig

* slight language cleanup

* update refernce

* more language cleanup

* citations and langauge cleanup

* more languge updates

* language update

* update

* updates

* add comment explaining usage of non-constexpr arthimetic

* fix mk tags

* MR feedback
…ess, and rename legacy functions (#44)

* make this a definition and add reference

* readme update

* add comments for decompositions and update docker file and .env

* pull this in via shell

* align with eigen api

* make _data a private accessor

* try new bracet syntax

* attempt to address bracing issues, regenerate test cases as a result, and lint

* add back in these cases

* add these back in

* align more closely with eigen api

* add tests to validate new member functions

* Allow for eigenvalues() and eigenvectors() to be called on matrix

* enforce compile time comparison

* add constexpr helper

* lint

* add check and comment explaning why

* Align with Eigen's Eigensolver to match their API. Remove ugly invocation from the matrix class

* invoke via namespace

* add is_float static assert check to fail early if users call these functions with incompatible types

* pass reference

* make these references too
* update i/j to row/col

* add free function for flat matrix definition

* i/j -> row/col
* ignore all generated things

* regenerate this w/o formatting
Comment thread .github/workflows/main.yml Outdated
* add profiling first pass

* add profiling scripts

* revert eigen changes

* add profiling

* add more cases

* update profiling

* update readme

* update this to remove time stamp

* DRY

* pull in function

* exclude generated files from formatting

* remove formatting

* regenerate profiling cases

* missed checking these in

* allow failure to capture time

* capture failures

* add more plots

* add matrix helper

* check in raw data

* use itertools

* massage profiling data

* correctly apply compiler limits

* cmake overhead causes profiling to be very slow, so extract args from compile_commands.json and manually apply them

* update data

* clean up profile generation and plotting

* clean-up

* add in lfs png

* update readme

* do not check in so many files

* readme update

* clean dir

* check in generated cases

* do not check in this file

* update readme

* reran profiling

* support macos

* add uv to Dockerfile

* bump tag

* re-ran profiling and update readme

* ran uv in container and update tool to pull in deps

* remove this

* include os name in data

* do not need pyproject

* address MR feedback

* reran profiling with new data

* address MR

* get feedback

* regenerate test cases determanistically

* workflow dispatch to use same technique as PR for finding Dockerfile changes

* fix diff command

* more git diff fix

* change diff stragety to support busybox

* address MR feedback;

* clean up documentation

* update readme

* more clean-up

* clean up redundant language

* readme clean-up
* first pass at generating docs

* update

* fix

* readme update

* clean-up

* update code docs

* start migrating docs

* add a performance md

* clean up index

* tighten up language

* language update

* language corrections

* slight update

* updates

* docs update

* use consistent titling

* update LICENSE and NOTICE

* update language

* get rid of weird ASCII symbols

* pare down README.md

* Add development.md

* move things around

* slight update

* more updates

* lots of updates

* host this temporarily

* lint

* language update

* move images around

* update workflow and see if symlinks are correct

* run pipeline on push

* git lfs

* this is almost certaintly not the issue

* fix gitattributes

* this feels like it will not work

* update doxy

* reorder

* address feedback

* address MR feedback

* forgot this

* address MR feedback

* better test name

* supposedly this will fix the image location

* address MR feedback

* fix link

* I think git lfs was messed up?

* try to address CI failure for check-generated

* re-order sections slightly

* target develop

* minor permissions and workflow update
* see what changed

* force architecture selection for OPENBLAS

* regenerate test cases

* add schedule

* try using ZEN3 since that's what I used locally

* revert (sort of) the cases changes. I changed the solver BLAS was using to be the same one I use. I'm hoping that it causes the gitlab runner to be consistent but who knows

* do not overwrite container on scheduled jobs

* go back to build and test

* add slight wording update
* make references point to main now

* use main for badge
@MitchellThompkins
Copy link
Copy Markdown
Owner Author

@coderabbitai summary

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 29, 2026

✅ Actions performed

Summary regeneration triggered.

@MitchellThompkins MitchellThompkins marked this pull request as ready for review March 29, 2026 01:59
@MitchellThompkins
Copy link
Copy Markdown
Owner Author

@coderabbitai summary

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 29, 2026

✅ Actions performed

Summary regeneration triggered.

@MitchellThompkins MitchellThompkins merged commit 35d4157 into main Mar 29, 2026
13 checks passed
@MitchellThompkins MitchellThompkins deleted the develop branch March 29, 2026 06:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant