Polynomial Features — Machine Learning/Feature Engineering
Machine_Learning/Feature_Engineering/Polynomial_Features · 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.
Polynomial Features
Machine Learning / Feature Engineering
Expands a feature column into every term of a second-order model,
scikit-learn's PolynomialFeatures(degree=2) at inference:
[ 1, uᵢ, uᵢ·uⱼ ] – the constant, each feature, and every pairwise product including the squares.
It is the cheapest way to give a linear model curvature and interaction: a Dense Layer with a Linear activation placed after this block fits a full quadratic, and stays a matrix multiply on the target.
Ports
- u – the feature column, [d,1]. Any d ≥ 1; the block reads the width from whatever is connected.
- Output – the expanded column. Its width follows from d and the two options: 1 + d + d(d+1)÷2 by default, so a [3,1] input gives [10,1] and a [4,1] input gives [15,1]. The block resizes itself when the input width changes.
Parameters
- Include Bias – whether the leading constant 1 is emitted. Leave it On for a model fitted with an intercept column; turn it Off when the downstream block carries its own bias, as a Dense Layer does, otherwise the intercept is fitted twice.
- Interaction Only – when On, the squares are dropped and only the cross terms uᵢ·uⱼ with i < j are emitted. This is the right choice when a feature's own square is meaningless but its interaction with another is not – and it narrows the output to 1 + d + d(d−1)÷2.
- Sampling Time (s) – zero or less inherits the solver's rate; a positive value runs the block at that period.
Term order
The order is part of the block's contract, because the model consuming it reads its coefficients positionally. It matches scikit-learn's: the bias first if enabled, then the linear terms in index order, then the products (i, j) taken lexicographically with i ≤ j – so for a [3,1] input with both defaults:
[ 1, u₀, u₁, u₂, u₀u₀, u₀u₁,
u₀u₂, u₁u₁, u₁u₂, u₂u₂ ]
Code export
All ten targets: Python, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog and PLC Structured Text. The expansion is emitted fully unrolled, so no target needs a loop bound or an index type.
The three HDL targets are genuine Q16.16 fixed point and synthesizable – there is nothing here but multiplication. ⚠ Note that a product SQUARES the magnitude: a feature reaching 100 gives a term of 10⁴, and Q16.16 saturates above 32768. Scale the features before expanding them, which is what a fitted pipeline does anyway.
Simulink bridge
None, and the first reason is about this installation: 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 polynomial-expansion
block either – the nearest thing is a hand-wired mesh of Product blocks,
which is a diagram rather than an equivalent. ⚠ Not to be confused with
Control_Systems/Base_Blocks/Polynomial, which evaluates ONE
polynomial in its input rather than expanding the input into a feature vector.
Notes
- Algebraic and stateless.
- No state space. The map is quadratic, so no A/B/C/D can be true of it; model reduction correctly refuses the block.
- Degree is fixed at 2. Degree 3 multiplies the width again (d(d+1)(d+2)÷6 extra terms) and is better served by a small network than by an expansion the size of one.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Feature_Engineering/Polynomial_Features |
| family | Machine_Learning/Feature_Engineering |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Feature_Engineering_2_Polynomial_Features |
| source | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Feature_Engineering/Polynomial_Features/ICoreBlock_0_Machine_Learning_1_Feature_Engineering_2_Polynomial_Features.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Feature_Engineering/Polynomial_Features/ICoreBlock_0_Machine_Learning_1_Feature_Engineering_2_Polynomial_Features.h |
| default size on canvas | 130 × 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 |
|---|---|---|
Include Bias | On%~%Off~~On | — |
Interaction Only | Off%~%On~~Off | — |
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. 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; and base Simulink has no polynomial-expansion block -- a mesh of Product blocks wired by hand is a diagram, not an equivalent. Note this is NOT Control_Systems/Base_Blocks/Polynomial, which evaluates one polynomial in its input
Catalog contract: src/ICoreSDK/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).
Polynomial Features — sklearn's PolynomialFeatures(degree=2), evaluated at inference [ 1, u0 .. u(d-1), u0*u0, u0*u1 .. u(d-1)*u(d-1) ] width 1 + d + d(d+1)/2
The cheapest nonlinearity in this family: a linear model behind this block fits curvature and pairwise interaction without becoming a network.
⚠ Two things make this block different from the scalers, and both are in terms():
- The OUTPUT WIDTH comes from the INPUT width, not from config, so initializePortSignalSize()
reads the input port's settled size the way Mux does and calls setPortSignalSize().
- TERM ORDER IS THE CONTRACT. It is defined once, in terms(), and compute_h plus all ten
generators iterate that -- none of them re-derives it. A backend that emitted the same terms in another order would produce a vector of the right width whose entries mean different things, which no size check can catch and which silently invalidates the coefficients of whatever model consumes it.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 [3x1] entry 0 |
|---|---|---|
| 0 | -2 | [1, -2, 4] |
| 0.4 | 0.5 | [1, 0.5, 0.25] |
| 0.8 | -2 | [1, -2, 4] |
| 1.2 | 0.5 | [1, 0.5, 0.25] |
| 1.6 | -2 | [1, -2, 4] |
| 2 | 0.5 | [1, 0.5, 0.25] |
| 2.4 | -2 | [1, -2, 4] |
| 2.8 | 0.5 | [1, 0.5, 0.25] |
| 3.2 | -2 | [1, -2, 4] |
| 3.6 | 0.5 | [1, 0.5, 0.25] |
| 4 | -2 | [1, -2, 4] |
| 4.4 | 0.5 | [1, 0.5, 0.25] |
| 4.8 | -2 | [1, -2, 4] |
| 5.2 | 0.5 | [1, 0.5, 0.25] |
Every 4th of 60 samples, from the table stimulus.
The same rig also ran:
| Stimulus | What it is | Output range |
|---|---|---|
impulse | Impulse: one sample of 1 at k = 5, 0 elsewhere (Repeating Sequence Stair) | 1 … 1 |
ramp | Ramp: slope 1 from t = 0 | 1 … 1 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | 1 … 1 |
step | Step: 0 -> 1 at t = 1 s | 1 … 1 |
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 ccf005c8 · produced by docsSample --out <folder> --steps 60 · data docs/generated/samples/Machine_Learning__Feature_Engineering__Polynomial_Features.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).