Generated reference › Invert 3x3 Matrix — Control Systems/Matrix Operations
kind: generated#block#control-systems-matrix-operations

Invert 3x3 Matrix — Control Systems/Matrix Operations

-1

Control_Systems/Matrix_Operations/Invert_3x3_Matrix · 1 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Description#

The block's own DESCRIPTION_HTML, rendered verbatim — the same text the config dialog's info panel and the library navigator show. Fix a wrong sentence in the block's .cpp (R-D9), never here.

Invert 3x3 Matrix

Control Systems / Matrix Operations

The inverse of a 3×3 matrix, in closed form:

  • A⁻¹ = adj(A) / det(A)

Nine 2×2 minors over one six-term determinant. There is no elimination and no pivoting, so the same arithmetic runs on every sample and the block never takes a data-dependent number of steps.

It is exactly the companion Adjoint of 3x3 Matrix divided by Determinant of 3x3 Matrix, and the three blocks emit the same two expressions, so they agree with each other to the last bit.

⚠ A singular matrix – determinant exactly zero – has no inverse, and the block answers all zeros rather than infinities. The test is on an exact zero, not on a tolerance band: a near-singular matrix has a real inverse with large entries and gets it.

Ports

  • A – the matrix, a [3,3] signal. The size is fixed: this is the 3×3 closed form and nothing else.
  • inv(A) – the inverse, also [3,3]; all zeros where the determinant is exactly zero.

Parameters

  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

Code export

All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. Nothing is exposed as a tunable parameter, because the block has no parameter at all – the matrix arrives on a port.

Every core computes the determinant once and divides each of the nine minors by it, guarded by the same exact-zero test the block itself uses. The seven software targets carry the determinant in double precision; the three hardware ones carry it in Q16.16 and divide in real.

The three HDL targets are simulation-only. Nine divisions by a quantity that is itself a difference of six triple products has no useful fixed-point form – the divisor can be many orders smaller than the terms it is built from – so the generated cores convert at the port boundary and evaluate in real arithmetic. Correct in simulation, and not offered as synthesizable. On a singular matrix they answer zeros for a second reason as well: fixed point has no infinity and no NaN to return.

Simulink bridge

Both directions, onto aerolibutil/Invert 3x3 Matrix in the Aerospace Blockset. The block has no configuration, so no parameter pairs cross.

Its name is drawn on two lines, so the real library path carries an embedded newline after Invert – and a trailing space before it; the flattened one-line spelling resolves to nothing at all. And the block defines no SampleTime parameter, so the rate stays on the ICore side and a block configured with an explicit positive rate reports that the rate did not cross.

⚠ The two blocks do not compute the inverse the same way, and they are not bit-identical. Under the Aerospace block's mask are its determinant, an assertion and a solve: the determinant is there to reject a singular matrix, and the inverse comes from the solve. Measured on A = [1 2 3; 4 −5 6; 7 8 −9], it agrees with this block to about 2×10⁻¹⁷ – the last two or three bits – which is eight orders inside the tolerance the two are compared at. The other difference is at the singular matrix itself, where Simulink raises an assertion and this block answers zeros.

Notes

  • Algebraic and stateless: the output depends only on the current input, so the block cannot break an algebraic loop.
  • Deliberately no state space. An inverse is a rational function of its input, so there is no linear form to fabricate, and model reduction refuses a block whose feed-through is nonlinear.
  • Conditioning is the user's to watch. The closed form is accurate for a well-conditioned matrix and loses digits for an ill-conditioned one exactly as any other method would; what it does not do is fail differently on different samples, because it never pivots.

Code facts#

FactValue
registered typeControl_Systems/Matrix_Operations/Invert_3x3_Matrix
familyControl_Systems/Matrix_Operations
solver environment classICoreBlock_0_Control_Systems_1_Matrix_Operations_2_Invert_3x3_Matrix
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Matrix_Operations/Invert_3x3_Matrix/ICoreBlock_0_Control_Systems_1_Matrix_Operations_2_Invert_3x3_Matrix.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Matrix_Operations/Invert_3x3_Matrix/ICoreBlock_0_Control_Systems_1_Matrix_Operations_2_Invert_3x3_Matrix.h
default size on canvas112 × 70 px
ports at insert1 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleA
2outICoreDoubleinv(A)

Ports the constructor creates. A block whose port list changes with its configuration adds or removes ports at load time; the count above is the one a freshly inserted block has.

