예제 #1
0
def array(array_like, dtype=None):
    """
    Initializes a new array. Creates a NumPy array if possible; if not, creates a CasADi array.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.array.html
    """
    if is_casadi_type(array_like, recursive=False):  # If you were literally given a CasADi array, just return it
        # Handles inputs like cas.DM([1, 2, 3])
        return array_like

    elif not is_casadi_type(array_like,
                            recursive=True):  # If you were given a list of iterables that don't have CasADi types:
        # Handles inputs like [[1, 2, 3], [4, 5, 6]]
        return _onp.array(array_like, dtype=dtype)

    else:
        # Handles inputs like [[opti_var_1, opti_var_2], [opti_var_3, opti_var_4]]
        def make_row(contents: List):
            try:
                return _cas.horzcat(*contents)
            except (TypeError, Exception):
                return contents

        return _cas.vertcat(
            *[
                make_row(row)
                for row in array_like
            ]
        )
예제 #2
0
def stack(arrays: Tuple, axis: int = 0):
    """
    Join a sequence of arrays along a new axis. Returns a NumPy array if possible; if not, returns a CasADi array.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.stack.html
    """
    if not is_casadi_type(arrays, recursive=True):
        return _onp.stack(arrays, axis=axis)

    else:
        ### Validate stackability
        for array in arrays:
            if is_casadi_type(array, recursive=False):
                if not array.shape[1] == 1:
                    raise ValueError("Can only stack Nx1 CasADi arrays!")
            else:
                if not len(array.shape) == 1:
                    raise ValueError("Can only stack 1D NumPy ndarrays alongside CasADi arrays!")

        if axis == 0 or axis == -2:
            return _cas.transpose(_cas.horzcat(*arrays))
        elif axis == 1 or axis == -1:
            return _cas.horzcat(*arrays)
        else:
            raise ValueError("CasADi-backend arrays can only be 1D or 2D, so `axis` must be 0 or 1.")
예제 #3
0
def interp(x, xp, fp, left=None, right=None, period=None):
    """
    One-dimensional linear interpolation, analogous to numpy.interp().

    Returns the one-dimensional piecewise linear interpolant to a function with given discrete data points (xp, fp),
    evaluated at x.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.interp.html

    Specific notes: xp is assumed to be sorted.
    """
    if not is_casadi_type([x, xp, fp], recursive=True):
        return _onp.interp(x=x,
                           xp=xp,
                           fp=fp,
                           left=left,
                           right=right,
                           period=period)

    else:
        ### If xp or x are CasADi types, this is unsupported :(
        if is_casadi_type([x, xp], recursive=True):
            raise NotImplementedError(
                "Unfortunately, CasADi doesn't yet support a dispatch for x or xp as CasADi types."
            )

        ### Handle period argument
        if period is not None:
            if any(logical_or(xp < 0, xp > period)):
                raise NotImplementedError(
                    "Haven't yet implemented handling for if xp is outside the period."
                )  # Not easy to implement because casadi doesn't have a sort feature.

            x = _cas.mod(x, period)

        ### Make sure x isn't an int
        if isinstance(x, int):
            x = float(x)

        ### Make sure that x is an iterable
        try:
            x[0]
        except TypeError:
            x = array([x], dtype=float)

        ### Make sure xp is an iterable
        xp = array(xp, dtype=float)

        ### Do the interpolation
        f = _cas.interp1d(xp, fp, x)

        ### Handle left/right
        if left is not None:
            f = where(x < xp[0], left, f)
        if right is not None:
            f = where(x > xp[-1], right, f)

        ### Return
        return f
