Skip to content
Oakfield Operator Calculus Function Reference Site

Nonlinear Operators

sim_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.

sim_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".

Rounding Operations:

  • floor: out=x\text{out} = \lfloor x \rfloor
  • fract: out=xx[0,1)\text{out} = x - \lfloor x \rfloor \in [0, 1)

Modulo:

out=xyx/y\text{out} = x - y \cdot \lfloor x / y \rfloor

with guard against division by values smaller than epsilon.

Step Function:

out={true_valueif xthresholdfalse_valueotherwise\text{out} = \begin{cases} \text{true\_value} & \text{if } x \geq \text{threshold} \\ \text{false\_value} & \text{otherwise} \end{cases}

Comparisons:

  • eq: out=(xyϵ)  ?  true_value:false_value\text{out} = (|x - y| \leq \epsilon) \;?\; \text{true\_value} : \text{false\_value}
  • lt: out=(x<y)  ?  true_value:false_value\text{out} = (x < y) \;?\; \text{true\_value} : \text{false\_value}
  • gt: out=(x>y)  ?  true_value:false_value\text{out} = (x > y) \;?\; \text{true\_value} : \text{false\_value}

Conditional Select:

out={yif xthresholdfalse_valueotherwise\text{out} = \begin{cases} y & \text{if } x \geq \text{threshold} \\ \text{false\_value} & \text{otherwise} \end{cases}

Core Parameters:

ParameterTypeDefaultDescription
modeenum "floor"Operation to perform (see below)
rhs_sourceenum "constant"Source for rhs: field or constant
rhs_constantdouble 1.0Constant rhs value when rhs_source = "constant"
accumulateboolean falseAdd to output instead of overwriting
scale_by_dtboolean trueScale accumulated writes by dt

Mode options: floor, fract, mod, step, eq, lt, gt, select

Comparison & Selection Parameters:

ParameterTypeDefaultRangeDescription
thresholddouble 0.0unboundedThreshold for step/select comparisons
epsilondouble 1e-6≥0Tolerance for eq comparisons and mod guards
true_valuedouble 1.0unboundedValue emitted when condition is true
false_valuedouble 0.0unboundedValue emitted when condition is false
  • 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)
  • All operations are unconditionally stable
  • floor/fract: Discontinuous at integers; may cause aliasing in smooth fields
  • mod: Protected against division by zero via epsilon guard
  • step: Discontinuous at threshold; consider smoothstep for continuous alternatives
  • Comparisons produce discrete 0/1-like outputs; consider smoothing for gradual transitions
  • 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
-- Floor quantization
ooc.sim_add_elementwise_math_operator(ctx, continuous, nil, quantized, {
mode = "floor"
})
-- Extract fractional part (sawtooth from ramp)
ooc.sim_add_elementwise_math_operator(ctx, phase, nil, sawtooth, {
mode = "fract"
})
-- Modulo 3 wrapping
ooc.sim_add_elementwise_math_operator(ctx, lhs, nil, out, {
mode = "mod",
rhs_constant = 3.0,
rhs_source = "constant"
})
-- Modulo with another field
ooc.sim_add_elementwise_math_operator(ctx, lhs, divisor, out, {
mode = "mod",
rhs_source = "field"
})
-- Step function (threshold at 0.5)
ooc.sim_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.sim_add_elementwise_math_operator(ctx, a, b, mask, {
mode = "gt",
rhs_source = "field"
})
-- Equality test with tolerance
ooc.sim_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.sim_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.sim_add_elementwise_math_operator(ctx, density, nil, mask, {
mode = "step",
threshold = 0.1,
true_value = 1.0,
false_value = 0.0
})

sim_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.

sim_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".

Binary Arithmetic:

For complex numbers z1=a+biz_1 = a + bi and z2=c+diz_2 = c + di:

  • add: z1+z2=(a+c)+(b+d)iz_1 + z_2 = (a+c) + (b+d)i
  • sub: z1z2=(ac)+(bd)iz_1 - z_2 = (a-c) + (b-d)i
  • mul: z1z2=(acbd)+(ad+bc)iz_1 \cdot z_2 = (ac - bd) + (ad + bc)i
  • div: z1/z2=ac+bdc2+d2+bcadc2+d2iz_1 / z_2 = \frac{ac + bd}{c^2 + d^2} + \frac{bc - ad}{c^2 + d^2}i
  • pow: z1z2=ez2ln(z1)z_1^{z_2} = e^{z_2 \ln(z_1)}

Unary Transcendental:

  • exp: ez=ea(cosb+isinb)e^z = e^a(\cos b + i \sin b)
  • log: lnz=lnz+iarg(z)\ln z = \ln|z| + i \arg(z)
  • sqrt: z=zeiarg(z)/2\sqrt{z} = \sqrt{|z|} e^{i \arg(z)/2}

Trigonometric:

  • sin: sinz=sinacoshb+icosasinhb\sin z = \sin a \cosh b + i \cos a \sinh b
  • cos: cosz=cosacoshbisinasinhb\cos z = \cos a \cosh b - i \sin a \sinh b
  • tan: tanz=sinz/cosz\tan z = \sin z / \cos z
  • sinh/cosh/tanh: Hyperbolic analogs

Component Extraction:

  • conj: zˉ=abi\bar{z} = a - bi
  • abs: z=a2+b2|z| = \sqrt{a^2 + b^2}
  • arg: arg(z)=atan2(b,a)\arg(z) = \text{atan2}(b, a)
  • real: Re(z)=a\text{Re}(z) = a
  • imag: Im(z)=b\text{Im}(z) = b
  • neg: z=abi-z = -a - bi

Processing Chain:

out=op(lhs_scalez1,rhs_scalez2)+bias\text{out} = \text{op}(\text{lhs\_scale} \cdot z_1, \text{rhs\_scale} \cdot z_2) + \text{bias}

Core Parameters:

ParameterTypeDefaultDescription
modeenum "add"Operation to perform (see below)
rhs_sourceenum "constant"Source for rhs: field or constant
accumulateboolean falseAdd to output instead of overwriting
scale_by_dtboolean trueScale 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:

ParameterTypeDefaultDescription
rhs_constant_redouble 0.0Real part of constant rhs
rhs_constant_imdouble 0.0Imaginary part of constant rhs

Scaling & Bias:

ParameterTypeDefaultDescription
lhs_scale_redouble 1.0Real scale applied to lhs
lhs_scale_imdouble 0.0Imaginary scale applied to lhs
rhs_scale_redouble 1.0Real scale applied to rhs
rhs_scale_imdouble 0.0Imaginary scale applied to rhs
bias_redouble 0.0Real bias added after operation
bias_imdouble 0.0Imaginary bias added after operation

Numerical Guards:

ParameterTypeDefaultRangeDescription
epsilondouble 1e-9≥0Tolerance for log/division guards

Output Configuration:

ParameterTypeDefaultDescription
output_componentenum "real"Component written to real outputs: real, imag, magnitude, phase
phase_wrapenum "none"Phase wrapping: none, signed, unsigned, unit

Phase wrap options:

  • none: No wrapping (raw atan2 output)
  • signed: Wrap to [π,π][-\pi, \pi]
  • unsigned: Wrap to [0,2π][0, 2\pi]
  • unit: Normalize to [0,1][0, 1]
  • 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
  • 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 e88e^{88}
  • 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
-- Complex exponential
ooc.sim_add_complex_math_operator(ctx, z, nil, out, {
mode = "exp"
})
-- Complex multiplication with constant (0.5 + 0.5i)
ooc.sim_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.sim_add_complex_math_operator(ctx, a, b, product, {
mode = "mul",
rhs_source = "field"
})
-- Extract magnitude
ooc.sim_add_complex_math_operator(ctx, z, nil, mag, {
mode = "abs"
})
-- Extract phase normalized to [0, 1]
ooc.sim_add_complex_math_operator(ctx, z, nil, phase, {
mode = "arg",
phase_wrap = "unit"
})
-- Extract phase in [-π, π]
ooc.sim_add_complex_math_operator(ctx, z, nil, phase, {
mode = "arg",
phase_wrap = "signed"
})
-- Complex conjugate
ooc.sim_add_complex_math_operator(ctx, z, nil, z_conj, {
mode = "conj"
})
-- Field-vs-field division with epsilon guard
ooc.sim_add_complex_math_operator(ctx, numerator, denominator, quotient, {
mode = "div",
rhs_source = "field",
epsilon = 1e-6
})
-- Complex logarithm
ooc.sim_add_complex_math_operator(ctx, z, nil, log_z, {
mode = "log",
epsilon = 1e-12
})
-- Complex power: z^(0.5) (square root alternative)
ooc.sim_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.sim_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
})

