pysindy.utils package

Submodules

pysindy.utils.axes module

A module that defines one external class, AxesArray, to act like a numpy array but keep track of axis definitions. It aims to allow meaningful replacement of magic numbers for axis conventions in code. E.g:

import numpy as np

arr = AxesArray(np.ones((2,3,4)), {"ax_time": 0, "ax_spatial": [1, 2]})
print(arr.axes)
print(arr.ax_time)
print(arr.n_time)
print(arr.ax_spatial)
print(arr.n_spatial)

Would show:

{"ax_time": 0, "ax_spatial": [1, 2]}
0
2
[1, 2]
[3, 4]

It is up to the user to handle the list[int] | int return values, but this module has several functions to deal with the axes dictionary, internally referred to as type CompatDict[T]:

Appending an item to a CompatDict[T]

compat_dict_append

Generating a CompatDict[int] of axes from list of axes names:

fwd_from_names

Create new CompatDict[int] from this AxesArray with new axis/axes added:

AxesArray.insert_axis

Create new CompatDict[int] from this AxesArray with axis/axes removed:

AxesArray.remove_axis

Todo

Add developer documentation here.

The recommended way to refactor existing code to use AxesArrays is to add them at the lowest level possible. Enter debug mode and see how long the expected axes persist throughout array operations. When AxesArray loses track of the correct axes, re-assign them with an AxesArray constructor (which only uses a view of the data).

Starting at the macro level runs the risk of triggering a great deal of errors from unimplemented functions.

exception pysindy.utils.axes.AxesWarning

Bases: SyntaxWarning

class pysindy.utils.axes.AxesArray(input_array: ndarray[Any, dtype[ScalarType]], axes: Dict[str, int | List[int]])[source]

Bases: NDArrayOperatorsMixin, ndarray

A numpy-like array that keeps track of the meaning of its axes.

Limitations:

  • Not all numpy functions, such as np.flatten(), have an implementation for AxesArray. In such cases a regular numpy array is returned.

  • For functions that are implemented for AxesArray, such as np.reshape(), use the numpy function rather than the bound method (e.g. arr.reshape)

  • Such functions may raise ValueError where numpy would not, when it is impossible to determine the output axis labels.

Current array function implementations:

  • np.concatenate

  • np.reshape

  • np.transpose

  • np.linalg.solve

  • np.einsum

  • np.tensordot

Indexing:

AxesArray supports all of the basic and advanced indexing of numpy arrays, with the addition that new axes can be inserted with a string name for the axis. E.g. arr = arr[..., "lineno"] will add a length-one axis at the end, along with the properties arr.ax_lineno and arr.n_lineno. If None or np.newaxis are passed, the axis is named “unk”.

Parameters:
  • input_array – the data to create the array.

  • axes – A dictionary of axis labels to shape indices. Axes labels must be of the format “ax_name”. indices can be either an int or a list of ints.

Attributes:
  • axes – dictionary of axis name to dimension index/indices

  • ax_<ax_name> – lookup ax_name in axes

  • n_<ax_name> – lookup shape of subarray defined by ax_name

Raises:
  • AxesWarning if axes does not match shape of input_array.

  • ValueError if assigning the same axis index to multiple meanings or – assigning an axis beyond ndim.

property axes
property shape

Shape of array. Unlike numpy ndarray, this is not assignable.

insert_axis(axis: Collection[int] | int, new_name: str) Dict[str, int | List[int]][source]

Create the constructor axes dict from this array, with new axis/axes

remove_axis(axis: Collection[int] | int) Dict[str, int | List[int]][source]

Create the constructor axes dict from this array, without axis/axes

pysindy.utils.axes.ravel(a, order='C')[source]
pysindy.utils.axes.ix_(*args: AxesArray)[source]
pysindy.utils.axes.concatenate(arrays, axis=0, out=None, dtype=None, casting='same_kind')[source]
pysindy.utils.axes.reshape(a: AxesArray, newshape: int | tuple[int], order='C')[source]

Gives a new shape to an array without changing its data.

