Feature Selector — Machine Learning/Preprocessing
Machine_Learning/Preprocessing/Feature_Selector · 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.
Feature Selector
Machine Learning / Preprocessing
Keeps an arbitrary, ordered list of entries out of a wider vector: yᵢ = u[Indicesᵢ]. This is what sits between a source that produces every channel available and a model that was fitted on a subset of them, in a particular order – the selection step of a deployed pipeline.
It is deliberately not a window. A fitted selector keeps entries like 11, 2 and 40; Submatrix in Matrix Operations takes a contiguous range and cannot express that.
Ports
- u – the full feature column, [d,1]. d must be large enough that every entry of Indices exists; the block checks this and reports rather than reading past the end.
- Output – y, [k,1], where k is the number of entries in Indices. The output width therefore comes from the parameter, not from the input – this block changes the signal dimension.
Parameters
- Indices – the entries to keep, in the order they are listed, as a column or a row. Order matters and is preserved, so this block also re-orders; the list may repeat an entry, which duplicates it. Interpreted relative to Index Base.
- Index Base – what the first entry of the input is called:
- Zero-based (PyTorch, numpy) – index 0 selects the first element. The default, and what a selector fitted in Python will give you.
- One-based (MATLAB) – index 1 selects the first element.
- 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 resolved indices are baked into the generated code as straight-line assignments; there is no tunable parameter, because the selection determines which assignments are emitted rather than a value they use.
Every target is exact, not merely within tolerance, because the block performs no arithmetic – each output element is a copy. For the same reason the three HDL targets are genuinely synthesizable: the body reduces to wiring, with no multiplier, no divider and nothing transcendental. This is the cheapest block in the family on every target.
Simulink bridge
None. Neither the Statistics and Machine Learning Toolbox nor
the Deep Learning Toolbox is installed here, so a bridge could not be run
against a parity testbench even if one were written. Base Simulink has no fitted
selector either – the nearest thing is a Selector block, whose index list
is a mask parameter rather than a fitted artefact, and mapping onto it would
claim an equivalence this block does not make. The bridge reports the block
rather than dropping it silently, and it has no parity testbench, which
is the documented consequence of Support::None rather than a gap.
Code export verification still covers it across all ten languages.
Notes
- Algebraic and stateless: the output depends only on the current sample, so the block cannot break an algebraic loop.
- It changes the signal width, from [d,1] to [k,1]. k may be larger than d if the list repeats entries.
- No state space, although selection genuinely is linear (y = S·u for a selection matrix of zeros and ones). The width of S depends on the input signal, which is not known when the block is constructed, and a state space that only appears after the first run is refused by model reduction anyway – so the block carries none rather than publishing one that is right only sometimes.
- The index base is resolved once when the configuration is loaded, so the block and all ten exported cores use the identical resolved list. A consequence worth knowing: code export verification cannot detect a wrong base, because both sides read the same resolved values. The range check at the start of the run is what catches it.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Preprocessing/Feature_Selector |
| family | Machine_Learning/Preprocessing |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Feature_Selector |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Preprocessing/Feature_Selector/ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Feature_Selector.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Preprocessing/Feature_Selector/ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Feature_Selector.h |
| default size on canvas | 120 × 80 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 | u |
| 2 | out | ICoreDouble | y |
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 |
|---|---|---|
Indices | [2; 0; 4] | — |
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 verifiable Simulink equivalent. Neither the Statistics and Machine Learning Toolbox nor the Deep Learning Toolbox is installed on this machine, so a bridge could not be run against a parity testbench even if one were written. Simulink's Selector is the nearest block, but its index list is a mask parameter rather than a fitted artefact and it carries no notion of an index base, so mapping onto it would claim an equivalence this block does not make. Re-create the selection with a Selector and paste the same indices
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).
Feature Selector — keep an arbitrary, ordered list of features out of a wider vector y[i] = u[ Indices[i] ] for i = 0 .. k-1
The step between a source that produces every available channel and a model fitted on a SUBSET of them, in a particular order. Not Submatrix: that takes a contiguous window, and a fitted selector's indices almost never are.
⚠ There is NO arithmetic in this block. Every output element is a copy of an input element, so all ten targets are EXACT rather than within a tolerance, and the three HDL targets are genuinely synthesizable -- they reduce to wiring. That is why nothing below quantizes, accumulates, or reaches for the simulation-only
realescape hatch that the transcendental blocks in this family need.⚠ The index base is resolved ONCE, in loadBlockConfig(), and every generator bakes the resolved zero-based values in. One implementation of the rule instead of eleven. The cost is stated rather than hidden: export verification compares ICore against its own generated code, and BOTH read the same already-resolved list, so a green row proves nothing whatever about "Index Base". That is the vacuous-rig trap of §7, and the honest place for the base rule is the range check in verifyInitializedPortSignals() -- which does fire, loudly, and is where a user actually finds a one-based list pasted into a zero-based block.
Sample results#
No stimulus produced a sampled output in this rig — Index out of range at: ICore Blocks/Home/Feature Selector. 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__Preprocessing__Feature_Selector.json