sim_add_chaos_map_operator(ctx, input, out, opts)

Iterate discrete chaotic maps on a complex state field. The real and imaginary components encode the two-dimensional phase space. Useful for generating deterministic chaos, studying nonlinear dynamics, and creating complex textures.

sim_add_chaos_map_operator(ctx, input, output, [options]) -> operator

Returns: Operator handle (userdata)

Standard (Chirikov) Map:

The standard map is a canonical example of Hamiltonian chaos, encoding angle θ\theta in the real part and momentum pp in the imaginary part:

pn+1=pn+Ksin(αθn)θn+1=θn+pn+1(mod2π)\begin{aligned} p_{n+1} &= p_n + K \sin(\alpha \theta_n) \\ \theta_{n+1} &= \theta_n + p_{n+1} \pmod{2\pi} \end{aligned}

where KK is the chaos parameter and α\alpha is angle_scale.

Kick modes:

  • kick_drift: Update pp first, then θ\theta (default)
  • drift_kick: Update θ\theta first, then pp
  • symmetric: Half-kick, drift, half-kick (symplectic)

Ikeda Map:

Models light in a nonlinear optical resonator:

zn+1=A+uznei(zn2b+a)z_{n+1} = A + u \cdot z_n \cdot e^{i(|z_n|^2 b + a)}