Parameters:
  • a – Array to be reshaped

  • newshape – int or tuple of ints The new shape should be compatible with the original shape. In addition, the axis labels must make sense when the data is translated to a new shape. Currently, the only use case supported is to flatten an outer product of two or more axes with the same label and size.

  • order – Must be “C”

pysindy.utils.axes.transpose(a: AxesArray, axes: Tuple[int] | List[int] | None = None)[source]

Returns an array with axes transposed.

Parameters:
  • a – input array

  • axes – As the numpy function

pysindy.utils.axes.einsum(subscripts: str, *operands: AxesArray, out: ndarray[Any, dtype[ScalarType]] | None = None, **kwargs) AxesArray[source]
pysindy.utils.axes.linalg_solve(a: AxesArray, b: AxesArray) AxesArray[source]
pysindy.utils.axes.tensordot(a: AxesArray, b: AxesArray, axes: int | Sequence[Sequence[int]] = 2) AxesArray[source]
pysindy.utils.axes.comprehend_axes(x)[source]
class pysindy.utils.axes.SampleConcatter[source]

Bases: TransformerMixin

fit(x_list, y_list)[source]
transform(x_list)[source]
pysindy.utils.axes.concat_sample_axis(x_list: List[AxesArray])[source]

Concatenate all trajectories and axes used to create samples.

pysindy.utils.axes.wrap_axes(axes: dict, obj)[source]

Add axes to object (usually, a sparse matrix)

pysindy.utils.axes.compat_dict_append(compat_dict: Dict[str, T | List[T]], key: str, item_or_list: T | List[T]) None[source]

Add an element or list of elements to a dictionary, preserving old values

pysindy.utils.axes.fwd_from_names(names: List[str]) Dict[str, int | List[int]][source]

Create mapping of name: axis or name: [ax_1, ax_2, …]

pysindy.utils.base module

pysindy.utils.base.flatten_2d_tall(x)[source]
pysindy.utils.base.validate_input(x, t=<object object>)[source]

Forces input data to have compatible dimensions, if possible.

Parameters:
  • x – array of input data (measured coordinates across time)

  • t – time values for measurements.

Returns:

x as 2D array, with time dimension on first axis and coordinate index on second axis.

pysindy.utils.base.validate_no_reshape(x, t=<object object>)[source]

Check types and numerical sensibility of arguments.

Parameters:
  • x – array of input data (measured coordinates across time)

  • t – time values for measurements.

Returns:

x as 2D array, with time dimension on first axis and coordinate index on second axis.

pysindy.utils.base.validate_control_variables(x: Sequence[AxesArray], u: Sequence[AxesArray], trim_last_point: bool = False) None[source]

Ensure that control variables u are compatible with the data x.

Parameters:
  • x – trajectories of system variables

  • u – trajectories of control variables

  • trim_last_point – whether to remove last time point of controls

pysindy.utils.base.drop_nan_samples(x, y)[source]

Drops samples from x and y where either has a nan value

pysindy.utils.base.reorder_constraints(c, n_features, output_order='row')[source]

Reorder constraint matrix.

pysindy.utils.base.prox_l0(x, threshold)[source]

Proximal operator for L0 regularization.

pysindy.utils.base.prox_weighted_l0(x, thresholds)[source]

Proximal operator for weighted l0 regularization.

pysindy.utils.base.prox_l1(x, threshold)[source]

Proximal operator for L1 regularization.

pysindy.utils.base.prox_weighted_l1(x, thresholds)[source]

Proximal operator for weighted l1 regularization.

pysindy.utils.base.prox_l2(x, threshold)[source]

Proximal operator for ridge regularization.

pysindy.utils.base.prox_weighted_l2(x, thresholds)[source]

Proximal operator for ridge regularization.

pysindy.utils.base.prox_cad(x, lower_threshold)[source]

Proximal operator for CAD regularization

prox_cad(z, a, b) =
    0                    if |z| < a
    sign(z)(|z| - a)   if a < |z| <= b
    z                    if |z| > b

Entries of \(x\) smaller than a in magnitude are set to 0, entries with magnitudes larger than b are untouched, and entries in between have soft-thresholding applied.

For simplicity we set \(b = 5*a\) in this implementation.

