Adjoint Of 3x3 Matrix — Control Systems/Matrix Operations
Control_Systems/Matrix_Operations/Adjoint_Of_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.
Adjoint of 3x3 Matrix
Control Systems / Matrix Operations
The adjugate of a 3×3 matrix – the transpose of the cofactor matrix, and the matrix that satisfies
- A · adj(A) = adj(A) · A = det(A) · I
Each of the nine entries is one 2×2 minor with a checkerboard sign: adj(A)(i,j) = (−1)i+j Mji, where Mji is the determinant of A with row j and column i deleted. Note the swapped subscripts – that transpose is what makes it the adjugate rather than the cofactor matrix.
There is no division, so a singular matrix is not a special case: its adjugate is an ordinary matrix, and it is where the inverse cannot go. Dividing this output by Determinant of 3x3 Matrix gives exactly what Invert 3x3 Matrix computes.
Ports
- A – the matrix, a [3,3] signal. The size is fixed: this is the 3×3 closed form and nothing else.
- adj(A) – the adjugate, also [3,3].
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 entry is emitted as a single p·q − r·s. The cofactor's sign is folded in by swapping the two products rather than by negating their difference, so all ten backends carry one shape; negation is exact in floating point, so the two spellings are the same number.
The three HDL targets are genuinely synthesizable Q16.16, not simulation-only: two multiplies and one subtract per entry, no division, root or trigonometry. The whole difference is formed before it is brought back to Q16.16, so the rounding lands on the difference rather than on each product separately.
⚠ Size the matrix before exporting to hardware. Each entry is quadratic in the matrix, so entries near 180 already reach the top of the Q16.16 range (±32768). The software targets have no such limit.
Simulink bridge
Both directions, onto aerolibutil/Adjoint of 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 between of and 3x3; 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.
Notes
- Algebraic and stateless: the output depends only on the current input, so the block cannot break an algebraic loop.
- Deliberately no state space. Every entry is quadratic in the input, so there is no linear form to fabricate, and model reduction refuses a block whose feed-through is nonlinear.
- ⚠ The adjugate, not the cofactor matrix. They differ by a transpose and agree on the diagonal, so the difference is only visible off it. On A = [1 2 3; 4 −5 6; 7 8 −9] this block's first row is [−3 42 27]; the cofactor matrix's first row would be [−3 78 67].
- Not linear in A, despite looking tidy: adj(2A) = 4·adj(A) in three dimensions, not 2·adj(A).
Code facts#
| Fact | Value |
|---|---|
| registered type | Control_Systems/Matrix_Operations/Adjoint_Of_3x3_Matrix |
| family | Control_Systems/Matrix_Operations |
| solver environment class | ICoreBlock_0_Control_Systems_1_Matrix_Operations_2_Adjoint_Of_3x3_Matrix |
| source | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Matrix_Operations/Adjoint_Of_3x3_Matrix/ICoreBlock_0_Control_Systems_1_Matrix_Operations_2_Adjoint_Of_3x3_Matrix.cpp |
| header | src/ICoreBlocks/ICoreBlockLibrary/Blocks/Control_Systems/Matrix_Operations/Adjoint_Of_3x3_Matrix/ICoreBlock_0_Control_Systems_1_Matrix_Operations_2_Adjoint_Of_3x3_Matrix.h |
| default size on canvas | 112 × 70 px |
| ports at insert | 1 in, 1 out |
| code generators implemented | Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text |
Ports#
| # | Direction | Signal type | Description label |
|---|---|---|---|
| 1 | in | ICoreDouble | A |
| 2 | out | ICoreDouble | adj(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.
Simulink bridge#
| support | Support::Both |
| Simulink path | aerolibutil/Adjoint of\n3x3 Matrix |
| port-count rule | PortsParam::None |
SampleTime parameter | no — 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. It is the ADJUGATE (the transpose of the cofactor matrix), measured rather than assumed: it answers integers where det(A)*inv(A) would round. 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:
B0every 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).
Adjoint of 3x3 Matrix -- adj(A), the ADJUGATE One [3,3] input, one [3,3] output. Nine 2x2 minors, each two products and one subtraction: algebraic, stateless, and with no division anywhere, so no matrix is a special case.
MEASURED against aerolibutil/Adjoint of\n3x3 Matrix (R2026a, 2026-09-10). On A = [1 2 3; 4 -5 6; 7 8 -9] it answers
[-3 42 27] [78 -30 6] [67 6 -13]
exactly -- integers, not the rounded values det(A)*inv(A) would give -- which is both the adjugate and the proof that the Simulink block evaluates the closed form rather than scaling an inverse. ⚠ THE COFACTOR MATRIX WOULD HAVE FIRST ROW [-3 78 67]: the adjugate is its TRANSPOSE, and the two agree on the diagonal, so a spot check of one diagonal element confirms whichever one you already believed.
Each entry is emitted as one "p*q - r*s". The cofactor's sign is folded in by SWAPPING the two products rather than negating the difference, which keeps all ten backends to a single shape and costs nothing: negation is exact in IEEE arithmetic, so a - b and -(b - a) are the same number to the last bit.
The three hardware targets are GENUINELY SYNTHESIZABLE Q16.16: two multiplies and one subtract per entry, with the whole difference formed before it is brought back to Q16.16 -- Cross Product's pattern, and for the same reason, that rounding each product separately would throw away the low bits of both instead of only of their difference.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at Adjoint of 3x3 Matrix block: ICore Blocks/Home/Adjoint Of 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__Adjoint_Of_3x3_Matrix.json