where:

  • AA is the offset (ikeda_offset_re + i * ikeda_offset_im)
  • uu is the contraction factor
  • aa is the phase bias
  • bb is the nonlinearity strength

Exponential Map:

zn+1=eszn+cz_{n+1} = e^{s \cdot z_n} + c

where ss is the complex scale and cc is the complex constant.

Blending:

zout=(1β)zold+βznewz_{\text{out}} = (1 - \beta) z_{\text{old}} + \beta \cdot z_{\text{new}}

where β\beta is the blend parameter.

Core Parameters:

ParameterTypeDefaultRangeDescription
map_typeenum "standard"see belowChaotic map family
iterations_per_stepinteger 1≥1Map iterations per simulation step
blenddouble 1.0[0, 1]Blend factor (1 = full update)

Map type options: standard, ikeda, exponential

Standard Map Parameters:

ParameterTypeDefaultRangeDescription
kdouble 1.0unboundedChaos parameter KK
angle_scaledouble 1.0unboundedScale α\alpha for sine argument
kick_modeenum "kick_drift"see belowKick/drift ordering

Kick mode options: kick_drift, drift_kick, symmetric

Ikeda Map Parameters:

ParameterTypeDefaultRangeDescription
ikeda_udouble 0.9[0, 1]Contraction factor
ikeda_adouble 0.4unboundedPhase bias
ikeda_bdouble 6.0unboundedNonlinearity strength
ikeda_offset_redouble 1.0unboundedReal part of offset AA
ikeda_offset_imdouble 0.0unboundedImaginary part of offset AA

Exponential Map Parameters:

