Linear2#
Description#
Two-input affine combination:
Stateless 2→1 function (FunctorBase<_, 2, 1>). Inputs are paired column-by-column for arrays.
The class is small but composes nicely with the existing element-wise transforms (Sign, Relu, Sigmoid, ...) to build common idioms in a single chain:
Expression |
Compact form |
Meaning |
|---|---|---|
|
\(x - y\) |
signed difference |
|
\(\text{sign}(x - y)\) |
is |
|
\(\max(x - y, 0)\) |
positive excess |
|
\(0.7x + 0.3y\) |
weighted blend |
|
\(\sigma(ax + by + c)\) |
logistic mix |
Parameters:
a(float): coefficient on the first input.b(float): coefficient on the second input.c(float, optional): additive constant. Defaults to0.0.
NaN handling: a NaN in either input produces a NaN output (arithmetic propagation).
NaN handling#
Policy: ignore. A NaN in any input at index t causes the function to skip that step: output at t is NaN and internal state is unchanged. Subsequent finite samples are processed as if step t had not occurred.
Examples#
Usage example#
import numpy as np
from screamer import Linear2, Sign, Relu
x = np.array([1.0, 2.0, 3.0, 4.0])
y = np.array([2.0, 2.0, 2.0, 2.0])
Linear2(1, -1, 0)(x, y) # array([-1., 0., 1., 2.])
Sign()(Linear2(1, -1, 0)(x, y)) # array([-1., 0., 1., 1.])
Relu()(Linear2(1, -1, 0)(x, y)) # array([0., 0., 1., 2.])
# Two parallel 2D arrays (column-by-column pairing)
X = np.random.randn(100, 4)
Y = np.random.randn(100, 4)
Linear2(0.5, 0.5)(X, Y).shape # (100, 4)
Visual example: positive excess of a price over its trend#
Relu(Linear2(1, -1)(price, trend)) returns max(price - trend, 0): zero when the price is at or below the trend, otherwise the gap. A natural way to highlight regimes where the price is above its smoothed trendline.
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from screamer import Linear2, Relu, EwMean
rng = np.random.default_rng(0)
n = 400
# A drifting price with occasional jumps above and below.
noise = rng.normal(0.0, 0.5, n)
drift = np.linspace(0, 6, n)
bumps = 1.5 * np.sin(np.linspace(0, 4 * np.pi, n))
price = drift + bumps + noise
trend = EwMean(span=30)(price)
excess = Relu()(Linear2(1, -1)(price, trend))
fig = make_subplots(rows=2, cols=1, shared_xaxes=True,
row_heights=[0.65, 0.35], vertical_spacing=0.08)
fig.add_trace(go.Scatter(y=price, mode='lines', name='Price',
line=dict(color='steelblue')),
row=1, col=1)
fig.add_trace(go.Scatter(y=trend, mode='lines', name='EW trend (span=30)',
line=dict(color='gray', dash='dash')),
row=1, col=1)
fig.add_trace(go.Scatter(y=excess, mode='lines',
name='Relu(price - trend)',
fill='tozeroy',
line=dict(color='red')),
row=2, col=1)
fig.update_layout(
title="Positive excess: Relu(Linear2(1, -1)(price, trend))",
xaxis_title="Index",
yaxis_title="Price",
yaxis2_title="Excess",
margin=dict(l=20, r=20, t=60, b=20),
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1),
)
fig.show()
Reference#
There is no direct numpy / pandas / TA-Lib counterpart -- it is a primitive intended for composition. The single-input sibling is Linear(scale, shift).