Generated reference › Incremental Classification Naive Bayes Fit — Machine Learning/Incremental Learning
kind: generated#block#machine-learning-incremental-learning

Incremental Classification Naive Bayes Fit — Machine Learning/Incremental Learning

NB fit

Machine_Learning/Incremental_Learning/Incremental_Classification_Naive_Bayes_Fit · 2 input / 1 output port(s) at insert · exports to Python, MATLAB, Java, Rust, C, C++

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.

Incremental Classification Naive Bayes Fit

Machine Learning / Incremental Learning

Fits a Gaussian naive Bayes classifier online, one observation per step, and puts the model on a bus every step. For each class k it keeps the count nk and, for each predictor j, the running mean μkj and standard deviation σkj of the observations labelled k; the prior of class k is nk/Σn. This is MATLAB's incrementalClassificationNaiveBayes learner (Statistics and Machine Learning Toolbox) as Simulink's IncrementalClassificationNaiveBayes Fit block runs it. Feed the bus to an IncrementalClassificationNaiveBayes Predict block.

Ports

  • x – one observation of the P predictors, a row [1,P]. P is read off this width.
  • y – that observation's class label, [1,1]: one of Class Names. A NaN, or a label that is not one of them, fits nothing; the step still counts toward the warm-up.
  • mdl (ICoreBus) – the model after this observation, a bus of the six elements below.

The bus

  • DistrMean [K,P] – μkj; 0 for a class not yet seen.
  • DistrStd [K,P] – σkj, the POPULATION standard deviation (the sum of squared deviations divided by nk, as MATLAB's is); 0 for a class seen fewer than twice.
  • Prior [K,1] – nk/Σn; 1/K for every class before the first observation is fitted.
  • CanPredict (bool) – true from the first step, as Simulink's is.
  • IsWarm (bool) – true once Metrics Warmup Period observations arrived BEFORE this step.
  • MajorityClass (uint16) – the 1-based index into Class Names of the most frequent label so far, this one included; the first of a tie, and 1 before any.

Simulink carries the means and deviations together as one [K,P,2] element, DistrNormal; an ICore bus element is two-dimensional, so they are two here. Its Prior is 1-D [K]; here a column.

Parameters

  • Class Names – the K class labels, a row or a column of distinct numbers, at least two: MATLAB's ClassNames, which the learner requires. Order matters: it is the row order of DistrMean, DistrStd and Prior, and what MajorityClass counts in.
  • Metrics Warmup Period – how many observations come before IsWarm turns true, a whole number, 0 or more: MATLAB's MetricsWarmupPeriod, default 1000.
  • Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.

When a run is refused

x that is not a row, y that is not a scalar, Class Names that are not distinct finite numbers, or a warm-up that is not a whole number.

Code export

Six targets: Python, MATLAB, Java, Rust, C and C++, each keeping the counts, means and sums of squared deviations as persistent state and writing the six elements of the bus every step, with the update in the live block's order. The hardware targets (VHDL, Verilog, SystemVerilog) and PLC Structured Text carry no bus, so an export to one stops and names the block.

Simulink bridge

None (Support::None). Simulink's block takes its learner as InitialLearner, the name of an incrementalClassificationNaiveBayes object in the MATLAB workspace, which has no public constructor a generated script could write, so the bridge reports this block rather than dropping it, and it has no parity testbench. Code export verification covers it in the six targets above.

Notes

  • Stateful and discrete: the state is every class's count, means and sums of squared deviations, updated once per sample hit and reset at the start of a run.
  • ⚠ Every class is learned. Measured on R2026a: Simulink's block never fits the LAST class in ClassNames – its labels are counted for MajorityClass and then dropped, so with ClassNames [0 1] its Prior stays [1 0] for the whole run – while the learner's own fit learns every class. This block does what fit does.
  • ⚠ A label that is not a class fits nothing. Measured on R2026a: Simulink's block fits such an observation – a NaN label, or one not in Class Names – as the PREVIOUS valid label, and counts it for MajorityClass. Here it counts only toward the warm-up.
  • ⚠ An observation with a NaN or infinite predictor is not fitted (its label still counts for MajorityClass). Simulink's block adds it to the running sums, which leaves that class's mean and deviation NaN for the rest of the run.
  • Where both apply, the statistics agree with Simulink's to rounding: Welford's update is used for the running deviation.

Code facts#

FactValue
registered typeMachine_Learning/Incremental_Learning/Incremental_Classification_Naive_Bayes_Fit
familyMachine_Learning/Incremental_Learning
solver environment classICoreBlock_0_Machine_Learning_1_Incremental_Learning_2_Incremental_Classification_Naive_Bayes_Fit
sourcesrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Machine_Learning/Incremental_Learning/Incremental_Classification_Naive_Bayes_Fit/ICoreBlock_0_Machine_Learning_1_Incremental_Learning_2_Incremental_Classification_Naive_Bayes_Fit.cpp
headersrc/ICoreBlocks/ICoreBlockLibrary/Blocks/Machine_Learning/Incremental_Learning/Incremental_Classification_Naive_Bayes_Fit/ICoreBlock_0_Machine_Learning_1_Incremental_Learning_2_Incremental_Classification_Naive_Bayes_Fit.h
default size on canvas150 × 80 px
ports at insert2 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++

Ports#

#DirectionSignal typeDescription label
1inICoreDoublex
2inICoreDoubley
3outICoreBusmdl

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 variableDefaultSimulink parameter
Class Names[1 2 3]—
Metrics Warmup Period1000—

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::None
Simulink path—
port-count rulePortsParam::None
SampleTime parameteryes

Caveat (shown to the user): Simulink's IncrementalClassificationNaiveBayes Fit takes its learner as InitialLearner, the name of an incrementalClassificationNaiveBayes object in the MATLAB workspace, which has no public constructor a generated script could write; the block is reported rather than dropped

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

Description vs code#

The lists agree. check_block_descriptions.py finds no disagreement between the description's Ports, Parameters, Code export and Simulink bridge lists and the code's.

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).