ParameterTypeDefaultRangeDescription
exp_scale_redouble 1.0unboundedReal part of scale ss
exp_scale_imdouble 0.0unboundedImaginary part of scale ss
exp_c_redouble 0.0unboundedReal part of constant cc
exp_c_imdouble 0.0unboundedImaginary part of constant cc
  • Operates elementwise; no spatial boundary handling
  • Initial conditions determine the trajectory; small changes can lead to vastly different outcomes (sensitive dependence)
  • Standard map: Typically initialize with θ[0,2π)\theta \in [0, 2\pi) and pp near zero
  • Ikeda map: Typically initialize near the fixed point or attractor
  • Exponential map: Initialize within bounded region to avoid overflow
  • Standard map:

    • K<Kc0.9716K < K_c \approx 0.9716 produces mostly regular (KAM tori) behavior
    • K>KcK > K_c transitions to widespread chaos
    • K1K \approx 1 shows mixed regular/chaotic phase space
    • Large KK values produce fully chaotic behavior
  • Ikeda map:

    • u<1u < 1 ensures contraction (bounded attractor)
    • Multiple attractors possible; initial conditions determine which is reached
    • Larger bb increases complexity of the attractor
  • Exponential map:

    • Can escape to infinity; consider clamping or careful parameter choice
    • Julia sets exist for certain cc values (e.g., c0.65c \approx -0.65)
  • iterations_per_step > 1 multiplies computation per timestep
  • Standard map uses one sin evaluation per iteration
  • Ikeda map requires magnitude calculation and complex exponential
  • Exponential map requires complex exponential (expensive)
  • blend < 1 adds interpolation overhead but smooths transitions
-- Standard map with K = 1 (near chaotic threshold)
ooc.sim_add_chaos_map_operator(ctx, state, out, {
map_type = "standard",
k = 1.0,
kick_mode = "symmetric"
})
-- Standard map with strong chaos
ooc.sim_add_chaos_map_operator(ctx, state, out, {
map_type = "standard",
k = 5.0,
kick_mode = "kick_drift"
})
-- Standard map with regular (integrable) motion
ooc.sim_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.sim_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.sim_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
})
-- Exponential map (Julia set exploration)
ooc.sim_add_chaos_map_operator(ctx, state, out, {
map_type = "exponential",
exp_c_re = -0.8,
exp_c_im = 0.156
})
-- Exponential map with scaling
ooc.sim_add_chaos_map_operator(ctx, state, out, {
map_type = "exponential",
exp_scale_re = 0.5,
exp_scale_im = 0.1,
exp_c_re = -0.65,
exp_c_im = 0.0
})
-- Multiple iterations per step with blending (smooth animation)
ooc.sim_add_chaos_map_operator(ctx, state, out, {
map_type = "standard",
k = 0.95,
iterations_per_step = 4,
blend = 0.75
})
-- Fast iteration for texture generation
ooc.sim_add_chaos_map_operator(ctx, state, out, {
map_type = "ikeda",
ikeda_u = 0.9,
ikeda_b = 6.0,
iterations_per_step = 10,
blend = 1.0
})

sim_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.

sim_add_hysteretic_operator(ctx, input, output, [options]) -> operator

Returns: Operator handle (userdata)

Schmitt Trigger Mode:

Binary output with hysteresis band:

