reservoirpy.nodes.NVAR#

class reservoirpy.nodes.NVAR(
delay: int,
order: int,
strides: int = 1,
input_dim: int | None = None,
name: str | None = None,
)[source]#

Non-linear Vector AutoRegressive machine.

NVAR is implemented as described in [1].

The state \(\mathbb{O}_{total}\) of the NVAR first contains a series of linear features \(\mathbb{O}_{lin}\) made of input data concatenated with delayed inputs:

\[\mathbb{O}_{lin}[t] = \mathbf{X}[t] \oplus \mathbf{X}[t - s] \oplus \mathbf{X}[t - 2s] \oplus \dots \oplus \mathbf{X}[t - (k-1)s]\]

where \(\mathbf{X}[t]\) are the inputs at time \(t\), \(k\) is the delay and \(s\) is the strides (only one input every \(s\) inputs within the delayed inputs is used). The operator \(\oplus\) denotes the concatenation.

In addition to these linear features, nonlinear representations \(\mathbb{O}_{nonlin}^n\) of the inputs are constructed using all unique monomials of order \(n\) of these inputs:

\[\mathbb{O}_{nonlin}^n[t] = \mathbb{O}_{lin}[t] \otimes \mathbb{O}_{lin}[t] \overbrace{\otimes \dots \otimes}^{n-1~\mathrm{times}} \mathbb{O}_{lin}[t]\]

where \(\otimes\) is the operator denoting an outer product followed by the selection of all unique monomials generated by this outer product.

Note

Under the hood, this product is computed by finding all unique combinations of input features and multiplying each combination of terms.

Finally, all representations are gathered to form the final feature vector \(\mathbb{O}_{total}\):

\[\mathbb{O}_{total} = \mathbb{O}_{lin}[t] \oplus \mathbb{O}_{nonlin}^n[t]\]
Parameters:
  • delay (int) – Maximum delay of inputs.

  • order (int) – Order of the non-linear monomials.

  • strides (int, default to 1) – Strides between delayed inputs.

  • input_dim (int, optional) – Input dimension. Can be inferred at first call.

  • name (str, optional) – Node name.

References

Example

>>> import numpy as np
>>> from reservoirpy.nodes import NVAR, Ridge
>>> nvar = NVAR(delay=2, order=2, strides=1)
>>> readout = Ridge(ridge=2.5e-6, output_dim=3)
>>> model = nvar >> readout

Using the lorenz() timeseries and learning to predict the next difference:

>>> from reservoirpy.datasets import lorenz
>>> X = lorenz(5400, x0=[17.677, 12.931, 43.914], h=0.025, method="RK23")
>>> Xi  = X[:600]
>>> dXi = X[1:601] - X[:600]  # difference u[t+1] - u[t]
>>> Y_test = X[600:]  # testing data
>>> _ = model.fit(Xi, dXi, warmup=200)

We can now predict the differences and integrate these predictions:

>>> u = X[600]
>>> res = np.zeros((5400-600, readout.output_dim))
>>> for i in range(5400-600):
...     u = u + model(u)
...     res[i, :] = u
...
../../_images/nvar_example.png

Methods

__init__(delay, order[, strides, input_dim, ...])

initialize(x)

Define input and output dimensions, and instantiate variables.

predict([x, iters, workers])

Alias for run()

reset()

Reset all Node state

run([x, iters, workers])

Run the Node on a sequence of data.

step([x])

Call the Node function on a single step of data and update the state of the Node.

Attributes

initialized

True if the Node has been initialized

input_dim

Expected dimension of the Node input.

name

Optional name of the Node.

output_dim

Expected dimension of the Node input.

store

Time window over the inputs (of shape (delay * strides, features)).

delay

Maximum delay of inputs (\(k\)).

order

Order of the non-linear monomials (\(n\)).

strides

Strides between delayed inputs, by default 1 (\(s\)).

state

Current state of the Node.

delay: int#

Maximum delay of inputs (\(k\)).

initialize(x: Array2D | Array3D | Sequence[Timeseries] | Array1D)[source]#

Define input and output dimensions, and instantiate variables.

Only called once, before fitting or running the node.

Parameters:
  • x (array of shape (input_dim,) or (timestep, input_dim)) – Input data to the node.

  • y (None) – Training data to the node. As it is not a trainable node, y is expected to be None.

initialized: bool = False#

True if the Node has been initialized

input_dim: int = None#

Expected dimension of the Node input. Can be None before initialization

name: str | None = None#

Optional name of the Node.

order: int#

Order of the non-linear monomials (\(n\)).

output_dim: int = None#

Expected dimension of the Node input. Can be None before initialization

predict(
x: array(t, d) | array(s, t, d) | ~typing.Sequence[array(t, d)] | None = None,
iters: int | None = None,
workers=1,
) array(t, d) | array(s, t, d) | ~typing.Sequence[array(t, d)][source]#

Alias for run()

Run the Node on a sequence of data. Can update the state of the Node several times.

Parameters:
  • x (array-like of shape ([n_inputs,] timesteps, input_dim) or list of) – arrays of shape (timesteps, input_dim), optional A sequence of data of shape (timesteps, features).

  • iters (int, optional) – If x is None, a dimensionless timeseries of length iters is used instead.

  • workers (int, default to 1) – Number of workers used for parallelization. If set to -1, all available workers (threads or processes) are used.

Returns:

A sequence of output vectors.

Return type:

array of shape ([n_inputs,] timesteps, output_dim) or list of arrays

reset() dict[str, ndarray][source]#

Reset all Node state

Returns:

dict[str, np.array]

Return type:

previous state of the Node.

run(
x: array(t, d) | array(s, t, d) | ~typing.Sequence[array(t, d)] | None = None,
iters: int | None = None,
workers=1,
) array(t, d) | array(s, t, d) | ~typing.Sequence[array(t, d)][source]#

Run the Node on a sequence of data. Can update the state of the Node several times.

Parameters:
  • x (array-like of shape ([n_inputs,] timesteps, input_dim) or list of arrays of shape (timesteps, input_dim), optional) – A timeseries, array of shape (timesteps, features), or a sequence of timeseries. Input of the Node.

  • iters (int, optional) – If x is None, a dimensionless timeseries of length iters is used instead.

  • workers (int, default to 1) – Number of workers used for parallelization. If set to -1, all available workers (threads or processes) are used.

Returns:

A sequence of output vectors.

Return type:

array of shape ([n_inputs,] timesteps, output_dim) or list of arrays

state: dict[str, ndarray]#

Current state of the Node. Must have “out” as one of the keys.

step(x: array(d) | None = None)[source]#

Call the Node function on a single step of data and update the state of the Node.

Parameters:

x (array of shape (input_dim,), optional) – One single step of input data. If None, an empty array is used instead and the Node is assumed to have an input_dim of 0

Returns:

An output vector.

Return type:

array of shape (output_dim,)

store: ndarray#

Time window over the inputs (of shape (delay * strides, features)).

strides: int#

Strides between delayed inputs, by default 1 (\(s\)).