IncrementalClassificationNaiveBayes Fit -- an online Gaussian naive Bayes, its model on a bus statsIncremental/Classification/NaiveBayes/IncrementalClassificationNaiveBayes Fit, MEASURED on R2026a 2026-10-02 (BLOCKS_TO_ADD_TOOLBOXES.md statsIncremental, on FEATURES_TO_ADD.md BF1). Simulink's block takes its learner as InitialLearner, the name of an incrementalClassificationNaiveBayes object in the MATLAB workspace; here the two options the block reads are configs, "Class Names" and "Metrics Warmup Period", with MATLAB's default warm-up (1000). The predictor count is x's width.

WHAT EACH STEP DOES, all of it measured against the Simulink block and the object's fit():

  • IsWarm is decided from the observations BEFORE this step: true once Metrics Warmup Period

of them have arrived -- every step counts, a NaN or unknown label included -- so it flips one step after the object's fit() would set it (warm-up 3: step 4, in three runs).

  • A label that is one of Class Names is counted for MajorityClass (1-based, the FIRST of a

tie, the current label included); a NaN or a label not in Class Names is ignored.

  • The observation then updates its class: the count, and each predictor's running mean and

sum of squared deviations (Welford's update). The published standard deviation divides by n -- the POPULATION one, measured: two observations -0.8968 and 0.6531 give 0.7749 -- and is 0 for a class seen once; mean and deviation are 0 for a class not yet seen.

  • Prior is each class's share of the fitted observations, and 1/K each before the first.
  • CanPredict is true from the first step, as R2026a's is.

⚠ THREE DELIBERATE DIVERGENCES FROM THE SIMULINK BLOCK, all measured and all stated in the description:

  1. R2026a's block NEVER FITS THE LAST CLASS in ClassNames. Its observations are counted for

MajorityClass and then dropped: with ClassNames [0 1] the Prior stays [1 0] for the whole run, and with [10 20 30 40] class 40 keeps a zero prior and zero statistics, where the object's own fit() learns every class. This block learns every class, as fit() does.

  1. A NaN predictor reaches R2026a's running sums and turns that class's mean and deviation

into NaN for the rest of the run. Here an observation with a non-finite predictor is not fitted (its label is still counted for MajorityClass).

  1. R2026a's block fits an observation whose label is NOT a class -- a NaN, a 7 -- as the

PREVIOUS valid label: labels 2 3 NaN 2 3 7 fitted x(3) and x(6) as class 3 and counted them for MajorityClass (with interpolation off, so it is the block, not its source), and two leading NaNs fitted nothing. Here such an observation fits nothing and counts for nothing but the warm-up, which the learner's fit() -- which refuses an unknown label -- supports better than a silent relabelling.

The bus is R2026a's with DistrNormal [K P 2] split into DistrMean and DistrStd [K,P] (ICoreIncrementalNaiveBayesSupport.h says why), and Prior a column [K,1] where Simulink's is 1-D [K].

Sample results#

Incremental Classification Naive Bayes Fit — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sampleIncremental Classification Naive Bayes Fit — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample-202012345t (s)in ICoreDouble-Out-0in ICoreDouble-Out-0

This block carries a ICoreBus signal, whose value is text rather than a number and is not something a plot has an axis for. The samples are in the table below, exactly as the run recorded them.

tin ICoreDouble-Out-0in ICoreDouble-Out-0out ICoreBus-Out-0
0-2-2{'DistrMean': [0, 0, 0], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
0.40.50.5{'DistrMean': [0, 0, 0], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
0.8-2-2{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
1.20.50.5{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
1.6-2-2{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
20.50.5{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
2.4-2-2{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
2.80.50.5{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
3.2-2-2{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
3.60.50.5{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
4-2-2{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
4.40.50.5{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
4.8-2-2{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}
5.20.50.5{'DistrMean': [1, 2, 3], 'DistrStd': [0, 0, 0], 'Prior': [0.3333333333, 0.3333333333, 0.3333333333], 'CanPredict': 1, 'IsWarm': 0, 'MajorityClass': 1}

Every 4th of 60 samples, from the table stimulus.

The same rig also ran:

StimulusWhat it isOutput range
impulseImpulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair)—
rampRamp: slope 1 from t = 0—
sineSine Wave: amplitude 1, 2 rad/s, no phase, no bias—
stepStep: 0 -> 1 at t = 1 s—

Plotted: table — Repeating Sequence Stair: [-2 -1 -0.5 0 0.5 1 2 3], one entry per sample

Category static · sample time 0.1 · 60 steps · commit ab8631aa8 · produced by docsSample --out <folder> --blocks Incremental_Classification_Naive_Bayes_Fit Incremental_Classification_Naive_Bayes_Predict --steps 60 · data docs/generated/samples/Machine_Learning__Incremental_Learning__Incremental_Classification_Naive_Bayes_Fit.json · the SVG is generated from those numbers by tools/docs/plot_svg.py, so it is a run and not a drawing (R-D10).