yn={yhighif xn>Thighylowif xn<Tlowyn1otherwisey_n = \begin{cases} y_{\text{high}} & \text{if } x_n > T_{\text{high}} \\ y_{\text{low}} & \text{if } x_n < T_{\text{low}} \\ y_{n-1} & \text{otherwise} \end{cases}

where TlowT_{\text{low}} and ThighT_{\text{high}} define the hysteresis thresholds.

Play Model:

Deadband hysteresis where output only changes when input exceeds accumulated play:

yn={xnrif xn>yn1+rxn+rif xn<yn1ryn1otherwisey_n = \begin{cases} x_n - r & \text{if } x_n > y_{n-1} + r \\ x_n + r & \text{if } x_n < y_{n-1} - r \\ y_{n-1} & \text{otherwise} \end{cases}

where rr is the play_radius.

Bouc-Wen Model:

Differential hysteresis model for structural mechanics:

z˙=Ax˙βx˙zn1zγx˙zn\dot{z} = A\dot{x} - \beta|\dot{x}||z|^{n-1}z - \gamma\dot{x}|z|^n y=αz+(1α)xy = \alpha \cdot z + (1-\alpha) \cdot x

where zz is the internal hysteretic variable and α\alpha, AA, β\beta, γ\gamma, nn are shape parameters.

Core Parameters:

ParameterTypeDefaultDescription
modeenum "schmitt"Hysteresis model: schmitt, play, bouc_wen
threshold_modeenum "bounds"Threshold specification: bounds or center_width
input_modeenum "direct"Input preprocessing: direct, abs, squared
input_gaindouble 1.0Gain applied to input before processing
input_biasdouble 0.0Bias added to input
output_gaindouble 1.0Gain applied to output
output_biasdouble 0.0Bias added to output
accumulateboolean falseAdd to output instead of overwriting
scale_by_dtboolean trueScale accumulated writes by dt

Threshold Parameters (bounds mode):

ParameterTypeDefaultDescription
threshold_lowdouble -0.5Lower threshold for hysteresis band
threshold_highdouble 0.5Upper threshold for hysteresis band

Threshold Parameters (center_width mode):

ParameterTypeDefaultDescription
threshold_centerdouble 0.0Center of hysteresis band
threshold_widthdouble 1.0Width of hysteresis band (≥0)

Schmitt Trigger Parameters:

ParameterTypeDefaultDescription
output_lowdouble -1.0Output when below lower threshold
output_highdouble 1.0Output when above upper threshold

Play Model Parameters:

ParameterTypeDefaultDescription
play_radiusdouble 0.0Deadband radius for play hysteresis

Bouc-Wen Parameters:

ParameterTypeDefaultDescription
bw_alphadouble 0.1Ratio of post-yield to pre-yield stiffness
bw_Adouble 1.0Controls tangent stiffness
bw_betadouble 0.5Shape parameter (softening/hardening)
bw_gammadouble 0.5Shape parameter (pinching)
bw_ndouble 2.0Exponent controlling sharpness
bw_z_clampdouble 0.0Clamp on internal variable z (0 = no clamp)
bw_xdot_clampdouble 0.0Clamp on velocity estimate (0 = no clamp)

Smoothing & Rate Limiting:

ParameterTypeDefaultDescription
smoothdouble 0.0Exponential smoothing factor [0, 1]
rate_limitdouble 0.0Maximum
state_mindouble -1e6Minimum internal state value
state_maxdouble 1e6Maximum internal state value

Initialization:

ParameterTypeDefaultDescription
initialize_from_inputboolean trueInitialize state from first input sample
initial_outputdouble 0.0Initial output if not from input
initial_inputdouble 0.0Initial input reference
initial_zdouble 0.0Initial Bouc-Wen internal variable
  • Operates elementwise; no spatial boundary handling
  • Internal state is maintained per-element across timesteps
  • Use initialize_from_input = true for automatic state initialization
  • For deterministic behavior, set explicit initial values
  • Schmitt mode: Unconditionally stable; discrete state transitions
  • Play mode: Unconditionally stable; bounded by input range
  • Bouc-Wen mode: Stability depends on parameter choices:
    • β+γ>0\beta + \gamma > 0 ensures bounded dissipation
    • Large nn values can cause stiff dynamics; reduce timestep accordingly
    • Use bw_z_clamp to prevent runaway internal states
  • 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
  • rate_limit > 0 adds conditional logic per element
-- Schmitt trigger with ±0.3 thresholds
ooc.sim_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.sim_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.sim_add_hysteretic_operator(ctx, position, force, {
mode = "play",
play_radius = 0.1,
input_gain = 100.0 -- spring constant
})
-- Bouc-Wen for structural hysteresis
ooc.sim_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.sim_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.sim_add_hysteretic_operator(ctx, ac_signal, envelope, {
mode = "play",
input_mode = "abs",
play_radius = 0.05,
smooth = 0.8
})