pysindy.utils.base.get_prox(regularization)[source]
pysindy.utils.base.get_regularization(regularization)[source]
pysindy.utils.base.capped_simplex_projection(trimming_array, trimming_fraction)[source]

Projection of trimming_array onto the capped simplex

pysindy.utils.base.print_model(coef, input_features, errors=None, intercept=None, error_intercept=None, precision=3, pm='±')[source]
Parameters:
  • coef

  • input_features

  • errors

  • intercept

  • sigma_intercept

  • precision

  • pm

Returns:

pysindy.utils.base.equations(pipeline, input_features=None, precision=3, input_fmt=None)[source]
pysindy.utils.base.supports_multiple_targets(estimator)[source]

Checks whether estimator supports multiple targets.

pysindy.utils.odes module

pysindy.utils.odes.linear_damped_SHO(t, x)[source]
pysindy.utils.odes.cubic_damped_SHO(t, x)[source]
pysindy.utils.odes.linear_3D(t, x)[source]
pysindy.utils.odes.van_der_pol(t, x, p=[0.5])[source]
pysindy.utils.odes.duffing(t, x, p=[0.2, 0.05, 1])[source]
pysindy.utils.odes.lotka(t, x, p=[1, 10])[source]
pysindy.utils.odes.cubic_oscillator(t, x, p=[-0.1, 2, -2, -0.1])[source]
pysindy.utils.odes.rossler(t, x, p=[0.2, 0.2, 5.7])[source]
pysindy.utils.odes.hopf(t, x, mu=-0.05, omega=1, A=1)[source]
pysindy.utils.odes.logistic_map(x, mu)[source]
pysindy.utils.odes.logistic_map_control(x, mu, u)[source]
pysindy.utils.odes.logistic_map_multicontrol(x, mu, u)[source]
pysindy.utils.odes.lorenz(t, x, sigma=10, beta=2.66667, rho=28)[source]
pysindy.utils.odes.lorenz_u(t)[source]
pysindy.utils.odes.lorenz_control(t, x, u_fun, sigma=10, beta=2.66667, rho=28)[source]
pysindy.utils.odes.meanfield(t, x, mu=0.01)[source]
pysindy.utils.odes.oscillator(t, x, mu1=0.05, mu2=-0.01, omega=3.0, alpha=-2.0, beta=-5.0, sigma=1.1)[source]
pysindy.utils.odes.mhd(t, x, nu=0.0, mu=0.0, sigma=0.0)[source]
pysindy.utils.odes.burgers_galerkin(sigma=0.1, nu=0.025, U=1.0)[source]
pysindy.utils.odes.enzyme(t, x, jx=0.6, Vmax=1.5, Km=0.3)[source]
pysindy.utils.odes.bacterial(t, x, a1=0.004, a2=0.07, a3=0.04, b1=0.82, b2=1854.5)[source]
pysindy.utils.odes.yeast(t, x, c1=2.5, c2=-100, c3=13.6769, d1=200, d2=13.6769, d3=-6, d4=-6, e1=6, e2=-64, e3=6, e4=16, f1=64, f2=-13, f3=13, f4=-16, f5=-100, g1=1.3, g2=-3.1, h1=-200, h2=13.6769, h3=128, h4=-1.28, h5=-32, j1=6, j2=-18, j3=-100)[source]
pysindy.utils.odes.pendulum_on_cart(t, x, m=1, M=1, L=1, F=0, g=9.81)[source]
pysindy.utils.odes.f_steer(x, u, min_sangle=-0.91, max_sangle=0.91, min_svel=-0.4, max_svel=0.4, min_vel=-13.9, max_vel=45.8, switch_vel=4.755, amax=11.5)[source]
pysindy.utils.odes.f_acc(y, u, min_sangle=-0.91, max_sangle=0.91, min_svel=-0.4, max_svel=0.4, min_vel=-13.9, max_vel=45.8, switch_vel=4.755, amax=11.5)[source]
pysindy.utils.odes.kinematic_commonroad(t, x, u_fun, amax=11.5, lwb=2.391)[source]
pysindy.utils.odes.double_pendulum(t, x, m1=0.2704, m2=0.2056, a1=0.191, a2=0.1621, L1=0.2667, L2=0.2667, I1=0.003, I2=0.0011, g=9.81, k1=0, k2=0)[source]

