libeigen/eigen!2718 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. AGENTS.md is the AI-facing repository contract and routes
readers to focused guides for testing, numerical work, performance, SIMD/GPU, Tensor/ThreadPool, and CI. Those guides
are also useful to human contributors working in the corresponding areas.
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
this file and the guide map in
AGENTS.md) - 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.
For focused build recipes, test registration, split-test mechanics, and assertion guidance, see
.agents/testing.md. Packet and accelerator validation is covered by
.agents/simd-gpu.md. The checked-out CMake files remain authoritative for current options.
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 repository-wide rules are in
AGENTS.md, which also routes to task-specific guidance. 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— repository-wide agent contract, standard workflow, essential Eigen hazards, and the map to task-specific guidance.- Task guides: testing, numerical code, benchmarking, SIMD/GPU, Tensor/ThreadPool, and formatting/CI.
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!