KNN Classifier — Machine Learning/Classical Models
Machine_Learning/Classical_Models/KNN_Classifier · 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.
KNN Classifier
Machine Learning / Classical Models
Classifies a sample by the majority label of its k nearest training points:
d²i = Σj (uj − Xij)², then the k smallest distances vote.
This is KNeighborsClassifier.predict with _fit_X and
_y pasted in as config. kNN is the one classical model with no
fitted parameters – the training set is the model – which is
why the configuration here is a matrix and a label column rather than
coefficients.
Ports
- u – the sample, a column [d,1] matching the d columns of Training Set.
- cls – a scalar [1,1]: the winning class, plus Index Base.
- votes – a scalar [1,1]: how many of the k neighbours carried the winning label. At most k, at least one. Read it as a confidence – 2 of 5 is a far weaker answer than 5 of 5.
Parameters
- Training Set – the [N,d] matrix, one training sample per row, which is sklearn's orientation. N rows is the number of stored examples, d columns the feature count the input must match.
- Training Labels – an [N,1] column giving each row's class position, counted from 0 whatever the index base. It is the only source of the class count: C is one past the largest label, so no separate setting can disagree with the data beside it.
- Neighbors – k, a whole number ≥ 1: how many nearest points vote. Larger k smooths the boundary; k above N simply lets every point vote.
- Index Base – what the first class is called:
- Zero-based (PyTorch, numpy) – the first class is 0. The default.
- 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. The training set, the labels, k and the base are baked into the body at export time; there is no tunable parameter, because the training set determines how much code is emitted.
The three HDL targets are genuine synthesizable Q16.16: the distance is squared and never rooted, so the block is multiplies, adds and comparisons with no division and no transcendental anywhere.
Simulink bridge
None, and for two independent reasons. Nearest-neighbour classification lives in the Statistics and Machine Learning Toolbox, which is not installed on this machine; and its block takes a fitted model object rather than parameters, which no parameter rule could carry across even if the toolbox were present. There is therefore no parameter set to map onto and no reference to run a parity testbench against. A model carrying this block exports with the block reported rather than silently dropped.
Notes
- Algebraic and stateless: the outputs depend only on the current sample.
- Two tie rules, and both are part of the contract. Among equal distances the lower training-set row counts as nearer; among equal vote counts the lowest class index wins, which is Argmax Decision's rule. Both are decided by counting rather than by sorting, so every backend agrees on exactly which points tie.
- The distance is squared and never rooted, exactly as in K Means Assign. Ranking is monotone under squaring, so the root would change no answer while costing every backend its exactness.
- Cost is O(N²·d) per sample – inherent to ranking without storing a sorted order, and fine for the small baked sets this family targets. A training set of hundreds of rows belongs behind a real index rather than in a block, and will emit a great deal of code.
- Nonlinear and discontinuous, and deliberately carries no state space: the class steps rather than varies, so no A/B/C/D describes it and model reduction correctly refuses the block.
- At a near-tie in distance the HDL targets can rank differently. They compare Q16.16 values, one quantum of which is about 1.5e-5, where the in-app run compares doubles – so two training points closer together than that can swap places and change the vote. This is inherent to a discrete decision taken in fixed point, and it is the same caveat Argmax Decision carries.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Classical_Models/KNN_Classifier |
| family | Machine_Learning/Classical_Models |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Classical_Models_2_KNN_Classifier |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Classical_Models/KNN_Classifier/ICoreBlock_0_Machine_Learning_1_Classical_Models_2_KNN_Classifier.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Classical_Models/KNN_Classifier/ICoreBlock_0_Machine_Learning_1_Classical_Models_2_KNN_Classifier.h |
| default size on canvas | 140 × 80 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 | cls |
| 3 | out | ICoreDouble | votes |
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 |
|---|---|---|
Training Set | [0 0; 0.2 0.1; 1 1; 1.2 0.9; -1 0.5; -0.8 0.7] | — |
Training Labels | [0; 0; 1; 1; 2; 2] | — |
Neighbors | 5 | — |
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: nearest-neighbour classification belongs to the Statistics and Machine Learning Toolbox, which is not installed on this machine, and its block takes a fitted MODEL OBJECT rather than parameters -- which no ParamRule could carry even if it were present. There is therefore no parameter set to map onto and no reference to run a parity testbench against
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).
KNN Classifier — k nearest of a baked training set, then a majority vote d2_i = sum_j (u_j - X[i][j])^2 (squared, never rooted) rank_i = #{ j : d2_j < d2_i } + #{ j < i : d2_j == d2_i } cls = argmax_c #{ i : rank_i < k and y_i == c } (+ base)
RANK BY COUNTING is what makes this exact without a sort, a swap or a selected/not-selected flag: it IS "order by (distance, index)", evaluated independently per point, so every backend computes the same selection from the same comparisons and no two of them can disagree about which points tie.
⚠ Unrolling it in the two Verilog dialects buys a compile-time simplification worth naming: for a fixed i, whether j < i is known at EXPORT time, so the tie term folds into the operator -- j < i emits
d2_j <= d2_iand j > i emitsd2_j < d2_i, with j = i skipped entirely. No index comparison survives into the hardware.⚠ VHDL gets a FUNCTION instead (see the header): a block body's only scratch is acc/acc2/ iacc, and this needs N distances plus a rank, a tally and a running best live at once.
Sample results#
No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/KNN Classifier. 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__KNN_Classifier.json