Eigen underneath.
Our interface on top.

The numerics are Eigen, a mature linear-algebra library. You write against ICoreMatrix and its neighbours. Exactly one directory in the product is allowed to name Eigen, and a check that runs before every release proves nothing else does.

Eigen 5.0.0 Dense + 6 modules 0 Eigen references outside the wrapper Checked before every release
ICoreMath | the one place Eigen is named 0 leaks
You write · ICore typeswallInside ICoreMath · Eigen
  1. x = A.solve(b)→A.colPivHouseholderQr().solve(B)QR
  2. expM = (M * Ts).expm()→A.exp()Matrix fns
  3. U = A.svdU()→JacobiSVD<MatrixXd>SVD
  4. L = A.choleskyL()→LLT<MatrixXd>Cholesky
  5. v = A.symmetricEigenvalues()→SelfAdjointEigenSolver<MatrixXd>Eigenvalues
  6. r = p.roots()→PolynomialSolver<double, Dynamic>Polynomials
  7. ICoreSpline::bSplineFit(x, y, xq, 3)→SplineFitting<Spline<double, 1>>Splines
  8. ICoreFFT::forward(signal)→FFT<double>FFT
  9. fitTransferFunction(u, y, 1, 2, Ts)→LevenbergMarquardt<NumericalDiff<…>>LM
Source files checked4,178
Eigen outside ICoreMath0
VerdictPASS

Nine calls you can make, and what each one runs on the other side. The left column is all the rest of the product ever writes, and all your code needs to. The right column exists in one directory only, so every call comes back as an ICoreMatrix or another ICore type, and never as an Eigen one.

Outside the wrapper
0
Eigen references in the 4,178 source files outside the numerics module
Modules in use
7
Dense, plus six of Eigen's specialist modules
Eigen
5.0.0
a vendored copy, built with the product, so there is nothing for you to install
Boundary check
PASS
in the architecture-rules suite, run before every release
01 · What is underneath

Solved problems, not reinvented ones.

Root finding, matrix exponentials, spline fitting, spectra and nonlinear least squares are the work of a library that has done them for years. These are the modules the wrapper includes. There is one list of them, kept in one header.

Dense
Core · LU · QR · Cholesky · SVD · Eigenvalues · Geometry

The dense linear algebra behind solve, inverse, determinant, the LU, QR, Cholesky, LDLᵀ and SVD factors, pseudoInverse, rank, conditionNumber, and both the general and the self-adjoint eigensolvers. Quaternions and rotations come from its Geometry part.

Polynomials
roots

ICorePolynomial::roots(), which returns real and complex roots together.

Matrix Functions
expm · logm · sqrtm

The matrix exponential that turns a continuous state space into a zero-order-hold discrete one.

Splines
B-spline fitting

ICoreSpline::bSplineFit, which interpolates through the points at the degree you ask for.

FFT
forward · inverse

ICoreFFT, with its magnitude and phase built on top of it.

Numerical Differentiation
central differences

Jacobians of functions that have no analytic derivative.

Levenberg–Marquardt
nonlinear least squares

Fits a transfer function to measured input and output data.

02 · What you write against

It reads like the maths.

This is the product's own zero-order-hold discretization, verbatim. It builds a block matrix, scales it by the sample time and takes its exponential, and it never names Eigen. | joins matrices side by side, & stacks them, and expm() is the matrix exponential.

Every part of the product outside the numerics module that needs linear algebra is written this way, and your code would be too. Nothing on this side of the wall has to know which library is on the other side.

zero-order-hold discretization · verbatim
// Conversion idea:
//      Construct [ A  B ]  ->  [ Ad  Bd ]
//                [ 0  0 ]      [ 0   I  ]
ICoreMatrix top    = ss_cont.A | ss_cont.B;   // n x (n+m)
ICoreMatrix bottom = Z_mn       | Z_mm;       // m x (n+m)
ICoreMatrix M      = top & bottom;            // (n+m) x (n+m)

// Exponentiate
ICoreMatrix expM = (M * Ts).expm();
03 · Checked, not promised

The boundary is a test that can fail.

Keeping a dependency behind a wall usually relies on everyone being careful. Here a check scans every source file for an Eigen include, an Eigen type or the wrapper's own umbrella header, and one hit outside the numerics module fails the rule. The check runs as its own suite in the pre-release run.

01 · Need

A capability is missing

Code elsewhere needs a factorization, a norm or a fit that ICoreMatrix doesn't offer yet.

02 · Inside

It is added in the wrapper

The new code goes inside the numerics module, next to the Eigen code it uses. Nobody reaches around the wrapper to get it.

03 · Surface

It comes out as an ICore type

The caller gets a method on ICoreMatrix or a neighbouring type, never an Eigen type.

04 · Gate

The release checks it

A single Eigen reference outside the module fails the rule, and the release doesn't ship.

04 · Why the wrapping is the point

Eigen's answers, in MATLAB's shapes.

Because every call passes through one place, that place can decide what the answer looks like. A capability is added or fixed once, for every caller. These are cases where the wrapper does more than pass the call through.

Solve

Backslash semantics, and a refusal

callx = A.solve(b)
getssquare → exact · tall → least squares · wide → refused

It is a column-pivoted QR, which is what MATLAB's \ means for a tall matrix. For a wide one it refuses, rather than returning one of infinitely many solutions.

Cholesky

A failure that says where

callR = A.choleskyUpper(&p)
getsA = R'·R, or the pivot p it stopped at

This one is written by hand instead of calling Eigen's LLT, because a decomposition that only reports failure can't tell you p, the pivot where it failed. MATLAB's [R, p] = chol(A) returns it, so this does too.

Eigenvalues

Pairs you can trust

callA.symmetricEigenvalues() A.symmetricEigenvectors()
getsvalue k belongs to column k, ascending

This is the order MATLAB's eig uses for a symmetric matrix. Code that needs the pairing asks for it here by name, and doesn't have to rely on the order of two separate solvers.

Norms

Exact, not iterated

callA.norm_2()
getsthe largest singular value, from the SVD

It used to be a power iteration with a 1e-6 tolerance. It was moved onto the SVD so that it matches MATLAB's exact norm(A, 2), and every caller got the fix at once.

Honest edges

Where the wall still has a door.

  • One header names EigenICoreMatrix.h still declares two conversion members that take and return an Eigen matrix, so that one header needs Eigen to parse. It is recorded debt: a separate check allows exactly one such header, a second one fails outright, and the allowance can only go down. The Blocks SDK's public icore/ headers do not include it.
  • Two eigen accessors don't paireigenvalues() and eigenvectors() run different Eigen solvers, which order their answers by different rules. When you need value k to belong to column k, use the symmetric pair above.
  • Everything is a doubleMatrices store IEEE doubles. There are no single, integer or sparse types in the wrapper.
  • Singular matricesinverse() of a singular matrix logs an error and returns a 1×1 zero, so check the log rather than the value. inverseOrInf() gives MATLAB's all-Inf answer instead. solve() returns a vector without a warning, and nothing checks conditioning automatically, so ask conditionNumber(). The full conventions are on Numerics - what the solver will and will not do.

The whole API is in the reference: ICoreMath · Foundation, which covers ICoreMatrix, ICorePolynomial, ICoreSpline and the rest.

See also: The maths in one place  ·  Global solvers, per-rate subsystems

Get started

See it run on your own model.

Download the application from the customer portal, or read the documentation first - the manual, a page for every block, and the full command reference are public.