libeigen/eigen!2574 Co-authored-by: Rasmus Munk Larsen <rmlarsen@gmail.com>
17 KiB
Contributing to Eigen
Eigen is written and maintained by volunteers. Contributions — code, documentation, bug triage, tests on uncommon platforms, design feedback — are all welcome.
This document is the human-facing on-ramp. For the deeper "how this codebase actually works" reference (architecture, expression templates, SIMD layer, GPU stories, pitfalls), see AGENTS.md; it's written for AI coding agents but is also the most up-to-date single-file overview of the repo.
Where Eigen lives
- Upstream repository: https://gitlab.com/libeigen/eigen — bugs, merge requests, and discussion all happen here. The GitHub mirror is read-only.
- Issue tracker: https://gitlab.com/libeigen/eigen/-/issues
- CI pipelines: https://gitlab.com/libeigen/eigen/-/pipelines
- API documentation (nightly): https://libeigen.gitlab.io/eigen/docs-nightly
- Project site: https://libeigen.gitlab.io (note: some pages predate current practice — when in doubt, prefer
AGENTS.mdand this file) - Chat: Discord — the primary support and discussion channel.
Ways to contribute
You don't have to write C++ to help.
- Answer questions on Discord. New users often ask things that point at gaps in our documentation — patches to fill those gaps are very welcome.
- Triage bugs. Reproduce reports, ask reporters for missing details (compiler, OS, ISA, minimal example), and weigh in on issues labelled
decision needed. Issues labelledcontributions welcomeare good entry points. - Run the test suite on rarely-tested compilers, OSes, or architectures and report failures. The nightly matrix is visible in the CI pipelines link above.
- Improve documentation — both the Doxygen reference (comments in headers) and the prose pages at https://gitlab.com/libeigen/libeigen.gitlab.io.
- Contribute code — bug fixes, new features, new tests, new benchmarks. See below.
Submitting a merge request
- Sign in to GitLab and fork https://gitlab.com/libeigen/eigen.
- Clone your fork and add
libeigen/eigenas an upstream remote (use thehttps://clone URL if you don't have an SSH key set up):git clone git@gitlab.com:<your-username>/eigen.git # or: https://gitlab.com/<your-username>/eigen.git cd eigen git remote add upstream https://gitlab.com/libeigen/eigen.git - Create a topic branch off
masterfor your change:git fetch upstream git checkout -b my-topic upstream/master - Make your changes, with tests (and a benchmark if it's a performance-sensitive change — see Tests and benchmarks).
- Format with
clang-format-17(see Coding standards). - Commit with an
Area: short imperative subjectmessage (see Commit messages). Stage files by path — don't usegit add -A. - Push to your fork and open a merge request against
libeigen/eigenmaster. - Be patient and responsive. Reviewers are volunteers; reviews can take a while. If your MR is being ignored for a long time, don't be shy about pinging it.
If you're planning a large change (new module, API redesign, significant refactor), open an issue or start a discussion first. Aligning on direction before you write code avoids wasted work for everyone.
Build and test
Eigen is header-only, so consumers don't need to build the library itself — but contributors do need to build the test suite. CMake configure happens out-of-source, and tests are intentionally not in the default all target — drive everything through the named targets.
cmake -S . -B build -G Ninja
cmake --build build --target buildtests # build all unit tests
cmake --build build --target check # build + run all tests
cmake --build build --target buildsmoketests # the smoke set CI gates MRs on
ctest --test-dir build --parallel --output-on-failure
Other useful targets: BuildOfficial (just test/), BuildUnsupported (just unsupported/test/), buildtests_gpu, check_gpu. Once configured, the build dir also exposes ./buildtests.sh <regex> and ./check.sh <regex> for narrowing by test-name regex.
Full reference for CMake options (per-ISA test flags, GPU/SYCL toggles, external BLAS/LAPACK, etc.), the test-split mechanism, and the VERIFY_* macro family lives in AGENTS.md § "Build / test".
In-flight migration: MR 2159 is migrating the test framework from Eigen's own
EIGEN_DECLARE_TEST/CALL_SUBTEST_Nmacros to Google Test. Until it lands, write new tests with the existing framework (test/main.h,VERIFY_*,EIGEN_DECLARE_TEST,ei_add_testin the matchingCMakeLists.txt).In-flight rename: MR 2522 renames the top-level
unsupported/directory tocontrib/. Paths in this document follow master (stillunsupported/); substitutecontrib/mechanically once it lands.
Tests and benchmarks
- Every new feature lands with tests. Bug fixes should add a regression test that fails before the fix and passes after.
- Performance-sensitive changes land with a benchmark under
benchmarks/orunsupported/benchmarks/. Don't defer benchmarks to a follow-up MR. - Cover numerical corner cases, not just typical inputs: ±0, ±∞, NaN, subnormals, domain boundaries, near-overflow / underflow values. Decomposition and solver tests should exercise ill-conditioned and structured matrices (Hilbert, Vandermonde, rank-deficient, near-singular, Jordan blocks, …). The bar is matching LAPACK on conditioning, pivoting strategy, and backward stability. Standard references: Higham's Accuracy and Stability of Numerical Algorithms / Functions of Matrices, Golub & van Loan's Matrix Computations.
- New SIMD intrinsics need a
test/packetmath.cppentry (orunsupported/test/special_packetmath.cppfor special functions), and a specialization in every architecture backend that supports the type.Eigen/src/Core/arch/Default/holds generic SIMD implementations shared across backends; scalar fallbacks live inEigen/src/Core/GenericPacketMath.handEigen/src/Core/MathFunctions.h. - Benchmarking discipline. Benchmarks on a loaded system are meaningless. Before running one: check
uptimeshows a low load average, finish or cancel background builds, and never run two benchmark binaries in the same shell invocation (parallel or chained with&&). Run each in its own shell, take medians within a binary, and optionally alternate (A, B, A, B) across separate invocations to detect drift.
Coding standards
Eigen has a few hard rules that catch contributors most often. The full discussion is in AGENTS.md § "Agent guidelines (read first)"; the short version:
- Header-only contract. Never
#includeanything underEigen/src/...orunsupported/Eigen/src/...—InternalHeaderCheck.hmakes that a hard compile error. User code reaches implementation only through the umbrella headers (Eigen/Core,Eigen/Dense,Eigen/SVD, …). - Preserve
EIGEN_DEVICE_FUNCon coefficient-level methods. Dropping it silently breaks CUDA / HIP / SYCL builds and rarely shows up in local testing. - Format with
clang-format-17exactly — Google base, 120 columns, configured in.clang-format. Newer or olderclang-formatwill diff against CI. Runscripts/format.sh(whole tree) orclang-format-17 -i <file>(one file) before pushing. Format failures are the single most common reason an MR is red. - Don't apply general C++ "modernize" cleanups. No
modernize-*/cppcoreguidelines-*clang-tidy fixes, no replacingEIGEN_STRONG_INLINEwithinline, no reordering includes (.clang-formathasSortIncludes: false). Eigen's conventions are encoded in.clang-format'sStatementMacrosandAttributeMacroslists — don't "fix" their indentation. - Tests use
test/main.h, not gtest (today — see migration note above).VERIFY_*assertions,CALL_SUBTEST_N/EIGEN_TEST_PART_Nfor splitting,EIGEN_DECLARE_TEST(<name>) { ... }as the entry point. autotraps.auto x = A + B;captures a lazy expression holding references that can dangle. Use.eval()or an explicit type. Similarly,.noalias()is a promise from the caller — only use it when the destination doesn't appear on the right side (somat.noalias() = mat * matis wrong).- Stage commits explicitly. Don't
git add -A/git add .— the repo root accumulates.vscode/,.idea/,build*/, and other untracked files that must not enter commits. Add by path or with targeted globs.
Naming conventions:
- Classes: PascalCase (
Matrix,BDCSVD). - Methods: camelCase (
coeffRef,applyOnTheLeft). - Macros and compile-time constants:
EIGEN_UPPER_CASE(EIGEN_DEVICE_FUNC,EIGEN_STRONG_INLINE). - Internal implementation lives in the
Eigen::internalnamespace; public API stays inEigen::or module namespaces. - Use
eigen_assert(cond)for runtime preconditions (not rawassert);EIGEN_STATIC_ASSERT(cond, MSG_TOKEN)for compile-time conditions;eigen_internal_assertfor internal-only invariants gated onEIGEN_INTERNAL_DEBUGGING.
The canonical class layout is visible in recent additions such as unsupported/Eigen/src/GPU/DeviceMatrix.h. Template parameters that get re-exported as public aliases carry a trailing underscore (template <typename Scalar_, ...> paired with using Scalar = Scalar_; — prefer using over typedef in new code), member variables use an m_ prefix (m_matrix, m_isInitialized), implementation headers under Eigen/src/... begin with // IWYU pragma: private and #include "./InternalHeaderCheck.h", header guards follow EIGEN_<NAME>_H, and implementation detail lives inside nested namespace Eigen { namespace internal { ... } }. Public classes carry Doxygen blocks (\class, \brief, \tparam, \sa) and link to runnable snippets from doc/snippets/ via \include / \verbinclude. When in doubt, copy the style from a recent neighbouring file rather than inventing a new convention.
License and SPDX/REUSE headers
Every new source file must carry an inline copyright + license header. The checkformat:reuse CI job (reuse lint) blocks otherwise. Two header styles are in active use; pick whichever fits.
Attributed to an individual contributor:
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) <year> <Your Name> <your.email@example.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
Attributed collectively (common for files written by multiple contributors, or where individual attribution isn't useful):
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) <year> The Eigen Authors.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0
Markdown docs, generated files (*.in), and binary assets that can't carry inline headers are covered by path annotations in REUSE.toml — add your path there if you're creating one.
Provenance and attribution
This is non-negotiable.
- Eigen code must be original, or derived from publicly published MPL-2.0-compatible material.
- Do not copy — verbatim, paraphrased, or "translated" to another syntax — from incompatibly-licensed sources (proprietary, NDA-encumbered, prior-employer internal, GPL/AGPL). Paraphrasing is still a derivative work. The same discipline applies to AI-suggested code: cite the source, or rewrite from a known reference and cite that, or drop it. Ideas aren't copyrightable; specific expressions are — learn from the source, write your own, and credit it.
- Cite published references inline when they inform an implementation: LAPACK / LAWN, ACM TOMS / SIAM papers, Higham, Golub & van Loan, textbook algorithms, Boost components, vendor application notes — by name (author, year, identifier). A comment or Doxygen
\noteblock is enough. - When copying permissively-licensed code into an MPL-2.0 file, follow Mozilla's Guidelines for Developers.
Copyright and credit
- No copyright assignment. Everyone keeps copyright on their own contributions. There is no CLA.
- Commit under your own identity. Make sure
user.nameanduser.emailin your git config are set to credit you correctly. - When contributing on behalf of your employer, commit in your own name where possible rather than your employer's.
- For substantial improvements to a source file, feel free to add yourself to its copyright line — but it isn't required; you get copyright implicitly on the code you wrote. The collective
The Eigen Authorsattribution is fine when individual credit isn't useful.
Commit messages
Format: Area: short imperative subject.
Examples (from recent history):
BDCSVD: fix edge caseGPU: Drop direct LruCache.h include from CuBlasSupport.hci: drop CodeRabbit summaryTriangularView: alias-aware fallback for structured-diagonal product fast path
Keep the subject under ~72 characters; use the body for the why, not the what — the diff already shows what changed. Reference issues by #<n> when relevant.
Quality bar
Eigen aspires to state-of-the-art on two axes — performance and numerical accuracy / IEEE-754 conformance — and treats them as separate goals that are sometimes in tension.
- Performance. Eigen Core is mostly optimized for single-core throughput via per-architecture packet backends (SIMD) and cache-aware blocking. Multi-core in Core is opt-in (OpenMP or
EIGEN_GEMM_THREADPOOL) and covers a subset of operations. The Tensor module is multi-core by design viaThreadPoolDevice. - Numerical accuracy. LAPACK-level for linear algebra (decompositions, solvers — backward stability, pivoting, conditioning) and C++ standard-library level for standard math functions on scalars. On regular inputs, a few ULPs of error in vectorized math is the long-standing trade-off for SIMD throughput; larger deviations need explicit justification.
- IEEE-754 / special values. For special values (NaN, ±0, ±∞, subnormals, singularities, branch boundaries — e.g.
log(0),pow(0, 0)) the bar is exact conformance to IEEE 754 / ISO C / C++ specifications, with cppreference as the authoritative spec. Special-value handling is not subject to the few-ULPs trade-off.
For decompositions and solvers specifically, the bar is matching LAPACK on conditioning, pivoting strategy, and backward stability. Don't trade numerical robustness for speed in those code paths without explicit sign-off.
Load-bearing modules
Some "unsupported" modules carry stability guarantees beyond what the name suggests:
unsupported/Eigen/TensorandEigen/ThreadPooltogether form TensorFlow's core compute backend. "Unsupported" here means looser API-stability guarantees — it does not mean low-traffic or low-stakes. Breaking changes to header layout, signatures, semantics, or contraction / reduction kernel performance ripple into every TensorFlow build. Prefer additive changes, keep header paths stable, rununsupported/test/tensor_*before submitting, and call out any behaviour change prominently in the MR description.
Communication
- Discord is the primary chat channel (link above). Most informal design discussion happens there.
- GitLab issues are the place for bug reports, feature requests, and threaded design discussions tied to a specific topic.
- For larger contributions, discuss the plan first to avoid duplicated effort and to align on API decisions before implementation.
Further reading
AGENTS.md— deep dive on architecture, expression templates, evaluators, the SIMD packet layer, CUDA / HIP / SYCL, multi-threading, common pitfalls, and CI structure.README.md— high-level project description and pointers to the websites.CHANGELOG.md— release-by-release notes.- API reference (nightly): https://libeigen.gitlab.io/eigen/docs-nightly.
Thank you for contributing to Eigen!