예제 #4
0
def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None, manual=False):
    """
    Return the cross product of two (arrays of) vectors.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.cross.html
    """
    if manual:
        cross_x = a[1] * b[2] - a[2] * b[1]
        cross_y = a[2] * b[0] - a[0] * b[2]
        cross_z = a[0] * b[1] - a[1] * b[0]
        return cross_x, cross_y, cross_z

    if not is_casadi_type([a, b], recursive=True):
        return _onp.cross(a,
                          b,
                          axisa=axisa,
                          axisb=axisb,
                          axisc=axisc,
                          axis=axis)

    else:
        if axis is not None:
            if not (axis == -1 or axis == 0 or axis == 1):
                raise ValueError("`axis` must be -1, 0, or 1.")
            axisa = axis
            axisb = axis
            axisc = axis

        if axisa == -1 or axisa == 1:
            if not is_casadi_type(a):
                a = _cas.DM(a)
            a = a.T
        elif axisa == 0:
            pass
        else:
            raise ValueError("`axisa` must be -1, 0, or 1.")

        if axisb == -1 or axisb == 1:
            if not is_casadi_type(b):
                b = _cas.DM(b)
            b = b.T
        elif axisb == 0:
            pass
        else:
            raise ValueError("`axisb` must be -1, 0, or 1.")

        # Compute the cross product, horizontally (along axis 1 of a 2D array)
        c = _cas.cross(a, b)

        if axisc == -1 or axisc == 1:
            c = c.T
        elif axisc == 0:
            pass
        else:
            raise ValueError("`axisc` must be -1, 0, or 1.")

        return c
예제 #5
0
def mod(x1, x2):
    """
    Return element-wise remainder of division.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.mod.html
    """
    if not is_casadi_type(x1) and not is_casadi_type(x2):
        return _onp.mod(x1, x2)

    else:
        return _cas.mod(x1, x2)
예제 #6
0
def reshape(a, newshape):
    """Gives a new shape to an array without changing its data."""

    if not is_casadi_type(a):
        return _onp.reshape(a, newshape)
    else:
        return _cas.reshape(a, newshape)
예제 #7
0
def vstack(arrays):
    if not is_casadi_type(arrays, recursive=True):
        return _onp.vstack(arrays)
    else:
        raise ValueError(
            "Use `np.stack()` or `np.concatenate()` instead of `np.vstack()` when dealing with mixed-backend arrays."
        )
예제 #8
0
def roll(a, shift, axis: int = None):
    """
    Roll array elements along a given axis.

    Elements that roll beyond the last position are re-introduced at the first.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.roll.html

    Parameters
    ----------
    a : array_like
        Input array.
    shift : int
        The number of places by which elements are shifted.

    Returns
    -------
    res : ndarray
        Output array, with the same shape as a.

    """
    if not is_casadi_type(a):
        return _onp.roll(a, shift, axis=axis)
    else:  # TODO add some checking to make sure shift < len(a), or shift is modulo'd down by len(a).
        # assert shift < a.shape[axis]
        if 1 in a.shape and axis == 0:
            return _cas.vertcat(a[-shift, :], a[:-shift, :])
        elif axis == 0:
            return _cas.vertcat(a.T[:, -shift], a.T[:, :-shift]).T
        elif axis == 1:
            return _cas.horzcat(a[:, -shift], a[:, :-shift])
        elif axis is None:
            return roll(a, shift=shift, axis=0)
        else:
            raise Exception("CasADi types can only be up to 2D, so `axis` must be None, 0, or 1.")