Module contents

class pysindy.utils.AxesArray(input_array: ndarray[Any, dtype[ScalarType]], axes: Dict[str, int | List[int]])[source]

Bases: NDArrayOperatorsMixin, ndarray

A numpy-like array that keeps track of the meaning of its axes.

Limitations:

  • Not all numpy functions, such as np.flatten(), have an implementation for AxesArray. In such cases a regular numpy array is returned.

  • For functions that are implemented for AxesArray, such as np.reshape(), use the numpy function rather than the bound method (e.g. arr.reshape)

  • Such functions may raise ValueError where numpy would not, when it is impossible to determine the output axis labels.

Current array function implementations:

  • np.concatenate

  • np.reshape

  • np.transpose

  • np.linalg.solve

  • np.einsum

  • np.tensordot

Indexing:

AxesArray supports all of the basic and advanced indexing of numpy arrays, with the addition that new axes can be inserted with a string name for the axis. E.g. arr = arr[..., "lineno"] will add a length-one axis at the end, along with the properties arr.ax_lineno and arr.n_lineno. If None or np.newaxis are passed, the axis is named “unk”.

Parameters:
  • input_array – the data to create the array.

  • axes – A dictionary of axis labels to shape indices. Axes labels must be of the format “ax_name”. indices can be either an int or a list of ints.

Attributes:
  • axes – dictionary of axis name to dimension index/indices

  • ax_<ax_name> – lookup ax_name in axes

  • n_<ax_name> – lookup shape of subarray defined by ax_name

Raises:
  • AxesWarning if axes does not match shape of input_array.

  • ValueError if assigning the same axis index to multiple meanings or – assigning an axis beyond ndim.

property axes
property shape

Shape of array. Unlike numpy ndarray, this is not assignable.

insert_axis(axis: Collection[int] | int, new_name: str) Dict[str, int | List[int]][source]

Create the constructor axes dict from this array, with new axis/axes

remove_axis(axis: Collection[int] | int) Dict[str, int | List[int]][source]

Create the constructor axes dict from this array, without axis/axes

class pysindy.utils.SampleConcatter[source]

Bases: TransformerMixin

fit(x_list, y_list)[source]
transform(x_list)[source]
pysindy.utils.concat_sample_axis(x_list: List[AxesArray])[source]

Concatenate all trajectories and axes used to create samples.

pysindy.utils.wrap_axes(axes: dict, obj)[source]

Add axes to object (usually, a sparse matrix)

pysindy.utils.comprehend_axes(x)[source]
pysindy.utils.capped_simplex_projection(trimming_array, trimming_fraction)[source]

Projection of trimming_array onto the capped simplex

pysindy.utils.drop_nan_samples(x, y)[source]

Drops samples from x and y where either has a nan value

pysindy.utils.equations(pipeline, input_features=None, precision=3, input_fmt=None)[source]
pysindy.utils.get_prox(regularization)[source]
pysindy.utils.get_regularization(regularization)[source]
pysindy.utils.print_model(coef, input_features, errors=None, intercept=None, error_intercept=None, precision=3, pm='±')[source]
Parameters:
  • coef

  • input_features

  • errors

  • intercept

  • sigma_intercept

  • precision

  • pm

Returns:

pysindy.utils.prox_cad(x, lower_threshold)[source]

Proximal operator for CAD regularization

prox_cad(z, a, b) =
    0                    if |z| < a
    sign(z)(|z| - a)   if a < |z| <= b
    z                    if |z| > b

Entries of \(x\) smaller than a in magnitude are set to 0, entries with magnitudes larger than b are untouched, and entries in between have soft-thresholding applied.

For simplicity we set \(b = 5*a\) in this implementation.

pysindy.utils.prox_l0(x, threshold)[source]

Proximal operator for L0 regularization.

pysindy.utils.prox_weighted_l0(x, thresholds)[source]

Proximal operator for weighted l0 regularization.

pysindy.utils.prox_l1(x, threshold)[source]

Proximal operator for L1 regularization.

