Generated reference › Power Transformer — Machine Learning/Preprocessing
kind: generated#block#machine-learning-preprocessing

Power Transformer — Machine Learning/Preprocessing

λ

Machine_Learning/Preprocessing/Power_Transformer · 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.

Power Transformer

Machine Learning / Preprocessing

Per-feature power transform, scikit-learn's PowerTransformer at inference – the one transform in this family that is not affine. With the fitted λ per feature: Yeo-Johnson maps u ≥ 0 to ((1+u)λ − 1)÷λ (log(1+u) at λ = 0) and u < 0 to −((1−u)2−λ − 1) ÷(2−λ) (−log(1−u) at λ = 2); Box-Cox maps a positive input to (uλ − 1) ÷λ (log u at λ = 0).

Ports

  • u – the feature column, [m,1], where m is the number of entries in Lambdas. The size is checked rather than broadcast.
  • Outputy, the same [m,1] shape: the transform is elementwise and never changes dimensions.

Parameters

  • Lambdasλ, an [m,1] column, one fitted exponent per feature: transformer.lambdas_. The values 0 and 2 select the exact logarithmic branches and are compared exactly, matching scikit-learn.
  • Method
    • Yeo-Johnson – defined for any sign; the default, as in scikit-learn.
    • Box-Cox – defined for positive inputs only. An input at or below 0.001 is clamped to 0.001 rather than stopping the run – a totality guard for a transform fitted on positive data, not a domain extension. Fit with Yeo-Johnson instead if your data can reach zero.
  • 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. Each feature's λ is resolved at export time, so the generated code carries only the branch that feature selects – the one runtime branch is the sign of u (Yeo-Johnson) or the clamp (Box-Cox). λ and its reciprocals are baked as literals at full precision; nothing is tunable after export, because a fitted exponent is not something to retune on the target.

The three HDL targets are simulation-only real arithmetic – log and pow have no Q16.16 datapath – quantizing at the port boundary. They are not offered as synthesizable.

Simulink bridge

None. 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; base Simulink offers no fitted power-transform block in any case – the Math Function block computes a plain power, without the (⋅λ − 1)÷λ normalization, the sign split or the per-feature λ. The bridge reports the block rather than dropping it silently.

Notes

  • Algebraic and stateless: the output depends only on the current input.
  • No state space: log/pow is genuinely nonlinear, and a fabricated A/B/C/D would be false. Model reduction reports the block as unmergeable, which is the honest answer.
  • The block does not standardize its output. scikit-learn's standardize=True is a StandardScaler fused on for convenience; chain this library's Standard Scaler after this block and paste the fitted mean and scale there.
  • The inverse transform is not offered. The forward map is what a deployed feature pipeline runs; add a Direction mode here if a model's output ever needs un-transforming, as Standard Scaler does.
  • Yeo-Johnson is continuous (and C¹) across u = 0, so the sign branch introduces no step.

Code facts#

FactValue
registered typeMachine_Learning/Preprocessing/Power_Transformer
familyMachine_Learning/Preprocessing
solver environment classICoreBlock_0_Machine_Learning_1_Preprocessing_2_Power_Transformer
sourcesrc/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Preprocessing/Power_Transformer/ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Power_Transformer.cpp
headersrc/ICoreSDK/ICoreBlockLibrary/Blocks/Machine_Learning/Preprocessing/Power_Transformer/ICoreBlock_0_Machine_Learning_1_Preprocessing_2_Power_Transformer.h
default size on canvas120 × 80 px
ports at insert1 in, 1 out
code generators implementedPython, MATLAB, Java, Rust, C, C++, VHDL, Verilog, SystemVerilog, PLC Structured Text

Ports#

#DirectionSignal typeDescription label
1inICoreDoubleu
2outICoreDoubley

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
Lambdas[0.5; 0; 2]
MethodYeo-Johnson%~%Box-Cox~~Yeo-Johnson

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): 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. Base Simulink offers no fitted power-transform block in any case: Math Function's pow is the raw power, without the (x^lambda - 1)/lambda normalization, the Yeo-Johnson sign split or a per-feature lambda. Rebuild the transform from Math Function blocks and paste the same lambdas in

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:

  • B0 every 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).

Power Transformer — sklearn's PowerTransformer at inference, Yeo-Johnson and Box-Cox Per feature, with the fitted lambda as config:

Yeo-Johnson (any sign): u >= 0: lam != 0: ((1+u)^lam - 1) * (1/lam) lam == 0: log(1+u) u < 0: lam != 2: -((1-u)^(2-lam) - 1) * (1/(2-lam)) lam == 2: -log(1-u) Box-Cox (positive domain), v = max(u, 0.001): lam != 0: (v^lam - 1) * (1/lam) lam == 0: log(v)

⚠ The lambda branch is resolved at CONFIG LOAD / EXPORT TIME. lambda is a baked constant, so each feature's generators emit ONLY the branch its lambda selects; the sole runtime branch in any backend is the sign of u (Yeo-Johnson) or the clamp (Box-Cox). lam == 0 and lam == 2 are compared EXACTLY: sklearn stores the special cases exactly, and a lambda of 1e-9 must take the pow branch rather than a "nearly log" one.

⚠ The two exact-quadratic cases are emitted as MULTIPLICATION, not pow: at lam == 0 the negative side is -((1-u)^2 - 1)/2 and at lam == 2 the positive side is ((1+u)^2 - 1)/2. compute_h() special-cases them identically, so the in-app run and all ten backends evaluate the same expression -- pow(x, 2.0) equalling x*x is a libm property, not a guarantee.

⚠ Box-Cox's clamp v = max(u, 0.001) is a TOTALITY guard. sklearn raises on u <= 0; a realtime block cannot raise per sample, so it clamps and the description says so. 0.001 rather than machine epsilon is a measured trade: the HDL targets quantize u to Q16.16 (quantum ~1.5e-5) BEFORE the math, and log's slope at v is 1/v -- at a 1e-9 floor a sample near zero disagrees with the double-precision reference by ~20 whole units, where a 0.001 floor caps the quantization-induced error at ~1.5e-2. The clamp is where log's slope is bounded, so it is what keeps the simulation-only HDL rows inside their 1 % band.

⚠ The three HDL targets are SIMULATION-ONLY real arithmetic (Dense_Layer's escape hatch): log and pow have no Q16.16 datapath. to_real() at the port boundary, to_fx() on the way out, stated in the description.

Sample results#

No stimulus produced a sampled output in this rig — Invalid input size at: ICore Blocks/Home/Power Transformer. 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__Power_Transformer.json