Configuration variables#

No config variable beyond the Sampling Time (s) every block carries.

Every block also carries Sampling Time (s) from ICoreBlockSolverEnvironment: zero or less inherits the solver's rate, a positive value runs the block at that period.

supportSupport::Both
Simulink pathaerolibutil/Invert \n3x3 Matrix
port-count rulePortsParam::None
SampleTime parameterno — the counterpart defines none; the rate stays on the ICore side

Caveat (shown to the user): the Aerospace Blockset block is a masked subsystem with no dialog parameters, so nothing but the signal crosses. ⚠ The two do NOT compute the inverse the same way: under that mask are a determinant, an ASSERTION and a solve, so the determinant rejects a singular matrix and the inverse comes from the solve, where this block evaluates adj(A)/det(A). Measured, they agree to about 2e-17 -- eight orders inside the algebraic tolerance -- and differ at a singular matrix, where Simulink asserts and this block answers zeros. Note it defines no SampleTime parameter: an ICore rate set explicitly stays on this side and is reported

Catalog contract: src/ICoreBlocks/ICoreCoder/ICoreCommandSystem/SimulinkBridge/ICoreSimulinkBlockCatalog.h

Description vs code#

The checker has a blind spot here — it could not resolve something (a grouped port bullet, a computed config name), which is reported and never counted as a pass. A reader has to settle it:

  • B0 every stimulus in the sample errored — cross-checks skipped

The verdict above is tools/docs/check_block_descriptions.py (P7.1), which compares LISTS. It cannot read a sentence: "stateless" on a block with a state, an initial-value semantic the recursion does not implement, a "not synthesizable" caveat the HDL banner contradicts. That is the agent audit (P7.3) on BLOCK_DESCRIPTION_AUDIT.md, and this tool's green is not a substitute for one.

File banner (developer view)#

The top comment of the block's .cpp — the maths, the realization and the export strategy, addressed to whoever changes it. It must not contradict the description above (P7.5).

Invert 3x3 Matrix -- A^-1 = adj(A) / det(A), closed form One [3,3] input, one [3,3] output. Nine 2x2 minors over one six-term determinant: the same two expressions the Adjoint and Determinant siblings emit, repeated here rather than shared, so the three blocks agree bit for bit on the same input.

MEASURED against aerolibutil/Invert \n3x3 Matrix (R2026a, 2026-09-10), and what came back is a finding rather than a confirmation. Under the mask are the Determinant subsystem, an Assertion and one Product block: the determinant is there to ASSERT non-singularity, and the inverse comes out of a SOLVE. On A = [1 2 3; 4 -5 6; 7 8 -9] the block's answer equals MATLAB's A\eye(3) exactly and equals neither adj(A)/det(A) nor inv(A) -- the three agree to about 2e-17 and differ in the last two or three bits.

This block emits the closed form anyway, deliberately, for two reasons. An LU solve with pivoting has no useful shape in a Q16.16 datapath, so three of the ten targets could not carry it; and the parity band for an algebraic block is 1e-12, eight orders wider than the disagreement. The description says all of this where a user will read it rather than claiming a bit-exact match the block does not have.

A SINGULAR matrix answers ALL ZEROS. The test is on the determinant being EXACTLY zero, not on a tolerance band: a near-singular matrix has a genuine inverse with large entries and gets it, and only the one value that would divide by zero is intercepted. The three hardware targets take the same branch, where the reason is sharper still -- fixed point has no infinity and no NaN to return.

The three HDL targets are SIMULATION-ONLY real arithmetic: nine divisions by a quantity that is itself a difference of six triple products has no synthesizable Q16.16 form. They quantize at the port boundary and evaluate in real, which is correct in simulation and is not offered as hardware.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at Invert 3x3 Matrix block: ICore Blocks/Home/Invert 3x3 Matrix. That is a fact about the single-block rig, not a verdict on the block: an offline batch fit, a block whose output only appears at onSolverFinish, or one that needs a driven environment cannot be exercised alone.

Category unsampled · sample time 0.1 · 60 steps · commit 7d7903fbad81ee6be6501ad2be0e1260e9995f8f · produced by docsSample --out <folder> --blocks Determinant_Of_3x3_Matrix Adjoint_Of_3x3_Matrix Invert_3x3_Matrix Create_3x3_Matrix --steps 60

Sample data: docs/generated/samples/Control_Systems__Matrix_Operations__Invert_3x3_Matrix.json