pysindy.utils.prox_weighted_l1(x, thresholds)[source]

Proximal operator for weighted l1 regularization.

pysindy.utils.prox_l2(x, threshold)[source]

Proximal operator for ridge regularization.

pysindy.utils.prox_weighted_l2(x, thresholds)[source]

Proximal operator for ridge regularization.

pysindy.utils.reorder_constraints(c, n_features, output_order='row')[source]

Reorder constraint matrix.

pysindy.utils.supports_multiple_targets(estimator)[source]

Checks whether estimator supports multiple targets.

pysindy.utils.validate_control_variables(x: Sequence[AxesArray], u: Sequence[AxesArray], trim_last_point: bool = False) None[source]

Ensure that control variables u are compatible with the data x.

Parameters:
  • x – trajectories of system variables

  • u – trajectories of control variables

  • trim_last_point – whether to remove last time point of controls

pysindy.utils.validate_input(x, t=<object object>)[source]

Forces input data to have compatible dimensions, if possible.

Parameters:
  • x – array of input data (measured coordinates across time)

  • t – time values for measurements.

Returns:

x as 2D array, with time dimension on first axis and coordinate index on second axis.

pysindy.utils.validate_no_reshape(x, t=<object object>)[source]

Check types and numerical sensibility of arguments.

Parameters:
  • x – array of input data (measured coordinates across time)

  • t – time values for measurements.

Returns:

x as 2D array, with time dimension on first axis and coordinate index on second axis.

pysindy.utils.flatten_2d_tall(x)[source]
pysindy.utils.linear_damped_SHO(t, x)[source]
pysindy.utils.cubic_damped_SHO(t, x)[source]
pysindy.utils.linear_3D(t, x)[source]
pysindy.utils.lotka(t, x, p=[1, 10])[source]
pysindy.utils.van_der_pol(t, x, p=[0.5])[source]
pysindy.utils.duffing(t, x, p=[0.2, 0.05, 1])[source]
pysindy.utils.rossler(t, x, p=[0.2, 0.2, 5.7])[source]
pysindy.utils.cubic_oscillator(t, x, p=[-0.1, 2, -2, -0.1])[source]
pysindy.utils.hopf(t, x, mu=-0.05, omega=1, A=1)[source]
pysindy.utils.lorenz(t, x, sigma=10, beta=2.66667, rho=28)[source]
pysindy.utils.lorenz_control(t, x, u_fun, sigma=10, beta=2.66667, rho=28)[source]
pysindy.utils.lorenz_u(t)[source]
pysindy.utils.meanfield(t, x, mu=0.01)[source]
pysindy.utils.oscillator(t, x, mu1=0.05, mu2=-0.01, omega=3.0, alpha=-2.0, beta=-5.0, sigma=1.1)[source]
pysindy.utils.burgers_galerkin(sigma=0.1, nu=0.025, U=1.0)[source]
pysindy.utils.mhd(t, x, nu=0.0, mu=0.0, sigma=0.0)[source]
pysindy.utils.enzyme(t, x, jx=0.6, Vmax=1.5, Km=0.3)[source]
pysindy.utils.yeast(t, x, c1=2.5, c2=-100, c3=13.6769, d1=200, d2=13.6769, d3=-6, d4=-6, e1=6, e2=-64, e3=6, e4=16, f1=64, f2=-13, f3=13, f4=-16, f5=-100, g1=1.3, g2=-3.1, h1=-200, h2=13.6769, h3=128, h4=-1.28, h5=-32, j1=6, j2=-18, j3=-100)[source]
pysindy.utils.bacterial(t, x, a1=0.004, a2=0.07, a3=0.04, b1=0.82, b2=1854.5)[source]
pysindy.utils.pendulum_on_cart(t, x, m=1, M=1, L=1, F=0, g=9.81)[source]
pysindy.utils.kinematic_commonroad(t, x, u_fun, amax=11.5, lwb=2.391)[source]
pysindy.utils.double_pendulum(t, x, m1=0.2704, m2=0.2056, a1=0.191, a2=0.1621, L1=0.2667, L2=0.2667, I1=0.003, I2=0.0011, g=9.81, k1=0, k2=0)[source]