Nonlinear Operators
On this page
Elementwise Math 🧮
add_elementwise_math_operator(ctx, lhs, rhs, out, opts)
Perform elementwise discrete math operations including floor, fractional part, modulo, step functions, comparisons, and conditional selection. Essential for creating masks, quantization, and control flow in field processing.
Method Signature
add_elementwise_math_operator(ctx, lhs, [rhs], output, [options]) -> operator
Returns: Operator handle (userdata)
Note: The rhs field is optional and can be nil when using rhs_source = "constant".
Mathematical Formulation
Rounding Operations:
- floor:
- fract:
Modulo:
with guard against division by values smaller than epsilon.
Step Function:
Comparisons:
- eq:
- lt:
- gt:
Conditional Select:
Parameters
Core Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
enum |
"floor" |
Operation to perform (see below) |
rhs_source |
enum |
"constant" |
Source for rhs: field or constant |
rhs_constant |
double |
1.0 |
Constant rhs value when rhs_source = "constant" |
accumulate |
boolean |
false |
Add to output instead of overwriting |
scale_by_dt |
boolean |
true |
Scale accumulated writes by dt |
Mode options: floor, fract, mod, step, eq, lt, gt, select
Comparison & Selection Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
threshold |
double |
0.0 |
unbounded | Threshold for step/select comparisons |
epsilon |
double |
1e-6 |
≥0 | Tolerance for eq comparisons and mod guards |
true_value |
double |
1.0 |
unbounded | Value emitted when condition is true |
false_value |
double |
0.0 |
unbounded | Value emitted when condition is false |
Boundary & Initial Conditions
- Operates elementwise; no boundary handling required
- For binary operations with
rhs_source = "field", both fields must have matching dimensions - Complex fields: operations apply to real part only (use Complex Math for full complex operations)
Stability & Convergence
- All operations are unconditionally stable
- floor/fract: Discontinuous at integers; may cause aliasing in smooth fields
- mod: Protected against division by zero via
epsilonguard - step: Discontinuous at threshold; consider smoothstep for continuous alternatives
- Comparisons produce discrete 0/1-like outputs; consider smoothing for gradual transitions
Performance Notes
- Lightweight pointwise operations; O(N) complexity
- Floor/fract use fast hardware intrinsics when available
- Comparisons with
rhs_source = "constant"avoid second field read - Select mode is branch-free on most architectures
Examples
-- Floor quantization
ooc.add_elementwise_math_operator(ctx, continuous, nil, quantized, {
mode = "floor"
})
-- Extract fractional part (sawtooth from ramp)
ooc.add_elementwise_math_operator(ctx, phase, nil, sawtooth, {
mode = "fract"
})
-- Modulo 3 wrapping
ooc.add_elementwise_math_operator(ctx, lhs, nil, out, {
mode = "mod",
rhs_constant = 3.0,
rhs_source = "constant"
})
-- Modulo with another field
ooc.add_elementwise_math_operator(ctx, lhs, divisor, out, {
mode = "mod",
rhs_source = "field"
})
-- Step function (threshold at 0.5)
ooc.add_elementwise_math_operator(ctx, signal, nil, binary, {
mode = "step",
threshold = 0.5,
true_value = 1.0,
false_value = 0.0
})
-- Field-vs-field comparison (greater than)
ooc.add_elementwise_math_operator(ctx, a, b, mask, {
mode = "gt",
rhs_source = "field"
})
-- Equality test with tolerance
ooc.add_elementwise_math_operator(ctx, measured, expected, match, {
mode = "eq",
rhs_source = "field",
epsilon = 0.01
})
-- Conditional select (choose values where mask >= 0.5)
ooc.add_elementwise_math_operator(ctx, mask, values, out, {
mode = "select",
threshold = 0.5,
rhs_source = "field",
false_value = 0.0
})
-- Create binary mask from continuous field
ooc.add_elementwise_math_operator(ctx, density, nil, mask, {
mode = "step",
threshold = 0.1,
true_value = 1.0,
false_value = 0.0
})
Complex Math 🔢
add_complex_math_operator(ctx, lhs, rhs, out, opts)
Perform elementwise complex arithmetic, transcendental functions, and component extraction. Supports full complex number operations with configurable scaling, bias, and phase wrapping.
Method Signature
add_complex_math_operator(ctx, lhs, [rhs], output, [options]) -> operator
Returns: Operator handle (userdata)
Note: The rhs field is optional for unary operations or when using rhs_source = "constant".
Mathematical Formulation
Binary Arithmetic:
For complex numbers and :
- add:
- sub:
- mul:
- div:
- pow:
Unary Transcendental:
- exp:
- log:
- sqrt:
Trigonometric:
- sin:
- cos:
- tan:
- sinh/cosh/tanh: Hyperbolic analogs
Component Extraction:
- conj:
- abs:
- arg:
- real:
- imag:
- neg:
Processing Chain:
Parameters
Core Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
enum |
"add" |
Operation to perform (see below) |
rhs_source |
enum |
"constant" |
Source for rhs: field or constant |
accumulate |
boolean |
false |
Add to output instead of overwriting |
scale_by_dt |
boolean |
true |
Scale accumulated writes by dt |
Mode options:
- Binary:
add,sub,mul,div,pow - Unary transcendental:
exp,log,sqrt - Trigonometric:
sin,cos,tan,sinh,cosh,tanh - Component:
conj,abs,arg,real,imag,neg
Constant RHS:
| Parameter | Type | Default | Description |
|---|---|---|---|
rhs_constant_re |
double |
0.0 |
Real part of constant rhs |
rhs_constant_im |
double |
0.0 |
Imaginary part of constant rhs |
Scaling & Bias:
| Parameter | Type | Default | Description |
|---|---|---|---|
lhs_scale_re |
double |
1.0 |
Real scale applied to lhs |
lhs_scale_im |
double |
0.0 |
Imaginary scale applied to lhs |
rhs_scale_re |
double |
1.0 |
Real scale applied to rhs |
rhs_scale_im |
double |
0.0 |
Imaginary scale applied to rhs |
bias_re |
double |
0.0 |
Real bias added after operation |
bias_im |
double |
0.0 |
Imaginary bias added after operation |
Numerical Guards:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
epsilon |
double |
1e-9 |
≥0 | Tolerance for log/division guards |
Output Configuration:
| Parameter | Type | Default | Description |
|---|---|---|---|
output_component |
enum |
"real" |
Component written to real outputs: real, imag, magnitude, phase |
phase_wrap |
enum |
"none" |
Phase wrapping: none, signed, unsigned, unit |
Phase wrap options:
none: No wrapping (raw atan2 output)signed: Wrap tounsigned: Wrap tounit: Normalize to
Boundary & Initial Conditions
- Operates elementwise; no boundary handling required
- For binary operations with
rhs_source = "field", both fields must have matching dimensions - Division and log operations are protected against zero by
epsilon
Stability & Convergence
- All operations are numerically stable within floating-point precision
- Division: Protected against division by zero; denominator clamped to
epsilon - Log: Protected against log(0); magnitude clamped to
epsilon - Pow: May produce large values for complex exponents; consider clamping outputs
- Exp: Can overflow for large real parts; typical float range is
Performance Notes
- Unary operations require single field read
- Binary operations with constant rhs avoid second field read
- Trigonometric and transcendental functions use hardware intrinsics when available
- Component extraction (abs, arg, real, imag) is highly optimized
- Consider using
phase_wrap = "unit"for normalized phase comparisons
Examples
-- Complex exponential
ooc.add_complex_math_operator(ctx, z, nil, out, {
mode = "exp"
})
-- Complex multiplication with constant (0.5 + 0.5i)
ooc.add_complex_math_operator(ctx, z, nil, out, {
mode = "mul",
rhs_source = "constant",
rhs_constant_re = 0.5,
rhs_constant_im = 0.5
})
-- Field-vs-field multiplication
ooc.add_complex_math_operator(ctx, a, b, product, {
mode = "mul",
rhs_source = "field"
})
-- Extract magnitude
ooc.add_complex_math_operator(ctx, z, nil, mag, {
mode = "abs"
})
-- Extract phase normalized to [0, 1]
ooc.add_complex_math_operator(ctx, z, nil, phase, {
mode = "arg",
phase_wrap = "unit"
})
-- Extract phase in [-π, π]
ooc.add_complex_math_operator(ctx, z, nil, phase, {
mode = "arg",
phase_wrap = "signed"
})
-- Complex conjugate
ooc.add_complex_math_operator(ctx, z, nil, z_conj, {
mode = "conj"
})
-- Field-vs-field division with epsilon guard
ooc.add_complex_math_operator(ctx, numerator, denominator, quotient, {
mode = "div",
rhs_source = "field",
epsilon = 1e-6
})
-- Complex logarithm
ooc.add_complex_math_operator(ctx, z, nil, log_z, {
mode = "log",
epsilon = 1e-12
})
-- Complex power: z^(0.5) (square root alternative)
ooc.add_complex_math_operator(ctx, z, nil, sqrt_z, {
mode = "pow",
rhs_source = "constant",
rhs_constant_re = 0.5,
rhs_constant_im = 0.0
})
-- Scale and bias: (2+i)*z + (0.1 + 0.2i)
ooc.add_complex_math_operator(ctx, z, nil, out, {
mode = "mul",
rhs_source = "constant",
rhs_constant_re = 1.0,
rhs_constant_im = 0.0,
lhs_scale_re = 2.0,
lhs_scale_im = 1.0,
bias_re = 0.1,
bias_im = 0.2
})
Chaos Map 🌀
add_chaos_map_operator(ctx, input, out, opts)
Iterate discrete chaotic maps on a real or complex state field. Complex fields use the real and imaginary components as the two phase-space coordinates; real fields seed the imaginary coordinate at zero and write back the updated real component.
Method Signature
add_chaos_map_operator(ctx, input, output, [options]) -> operator
Returns: Operator handle (userdata)
Mathematical Formulation
At each application, the operator advances the selected map family
and optionally blends the result with the previous state:
where is blend. iterations_per_step applies the selected map multiple times per simulation step before the final blend.
Standard (Chirikov) Map:
where is the chaos parameter and is angle_scale. kick_mode chooses whether the map is applied as kick-drift, drift-kick, or a symmetric half-kick split.
Ikeda Map:
where is the complex offset, is the contraction factor, and , control the nonlinear phase shift.
Exponential Map:
with complex scale and offset .
Quadratic Map:
Henon Map:
Lozi Map:
When lozi_abs_epsilon > 0, the absolute value is softened to .
Tinkerbell Map:
When present, k_field, u_field, a_field, b_field, c_field, and d_field override the corresponding constants per sample. wrap_* constrains the real and imaginary coordinates after each update, and escape_* defines how runaway states are handled once |z| exceeds escape_radius.
Parameters
Core Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
map_type |
enum |
"standard" |
see below | Chaotic map family |
iterations_per_step |
integer |
1 |
≥1 | Map iterations per simulation step |
blend |
double |
1.0 |
[0, 1] | Blend factor (1 = full update) |
Map type options: standard, ikeda, exponential, quadratic, henon, lozi, tinkerbell
Standard Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
kick_mode |
enum |
"kick_drift" |
see below | Kick/drift ordering |
k |
double |
1.0 |
unbounded | Chaos parameter |
angle_scale |
double |
1.0 |
unbounded | Scale factor for the sine argument |
Kick mode options: kick_drift, drift_kick, symmetric
Ikeda Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
ikeda_u |
double |
0.9 |
[0, 1] | Contraction factor |
ikeda_a |
double |
0.4 |
unbounded | Phase bias |
ikeda_b |
double |
6.0 |
unbounded | Nonlinearity strength |
ikeda_offset_re |
double |
1.0 |
unbounded | Real part of offset |
ikeda_offset_im |
double |
0.0 |
unbounded | Imaginary part of offset |
Exponential Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
exp_scale_re |
double |
1.0 |
unbounded | Real part of scale |
exp_scale_im |
double |
0.0 |
unbounded | Imaginary part of scale |
exp_c_re |
double |
0.0 |
unbounded | Real part of constant |
exp_c_im |
double |
0.0 |
unbounded | Imaginary part of constant |
Quadratic Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
quad_a_re |
double |
1.0 |
unbounded | Real part of quadratic coefficient |
quad_a_im |
double |
0.0 |
unbounded | Imaginary part of quadratic coefficient |
quad_b_re |
double |
0.0 |
unbounded | Real part of linear coefficient |
quad_b_im |
double |
0.0 |
unbounded | Imaginary part of linear coefficient |
quad_c_re |
double |
0.0 |
unbounded | Real part of constant |
quad_c_im |
double |
0.0 |
unbounded | Imaginary part of constant |
Henon Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
henon_a |
double |
1.4 |
unbounded | Quadratic coefficient |
henon_b |
double |
0.3 |
unbounded | Coupling coefficient |
henon_x_gain |
double |
0.0 |
unbounded | Linear X gain |
henon_y_gain |
double |
1.0 |
unbounded | Cross-coupling gain |
henon_offset_re |
double |
1.0 |
unbounded | X offset |
henon_offset_im |
double |
0.0 |
unbounded | Y offset |
Lozi Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
lozi_a |
double |
1.7 |
unbounded | Absolute-value coefficient |
lozi_b |
double |
0.5 |
unbounded | Coupling coefficient |
lozi_x_gain |
double |
0.0 |
unbounded | Linear X gain |
lozi_y_gain |
double |
1.0 |
unbounded | Cross-coupling gain |
lozi_offset_re |
double |
1.0 |
unbounded | X offset |
lozi_offset_im |
double |
0.0 |
unbounded | Y offset |
lozi_abs_epsilon |
double |
0.0 |
≥0 | Smooth-absolute epsilon (0 uses exact abs) |
Tinkerbell Map Parameters:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
tinkerbell_a |
double |
0.9 |
unbounded | Linear X coefficient |
tinkerbell_b |
double |
-0.6013 |
unbounded | Linear Y coefficient in the X update |
tinkerbell_c |
double |
2.0 |
unbounded | Linear X coefficient in the Y update |
tinkerbell_d |
double |
0.5 |
unbounded | Linear Y coefficient in the Y update |
tinkerbell_x2_gain |
double |
1.0 |
unbounded | Quadratic X gain |
tinkerbell_y2_gain |
double |
-1.0 |
unbounded | Quadratic Y gain |
tinkerbell_xy_gain |
double |
2.0 |
unbounded | Cross term gain |
tinkerbell_offset_re |
double |
0.0 |
unbounded | X offset |
tinkerbell_offset_im |
double |
0.0 |
unbounded | Y offset |
Per-Element Override Fields:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
k_field |
field handle | nil |
— | Optional per-sample override for k on the standard map |
u_field |
field handle | nil |
— | Optional per-sample override for ikeda_u |
a_field |
field handle | nil |
— | Optional per-sample override for the map-specific a coefficient |
b_field |
field handle | nil |
— | Optional per-sample override for the map-specific b coefficient |
c_field |
field handle | nil |
— | Optional per-sample override for the map-specific c coefficient |
d_field |
field handle | nil |
— | Optional per-sample override for the map-specific d coefficient |
Domain & Escape Controls:
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
wrap_mode_re |
enum |
"none" |
see below | Value-space wrapping mode for the real component |
wrap_mode_im |
enum |
"none" |
see below | Value-space wrapping mode for the imaginary component |
wrap_min_re |
double |
0.0 |
unbounded | Lower real-component wrap bound |
wrap_max_re |
double |
2π |
unbounded | Upper real-component wrap bound |
wrap_min_im |
double |
0.0 |
unbounded | Lower imaginary-component wrap bound |
wrap_max_im |
double |
2π |
unbounded | Upper imaginary-component wrap bound |
escape_mode |
enum |
"none" |
see below | Action to take when ` |
escape_radius |
double |
0.0 |
≥0 | Escape threshold (<= 0 disables escape handling) |
escape_reset_re |
double |
0.0 |
unbounded | Real component used by escape_mode = "reset" |
escape_reset_im |
double |
0.0 |
unbounded | Imaginary component used by escape_mode = "reset" |
Wrap mode options: none, periodic, clamp, mirror
Escape mode options: none, clamp, reset, nan
Boundary & Initial Conditions
- Operates elementwise; no spatial boundary handling is involved
- Initial conditions determine the trajectory; nearby states can diverge rapidly
- Real input fields evolve on the real axis (
Im(z) = 0) and write back only the updated real component wrap_*acts on state coordinates, not on spatial samplingescape_radius <= 0disables escape handling entirely
Stability & Convergence
- Standard map: Larger
kand higheriterations_per_stepgenerally increase chaotic mixing - Ikeda map:
|ikeda_u| < 1promotes bounded attractors; largerikeda_bincreases nonlinear folding - Quadratic, exponential, and tinkerbell maps: Can diverge quickly;
wrap_*andescape_*are useful safety valves - Lozi:
lozi_abs_epsilon > 0smooths the non-differentiable corner at the origin blend < 1damps abrupt state changes but also changes the raw map dynamics
Performance Notes
iterations_per_step > 1scales cost linearly with the number of iterations- Standard, Henon, and Lozi are comparatively cheap polynomial/elementary maps
- Ikeda and exponential families require complex exponentials and are the most expensive per iteration
- Per-element override fields add extra field reads
wrap_*andescape_*introduce lightweight branching but can prevent runaway values from poisoning later stages
Examples
-- Standard map with K = 1 (near chaotic threshold)
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "standard",
k = 1.0,
kick_mode = "symmetric"
})
-- Standard map with strong chaos
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "standard",
k = 5.0,
kick_mode = "kick_drift"
})
-- Standard map with regular (integrable) motion
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "standard",
k = 0.5, -- below critical value
angle_scale = 1.0
})
-- Ikeda map (classic parameters)
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "ikeda",
ikeda_u = 0.9,
ikeda_a = 0.4,
ikeda_b = 6.0
})
-- Ikeda map with offset
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "ikeda",
ikeda_u = 0.85,
ikeda_a = 0.4,
ikeda_b = 6.0,
ikeda_offset_re = 1.0,
ikeda_offset_im = 0.5
})
-- Quadratic complex map
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "quadratic",
quad_a_re = 1.0,
quad_c_re = -0.8,
quad_c_im = 0.156
})
-- Exponential map (escape-clamped)
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "exponential",
exp_c_re = -0.8,
exp_c_im = 0.156,
escape_mode = "clamp",
escape_radius = 8.0
})
-- Henon map with explicit linear gains
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "henon",
henon_a = 1.4,
henon_b = 0.3,
henon_y_gain = 1.0
})
-- Lozi map with smoothed absolute value near the origin
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "lozi",
lozi_a = 1.7,
lozi_b = 0.5,
lozi_abs_epsilon = 0.01
})
-- Tinkerbell attractor with softened updates
ooc.add_chaos_map_operator(ctx, state, out, {
map_type = "tinkerbell",
tinkerbell_a = 0.9,
tinkerbell_b = -0.6013,
tinkerbell_c = 2.0,
tinkerbell_d = 0.5,
blend = 0.8
})
-- Spatially varying standard-map chaos parameter
ooc.add_chaos_map_operator(ctx, phase_space, next_phase_space, {
map_type = "standard",
k_field = local_k,
angle_scale = 1.0,
iterations_per_step = 2
})
Hysteretic 🔁
add_hysteretic_operator(ctx, input, output, opts)
Stateful hysteresis operator supporting Schmitt trigger, play model, and Bouc-Wen dynamics. Models memory-dependent nonlinear transformations common in mechanical systems, electronic circuits, and material science. Complex fields are supported and are processed component-wise with independent state on the real and imaginary channels.
Method Signature
add_hysteretic_operator(ctx, input, output, [options]) -> operator
Returns: Operator handle (userdata)
Mathematical Formulation
Schmitt Trigger Mode:
Binary output with hysteresis band:
where and define the hysteresis thresholds.
Play Model:
Deadband hysteresis where output only changes when input exceeds accumulated play:
where is the play_radius.
Bouc-Wen Model:
Differential hysteresis model for structural mechanics:
where is the internal hysteretic variable and , , , , are shape parameters. The input is first preprocessed by input_gain, input_bias, and input_mode; complex fields are processed component-wise.
For a complex sample , the operator evaluates the same hysteresis law independently on and , then recombines the result:
Parameters
Core Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
mode |
enum |
"schmitt" |
Hysteresis model: schmitt, play, bouc_wen |
threshold_mode |
enum |
"bounds" |
Threshold specification: bounds or center_width |
input_mode |
enum |
"direct" |
Input preprocessing: direct, abs, squared |
input_gain |
double |
1.0 |
Gain applied to input before processing |
input_bias |
double |
0.0 |
Bias added to input |
output_gain |
double |
1.0 |
Gain applied to output |
output_bias |
double |
0.0 |
Bias added to output |
accumulate |
boolean |
false |
Add to output instead of overwriting |
scale_by_dt |
boolean |
true |
Scale accumulated writes by dt |
Threshold Parameters (bounds mode):
| Parameter | Type | Default | Description |
|---|---|---|---|
threshold_low |
double |
-0.5 |
Lower threshold for hysteresis band |
threshold_high |
double |
0.5 |
Upper threshold for hysteresis band |
Threshold Parameters (center_width mode):
| Parameter | Type | Default | Description |
|---|---|---|---|
threshold_center |
double |
0.0 |
Center of hysteresis band |
threshold_width |
double |
1.0 |
Width of hysteresis band (≥0) |
Schmitt Trigger Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
output_low |
double |
-1.0 |
Output when below lower threshold |
output_high |
double |
1.0 |
Output when above upper threshold |
Play Model Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
play_radius |
double |
0.0 |
Deadband radius for play hysteresis |
Bouc-Wen Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
bw_alpha |
double |
0.1 |
Ratio of post-yield to pre-yield stiffness |
bw_A |
double |
1.0 |
Controls tangent stiffness |
bw_beta |
double |
0.5 |
Shape parameter (softening/hardening) |
bw_gamma |
double |
0.5 |
Shape parameter (pinching) |
bw_n |
double |
2.0 |
Exponent controlling sharpness |
bw_z_clamp |
double |
0.0 |
Clamp on internal variable z (0 = no clamp) |
bw_xdot_clamp |
double |
0.0 |
Clamp on velocity estimate (0 = no clamp) |
Smoothing & Rate Limiting:
| Parameter | Type | Default | Description |
|---|---|---|---|
smooth |
double |
0.0 |
Exponential smoothing factor [0, 1] |
rate_limit |
double |
0.0 |
Maximum |
state_min |
double |
-1e6 |
Minimum internal state value |
state_max |
double |
1e6 |
Maximum internal state value |
Initialization:
| Parameter | Type | Default | Description |
|---|---|---|---|
initialize_from_input |
boolean |
true |
Initialize state from first input sample |
initial_output |
double |
0.0 |
Initial output if not from input |
initial_input |
double |
0.0 |
Initial input reference |
initial_z |
double |
0.0 |
Initial Bouc-Wen internal variable |
Boundary & Initial Conditions
- Operates elementwise; no spatial boundary handling
- Internal state is maintained per-element across timesteps
- Complex fields keep separate hysteresis state for the real and imaginary channels
- Use
initialize_from_input = truefor automatic state initialization - For deterministic behavior, set explicit initial values
Stability & Convergence
- Schmitt mode: Unconditionally stable; discrete state transitions
- Play mode: Unconditionally stable; bounded by input range
- Bouc-Wen mode: Stability depends on parameter choices:
- ensures bounded dissipation
- Large values can cause stiff dynamics; reduce timestep accordingly
- Use
bw_z_clampto prevent runaway internal states
Performance Notes
- Maintains per-element internal state; memory usage scales with field size
- Schmitt and play modes are computationally lightweight
- Bouc-Wen requires velocity estimation (finite difference) and is more expensive
- Complex fields approximately double the scalar state/work because the channels are evolved independently
rate_limit > 0adds conditional logic per element
Examples
-- Schmitt trigger with ±0.3 thresholds
ooc.add_hysteretic_operator(ctx, input, output, {
mode = "schmitt",
threshold_low = -0.3,
threshold_high = 0.3,
output_low = 0.0,
output_high = 1.0
})
-- Center-width threshold specification
ooc.add_hysteretic_operator(ctx, input, output, {
mode = "schmitt",
threshold_mode = "center_width",
threshold_center = 0.5,
threshold_width = 0.2 -- thresholds at 0.4 and 0.6
})
-- Play model with deadband
ooc.add_hysteretic_operator(ctx, position, force, {
mode = "play",
play_radius = 0.1,
input_gain = 100.0 -- spring constant
})
-- Bouc-Wen for structural hysteresis
ooc.add_hysteretic_operator(ctx, displacement, restoring_force, {
mode = "bouc_wen",
bw_alpha = 0.05,
bw_A = 1.0,
bw_beta = 0.5,
bw_gamma = 0.5,
bw_n = 2.0
})
-- Smooth Schmitt with rate limiting (debouncing)
ooc.add_hysteretic_operator(ctx, noisy_signal, clean_signal, {
mode = "schmitt",
threshold_low = -0.1,
threshold_high = 0.1,
smooth = 0.9,
rate_limit = 10.0 -- max 10 units/second change rate
})
-- Magnitude-based hysteresis (rectified input)
ooc.add_hysteretic_operator(ctx, ac_signal, envelope, {
mode = "play",
input_mode = "abs",
play_radius = 0.05,
smooth = 0.8
})
-- Complex I/Q hysteresis (applied independently to real and imaginary parts)
ooc.add_hysteretic_operator(ctx, iq_signal, iq_shaped, {
mode = "schmitt",
threshold_low = -0.2,
threshold_high = 0.2,
output_low = -1.0,
output_high = 1.0
})
Neural Infer 🧠
add_neural_infer_operator(ctx, input, out, opts)
Run an inference-only learned operator on a field while carrying explicit metadata about determinism, device placement, precision, and accepted tensor shape.
Experimental: Model adapters, execution contracts, and fallback behavior may evolve as the neural runtime is refined.
Method Signature
add_neural_infer_operator(ctx, input, output, [options]) -> operator
Returns: Operator handle (userdata)
Mathematical Formulation
Conceptually, the operator applies a learned map:
with optional affine input/output transforms
and writes
Here, normalize_input controls the affine preprocessing and scale_by_dt controls the optional writeback scaling.
If no backend model or custom inference callback is available, the current runtime falls back to an affine passthrough using the configured normalization/denormalization settings.
Parameters
Inference Contract:
| Parameter | Type | Default | Description |
|---|---|---|---|
model_id |
string |
"model" |
Model identifier resolved by the backend adapter |
determinism_policy |
enum |
"inherit" |
inherit, strict, best_effort, off |
device_requirement |
enum |
"any" |
any, cpu_only, accelerator_preferred, accelerator_required |
precision_mode |
enum |
"default" |
default, fp32, fp64, mixed, fp16, bf16 |
Shape Constraints:
| Parameter | Type | Default | Description |
|---|---|---|---|
min_rank |
integer |
1 |
Minimum accepted input rank |
max_rank |
integer |
0 |
Maximum accepted input rank (0 disables the upper bound) |
channel_axis |
integer |
255 |
Channel axis (255 = auto) |
channels_last |
boolean |
true |
Auto-axis policy when channel_axis = 255 |
allow_complex_input |
boolean |
true |
Allow complex-valued input tensors/fields |
Normalization & Writeback:
| Parameter | Type | Default | Description |
|---|---|---|---|
normalize_input |
boolean |
false |
Apply affine preprocessing before inference |
input_scale |
double |
1.0 |
Input normalization scale |
input_bias |
double |
0.0 |
Input normalization bias |
output_scale |
double |
1.0 |
Output denormalization scale |
output_bias |
double |
0.0 |
Output denormalization bias |
accumulate |
boolean |
false |
Add prediction into the output field |
scale_by_dt |
boolean |
true |
Scale writes by substep dt |
Boundary & Initial Conditions
- Input and output fields must have identical shape and storage type
- Rank and channel layout must satisfy the configured shape constraints
- Complex inputs are permitted only when
allow_complex_input = true
Stability & Convergence
- Numerical stability depends on the learned model rather than a fixed analytic formula
strictdeterminism may reduce backend choices but improves reproducibilityscale_by_dt = trueis appropriate when the model predicts a rate-like increment rather than a full state
Performance Notes
- Allocates a temporary prediction buffer each step
- Backend selection and precision can materially affect throughput
- The operator is nonlocal from the scheduler’s perspective even though the I/O shape matches pointwise field updates
Examples
-- Deterministic surrogate inference
ooc.add_neural_infer_operator(ctx, state, prediction, {
model_id = "burgers_surrogate_v1",
determinism_policy = "strict",
precision_mode = "fp32"
})
-- Explicit tensor layout contract
ooc.add_neural_infer_operator(ctx, input, output, {
model_id = "vision_block",
min_rank = 3,
max_rank = 3,
channel_axis = 0,
channels_last = false
})
-- Accumulate model output as an RHS term
ooc.add_neural_infer_operator(ctx, state, rhs, {
model_id = "residual_term",
accumulate = true,
scale_by_dt = true
})
Neural Hybrid 🔀
add_neural_hybrid_operator(ctx, input, out, opts)
Combine an analytic baseline with a learned residual prediction. This is useful when you want the model to correct, not replace, a known signal path.
Experimental: Model adapters, execution contracts, and blend semantics may evolve as the neural runtime is refined.
Method Signature
add_neural_hybrid_operator(ctx, input, output, [options]) -> operator
Returns: Operator handle (userdata)
Mathematical Formulation
The operator forms a hybrid write from the input field and a model prediction :
where:
- is
analytic_gain - is
residual_gain
As with add_neural_infer_operator, the runtime can normalize inputs before inference and apply output scaling/bias afterward. If no model backend is available, the residual path currently falls back to an affine-transformed copy of the input.
Parameters
Hybrid Weights:
| Parameter | Type | Default | Description |
|---|---|---|---|
analytic_gain |
double |
1.0 |
Scale applied to the direct analytic/input contribution |
residual_gain |
double |
1.0 |
Scale applied to the learned residual contribution |
Inference Contract:
| Parameter | Type | Default | Description |
|---|---|---|---|
model_id |
string |
"model" |
Residual model identifier |
determinism_policy |
enum |
"inherit" |
inherit, strict, best_effort, off |
device_requirement |
enum |
"any" |
any, cpu_only, accelerator_preferred, accelerator_required |
precision_mode |
enum |
"default" |
default, fp32, fp64, mixed, fp16, bf16 |
Shape Constraints & Normalization:
| Parameter | Type | Default | Description |
|---|---|---|---|
min_rank |
integer |
1 |
Minimum accepted input rank |
max_rank |
integer |
0 |
Maximum accepted input rank (0 disables the upper bound) |
channel_axis |
integer |
255 |
Channel axis (255 = auto) |
channels_last |
boolean |
true |
Auto-axis policy when channel_axis = 255 |
allow_complex_input |
boolean |
true |
Allow complex-valued input tensors/fields |
normalize_input |
boolean |
false |
Apply affine preprocessing before residual inference |
input_scale |
double |
1.0 |
Input normalization scale |
input_bias |
double |
0.0 |
Input normalization bias |
output_scale |
double |
1.0 |
Output denormalization scale on the residual path |
output_bias |
double |
0.0 |
Output denormalization bias on the residual path |
accumulate |
boolean |
false |
Add the hybrid output into the destination field |
scale_by_dt |
boolean |
true |
Scale writes by substep dt |
Boundary & Initial Conditions
- Input and output fields must match in shape and scalar/complex storage
- The same shape-contract rules as
Neural Inferapply - Complex outputs combine the analytic and residual paths component-wise
Stability & Convergence
analytic_gainandresidual_gaindirectly control how strongly the learned correction can perturb the baseline- Start with small
residual_gainvalues when introducing a new surrogate into an existing simulation scale_by_dt = trueis appropriate when the hybrid output represents an increment rather than a full-state overwrite
Performance Notes
- Same backend and buffer costs as
Neural Infer, plus the final blend with the input field - Useful for residual-learning workflows where the analytic path remains interpretable
- Determinism, device, and precision choices are exposed explicitly so the runtime contract stays inspectable
Examples
-- Residual correction on top of the current state
ooc.add_neural_hybrid_operator(ctx, state, next_state, {
model_id = "navier_stokes_residual_v2",
analytic_gain = 1.0,
residual_gain = 0.2
})
-- CPU-only deterministic hybrid for reproducible tests
ooc.add_neural_hybrid_operator(ctx, u, out, {
model_id = "test_residual",
determinism_policy = "strict",
device_requirement = "cpu_only",
residual_gain = 0.1
})
-- Accumulate learned correction into an RHS buffer
ooc.add_neural_hybrid_operator(ctx, state, rhs, {
model_id = "forcing_residual",
analytic_gain = 0.0,
residual_gain = 1.0,
accumulate = true,
scale_by_dt = true
})