Gaussian Naive Bayes — Machine Learning/Classical Models
Machine_Learning/Classical_Models/Gaussian_Naive_Bayes · 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 Naive Bayes
Machine Learning / Classical Models
A fitted Gaussian naive Bayes classifier, evaluated one sample at a time. Each class scores the sample by its own per-feature Gaussian, and the highest score wins:
logp[k] = log(prior[k]) − ½ Σj [ log(2π·var[k][j]) + (u[j] − mu[k][j])² ÷ var[k][j] ]
This is sklearn.naive_bayes.GaussianNB with theta_,
var_ and class_prior_ pasted in. It is the cheapest
probabilistic classifier there is – no matrix inverse, no kernel, no tree
walk – and it reports a calibrated-ish score per class rather than only a
decision, which is what lets a controller refuse to act when nothing scored
well.
Everything logarithmic is folded at configuration time, so the sample loop is subtract, square and multiply-accumulate and nothing else. That is what keeps this block synthesizable in fixed point.
Ports
- u – the sample, a [d,1] column, where d is the number of COLUMNS of Class Means. One sample per step; it is checked rather than broadcast.
- idx – [1,1], the winning class, plus Index Base. This is what a controller switches on.
- logp – [K,1], every class's log-score in class order,
where K is the number of ROWS of Class Means. The winner's own score is
logp[idx], so nothing downstream has to recompute it; feed the whole vector to Softmax for posteriors, or to Confidence Gate or Top K for a decision with a threshold.
Parameters
- Class Means – mu, a [K,d] matrix, one class per
ROW. This is sklearn's
theta_orientation, so it pastes in without transposing. Its shape decides both K and d. - Class Variances – var, [K,d] to match:
sklearn's
var_. Per class AND per feature – that the features are treated as independent within a class is exactly what makes the model "naive". - Class Priors – [K,1], sklearn's
class_prior_. Every entry must be greater than zero; a class with a zero prior can never win, and the log of it is not a number. - Variance Floor – the smallest variance used, applied before the
reciprocal is taken. sklearn's
var_smoothingexists for the same reason: a feature that never varied in training has zero variance and would divide by zero here. It is applied ONCE at configuration load, so it costs the generated code nothing. - Index Base – what the first class is numbered, spelled exactly
as Argmax Decision and K Means Assign spell it:
- Zero-based (PyTorch, numpy) – the first class is 0.
- One-based (MATLAB) – the first class 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 class's score is unrolled at export time, and
the constants baked into it are the FOLDED ones – one c[k] per
class carrying the log prior and all d log normalizers together, and one
−½/var[k][j] per feature. No logarithm, no division and
no exponential survives into the generated code.
The three HDL targets are therefore genuine synthesizable
Q16.16, not the simulation-only real arithmetic this family's
activation and distance blocks need: what is left in the datapath is a subtract,
a square, a multiply and an add per feature, then a comparison chain.
Simulink bridge
None. Simulink's classifier blocks live in the Statistics and Machine
Learning Toolbox, which is not installed on this machine – so there
is no ClassificationNaiveBayes predict block here to map onto, and a
bridge could not be verified even if it were written, since the parity suite
would need that toolbox on the machine running it. Independently of that, those
blocks take a fitted model OBJECT rather than parameter matrices, which no
configuration value can carry across the bridge. The block therefore has no
parity testbench, which is the documented consequence of
Support::None. Code export verification still covers it across all
ten languages.
Notes
- Stateless and algebraic: the answer depends on the current sample only.
- No state space: the score is quadratic in the input and the decision is a comparison, so no A/B/C/D describes it and model reduction correctly refuses the block.
- Ties go to the LOWEST class index. The scan keeps its running best and replaces it only on a strictly greater score – the same rule Argmax Decision states and K Means Assign mirrors for its argmin. Every backend spells the identical scan, because the samples that tie are exactly the ones where two implementations that both "find the maximum" disagree.
- The index is a DISCONTINUOUS function of the input. The three HDL targets compare Q16.16 values where the reference compares doubles, so two classes whose scores sit within one quantum (about 1.5×10−5) of each other can rank the other way round, and the index then differs by a whole step. That is a property of the block, not of the generated code; the logp output is continuous and does not have it.
- Naive, and it says so in the name. The features are assumed independent within a class. When they are not, use Mahalanobis Distance or a Gaussian Mixture Model, which carry a full covariance.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Classical_Models/Gaussian_Naive_Bayes |
| family | Machine_Learning/Classical_Models |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Classical_Models_2_Gaussian_Naive_Bayes |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Classical_Models/Gaussian_Naive_Bayes/ICoreBlock_0_Machine_Learning_1_Classical_Models_2_Gaussian_Naive_Bayes.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Classical_Models/Gaussian_Naive_Bayes/ICoreBlock_0_Machine_Learning_1_Classical_Models_2_Gaussian_Naive_Bayes.h |
| default size on canvas | 134 × 88 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 | logp |
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 |
|---|---|---|
Class Means | [0.4 -0.3; -0.6 0.8; 1.1 0.2] | — |
Class Variances | [0.5 0.7; 0.6 0.4; 0.8 0.55] | — |
Class Priors | [0.35; 0.4; 0.25] | — |
Variance Floor | 1e-9 | — |
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 naive Bayes predict block lives 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 Naive Bayes — a fitted GaussianNB evaluated at inference logp[k] = c[k] + SUM_j w[k][j] * (u[j] - mu[k][j])^2 idx = argmax_k logp[k] + base
Read the header before this file: it records the fold (every log is config-only, so none of it reaches the sample loop and the three HDL targets stay genuine Q16.16), the two-output shape, and the tie rule this block shares with Argmax_Decision and K_Means_Assign.
⚠ The FOLDED tables are what every generator emits --
_cand_w, never_means/_varsdirectly, and never anything a run has touched. The C++ reference below folds once in loadBlockConfig() and then computes from the same two tables, so the simulation and all ten exports evaluate the identical expression in the identical order.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Gaussian Naive Bayes. 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_Naive_Bayes.json