예제 #9
0
def norm(x, ord=None, axis=None):
    """
    Matrix or vector norm.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.linalg.norm.html
    """
    if not is_casadi_type(x):
        return _onp.linalg.norm(x, ord=ord, axis=axis)

    else:

        # Figure out which axis, if any, to take a vector norm about.
        if axis is not None:
            if not (
                axis==0 or
                axis==1 or
                axis == -1
            ):
                raise ValueError("`axis` must be -1, 0, or 1 for CasADi types.")
        elif x.shape[0] == 1:
            axis = 1
        elif x.shape[1] == 1:
            axis = 0

        if ord is None:
            if axis is not None:
                ord = 2
            else:
                ord = 'fro'

        if ord == 1:
            # return _cas.norm_1(x)
            return sum(
                abs(x),
                axis=axis
            )
        elif ord == 2:
            # return _cas.norm_2(x)
            return sum(
                x ** 2,
                axis=axis
            ) ** 0.5
        elif ord == 'fro':
            return _cas.norm_fro(x)
        elif np.isinf(ord):
            return _cas.norm_inf()
        else:
            try:
                return sum(
                    abs(x) ** ord,
                    axis=axis
                ) ** (1 / ord)
            except Exception as e:
                print(e)
                raise ValueError("Couldn't interpret `ord` sensibly! Tried to interpret it as a floating-point order "
                                 "as a last-ditch effort, but that didn't work.")
예제 #10
0
def empty_like(prototype, dtype=None, order='K', subok=True, shape=None):
    """Return a new array with the same shape and type as a given array."""
    if not is_casadi_type(prototype):
        return _onp.empty_like(prototype,
                               dtype=dtype,
                               order=order,
                               subok=subok,
                               shape=shape)
    else:
        return zeros_like(prototype)
예제 #11
0
def ones_like(a, dtype=None, order='K', subok=True, shape=None):
    """Return an array of ones with the same shape and type as a given array."""
    if not is_casadi_type(a):
        return _onp.ones_like(a,
                              dtype=dtype,
                              order=order,
                              subok=subok,
                              shape=shape)
    else:
        return _onp.ones(shape=length(a))
예제 #12
0
def where(
    condition,
    value_if_true,
    value_if_false,
):
    if not is_casadi_type([condition, value_if_true, value_if_false],
                          recursive=True):
        return _onp.where(condition, value_if_true, value_if_false)
    else:
        return _cas.if_else(condition, value_if_true, value_if_false)
예제 #13
0
def logspace(start: float = 0., stop: float = 1., num: int = 50):
    """
    Return numbers spaced evenly on a log scale.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.logspace.html
    """
    if not is_casadi_type([start, stop, num], recursive=True):
        return _onp.logspace(start, stop, num)
    else:
        return 10**linspace(start, stop, num)
예제 #14
0
def linspace(start: float = 0., stop: float = 1., num: int = 50):
    """
    Returns evenly spaced numbers over a specified interval.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.linspace.html
    """
    if not is_casadi_type([start, stop, num], recursive=True):
        return _onp.linspace(start, stop, num)
    else:
        return _cas.linspace(start, stop, num)
예제 #15
0
def logical_not(x):
    """
    Compute the truth value of NOT x element-wise.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.logical_not.html
    """
    if not is_casadi_type(x, recursive=False):
        return _onp.logical_not(x)

    else:
        return _cas.logic_not(x)
예제 #16
0
def logical_or(x1, x2):
    """
    Compute the truth value of x1 OR x2 element-wise.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.logical_or.html
    """
    if not is_casadi_type([x1, x2], recursive=True):
        return _onp.logical_or(x1, x2)

    else:
        return _cas.logic_or(x1, x2)
예제 #17
0
def det(A):
    """
    Returns the determinant of the matrix A.

    See: https://numpy.org/doc/stable/reference/generated/numpy.linalg.det.html
    """
    if not is_casadi_type(A):
        return _onp.linalg.det(A)

    else:
        return _cas.det(A)
예제 #18
0
def pinv(A):
    """
    Returns the Moore-Penrose pseudoinverse of the matrix A.

    See: https://numpy.org/doc/stable/reference/generated/numpy.linalg.pinv.html
    """
    if not is_casadi_type(A):
        return _onp.linalg.pinv(A)

    else:
        return _cas.pinv(A)
예제 #19
0
def full_like(a, fill_value, dtype=None, order='K', subok=True, shape=None):
    """Return a full array with the same shape and type as a given array."""
    if not is_casadi_type(a):
        return _onp.full_like(a,
                              fill_value,
                              dtype=dtype,
                              order=order,
                              subok=subok,
                              shape=shape)
    else:
        return fill_value * ones_like(a)
