Embedding Lookup — Machine Learning/Neural Networks
Machine_Learning/Neural_Networks/Embedding_Lookup · 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.
Embedding Lookup
Machine Learning / Neural Networks
Selects one row of a trained embedding table by index: y = table[k, :], delivered as a column [d,1].
This is what turns a token, a category or a mode number into the dense vector a network was trained on – the front end of any model whose input is not a measurement. The index arrives as an ordinary signal and is rounded to the nearest whole number, so 2.0 and 1.9997 select the same row.
Ports
- k – the index, a scalar [1,1]. Interpreted relative to Index Base.
- Output – y, a column [d,1], where d is the NUMBER OF COLUMNS of Embedding Table. The selected row transposed into a column; all zeros when the index is out of range and Out Of Range is All Zeros.
Parameters
- Embedding Table – the trained table, [V,d]: one row
per index, which is the orientation
torch.nn.Embedding.weightand a KerasEmbeddinglayer both store, so weights paste in without transposing. Its shape is the only size source – V is the number of indices the block knows and d is the width of the output, and there is no second config that could disagree with it. - Index Base – what the first row is called:
- Zero-based (PyTorch, numpy) – index 0 selects the first row. The default.
- One-based (MATLAB) – index 1 selects the first row.
- Out Of Range – what an index outside the V rows does:
- All Zeros – the output is entirely zero. The default, and the one that lets a downstream block notice that nothing was selected. It is also what a padding or unknown token usually means.
- Clamp To Range – below the first row selects the first, above the last selects the last.
- 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 table, the base and the out-of-range rule are structural and baked in; there is no tunable parameter.
No backend converts the index to an integer, and no backend indexes the
table with a signal. The lookup is emitted as one half-open comparison per
row – (k − base) − v in
−0.5, +0.5) – guarding a copy of that row's d
constants. That is the same rule One Hot Encoder uses, it needs no
integer type, and it leaves nothing in the emitted code that could read outside
the table.
The three HDL targets are ordinary Q16.16 fixed point and are offered for synthesis: one subtraction, V comparisons and d assignments, with no multiplier and no transcendental. The cost is V×d constants in the emitted body rather than one indexed read – the honest price of a lookup that carries no address arithmetic, at the table sizes a deployed model uses.
Simulink bridge
None. Simulink's Deep Learning blocks take a trained network
object, which no parameter mapping can carry, and
Direct Lookup Table (n-D) is not this block: it takes an index per
dimension and returns the single element they address, not a whole row. 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.
Notes
- Algebraic and stateless: the output depends only on the current index, so the block cannot break an algebraic loop.
- Nonlinear and discontinuous, and deliberately carries no state space.
- The rounding boundary is a discontinuity, and the HDL targets sit one quantum away from the reference. They compare Q16.16 values (one quantum ≈ 1.5e-5) where the in-app run compares doubles, so an index within that distance of a ±0.5 boundary can round the other way and select a different row – and a different row is a whole different vector, not a rounding error. Feed this block a genuinely integral index – which is what a token is – and the question never arises. The same caveat governs One Hot Encoder and Argmax Decision.
- Ordinary numbers, not a fitted object: the table is config, so nothing is loaded at run time and every target exports without a framework.
Code facts#
| Fact | Value |
|---|---|
| registered type | Machine_Learning/Neural_Networks/Embedding_Lookup |
| family | Machine_Learning/Neural_Networks |
| solver environment class | ICoreBlock_0_Machine_Learning_1_Neural_Networks_2_Embedding_Lookup |
| source | [src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Neural_Networks/Embedding_Lookup/ICoreBlock_0_Machine_Learning_1_Neural_Networks_2_Embedding_Lookup.cpp |
| header | src/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Neural_Networks/Embedding_Lookup/ICoreBlock_0_Machine_Learning_1_Neural_Networks_2_Embedding_Lookup.h |
| default size on canvas | 126 × 84 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 | k |
| 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 |
|---|---|---|
Embedding Table | 0.45 -1.2 0.75; -0.85 0.3 1.4; 1.15 0.95 -0.35; -0.25 -0… | — |
Index Base | Zero-based (PyTorch, numpy)%~%One-based (MATLAB)~~Zero-ba… | — |
Out Of Range | All Zeros%~%Clamp To Range~~All Zeros | — |
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: the Deep Learning blocks take a trained network OBJECT, which no parameter mapping can carry, and Direct Lookup Table (n-D) returns the single element its indices address rather than a whole row of a table
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).
Embedding Lookup — a token index in, the matching row of a [V,d] table out as [d,1] y = table[v, :]' where (k - base) - v lies in [-0.5, +0.5) else 0
The selection rule is One_Hot_Encoder's, shared deliberately rather than re-derived: the two blocks sit at the same seam of the same model, and an index the encoder calls class 3 must be the index this block calls row 3. See the header for why no backend converts the index to an integer, and why the selected row is ASSIGNED rather than accumulated through an indicator.
The three HDL targets are genuine Q16.16 -- one subtraction, V comparisons and d copies, with no multiplication anywhere and nothing transcendental.
Sample results#
| t | in ICoreDouble-Out-0 | out ICoreDouble-Out-0 [3x1] entry 0 |
|---|---|---|
| 0 | -2 | [0, 0, 0] |
| 0.4 | 0.5 | [-0.85, 0.3, 1.4] |
| 0.8 | -2 | [0, 0, 0] |
| 1.2 | 0.5 | [-0.85, 0.3, 1.4] |
| 1.6 | -2 | [0, 0, 0] |
| 2 | 0.5 | [-0.85, 0.3, 1.4] |
| 2.4 | -2 | [0, 0, 0] |
| 2.8 | 0.5 | [-0.85, 0.3, 1.4] |
| 3.2 | -2 | [0, 0, 0] |
| 3.6 | 0.5 | [-0.85, 0.3, 1.4] |
| 4 | -2 | [0, 0, 0] |
| 4.4 | 0.5 | [-0.85, 0.3, 1.4] |
| 4.8 | -2 | [0, 0, 0] |
| 5.2 | 0.5 | [-0.85, 0.3, 1.4] |
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) | -0.85 … 0.45 |
ramp | Ramp: slope 1 from t = 0 | -0.85 … 1.15 |
sine | Sine Wave: amplitude 1, 2 rad/s, no phase, no bias | -0.85 … 0.45 |
step | Step: 0 -> 1 at t = 1 s | -0.85 … 0.45 |
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__Neural_Networks__Embedding_Lookup.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).