Gaussian Mixture Model — Machine Learning/Classical Models
Machine_Learning/Classical_Models/Gaussian_Mixture_Model · 1 input / 2 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.
Gaussian Mixture Model
Machine Learning / Classical Models
A fitted Gaussian mixture, evaluated one sample at a time. Each component scores the sample by its own full-covariance Gaussian:
logp[k] = log(w[k]) − ½·d·log(2π) + ½log(det Sinv[k]) − ½·(u − mu[k])'· Sinv[k]·(u − mu[k])
This is sklearn.mixture.GaussianMixture with weights_,
means_ and precisions_ pasted in. It is Gaussian
Naive Bayes with a full covariance: that block's per-feature variances make
the quadratic form diagonal, and carrying the off-diagonal terms is exactly the
difference between "naive" and a mixture component.
Use it as a soft clustering (which component does this sample belong to, and how strongly) or as a density model (how likely is this sample at all, which is what makes a mixture a novelty detector).
Ports
- u – the sample, a [d,1] column, d being the number of COLUMNS of Component Means.
- idx – [1,1], the winning component, plus Index Base. It is always present, whatever Output is set to.
- p – [K,1], one entry per component: either their log-likelihoods or their responsibilities, per Output. K is the number of ROWS of Component Means.
Parameters
- Component Means – mu, a [K,d] matrix, one
component per ROW: sklearn's
means_orientation. Its shape decides both K and d. - Inverse Covariances – the precision matrices, STACKED
VERTICALLY as [K·d, d]: component k occupies rows k·d to
k·d+d−1. A configuration matrix is 2-D, so a [K,d,d] tensor needs a
flattening convention and this is it. From sklearn,
numpy.vstack(gm.precisions_)produces exactly this layout. Each block must be symmetric and positive definite – both are checked, because a transposed or mis-stacked paste is otherwise a silently different model. - Component Weights – [K,1], sklearn's
weights_. Every entry must be greater than zero. - Output – what the p port carries. The two are different
code paths rather than a scaling, so each is verified as its own mode:
- Log Likelihood – the raw per-component log-likelihoods, in
component order. Their differences are what matter; the winner's own value
is
p[idx]. This is the mode to use for novelty scoring. - Responsibility – the posterior probability of each component, non-negative and summing to one: the E-step of the algorithm that fitted the model. This is the mode to use for soft clustering.
- Log Likelihood – the raw per-component log-likelihoods, in
component order. Their differences are what matter; the winner's own value
is
- Index Base – what the first component is numbered, spelled
exactly as Argmax Decision, K Means Assign and both Naive
Bayes blocks spell it:
- Zero-based (PyTorch, numpy) – the first component is 0.
- One-based (MATLAB) – the first component is 1.
- 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. Every component's quadratic form is unrolled at export time, and the constant baked in front of it is the FOLDED one: the log weight, the d/2 log(2π) and the half log-determinant together, computed once when the configuration loads. No logarithm and no determinant reaches the generated code.
The two modes differ in the HDL targets: Log Likelihood is
genuine synthesizable Q16.16 – a subtract, two multiplies and an add
per term, then a comparison chain. Responsibility exponentiates and
divides by a sum that depends on the sample, neither of which belongs in a Q16.16
datapath, so the three HDL targets carry that mode in simulation-only
real arithmetic.
In that mode the HDL cores also exponentiate the quantized log-likelihood, since the scores pass through the fixed-point output vector on their way; the difference is about one quantum in the exponent and stays far inside the verification band.
Simulink bridge
None. Simulink's mixture and clustering blocks live in the Statistics
and Machine Learning Toolbox, which is not installed on this machine, so
there is nothing here to map onto and a bridge could not be verified even if it
were written. Those blocks also take a fitted model OBJECT rather than parameter
matrices. The block therefore has no parity testbench, which is the
documented consequence of Support::None.
Notes
- Stateless and algebraic.
- The maximum is subtracted before exponentiating, exactly as
Softmax does and for the same reason: a component log-likelihood of
−40 is entirely ordinary, and
exp(−40)underflows to zero in single precision and in Q16.16 alike. Subtracting the winner makes the largest term exactly 1 and costs nothing, since the winner has already been found for the idx port. - Ties go to the LOWEST component index – Argmax Decision's rule, spelled identically in every backend.
- The index is a DISCONTINUOUS function of the input, so the three HDL targets can rank two near-equal components the other way round; one Q16.16 quantum is about 1.5×10−5. The p output is continuous and does not have that property.
- No matrix is inverted here. The precisions are configuration, as they
are for Mahalanobis Distance – no block body inverts a matrix, and
sklearn hands you
precisions_already. - For a single component this block is a log-density, and Mahalanobis Distance is the same quadratic form without the normalizer. For a DIAGONAL covariance use Gaussian Naive Bayes, which carries d terms instead of d².
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Classical_Models/Gaussian_Mixture_Model |
| family | Machine_Learning/Classical_Models |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Classical_Models_2_Gaussian_Mixture_Model |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Classical_Models/Gaussian_Mixture_Model/ICoreBlock_0_Machine_Learning_1_Classical_Models_2_Gaussian_Mixture_Model.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Classical_Models/Gaussian_Mixture_Model/ICoreBlock_0_Machine_Learning_1_Classical_Models_2_Gaussian_Mixture_Model.h |
| default size on canvas | 138 × 90 px |
| ports at insert | 1 in, 2 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 | u |
| 2 | out | ICoreDouble | idx |
| 3 | out | ICoreDouble | p |
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#
| Config variable | Default | Simulink parameter |
|---|---|---|
Component Means | [-0.5 0.3; 0.8 -0.2] | — |
Inverse Covariances | [2.5 0.6; 0.6 1.8; 1.4 -0.5; -0.5 2.2] | — |
Component Weights | [0.6; 0.4] | — |
Output | Log Likelihood%~%Responsibility~~Log Likelihood | — |
Index Base | Zero-based (PyTorch, numpy)%~%One-based (MATLAB)~~Zero-ba… | — |
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::None |
| Simulink path | — |
| port-count rule | PortsParam::None |
SampleTime parameter | yes |
Caveat (shown to the user): no Simulink equivalent available here: its mixture and clustering blocks live in the Statistics and Machine Learning Toolbox, which is not installed on this machine, so no mapping could be verified; and those blocks take a fitted model OBJECT rather than the parameter matrices this block configures
Catalog contract: src/ICoreSDK/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).
Gaussian Mixture Model — a fitted GaussianMixture evaluated at inference logp[k] = c[k] + SUM_a SUM_b W[k][a][b] * e[a] * e[b] e[a] = u[a] - mu[k][a] r[k] = exp(logp[k] - best) / SUM_j exp(logp[j] - best) best = max_j logp[j] idx = argmax_k logp[k] + base
Read the header before this file: it records the [K*d,d] stacking convention for the inverse covariances, the fold (log weights AND the determinant, at config load), why the argmax is a PORT rather than the third mode the board row asked for, and the per-mode HDL split.
⚠ ONE EMISSION SHAPE FOR ALL TEN BACKENDS: write each component's score into the output vector, scan those elements for the winner, and -- in Responsibility mode -- re-read them to exponentiate and normalize. That needs only two scratch values beyond the output itself, which is what lets VHDL (whose entire scratch is
accandacc2) spell the same algorithm as Python.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Gaussian Mixture Model. 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 ccf005c8 · produced by docsSample --out <folder> --steps 60
Sample data: docs/generated/samples/Machine_Learning__Classical_Models__Gaussian_Mixture_Model.json