예제 #20
0
def any(a):  # TODO add axis functionality
    """
    Test whether any array element along a given axis evaluates to True.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.any.html
    """
    if not is_casadi_type(a, recursive=False):
        return _onp.any(a)

    else:
        return _cas.logic_any(a)
예제 #21
0
def inner(x, y):
    """
    Inner product of two arrays.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.inner.html
    """
    if not is_casadi_type([x, y], recursive=True):
        return _onp.inner(x, y)

    else:
        return _cas.dot(x, y)
예제 #22
0
def dot(a, b):
    """
    Dot product of two arrays.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.dot.html
    """
    if not is_casadi_type([a, b], recursive=True):
        return _onp.dot(a, b)

    else:
        return _cas.dot(a, b)
예제 #23
0
def prod(x, axis: int = None):
    """
    Return the product of array elements over a given axis.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.prod.html
    """
    if not is_casadi_type(x):
        return _onp.prod(x, axis=axis)

    else:
        return _cas.exp(sum(_cas.log(x), axis=axis))
예제 #24
0
def transpose(a, axes=None):
    """
    Reverse or permute the axes of an array; returns the modified array.

    For an array a with two axes, transpose(a) gives the matrix transpose.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.transpose.html
    """
    if not is_casadi_type(a, recursive=False):
        return _onp.transpose(a, axes=axes)
    else:
        return _cas.transpose(a)
예제 #25
0
def outer(x, y):
    """
    Compute the outer product of two vectors.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.outer.html
    """
    if not is_casadi_type([x, y], recursive=True):
        return _onp.outer(x, y)

    else:
        if len(y.shape) == 1:  # Force y to be transposable if it's not.
            y = _onp.expand_dims(y, 1)
        return x @ y.T
예제 #26
0
def all(a):  # TODO add axis functionality
    """
    Test whether all array elements along a given axis evaluate to True.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.all.html
    """
    if not is_casadi_type(a, recursive=False):
        return _onp.all(a)

    else:
        try:
            return _cas.logic_all(a)
        except NotImplementedError:
            return False
예제 #27
0
def reshape(a, newshape):
    """Gives a new shape to an array without changing its data."""

    if not is_casadi_type(a):
        return _onp.reshape(a, newshape)
    else:
        if isinstance(newshape, int):
            newshape = (newshape, 1)

        if len(newshape) > 2:
            raise ValueError(
                "CasADi data types are limited to no more than 2 dimensions.")

        return _cas.reshape(a.T, newshape[::-1]).T
예제 #28
0
def geomspace(start: float = 1., stop: float = 10., num: int = 50):
    """
    Return numbers spaced evenly on a log scale (a geometric progression).

    This is similar to logspace, but with endpoints specified directly.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.geomspace.html
    """
    if not is_casadi_type([start, stop, num], recursive=True):
        return _onp.geomspace(start, stop, num)
    else:
        if start <= 0 or stop <= 0:
            raise ValueError("Both start and stop must be positive!")
        return _onp.log10(10**linspace(start, stop, num))
예제 #29
0
def dot(a, b, manual=False):
    """
    Dot product of two arrays.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.dot.html
    """
    if manual:
        return sum([ai * bi for ai, bi in zip(a, b)])

    if not is_casadi_type([a, b], recursive=True):
        return _onp.dot(a, b)

    else:
        return _cas.dot(a, b)
예제 #30
0
def inner(x, y, manual=False):
    """
    Inner product of two arrays.

    See syntax here: https://numpy.org/doc/stable/reference/generated/numpy.inner.html
    """
    if manual:
        return sum([xi * yi for xi, yi in zip(x, y)])

    if not is_casadi_type([x, y], recursive=True):
        return _onp.inner(x, y)

    else:
        return _cas.dot(x, y)