CasADi API

Expression tools

acos(...)

Arc cosine: x -> acos(x)

acos(float x) -> float
acos(DM x) -> DM
acos(SX x) -> SX
acos(MX x) -> MX

Elementwise; the result is dense (acos(0) == pi/2). Arguments outside [-1, 1] give NaN.

>>> acos(DM([0, 1]))
DM([1.5708, 0])
>> acos(DM([0; 1]))
[1.5708, 0]
julia> acos.(ca.DM([0, 1]))
DM([1.5708, 0])

See also: cos, asin

Extra doc | Doc source | Implementation

acosh(...)

Inverse hyperbolic cosine: x -> acosh(x)

acosh(float x) -> float
acosh(DM x) -> DM
acosh(SX x) -> SX
acosh(MX x) -> MX

Elementwise; the result is dense. Defined for x >= 1, NaN below.

>>> acosh(DM([1, 2]))
DM([0, 1.31696])
>> acosh(DM([1; 2]))
[0, 1.31696]
julia> acosh.(ca.DM([1, 2]))
DM([0, 1.31696])

See also: cosh

Extra doc | Doc source | Implementation

adj(...)

Adjugate (classical adjoint) of a square matrix.

adj(DM A) -> DM
adj(SX A) -> SX

Transpose of the cofactor matrix, computed by Laplace expansion. For an invertible matrix inv(A) == adj(A)/det(A). Cost grows factorially with the size; intended for small (symbolic) matrices. A structural zero cofactor stays structurally zero. A non-square input raises an error.

>>> adj(DM([[1, 2], [3, 4]]))
DM(
[[4, -2],
 [-3, 1]])
>>> X = SX.sym("X", 2, 2)
>>> adj(X)
SX(
[[X_3, (-X_2)],
 [(-X_1), X_0]])
>>> adj(DM(5)), adj(DM(Sparsity.diag(3))).nnz()
(DM(1), 3)
>> adj(DM([1 2; 3 4]))
[[4, -2],
[-3, 1]]
>> X = SX.sym('X', 2, 2);
>> adj(X)
[[X_3, (-X_2)],
[(-X_1), X_0]]
>> adj(DM(5)), adj(DM(Sparsity.diag(3))).nnz()
1
3
julia> ca.adj(ca.DM([1 2; 3 4]))
DM(
[[4, -2],
 [-3, 1]])
julia> X = ca.SX.sym("X", 2, 2);
julia> ca.adj(X)
SX(
[[X_3, (-X_2)],
 [(-X_1), X_0]])
julia> ca.adj(ca.DM(5)), ca.nnz(ca.adj(ca.DM(ca.Sparsity.diag(3))))
(1, 3)

See also: inv_minor, cofactor, det

Extra doc | Doc source | Implementation

asin(...)

Arc sine: x -> asin(x)

asin(float x) -> float
asin(DM x) -> DM
asin(SX x) -> SX
asin(MX x) -> MX

Elementwise; sparsity preserved. Arguments outside [-1, 1] give NaN.

>>> asin(DM([0, 1]))
DM([0, 1.5708])
>> asin(DM([0; 1]))
[0, 1.5708]
julia> asin.(ca.DM([0, 1]))
DM([0, 1.5708])

See also: sin, acos

Extra doc | Doc source | Implementation

asinh(...)

Inverse hyperbolic sin: x -> asinh(x)

asinh(float x) -> float
asinh(DM x) -> DM
asinh(SX x) -> SX
asinh(MX x) -> MX

Elementwise; sparsity preserved.

>>> asinh(DM([-1, 1]))
DM([-0.881374, 0.881374])
>> asinh(DM([-1; 1]))
[-0.881374, 0.881374]
julia> asinh.(ca.DM([-1, 1]))
DM([-0.881374, 0.881374])

See also: sinh

Extra doc | Doc source | Implementation

atan(...)

Arc tangent: x -> atan(x)

atan(float x) -> float
atan(DM x) -> DM
atan(SX x) -> SX
atan(MX x) -> MX

Elementwise; sparsity preserved. Result in (-pi/2, pi/2); use atan2 for a quadrant-aware angle.

>>> atan(DM([0, 1]))
DM([0, 0.785398])
>> atan(DM([0; 1]))
[0, 0.785398]
julia> atan.(ca.DM([0, 1]))
DM([0, 0.785398])

See also: atan2, tan

Extra doc | Doc source | Implementation

atan2(...)

Two argument arc tangent: (y,x) -> atan2(y,x)

atan2(float x, float y) -> float
atan2(DM x, DM y) -> DM
atan2(SX x, SX y) -> SX
atan2(MX x, MX y) -> MX

theta = atan2(y,x) corresponds to x = r cos(theta), y = r sin(theta)

Angle in (-pi, pi] of the point (x, y), taking the quadrant into account; the first argument is the y coordinate, as in C and numpy. Elementwise, shape rules as for plus. atan2(0, 0) is 0.

>>> atan2(DM([1, -1, 0]), DM([-1, -1, 1]))
DM([2.35619, -2.35619, 0])
>>> atan2(SX.sym("y"), SX.sym("x"))
SX(atan2(y,x))
>> atan2(DM([1; -1; 0]), DM([-1; -1; 1]))
[2.35619, -2.35619, 0]
>> atan2(SX.sym('y'), SX.sym('x'))
atan2(y,x)
julia> atan.(ca.DM([1, -1, 0]), ca.DM([-1, -1, 1]))
DM([2.35619, -2.35619, 0])
julia> atan(ca.SX.sym("y"), ca.SX.sym("x"))
SX(atan2(y,x))

See also: atan

Extra doc | Doc source | Implementation

atanh(...)

Inverse hyperbolic tangent: x -> atanh(x)

atanh(float x) -> float
atanh(DM x) -> DM
atanh(SX x) -> SX
atanh(MX x) -> MX

Elementwise; sparsity preserved. Defined for |x| < 1, infinite at +-1.

>>> atanh(DM([0, 0.5]))
DM([0, 0.549306])
>> atanh(DM([0; 0.5]))
[0, 0.549306]
julia> atanh.(ca.DM([0, 0.5]))
DM([0, 0.549306])

See also: tanh

Extra doc | Doc source | Implementation

bilin(...)

Calculate bilinear/quadratic form x^T A y.

bilin(DM A, DM x) -> DM
bilin(SX A, SX x) -> SX
bilin(MX A, MX x) -> MX
bilin(DM A, DM x, DM y) -> DM
bilin(SX A, SX x, SX y) -> SX
bilin(MX A, MX x, MX y) -> MX

x and y must be vectors (row vectors are transposed, sparse vectors densified) with x.numel() == A.size1() and y.numel() == A.size2(); otherwise an error is raised. The result is scalar. When y is omitted, the quadratic form x^T A x is calculated.

>>> A = DM([[1, 2], [3, 4]])
>>> bilin(A, DM([1, 1]), DM([1, 2]))
DM(16)
>>> bilin(A, DM([1, 1]))
DM(10)
>>> bilin(MX.sym("A", 2, 2), MX.sym("x", 2), MX.sym("y", 2))
MX(bilin(A, x, y))
>> A = DM([1 2; 3 4]);
>> bilin(A, DM([1; 1]), DM([1; 2]))
16
>> bilin(A, DM([1; 1]))
10
>> bilin(MX.sym('A', 2, 2), MX.sym('x', 2), MX.sym('y', 2))
bilin(A, x, y)
julia> A = ca.DM([1 2; 3 4]);
julia> ca.bilin(A, ca.DM([1, 1]), ca.DM([1, 2]))
DM(16)
julia> ca.bilin(A, ca.DM([1, 1]))
DM(10)
julia> ca.bilin(ca.MX.sym("A", 2, 2), ca.MX.sym("x", 2), ca.MX.sym("y", 2))
MX(bilin(A, x, y))

See also: rank1, dot, mtimes

Extra doc | Doc source

blazing_spline(...)

Construct a parametric-knots blazing_spline.

blazing_spline(str name, [[float]] knots, dict opts) -> Function
blazing_spline(str name, [int] knot_dims, dict opts) -> Function

Like blazing_spline, but the knot values are provided as a symbolic input at evaluation time instead of being fixed at construction time. Only knot vector sizes (per dimension) are needed at construction.

The resulting Function has inputs (x, C, knots) where knots is the stacked knot vector. Supports the same precompute_coeff and precompute_grid options as the fixed-knots variant.

Construct a specialized parametric BSpline.

Specialized in these ways:

  • order 3 is assumed

  • up to dimension 5 supported

  • a single scalar output (m=1)

Extra doc | Doc source | Implementation

blockcat(...)

Construct a matrix from a list of lists of blocks.

blockcat([[DM]] v) -> DM
blockcat([[SX]] v) -> SX
blockcat([[MX]] v) -> MX
blockcat(Sparsity A, Sparsity B, Sparsity C, Sparsity D) -> Sparsity
blockcat(DM A, DM B, DM C, DM D) -> DM
blockcat(SX A, SX B, SX C, SX D) -> SX
blockcat(MX A, MX B, MX C, MX D) -> MX

Each inner list is a block row: its entries are concatenated horizontally, and the resulting block rows are concatenated vertically. The usual concatenation rules apply: blocks in one block row need the same number of rows, block rows need the same total number of columns, otherwise an error is raised. Inverse of blocksplit: blockcat(blocksplit(x, ...)) == x.

Parameters:

v -- List of block rows, each a list of matrices

Returns:

Matrix of the same type as the blocks

>>> blockcat([[DM(1), DM([[2, 3]])], [DM([4, 5]), DM.eye(2)]])
DM(
[[1, 2, 3],
 [4, 1, 00],
 [5, 00, 1]])
>>> a, b, c, d = MX.sym("a", 2, 2), MX.sym("b", 2, 1), MX.sym("c", 1, 2), MX.sym("d")
>>> blockcat([[a, b], [c, d]])
MX(horzcat(horzcat(a, b)', horzcat(c, d)')')
>> blockcat({{DM(1), DM([2 3])}, {DM([4; 5]), DM.eye(2)}})
[[1, 2, 3],
[4, 1, 00],
[5, 00, 1]]
>> a = MX.sym('a', 2, 2); b = MX.sym('b', 2, 1); c = MX.sym('c', 1, 2); d = MX.sym('d');
>> blockcat({{a, b}, {c, d}})
horzcat(horzcat(a, b)', horzcat(c, d)')'
>> [a, b; c, d]
horzcat(horzcat(a, b)', horzcat(c, d)')'
julia> ca.blockcat([[ca.DM(1), ca.DM([2 3])], [ca.DM([4, 5]), ca.DM.eye(2)]])
DM(
[[1, 2, 3],
 [4, 1, 00],
 [5, 00, 1]])
julia> a, b = ca.MX.sym("a", 2, 2), ca.MX.sym("b", 2, 1);
julia> c, d = ca.MX.sym("c", 1, 2), ca.MX.sym("d");
julia> ca.blockcat([[a, b], [c, d]])
MX(horzcat(horzcat(a, b)', horzcat(c, d)')')
julia> print([a b; c d])
horzcat(horzcat(a, b)', horzcat(c, d)')'

See also: horzcat, vertcat, blocksplit

Extra doc | Doc source | Implementation

blocksplit(...)

Split a matrix into a grid of blocks.

blocksplit(Sparsity x, int vert_incr, int horz_incr) -> [[Sparsity]]
blocksplit(DM x, int vert_incr, int horz_incr) -> [[DM]]
blocksplit(SX x, int vert_incr, int horz_incr) -> [[SX]]
blocksplit(MX x, int vert_incr, int horz_incr) -> [[MX]]
blocksplit(Sparsity x, [int] vert_offset, [int] horz_offset) -> [[Sparsity]]
blocksplit(DM x, [int] vert_offset, [int] horz_offset) -> [[DM]]
blocksplit(SX x, [int] vert_offset, [int] horz_offset) -> [[SX]]
blocksplit(MX x, [int] vert_offset, [int] horz_offset) -> [[MX]]

The rows are split at vert_offset and every row block is then split at horz_offset. Both offset lists follow the rules of vertsplit and horzsplit: start at 0, non-decreasing, end at the row (column) count. Inverse of blockcat: blockcat(blocksplit(x, vert_offset, horz_offset)) == x.

Parameters:
  • x -- Matrix (or Sparsity) to split; any shape

  • vert_offset -- Row boundaries of the block rows

  • horz_offset -- Column boundaries of the block columns

Returns:

List of block rows, each a list of matrices of the same type as x

>>> x = DM([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> blocksplit(x, [0, 1, 3], [0, 2, 3])
[[DM([[1, 2]]), DM(3)], [DM(
[[4, 5],
 [7, 8]]), DM([6, 9])]]
>> x = DM([1 2 3; 4 5 6; 7 8 9]);
>> b = blocksplit(x, [0, 1, 3], [0, 2, 3]); disp(size(b)), disp(b{1}{1}), disp(b{2}{1})
1 2
[[1, 2]]
[[4, 5],
[7, 8]]
>> b{1}{2}, b{2}{2}
3
[6, 9]
julia> x = ca.DM([1 2 3; 4 5 6; 7 8 9]);
julia> ca.blocksplit(x, [0, 1, 3], [0, 2, 3])
2-element Vector{Vector{DM}}:
 DM[[[1, 2]], 3]
 DM[
[[4, 5],
 [7, 8]], [6, 9]]

See also: blockcat, vertsplit, horzsplit

Extra doc | Doc source | Implementation

bspline(...)

Evaluate a tensor-product B-spline with fixed coefficients.

bspline(MX x, DM coeffs, [[float]] knots, [int] degree, int m, dict opts) -> MX
bspline(MX x, MX coeffs, [[float]] knots, [int] degree, int m, dict opts) -> MX
bspline(MX x, MX coeffs, [MX] knots, [int] degree, int m, dict opts) -> MX

Returns an m-by-1 expression with the spline values at x. The spline is defined by one knot vector and one degree per dimension; the number of basis functions per dimension is len(knots[i]) - degree[i] - 1 and the coefficient vector must hold m times the product of these counts, in column- major order. Outside the knot range the spline is zero. Derivatives are available.

Parameters:
  • x -- Column vector with one entry per dimension

  • coeffs -- Coefficient vector; its length is not validated

  • knots -- One knot vector per dimension, numeric

  • degree -- Degree per dimension; must have as many entries as knots

  • m -- Number of outputs per evaluation

  • opts -- "lookup_mode" (see low) and "inline" (bool, default false: build an explicit expression instead of a BSpline node). Unknown keys are ignored.

>>> x = MX.sym("x")
>>> knots = [[0, 0, 0, 0, 1, 2, 3, 3, 3, 3]]
>>> c = DM(range(6))
>>> y = bspline(x, c, knots, [3], 1)
>>> f = Function("f", [x], [y])
>>> y, f(1.5), f(4)
(MX(BSpline(x)), DM(2.5), DM(0))
>>> Function("df", [x], [jacobian(y, x)])(1.5)
DM(1.125)
>>> try:
...   bspline(MX.sym("v", 2), c, knots, [3], 1)
... except Exception as e:
...   print("must match" in str(e))
True
>> x = MX.sym('x');
>> knots = {[0 0 0 0 1 2 3 3 3 3]};
>> c = DM((0:5)');
>> y = bspline(x, c, knots, 3, 1);
>> f = Function('f', {x}, {y});
>> y, f(1.5), f(4)
BSpline(x)
2.5
0
>> df = Function('df', {x}, {jacobian(y, x)});
>> df(1.5)
1.125
>> try, bspline(MX.sym('v', 2), c, knots, 3, 1); catch e, disp('must match'); end
must match
julia> x = ca.MX.sym("x");
julia> knots = [[0, 0, 0, 0, 1, 2, 3, 3, 3, 3]];
julia> c = ca.DM(0:5);
julia> y = ca.bspline(x, c, knots, [3], 1);
julia> f = ca.Function("f", [x], [y]);
julia> y, f(1.5), f(4)
(BSpline(x), 2.5, 0)
julia> ca.Function("df", [x], [ca.jacobian(y, x)])(1.5)
DM(1.125)
julia> try
           ca.bspline(ca.MX.sym("v", 2), c, knots, [3], 1)
       catch e
           println(occursin("must match", sprint(showerror, e)))
       end
true

See also: bspline_dual, interpolant

Extra doc | Doc source | Implementation

bspline_dual(...)

Evaluate the B-spline basis functions at given points.

bspline_dual([float] x, [[float]] knots, [int] degree, dict opts) -> DM

Returns the sparse matrix of basis function values such that bspline_dual(x, knots, degree) @ coeffs equals bspline(x, coeffs, knots, degree, 1) at the same points. Each row corresponds to one evaluation point and each row sums to one inside the knot range. Used to fit coefficients to data.

Parameters:
  • x -- Evaluation points, flattened: n_points * n_dims numbers, point by point

  • knots -- One knot vector per dimension

  • degree -- Degree per dimension

  • opts -- "lookup_mode": list with one of "linear", "exact", "binary" per dimension

Returns:

n_points-by-n_coeffs DM

>>> knots = [[0, 0, 0, 0, 1, 2, 3, 3, 3, 3]]
>>> B = MX.bspline_dual([0.5, 1.5], knots, [3])
>>> B.shape, sum2(B)
((2, 6), DM([1, 1]))
>>> B @ DM(range(6))
DM([1.17708, 2.5])
>> knots = {[0 0 0 0 1 2 3 3 3 3]};
>> B = MX.bspline_dual([0.5, 1.5], knots, 3);
>> size(B), sum2(B)
2 6
[1, 1]
>> B * DM((0:5)')
[1.17708, 2.5]
julia> knots = [[0, 0, 0, 0, 1, 2, 3, 3, 3, 3]];
julia> B = ca.MX.bspline_dual([0.5, 1.5], knots, [3]);
julia> size(B), sum(B, dims=2)
((2, 6), [1, 1])
julia> B * ca.DM(0:5)
DM([1.17708, 2.5])

See also: bspline

Extra doc | Doc source | Implementation

ceil(...)

Round up to nearest integer: x -> ceil(x)

ceil(float x) -> float
ceil(DM x) -> DM
ceil(SX x) -> SX
ceil(MX x) -> MX

Elementwise, towards plus infinity; sparsity preserved. The derivative is zero everywhere.

>>> ceil(DM([-1.5, 1.5]))
DM([-1, 2])
>> ceil(DM([-1.5; 1.5]))
[-1, 2]
julia> ceil.(ca.DM([-1.5, 1.5]))
DM([-1, 2])

See also: floor

Extra doc | Doc source | Implementation

chol(...)

Cholesky factorization of a symmetric positive definite matrix.

chol(DM A) -> DM
chol(SX A) -> SX

Returns the upper triangular factor R with R^T*R == A, obtained from the sparse LDL^T factorization (without fill-reducing permutation) as diag(sqrt(D))*L^T. The sparsity pattern of A must be symmetric; otherwise an error is raised. An indefinite A gives nan entries without an error. Works symbolically on SX.

>>> R = chol(DM([[4, 2], [2, 3]]))
>>> R
DM(
[[2, 1],
 [00, 1.41421]])
>>> mtimes(R.T, R)
DM(
[[4, 2],
 [2, 3]])
>>> chol(DM(Sparsity.diag(3)) * 4).nnz()
3
>> R = chol(DM([4 2; 2 3]));
>> R
[[2, 1],
[00, 1.41421]]
>> R'*R
[[4, 2],
[2, 3]]
>> chol(DM(Sparsity.diag(3)) * 4).nnz()
3
julia> R = ca.chol(ca.DM([4 2; 2 3]))
DM(
[[2, 1],
 [00, 1.41421]])
julia> R' * R
DM(
[[4, 2],
 [2, 3]])
julia> ca.nnz(ca.chol(ca.DM(ca.Sparsity.diag(3)) * 4))
3

See also: ldl, qr

Extra doc | Doc source | Implementation

cofactor(...)

Cofactor of a square matrix: (-1)^(i+j) times minor(x, i, j)

cofactor(DM x, int i, int j) -> DM
cofactor(SX x, int i, int j) -> SX

Same argument convention as minor: i is a column index, j a row index.

>>> A = DM([[1, 2, 3], [0, 1, 4], [5, 6, 0]])
>>> cofactor(A, 0, 1), cofactor(A, 0, 0)
(DM(18), DM(-24))
>> A = DM([1 2 3; 0 1 4; 5 6 0]);
>> cofactor(A, 0, 1), cofactor(A, 0, 0)
18
-24
julia> A = ca.DM([1 2 3; 0 1 4; 5 6 0]);
julia> ca.cofactor(A, 0, 1), ca.cofactor(A, 0, 0)
(18, -24)

See also: minor, adj

Extra doc | Doc source | Implementation

collocation_coeff(...)

Obtain collocation interpolating matrices.

collocation_coeff([float] tau) -> (DM, DM, DM)

A collocation method poses a polynomial Pi that interpolates exactly through an initial state (0,X_0) and helper states at collocation points (tau_j,Xc_j) with j=1..degree.

This function computes the linear mapping between dPi/dt and coefficients Z=[X_0 Xc].

Parameters:
  • tau -- location of collocation points (length: degree), as obtained from collocation_points

  • C -- interpolating coefficients to obtain derivatives. Size: (degree+1)-by-degree

You may find the slopes of Pi at the collocation points as

dPi/dt @ Xc = (1/h) Z*C,

with h the length of the integration interval.

Parameters:

D -- interpolating coefficients to obtain end state. Size: (degree+1)-by-1

You may find the end point of Pi as

Pi @X_f = Z*D

Parameters:

B -- quadrature coefficients Size: degree-by-1

Given quadrature righ-hand-sides 'quad' evaluated at the collocation points, you may find the integrated quadratures as

q = quad*B*h

Extra doc | Doc source | Implementation

collocation_interpolators(...)

Obtain collocation interpolating matrices.

collocation_interpolators([float] tau) -> ([[float]], [float])

A collocation method poses a polynomial Pi that interpolates exactly through an initial state (0,X_0) and helper states at collocation points (tau_j,X:collPoint(j)).

This function computes the linear mapping between dPi/dt and coefficients Z=[X_0 X:collPoints].

Parameters:
  • tau -- location of collocation points, as obtained from collocation_points

  • C -- interpolating coefficients to obtain derivatives. Length: order+1, order+1

dPi/dt @Z_j = (1/h) Sum_i C[j][i]*Z_i,

with h the length of the integration interval.

Parameters:

D -- interpolating coefficients to obtain end state. Length: order+1

Pi @X_f = Sum_i D[i]*Z_i

Extra doc | Doc source | Implementation

collocation_points(...)

Obtain collocation points of specific order and scheme.

collocation_points(int order, str scheme) -> [float]
Parameters:
  • order -- Which order (1 to 9 supported)

  • scheme -- 'radau' or 'legendre'

Extra doc | Doc source | Implementation

complement(...)

Returns the list of all i in [0, size[ not found in supplied list.

complement([int] v, int size) -> [int]

The supplied vector may contain duplicates and may be non-monotonous The supplied vector will be checked for bounds The result vector is guaranteed to be monotonously increasing

Extra doc | Doc source | Implementation

conditional(...)

Create a switch.

conditional(DM ind, [DM] x, DM x_default, bool short_circuit) -> DM
conditional(SX ind, [SX] x, SX x_default, bool short_circuit) -> SX
conditional(MX ind, [MX] x, MX x_default, bool short_circuit) -> MX

If the scalar condition ind evaluates to the integer k, where 0<=k<x.size(), then x[k] is returned, otherwise x_default is returned (also for negative or non-integer values). By default this is a chain of if_else expressions, so all cases are evaluated. With short_circuit true (MX only; SX raises an error) a Switch function evaluates only the selected case.

>>> conditional(DM(1), [DM(10), DM(20)], DM(-1))
DM(20)
>>> conditional(DM(5), [DM(10), DM(20)], DM(-1))
DM(-1)
>>> x = SX.sym("x"); y = SX.sym("y"); z = SX.sym("z")
>>> conditional(x, [y, z], 0)
SX(@1=(x==1), ((@1?z:0)+((!@1)?((x==0)?y:0):0)))
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> conditional(X, [Y, 2*Y], 0, True)
MX(switch(X, Y){0})
>> conditional(DM(1), {DM(10), DM(20)}, DM(-1))
20
>> conditional(DM(5), {DM(10), DM(20)}, DM(-1))
-1
>> x = SX.sym('x'); y = SX.sym('y'); z = SX.sym('z');
>> conditional(x, {y, z}, 0)
@1=(x==1), ((@1?z:0)+((!@1)?((x==0)?y:0):0))
>> X = MX.sym('X'); Y = MX.sym('Y');
>> conditional(X, {Y, 2*Y}, 0, true)
switch(X, Y){0}
julia> ca.conditional(ca.DM(1), [ca.DM(10), ca.DM(20)], ca.DM(-1))
DM(20)
julia> ca.conditional(ca.DM(5), [ca.DM(10), ca.DM(20)], ca.DM(-1))
DM(-1)
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); z = ca.SX.sym("z");
julia> ca.conditional(x, [y, z], 0)
SX(@1=(x==1), ((@1?z:0)+((!@1)?((x==0)?y:0):0)))
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.conditional(X, [Y, 2 * Y], 0, true)
MX(switch(X, Y){0})

See also: if_else, Function.conditional

Extra doc | Doc source | Implementation

conic_debug(...)

Generate native code in the interfaced language for debugging, to a stream.

conic_debug(Function f, std::ostream & file)
conic_debug(Function f, str filename)

Generate native code in the interfaced language for debugging.

Writes a standalone problem description in the solver's own language (e.g. a script for the solver's native API) for a Function created by conic. Only some plugins implement this; the others raise an error.

Parameters:
  • f -- Function created by conic (not qpsol)

  • filename -- Output file name

>>> import os, tempfile
>>> C = conic("C", "qrqp", {"h": Sparsity.dense(1)}, {"print_header": False})
>>> d = tempfile.mkdtemp(); fn = os.path.join(d, "C_debug.txt")
>>> try:
...     conic_debug(C, fn)
... except RuntimeError as e:
...     print("generateNativeCode not defined" in str(e))
True
>>> os.remove(fn); os.rmdir(d)
>> C = conic('C', 'qrqp', struct('h', Sparsity.dense(1)), struct('print_header', false));
>> fn = [tempname '.txt'];
>> try, conic_debug(C, fn); catch e, msg = e.message; end
>> contains(msg, 'generateNativeCode not defined')
1
>> delete(fn)
julia> opts = Dict("print_header" => false);
julia> C = ca.conic("C", "qrqp", Dict("h" => ca.Sparsity.dense(1)), opts);
julia> d = mktempdir(); fn = joinpath(d, "C_debug.txt");
julia> try
           ca.conic_debug(C, fn)
       catch e
           println(occursin("generateNativeCode not defined", sprint(showerror, e)))
       end
true
julia> rm(d, recursive=true)

Extra doc | Doc source | Implementation

conic_in(...)

Get the name of a QP solver input by index.

conic_in() -> [str]
conic_in(int ind) -> str
Parameters:

ind -- Index in 0.. conic_n_in() -1; any other value gives an empty string

>>> conic_in(0), conic_in(11), repr(conic_in(12))
('h', 'p', "''")
>> conic_in(0), conic_in(11), isempty(conic_in(12))
h
p
1
julia> ca.conic_in(0), ca.conic_in(11), ca.conic_in(12)
("h", "p", "")

Get the input scheme of QP solvers.

Returns the names of the 12 inputs of a Function created by conic, in order: h, g, a, lba, uba, lbx, ubx, x0, lam_x0, lam_a0, q, p. A Function created by qpsol uses the nlpsol scheme instead.

>>> conic_in()
['h', 'g', 'a', 'lba', 'uba', 'lbx', 'ubx', 'x0', 'lam_x0', 'lam_a0', 'q', 'p']
>> conic_in()
h
g
a
lba
uba
lbx
ubx
x0
lam_x0
lam_a0
q
p
julia> ca.conic_in()
12-element Vector{String}:
 "h"
 "g"
 "a"
 "lba"
 "uba"
 "lbx"
 "ubx"
 "x0"
 "lam_x0"
 "lam_a0"
 "q"
 "p"

See also: conic_out, conic_n_in, nlpsol_in

Extra doc | Doc source | Implementation

conic_n_in(...)

Get the number of QP solver inputs.

conic_n_in() -> int
>>> conic_n_in()
12
>> conic_n_in()
12
julia> ca.conic_n_in()
12

Extra doc | Doc source | Implementation

conic_n_out(...)

Get the number of QP solver outputs.

conic_n_out() -> int
>>> conic_n_out()
4
>> conic_n_out()
4
julia> ca.conic_n_out()
4

Extra doc | Doc source | Implementation

conic_option_info(...)

Get the documentation string of an option of a QP solver plugin.

conic_option_info(str name, str op) -> str
Parameters:
  • name -- Plugin name

  • op -- Option name; an unknown option raises an error

>>> conic_option_info("qrqp", "max_iter")
'Maximum number of iterations [1000].'
>> conic_option_info('qrqp', 'max_iter')
Maximum number of iterations [1000].
julia> ca.conic_option_info("qrqp", "max_iter")
"Maximum number of iterations [1000]."

Extra doc | Doc source | Implementation

conic_option_type(...)

Get the type of an option of a QP solver plugin.

conic_option_type(str name, str op) -> str
Parameters:
  • name -- Plugin name

  • op -- Option name; an unknown option raises an error

Returns:

Type name such as "OT_INT", "OT_BOOL", "OT_STRING"

>>> conic_option_type("qrqp", "max_iter"), conic_option_type("qrqp", "print_iter")
('OT_INT', 'OT_BOOL')
>> conic_option_type('qrqp', 'max_iter'), conic_option_type('qrqp', 'print_iter')
OT_INT
OT_BOOL
julia> ca.conic_option_type("qrqp", "max_iter"), ca.conic_option_type("qrqp", "print_iter")
("OT_INT", "OT_BOOL")

Extra doc | Doc source | Implementation

conic_options(...)

Get all options of a QP solver plugin.

conic_options(str name) -> [str]

Returns the names of the plugin-specific options only; the options shared by all plugins (e.g. "print_time", "discrete") are not included. Raises an error for an unknown plugin.

>>> "max_iter" in conic_options("qrqp"), "discrete" in conic_options("qrqp")
(True, False)
>> opts = cellstr(conic_options('qrqp'));
>> ismember({'max_iter', 'discrete'}, opts)
1 0
julia> "max_iter" in ca.conic_options("qrqp"), "discrete" in ca.conic_options("qrqp")
(true, false)

See also: conic_option_type, conic_option_info

Extra doc | Doc source | Implementation

conic_out(...)

Get the name of a QP solver output by index.

conic_out() -> [str]
conic_out(int ind) -> str
Parameters:

ind -- Index in 0.. conic_n_out() -1; any other value gives an empty string

>>> conic_out(1), repr(conic_out(4))
('cost', "''")
>> conic_out(1), isempty(conic_out(4))
cost
1
julia> ca.conic_out(1), ca.conic_out(4)
("cost", "")

Get the output scheme of QP solvers.

Returns the names of the 4 outputs of a Function created by conic, in order: x, cost, lam_a, lam_x.

>>> conic_out()
['x', 'cost', 'lam_a', 'lam_x']
>> conic_out()
x
cost
lam_a
lam_x
julia> ca.conic_out()
4-element Vector{String}:
 "x"
 "cost"
 "lam_a"
 "lam_x"

See also: conic_in, conic_n_out

Extra doc | Doc source | Implementation

constpow(...)

Elementwise power with const power: (x,y) -> x^y with y constant.

constpow(float x, float y) -> float
constpow(DM x, DM y) -> DM
constpow(SX x, SX y) -> SX
constpow(MX x, MX y) -> MX

Same value as pow, but the exponent is assumed constant: the derivative with respect to y is taken as zero. pow itself produces this operation for a non- integer constant exponent, so it is rarely needed directly. Passing a symbolic exponent gives a wrong derivative for MX; SX falls back to pow.

>>> constpow(DM(2), 3)
DM(8)
>>> x = MX.sym("x")
>>> constpow(x, 2.5), jacobian(constpow(x, 2.5), x)
(MX(pow(x,2.5)), MX((2.5*pow(x,1.5))))
>> constpow(DM(2), 3)
8
>> x = MX.sym('x');
>> constpow(x, 2.5), jacobian(constpow(x, 2.5), x)
pow(x,2.5)
(2.5*pow(x,1.5))
julia> ca.constpow(ca.DM(2), 3)
DM(8)
julia> x = ca.MX.sym("x");
julia> ca.constpow(x, 2.5), ca.jacobian(ca.constpow(x, 2.5), x)
(pow(x,2.5), (2.5*pow(x,1.5)))

See also: pow

Extra doc | Doc source | Implementation

contains(...)

Check if expression n is listed in v.

contains([DM] v, DM n) -> bool
contains([SX] v, SX n) -> bool
contains([MX] v, MX n) -> bool

This function checks for correspondence between nodes. The detection does not descend into the expression graph.

contains_all checks that every entry of n is listed in v, contains_any that at least one is. For SX the entries must be scalar. Not defined for DM.

For mathematical dependency, see depends_on

See also: depends_on

>>> x = SX.sym("x"); y = SX.sym("y"); z = SX.sym("z")
>>> e = x + y
>>> contains([x, y], y), contains([e], y), contains([e], e)
(True, False, True)
>>> contains([SX.sym("x")], x)
False
>>> contains_all([x, y, z], [x, y]), contains_all([x, y], [x, z])
(True, False)
>>> contains_any([x, y], [x, z]), contains_any([x, y], [z])
(True, False)
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> contains([X, Y], Y), contains([X + Y], Y)
(True, False)
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x + y;
>> fprintf('%d %d %d\n', contains({x, y}, y), contains({e}, y), contains({e}, e))
1 0 1
>> contains({SX.sym('x')}, x)
0
>> X = MX.sym('X'); Y = MX.sym('Y');
>> fprintf('%d %d\n', contains({X, Y}, Y), contains({X + Y}, Y))
1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); z = ca.SX.sym("z");
julia> e = x + y;
julia> ca.contains([x, y], y), ca.contains([e], y), ca.contains([e], e)
(true, false, true)
julia> ca.contains([ca.SX.sym("x")], x)
false
julia> ca.contains_all([x, y, z], [x, y]), ca.contains_all([x, y], [x, z])
(true, false)
julia> ca.contains_any([x, y], [x, z]), ca.contains_any([x, y], [z])
(true, false)
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.contains([X, Y], Y), ca.contains([X + Y], Y)
(true, false)

Extra doc | Doc source | Implementation

contains_all(...)

Check if expression n is listed in v.

contains_all([DM] v, [DM] n) -> bool
contains_all([SX] v, [SX] n) -> bool
contains_all([MX] v, [MX] n) -> bool

This function checks for correspondence between nodes. The detection does not descend into the expression graph.

contains_all checks that every entry of n is listed in v, contains_any that at least one is. For SX the entries must be scalar. Not defined for DM.

For mathematical dependency, see depends_on

See also: depends_on

>>> x = SX.sym("x"); y = SX.sym("y"); z = SX.sym("z")
>>> e = x + y
>>> contains([x, y], y), contains([e], y), contains([e], e)
(True, False, True)
>>> contains([SX.sym("x")], x)
False
>>> contains_all([x, y, z], [x, y]), contains_all([x, y], [x, z])
(True, False)
>>> contains_any([x, y], [x, z]), contains_any([x, y], [z])
(True, False)
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> contains([X, Y], Y), contains([X + Y], Y)
(True, False)
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x + y;
>> fprintf('%d %d %d\n', contains({x, y}, y), contains({e}, y), contains({e}, e))
1 0 1
>> contains({SX.sym('x')}, x)
0
>> X = MX.sym('X'); Y = MX.sym('Y');
>> fprintf('%d %d\n', contains({X, Y}, Y), contains({X + Y}, Y))
1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); z = ca.SX.sym("z");
julia> e = x + y;
julia> ca.contains([x, y], y), ca.contains([e], y), ca.contains([e], e)
(true, false, true)
julia> ca.contains([ca.SX.sym("x")], x)
false
julia> ca.contains_all([x, y, z], [x, y]), ca.contains_all([x, y], [x, z])
(true, false)
julia> ca.contains_any([x, y], [x, z]), ca.contains_any([x, y], [z])
(true, false)
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.contains([X, Y], Y), ca.contains([X + Y], Y)
(true, false)

Extra doc | Doc source | Implementation

contains_any(...)

Check if expression n is listed in v.

contains_any([DM] v, [DM] n) -> bool
contains_any([SX] v, [SX] n) -> bool
contains_any([MX] v, [MX] n) -> bool

This function checks for correspondence between nodes. The detection does not descend into the expression graph.

contains_all checks that every entry of n is listed in v, contains_any that at least one is. For SX the entries must be scalar. Not defined for DM.

For mathematical dependency, see depends_on

See also: depends_on

>>> x = SX.sym("x"); y = SX.sym("y"); z = SX.sym("z")
>>> e = x + y
>>> contains([x, y], y), contains([e], y), contains([e], e)
(True, False, True)
>>> contains([SX.sym("x")], x)
False
>>> contains_all([x, y, z], [x, y]), contains_all([x, y], [x, z])
(True, False)
>>> contains_any([x, y], [x, z]), contains_any([x, y], [z])
(True, False)
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> contains([X, Y], Y), contains([X + Y], Y)
(True, False)
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x + y;
>> fprintf('%d %d %d\n', contains({x, y}, y), contains({e}, y), contains({e}, e))
1 0 1
>> contains({SX.sym('x')}, x)
0
>> X = MX.sym('X'); Y = MX.sym('Y');
>> fprintf('%d %d\n', contains({X, Y}, Y), contains({X + Y}, Y))
1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); z = ca.SX.sym("z");
julia> e = x + y;
julia> ca.contains([x, y], y), ca.contains([e], y), ca.contains([e], e)
(true, false, true)
julia> ca.contains([ca.SX.sym("x")], x)
false
julia> ca.contains_all([x, y, z], [x, y]), ca.contains_all([x, y], [x, z])
(true, false)
julia> ca.contains_any([x, y], [x, z]), ca.contains_any([x, y], [z])
(true, false)
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.contains([X, Y], Y), ca.contains([X + Y], Y)
(true, false)

Extra doc | Doc source | Implementation

convexify(...)

Make a symmetric matrix positive definite at evaluation time.

convexify(MX H, dict opts) -> MX

Returns an expression with the sparsity pattern of H that, when evaluated, modifies the value of H so that it is positive definite. Intended for Hessians in SQP-type methods. H must be square and symmetric or triangular (a triangular pattern is interpreted as one half of a symmetric matrix); other patterns raise an error. The node has no derivatives.

Parameters:
  • H -- Square expression with a symmetric or triangular sparsity pattern

  • opts -- Options: "strategy": "eigen-clip" (default, eigenvalues below the margin are set to the margin), "eigen-reflect" (their absolute value is taken) or "regularize" (a multiple of the identity is added; symmetric patterns only); "margin": smallest allowed eigenvalue, default 1e-7, must be nonnegative; "max_iter_eig": iteration limit of the eigenvalue computation, default 200; "verbose": print the block structure found. Unknown keys raise an error.

>>> H = MX.sym("H", 2, 2)
>>> f = Function("f", [H], [convexify(H)])
>>> f(DM([[1, 0], [0, -2]]))
DM(
[[1, 0],
 [0, 1e-07]])
>>> f = Function("f", [H], [convexify(H, {"strategy": "eigen-reflect"})])
>>> f(DM([[1, 0], [0, -2]]))
DM(
[[1, 0],
 [0, 2]])
>>> f = Function("f", [H], [convexify(H, {"strategy": "regularize", "margin": 0.5})])
>>> f(DM([[1, 0], [0, -2]]))
DM(
[[3.5, 0],
 [0, 0.5]])
>>> try:
...   convexify(H, {"strategy": "foo"})
... except Exception as e:
...   print("Invalid convexify strategy" in str(e))
True
>> H = MX.sym('H', 2, 2);
>> f = Function('f', {H}, {convexify(H)});
>> f(DM([1 0; 0 -2]))
[[1, 0],
[0, 1e-07]]
>> f = Function('f', {H}, {convexify(H, struct('strategy', 'eigen-reflect'))});
>> f(DM([1 0; 0 -2]))
[[1, 0],
[0, 2]]
>> f = Function('f', {H}, {convexify(H, struct('strategy', 'regularize', 'margin', 0.5))});
>> f(DM([1 0; 0 -2]))
[[3.5, 0],
[0, 0.5]]
>> try, convexify(H, struct('strategy', 'foo')); catch e, disp('invalid strategy'); end
invalid strategy
julia> H = ca.MX.sym("H", 2, 2);
julia> f = ca.Function("f", [H], [ca.convexify(H)]);
julia> print(f([1 0; 0 -2]))
[[1, 0],
 [0, 1e-07]]
julia> f = ca.Function("f", [H], [ca.convexify(H, Dict("strategy" => "eigen-reflect"))]);
julia> f([1 0; 0 -2])
DM(
[[1, 0],
 [0, 2]])
julia> opts = Dict("strategy" => "regularize", "margin" => 0.5);
julia> f = ca.Function("f", [H], [ca.convexify(H, opts)]);
julia> f([1 0; 0 -2])
DM(
[[3.5, 0],
 [0, 0.5]])
julia> try
           ca.convexify(H, Dict("strategy" => "foo"))
       catch e
           println(occursin("Invalid convexify strategy", sprint(showerror, e)))
       end
true

See also: nlpsol

Extra doc | Doc source | Implementation

copysign(...)

Copy sign: (x,y) -> copysign(x,y)

copysign(float x, float y) -> float
copysign(DM x, DM y) -> DM
copysign(SX x, SX y) -> SX
copysign(MX x, MX y) -> MX

Elementwise value with the magnitude of x and the sign of y, as C copysign; a negative zero y counts as negative. Shape rules as for plus. The derivative with respect to y is zero.

>>> copysign(DM([1, -2]), DM([-1, 1]))
DM([-1, 2])
>>> copysign(DM(3), DM(-0.0))
DM(-3)
>>> copysign(SX.sym("x"), SX.sym("y"))
SX(copysign(x,y))
>> copysign(DM([1; -2]), DM([-1; 1]))
[-1, 2]
>> copysign(DM(3), DM(-0.0))
-3
>> copysign(SX.sym('x'), SX.sym('y'))
copysign(x,y)
julia> copysign.(ca.DM([1, -2]), ca.DM([-1, 1]))
DM([-1, 2])
julia> copysign.(ca.DM(3), ca.DM(-0.0))
DM(-3)
julia> ca.copysign(ca.SX.sym("x"), ca.SX.sym("y"))
SX(copysign(x,y))

See also: sign, abs

Extra doc | Doc source | Implementation

cos(...)

Cosine: x -> cos(x)

cos(float x) -> float
cos(DM x) -> DM
cos(SX x) -> SX
cos(MX x) -> MX

Elementwise; structural zeros become 1, so the result is dense.

>>> cos(DM.eye(2))
DM(
[[0.540302, 1],
 [1, 0.540302]])
>>> cos(SX.sym("s", Sparsity.diag(2)))
SX(@1=1,
[[cos(s_0), @1],
 [@1, cos(s_1)]])
>> cos(DM.eye(2))
[[0.540302, 1],
[1, 0.540302]]
>> cos(SX.sym('s', Sparsity.diag(2)))
@1=1,
[[cos(s_0), @1],
[@1, cos(s_1)]]
julia> cos.(ca.DM.eye(2))
DM(
[[0.540302, 1],
 [1, 0.540302]])
julia> cos.(ca.SX.sym("s", ca.Sparsity.diag(2)))
SX(@1=1,
[[cos(s_0), @1],
 [@1, cos(s_1)]])

See also: sin, tan, acos

Extra doc | Doc source | Implementation

cosh(...)

Hyperbolic cosine: x -> cosh(x)

cosh(float x) -> float
cosh(DM x) -> DM
cosh(SX x) -> SX
cosh(MX x) -> MX

Elementwise; the result is dense (cosh(0) == 1).

>>> cosh(DM([0, 1]))
DM([1, 1.54308])
>> cosh(DM([0; 1]))
[1, 1.54308]
julia> cosh.(ca.DM([0, 1]))
DM([1, 1.54308])

See also: acosh, sinh, tanh

Extra doc | Doc source | Implementation

cross(...)

Matlab's cross command.

cross(DM a, DM b, int dim) -> DM
cross(SX a, SX b, int dim) -> SX
cross(MX a, MX b, int dim) -> MX

Cross product of 3-vectors. a and b must have the same shape and one of the dimensions must be 3; for 3-by-n or n-by-3 matrices the products are taken per column or per row respectively.

Parameters:

dim -- 1 to take the products along the rows (3-by-n input), 2 along the columns, -1 (default) to pick the dimension of length 3 (rows first)

>>> cross(DM([1, 0, 0]), DM([0, 1, 0]))
DM([0, 0, 1])
>>> cross(DM([[1, 0, 0], [0, 1, 0]]), DM([[0, 1, 0], [0, 0, 1]]))
DM(
[[0, 0, 1],
 [1, 0, 0]])
>>> cross(SX.sym("a", 3), SX.sym("b", 3))
SX([((a_1*b_2)-(a_2*b_1)), ((a_2*b_0)-(a_0*b_2)), ((a_0*b_1)-(a_1*b_0))])
>> cross(DM([1; 0; 0]), DM([0; 1; 0]))
[0, 0, 1]
>> cross(DM([1 0 0; 0 1 0]), DM([0 1 0; 0 0 1]))
[[0, 0, 1],
[1, 0, 0]]
>> cross(SX.sym('a', 3), SX.sym('b', 3))
[((a_1*b_2)-(a_2*b_1)), ((a_2*b_0)-(a_0*b_2)), ((a_0*b_1)-(a_1*b_0))]
julia> ca.cross(ca.DM([1, 0, 0]), ca.DM([0, 1, 0]))
DM([0, 0, 1])
julia> ca.cross(ca.DM([1 0 0; 0 1 0]), ca.DM([0 1 0; 0 0 1]))
DM(
[[0, 0, 1],
 [1, 0, 0]])
julia> ca.cross(ca.SX.sym("a", 3), ca.SX.sym("b", 3))
SX([((a_1*b_2)-(a_2*b_1)), ((a_2*b_0)-(a_0*b_2)), ((a_0*b_1)-(a_1*b_0))])

See also: skew, dot

Extra doc | Doc source | Implementation

cse(...)

Common subexpression elimination.

cse(DM e) -> DM
cse([DM] e) -> [DM]
cse([SX] e) -> [SX]
cse(SX e) -> SX
cse(MX e) -> MX
cse([MX] e) -> [MX]

Returns an equivalent expression in which identical subexpressions that were built separately share a single node, reducing the number of nodes and the evaluation cost. The shape is preserved. DM is returned unchanged.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = sin(x + y)*cos(x + y)
>>> cse(e)
SX(@1=(x+y), (sin(@1)*cos(@1)))
>>> n_nodes(e), n_nodes(cse(e))
(7, 6)
>> x = SX.sym('x'); y = SX.sym('y');
>> e = sin(x + y)*cos(x + y);
>> cse(e)
@1=(x+y), (sin(@1)*cos(@1))
>> fprintf('%d %d\n', n_nodes(e), n_nodes(cse(e)))
7 6
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = sin(x + y) * cos(x + y);
julia> ca.cse(e)
SX(@1=(x+y), (sin(@1)*cos(@1)))
julia> ca.n_nodes(e), ca.n_nodes(ca.cse(e))
(7, 6)

See also: n_nodes, shared, extract

Extra doc | Doc source | Implementation

cumsum(...)

Returns cumulative sum along given axis (MATLAB convention)

cumsum(DM A, int axis) -> DM
cumsum(SX A, int axis) -> SX
cumsum(MX A, int axis) -> MX

Running sum down the rows (axis 0) or along the columns (axis 1); the shape is preserved. With axis -1, the columns are summed for a row vector and the rows otherwise. MATLAB numbers the axes 1 (rows) and 2 (columns).

>>> cumsum(DM([1, 2, 3]))
DM([1, 3, 6])
>>> cumsum(DM([[1, 2], [3, 4]]))
DM(
[[1, 2],
 [4, 6]])
>>> cumsum(DM([[1, 2], [3, 4]]), 1)
DM(
[[1, 3],
 [3, 7]])
>>> cumsum(SX.sym("x", 3))
SX(@1=(x_1+x_0), [x_0, @1, (x_2+@1)])
>> cumsum(DM([1; 2; 3]))
[1, 3, 6]
>> cumsum(DM([1 2; 3 4]))
[[1, 2],
[4, 6]]
>> cumsum(DM([1 2; 3 4]), 2)
[[1, 3],
[3, 7]]
>> cumsum(SX.sym('x', 3))
@1=(x_1+x_0), [x_0, @1, (x_2+@1)]
julia> cumsum(ca.DM([1, 2, 3]))
DM([1, 3, 6])
julia> cumsum(ca.DM([1 2; 3 4]); dims=1)
DM(
[[1, 2],
 [4, 6]])
julia> cumsum(ca.DM([1 2; 3 4]); dims=2)
DM(
[[1, 3],
 [3, 7]])
julia> cumsum(ca.SX.sym("x", 3))
SX(@1=(x_1+x_0), [x_0, @1, (x_2+@1)])

See also: diff, sum1, sum2

Extra doc | Doc source | Implementation

dae_init_gen(...)
dae_init_gen(dict:SX dae, dict:SX dae_red, str init_solver, dict:DM init_strength, dict init_solver_options) -> Function
dae_init_gen(dict:MX dae, dict:MX dae_red, str init_solver, dict:DM init_strength, dict init_solver_options) -> Function

Obtain a generator Function for producing consistent initial guesses of a reduced DAE.

Parameters:
  • dae -- Original (unreduced) DAE structure

  • dae_red -- Reduced DAE (see dae_reduce_index)

  • init_solver -- NLP solver plugin name for nlpsol used to construct an initial guess

  • init_strength -- Influence the nature of the NLP Structure with keys x_impl, dx_impl, z corresponding to inputs of init_gen Each key maps to a DM that should match the variable size corresponding to that key. For each variable the meaning of the corresponding DM value is as follows: When >=0, indicates that the provided initial guess is used in a quadratic penalty (value used as weight) When -1, indicates that the provided initial guess must be observed (simple bound on variable)

  • init_solver_options -- NLP solver options to be passed to nlpsol

Returns:

x_impl, dx_impl, z: initial guesses in the original DAE space p: parameters t: time Outputs: x0, z0: (semi explicit) integrator states and algebraic variables; typically used as input for integrators x_impl, dx_impl, z: initial guesses in the original DAE space p: parameters t: time Outputs: x0, z0: (semi explicit) integrator states and algebraic variables; typically used as input for integrators

Return type:

init_gen A function to generate a consistent initial guess that can be used to pass to an integrator constructed from a semi explict reduced DAE Inputs

See also: dae_reduce_index

Extra doc | Doc source | Implementation

dae_map_semi_expl(...)
dae_map_semi_expl(dict:SX dae, dict:SX dae_red) -> (dict:SX, Function, Function)
dae_map_semi_expl(dict:MX dae, dict:MX dae_red) -> (dict:MX, Function, Function)

Turn a reduced DAE into a semi explicit form suitable for CasADi integrator.

Parameters:
  • dae -- Original (unreduced) DAE structure

  • dae_red -- Reduced DAE (see dae_reduce_index)

  • state_to_orig -- A mapping of integrator (semi explicit) states to states of the original DAE

  • phi -- A function to compute the invariants of the reduced DAE Inputs: x and z: (semi explicit) integrator states; typically integrator outputs xf and zf p: parameters t: time x and z: (semi explicit) integrator states; typically integrator outputs xf and zf p: parameters t: time

Returns:

Semi explicit DAE dictionary, suitable to pass to a CasADi integrator

See also: dae_reduce_index

Extra doc | Doc source | Implementation

dae_reduce_index(...)
dae_reduce_index(dict:SX dae, dict opts) -> (dict:SX, dict)
dae_reduce_index(dict:MX dae, dict opts) -> (dict:MX, dict)

Reduce index.

Index reduction leads to a new set of variables and equations.

In the process, a set of constraints (algebraic equations or derivatives) a.k.a invariants is constructed that are invariant to the problem: whenever an initial point satisfies these constraints, the boundary-value-problem outcome will keep satisfying those constraints automatically, even though they are not part of the reduced DAE.

For any practical numerical integration method, there will be numerical drift away from satisfaction of those constraints. In other words, you will see the value of invariants slowly moving away from original zero.

A classic mitigation technique is Baumgarte stabilization: you add these invariants to the reduced DAE as a correction term that acts in a way to make small (numerical) perturbations to the invariants decay to the origin as a dampened linear system.

in which a certain set of constraints (algebraic equations or derivatives) has been dropped in favour of

Parameters:

dae -- Expression dictionary describing the DAE

Each value must be a dense column vector.

keys:

  • x_impl: symbol for implicit differential states

  • dx_impl: symbol for implicit differential state derivatives

  • z: symbol for algebraic variables

  • alg: expression for algebraic equations

  • t: symbol for time

  • p: symbol for parameters opts Option dictionary 'baumgarte_pole': double Poles (inverse time constants) of the Baumgarte invariant correction term. Must be <0 to dampen out perturbations 0 (default) amounts to no correction. Corresponds to -gamma of equation (1.5) in Ascher, Uri M., Hongsheng Chin, and Sebastian Reich. "Stabilization of DAEs and invariant manifolds." Numerische Mathematik 67.2 (1994): 131-149.

Parameters:

stats -- Statistics

Returns:

Expression dictionary describing the reduced DAE

In addition the fields allowed in the input DAE, the following keys occur:

  • x: symbol for explicit differential states

  • ode: expression for right-hand-side of explicit differential states

  • I: expression for invariants

Extra doc | Doc source | Implementation

densify(...)

Make the matrix dense if not already.

densify(DM x) -> DM
densify(SX x) -> SX
densify(MX x) -> MX
densify(DM x, DM val) -> DM
densify(SX x, SX val) -> SX
densify(MX x, MX val) -> MX

Structural zeros become stored numerical zeros; the shape and the values of the existing nonzeros are unchanged. A dense input is returned as is.

>>> densify(DM.eye(2))
DM(
[[1, 0],
 [0, 1]])
>>> densify(SX.sym("x", Sparsity.diag(2)))
SX(@1=0,
[[x_0, @1],
 [@1, x_1]])
>>> densify(MX.sym("x", Sparsity.diag(2)))
MX(dense(x))
>> densify(DM.eye(2))
[[1, 0],
[0, 1]]
>> densify(SX.sym('x', Sparsity.diag(2)))
@1=0,
[[x_0, @1],
[@1, x_1]]
>> densify(MX.sym('x', Sparsity.diag(2)))
dense(x)
julia> ca.densify(ca.DM.eye(2))
DM(
[[1, 0],
 [0, 1]])
julia> ca.densify(ca.SX.sym("x", ca.Sparsity.diag(2)))
SX(@1=0,
[[x_0, @1],
 [@1, x_1]])
julia> ca.densify(ca.MX.sym("x", ca.Sparsity.diag(2)))
MX(dense(x))

See also: project, sparsify, is_dense

Extra doc | Doc source | Implementation

depends_on(...)

Check if expression depends on the argument.

depends_on(DM f, DM arg) -> bool
depends_on(SX f, SX arg) -> bool
depends_on(MX f, MX arg) -> bool

The argument must be symbolic (for MX: symbolic primitives as created by MX.sym, not elements of them).

The dependency is in a mathematical way: Does the value of the argument affect the value of the expression? Equivalently, will the corresponding entry of the Jacobian by a non-zero? This is decided by sparsity propagation through the graph, so 0*x and x-x do not depend on x.

The symbol could still be present in the expression graph.

To check that kind of dependency, use contains(symvar(f),arg)

>>> x = SX.sym("x"); y = SX.sym("y")
>>> depends_on(x*y, x), depends_on(x*y, SX.sym("z"))
(True, False)
>>> depends_on(0*x, x), depends_on(x - x, x), depends_on(SX(3), x)
(False, False, False)
>>> depends_on(vertcat(x, 3), vertcat(x, y))
True
>>> v = MX.sym("v", 2)
>>> depends_on(v[0], v)
True
>> x = SX.sym('x'); y = SX.sym('y');
>> fprintf('%d %d\n', depends_on(x*y, x), depends_on(x*y, SX.sym('z')))
1 0
>> fprintf('%d %d %d\n', depends_on(0*x, x), depends_on(x - x, x), depends_on(SX(3), x))
0 0 0
>> depends_on(vertcat(x, 3), vertcat(x, y))
1
>> v = MX.sym('v', 2);
>> depends_on(v(1), v)
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.depends_on(x * y, x), ca.depends_on(x * y, ca.SX.sym("z"))
(true, false)
julia> ca.depends_on(0 * x, x), ca.depends_on(x - x, x), ca.depends_on(ca.SX(3), x)
(false, false, false)
julia> ca.depends_on([x; 3], [x; y])
true
julia> v = ca.MX.sym("v", 2);
julia> ca.depends_on(v[1], v)
true

See also: which_depends, symvar, contains, jacobian_sparsity

Extra doc | Doc source | Implementation

det(...)

Matrix determinant (experimental)

det(DM A) -> DM
det(SX A) -> SX
det(MX A) -> MX
det(DM A, str lsolver, dict opts) -> DM
det(SX A, str lsolver, dict opts) -> SX
det(MX A, str lsolver, dict opts) -> MX

For DM and SX the determinant is formed by minor expansion along the sparsest row or column (a 2-by-2 directly, a scalar is returned as is); the cost grows quickly with the matrix size. For MX a determinant node is created that is evaluated through the 'qr' linear solver. A non-square argument raises an error.

>>> det(DM([[1, 2], [3, 4]]))
DM(-2)
>>> det(SX.sym("A", 2, 2))
SX(((A_0*A_3)-(A_2*A_1)))
>>> det(MX.sym("A", 2, 2))
MX(det(A))
>> det(DM([1 2; 3 4]))
-2
>> det(SX.sym('A', 2, 2))
((A_0*A_3)-(A_2*A_1))
>> det(MX.sym('A', 2, 2))
det(A)
julia> ca.det(ca.DM([1 2; 3 4]))
DM(-2)
julia> ca.det(ca.SX.sym("A", 2, 2))
SX(((A_0*A_3)-(A_2*A_1)))
julia> ca.det(ca.MX.sym("A", 2, 2))
MX(det(A))

See also: inv, inv_minor

Extra doc | Doc source | Implementation

detect_simple_bounds(...)
detect_simple_bounds(SX xX, SX p, SX g, SX lbg, SX ubg) -> ([int], SX, SX, Function, Function)
detect_simple_bounds(MX xX, MX p, MX g, MX lbg, MX ubg) -> ([int], MX, MX, Function, Function)

Detect simple bounds from general constraints.

Given parametric constraints:

subject to lbg(p) <= g(x,p) <= ubg(p)

Returns an equivalent set

subject to  lbg(p)(gi) <= g(x,p)(gi) <= ubg(p)(gi)
            lbx(p) <= x                 <= ubx(p)
Parameters:
  • lam_forward -- (lam_g,p)->(lam_sg,lam_x)

  • lam_backward -- (lam_sg,lam_x,p)->(lam_g)

Extra doc | Doc source | Implementation

diag(...)

Get the diagonal of a matrix or construct a diagonal.

diag(DM A) -> DM
diag(SX A) -> SX
diag(MX A) -> MX

If the input is a vector (row or column), a square matrix with the vector on its diagonal and structural zeros elsewhere is constructed. Otherwise the diagonal entries are returned as a column vector of length min(size1(), size2()); only structurally nonzero entries are kept.

>>> diag(DM([1, 2]))
DM(
[[1, 00],
 [00, 2]])
>>> diag(DM([[1, 2], [3, 4]]))
DM([1, 4])
>>> diag(DM(Sparsity.upper(2), [1, 2, 3]))
DM([1, 3])
>>> diag(DM.ones(2, 3))
DM([1, 1])
>> diag(DM([1; 2]))
[[1, 00],
[00, 2]]
>> diag(DM([1 2; 3 4]))
[1, 4]
>> diag(DM(Sparsity.upper(2), [1; 2; 3]))
[1, 3]
>> diag(DM.ones(2, 3))
[1, 1]
julia> ca.diag(ca.DM([1, 2]))
DM(
[[1, 00],
 [00, 2]])
julia> ca.diag(ca.DM([1 2; 3 4]))
DM([1, 4])
julia> ca.diag(ca.DM(ca.Sparsity.upper(2), [1, 2, 3]))
DM([1, 3])
julia> ca.diag(ca.DM.ones(2, 3))
DM([1, 1])

See also: trace, diagcat, Sparsity.diag

Extra doc | Doc source | Implementation

diagcat(...)

Construct a block-diagonal matrix from a list of matrices.

_diagcat([Sparsity] A) -> Sparsity
_diagcat([DM] A) -> DM
_diagcat([SX] A) -> SX
_diagcat([MX] A) -> MX

Places the matrices along the diagonal, in order; all other entries are structural zeros. The blocks need not be square: the result has the sum of the row counts by the sum of the column counts. Type rules are those of horzcat. With no arguments the result is a 0-by-0 matrix. Inverse of diagsplit: diagcat(diagsplit(x, ...)) == x.

Parameters:

A -- List of matrices of any shape

Returns:

Block-diagonal matrix of the same type as the blocks

>>> diagcat(DM.ones(1, 2), 3)
DM(
[[1, 1, 00],
 [00, 00, 3]])
>>> diagcat(SX.sym("x"), SX.sym("y", 2))
SX(
[[x, 00],
 [00, y_0],
 [00, y_1]])
>>> diagcat(MX.sym("x"), MX.sym("y", 2, 2))
MX(diagcat(x, y))
>>> diagcat().shape
(0, 0)
>> diagcat(DM.ones(1, 2), 3)
[[1, 1, 00],
[00, 00, 3]]
>> diagcat(SX.sym('x'), SX.sym('y', 2))
[[x, 00],
[00, y_0],
[00, y_1]]
>> diagcat(MX.sym('x'), MX.sym('y', 2, 2))
diagcat(x, y)
julia> ca.diagcat(ca.DM.ones(1, 2), 3)
DM(
[[1, 1, 00],
 [00, 00, 3]])
julia> ca.diagcat(ca.SX.sym("x"), ca.SX.sym("y", 2))
SX(
[[x, 00],
 [00, y_0],
 [00, y_1]])
julia> ca.diagcat(ca.MX.sym("x"), ca.MX.sym("y", 2, 2))
MX(diagcat(x, y))

See also: horzcat, vertcat, diagsplit

Extra doc | Doc source | Implementation

diagsplit(...)

Split a matrix into diagonal blocks of given row and column boundaries.

diagsplit(Sparsity x, int incr) -> [Sparsity]
diagsplit(DM x, int incr) -> [DM]
diagsplit(SX x, int incr) -> [SX]
diagsplit(MX x, int incr) -> [MX]
diagsplit(Sparsity x, [int] output_offset) -> [Sparsity]
diagsplit(DM x, [int] output_offset) -> [DM]
diagsplit(SX x, [int] output_offset) -> [SX]
diagsplit(MX x, [int] output_offset) -> [MX]
diagsplit(Sparsity x, int incr1, int incr2) -> [Sparsity]
diagsplit(Sparsity x, [int] output_offset1, [int] output_offset2) -> [Sparsity]
diagsplit(DM x, int incr1, int incr2) -> [DM]
diagsplit(DM x, [int] output_offset1, [int] output_offset2) -> [DM]
diagsplit(SX x, int incr1, int incr2) -> [SX]
diagsplit(SX x, [int] output_offset1, [int] output_offset2) -> [SX]
diagsplit(MX x, int incr1, int incr2) -> [MX]
diagsplit(MX x, [int] output_offset1, [int] output_offset2) -> [MX]

Block i is x``[output_offset1[i]:output_offset1[i+1], output_offset2[i]:output_offset2[i+1]]. Both lists must have the same length, start at 0, be non-decreasing and end at the row (column) count of ``x. Entries of x outside the diagonal blocks must be zero (structurally zero for MX and Sparsity), otherwise an error is raised. Inverse of diagcat: diagcat(diagsplit(x, ...)) == x for block-diagonal x.

Parameters:
  • x -- Matrix (or Sparsity) to split; any shape

  • output_offset1 -- Row boundaries of the blocks

  • output_offset2 -- Column boundaries of the blocks

Returns:

List of matrices of the same type as x, one per block

>>> x = DM([[1, 2, 0], [0, 0, 6]])
>>> diagsplit(x, [0, 1, 2], [0, 2, 3])
[DM([[1, 2]]), DM(6)]
>> x = DM([1 2 0; 0 0 6]);
>> v = diagsplit(x, [0, 1, 2], [0, 2, 3]); disp(v{1}), disp(v{2})
[[1, 2]]
6
julia> x = ca.DM([1 2 0; 0 0 6]);
julia> ca.diagsplit(x, [0, 1, 2], [0, 2, 3])
2-element Vector{DM}:
 DM([[1, 2]])
 DM(6)

See also: diagcat

Extra doc | Doc source | Implementation

diff(...)

Returns difference (n-th order) along given axis (MATLAB convention)

diff(DM A, int n, int axis) -> DM
diff(SX A, int n, int axis) -> SX
diff(MX A, int n, int axis) -> MX

Each pass subtracts neighbouring rows (axis 0) or columns (axis 1), shrinking that dimension by one; n passes are applied. With axis -1 the first non-singleton dimension is used (columns for a row vector, rows otherwise) and, as in MATLAB, a scalar gives an empty 0-by-0 result.

Parameters:
  • n -- Order, at least 1

  • axis -- 0 (rows), 1 (columns) or -1 (automatic); 1 and 2 in MATLAB

>>> diff(DM([1, 4, 9, 16]))
DM([3, 5, 7])
>>> diff(DM([1, 4, 9, 16]), 2)
DM([2, 2])
>>> diff(DM([[1, 2], [4, 8], [9, 10]]), 1, 1)
DM([1, 4, 1])
>>> diff(SX.sym("x", 3))
SX([(x_1-x_0), (x_2-x_1)])
>>> diff(DM(3)).dim()
'0x0'
>> diff(DM([1; 4; 9; 16]))
[3, 5, 7]
>> diff(DM([1; 4; 9; 16]), 2)
[2, 2]
>> diff(DM([1 2; 4 8; 9 10]), 1, 2)
[1, 4, 1]
>> diff(SX.sym('x', 3))
[(x_1-x_0), (x_2-x_1)]
>> d = diff(DM(3)); disp(d.dim())
0x0
julia> diff(ca.DM([1, 4, 9, 16]))
DM([3, 5, 7])
julia> ca.diff(ca.DM([1, 4, 9, 16]), 2)
DM([2, 2])
julia> diff(ca.DM([1 2; 4 8; 9 10]); dims=2)
DM([1, 4, 1])
julia> diff(ca.SX.sym("x", 3))
SX([(x_1-x_0), (x_2-x_1)])
julia> ca.dim(diff(ca.DM(3)))
"0x1"

See also: cumsum

Extra doc | Doc source | Implementation

difference(...)

Return all elements of a that do not occur in b, preserving order.

difference([MX] a, [MX] b) -> [MX]

Comparison is by node identity, not by value: two separately built expressions with the same formula are different nodes. Duplicates in a are kept.

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> difference([x, y, x], [y]), difference([x + 1], [x + 1])
([MX(x), MX(x)], [MX((1+x))])
>> x = MX.sym('x'); y = MX.sym('y');
>> d = difference({x, y, x}, {y});
>> numel(d), d{1}, d{2}
2
x
x
>> d = difference({x + 1}, {x + 1});
>> numel(d), d{1}
1
(1+x)
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.difference([x, y, x], [y]), ca.difference([x + 1], [x + 1])
(MX[x, x], MX[(1+x)])

See also: symvar

Extra doc | Doc source | Implementation

doc_archiver(...)

Get the documentation string for a plugin.

doc_archiver(str name) -> str

Doc source | Implementation

doc_blas(...)
doc_blas(str name) -> str
doc_conic(...)

Get the documentation string of a QP solver plugin.

doc_conic(str name) -> str

The text includes the plugin-specific option table.

>>> "active-set" in doc_conic("qrqp")
True
>> contains(doc_conic('qrqp'), 'active-set')
1
julia> occursin("active-set", ca.doc_conic("qrqp"))
true

Extra doc | Doc source | Implementation

doc_dple(...)

Get the documentation string for a plugin.

doc_dple(str name) -> str

Doc source | Implementation

doc_expm(...)

Get the documentation string for a plugin.

doc_expm(str name) -> str

Doc source | Implementation

doc_filesystem(...)

Get the documentation string for a plugin.

doc_filesystem(str name) -> str

Doc source | Implementation

doc_graphmodel(...)

Get format-specific documentation.

doc_graphmodel(str name) -> str

Doc source | Implementation

doc_integrator(...)

Get the documentation string of an integrator plugin.

doc_integrator(str name) -> str

The text includes the plugin-specific option table.

>>> "Runge-Kutta" in doc_integrator("rk")
True
>> contains(doc_integrator('rk'), 'Runge-Kutta')
1
julia> occursin("Runge-Kutta", ca.doc_integrator("rk"))
true

Extra doc | Doc source | Implementation

doc_interpolant(...)

Get the documentation string for a plugin.

doc_interpolant(str name) -> str

Doc source | Implementation

doc_linsol(...)

Get the documentation string of a linear solver plugin.

doc_linsol(str name) -> str

The text includes the plugin-specific option table.

>>> "QR" in doc_linsol("qr")
True
>> contains(doc_linsol('qr'), 'QR')
1
julia> occursin("QR", ca.doc_linsol("qr"))
true

Extra doc | Doc source | Implementation

doc_modelicaparser(...)

Get solver specific documentation.

doc_modelicaparser(str name) -> str

Doc source | Implementation

doc_nlpsol(...)

Get the documentation string of an NLP solver plugin.

doc_nlpsol(str name) -> str

The text includes the plugin-specific option table.

>>> "max_iter" in doc_nlpsol("sqpmethod")
True
>> contains(doc_nlpsol('sqpmethod'), 'max_iter')
1
julia> occursin("max_iter", ca.doc_nlpsol("sqpmethod"))
true

Extra doc | Doc source | Implementation

doc_rootfinder(...)

Get the documentation string of a rootfinder plugin.

doc_rootfinder(str name) -> str

The text includes the plugin-specific option table.

>>> "newton iterations" in doc_rootfinder("newton")
True
>> contains(doc_rootfinder('newton'), 'newton iterations')
1
julia> occursin("newton iterations", ca.doc_rootfinder("newton"))
true

Extra doc | Doc source | Implementation

dot(...)

Inner product of two matrices.

dot(DM x, DM y) -> DM
dot(SX x, SX y) -> SX
dot(MX x, MX y) -> MX

Sum of the elementwise products over all entries, with x and y of the same shape (a matrix is treated as the vector of its entries). Only entries that are structurally nonzero in both arguments contribute. A shape mismatch raises an error.

>>> dot(DM([1, 2]), DM([3, 4]))
DM(11)
>>> dot(DM([[1, 2], [3, 4]]), DM([[1, 1], [1, 1]]))
DM(10)
>>> dot(DM(Sparsity.diag(2), [1, 2]), DM([[1, 1], [1, 1]]))
DM(3)
>>> dot(SX.sym("x", 2), SX.sym("y", 2))
SX(((x_0*y_0)+(x_1*y_1)))
>> dot(DM([1; 2]), DM([3; 4]))
11
>> dot(DM([1 2; 3 4]), DM([1 1; 1 1]))
10
>> dot(DM(Sparsity.diag(2), [1; 2]), DM([1 1; 1 1]))
3
>> dot(SX.sym('x', 2), SX.sym('y', 2))
((x_0*y_0)+(x_1*y_1))
julia> ca.dot(ca.DM([1, 2]), ca.DM([3, 4]))
DM(11)
julia> ca.dot(ca.DM([1 2; 3 4]), ca.DM([1 1; 1 1]))
DM(10)
julia> ca.dot(ca.DM(ca.Sparsity.diag(2), [1, 2]), ca.DM([1 1; 1 1]))
DM(3)
julia> ca.dot(ca.SX.sym("x", 2), ca.SX.sym("y", 2))
SX(((x_0*y_0)+(x_1*y_1)))

See also: mtimes, sumsqr, bilin

Extra doc | Doc source | Implementation

dple_in(...)

Get DPLE input scheme name by index.

dple_in() -> [str]
dple_in(int ind) -> str

Get input scheme of DPLE solvers.

Extra doc | Doc source | Implementation

dple_n_in(...)

Get the number of QP solver inputs.

dple_n_in() -> int

Extra doc | Doc source | Implementation

dple_n_out(...)

Get the number of QP solver outputs.

dple_n_out() -> int

Extra doc | Doc source | Implementation

dple_out(...)

Get DPLE output scheme name by index.

dple_out() -> [str]
dple_out(int ind) -> str

Get output scheme of DPLE solvers.

Extra doc | Doc source | Implementation

dplesol(...)
dplesol([DM] A, [DM] V, str solver, dict opts) -> [DM]
dplesol(MX A, MX V, str solver, dict opts) -> MX
dplesol([MX] A, [MX] V, str solver, dict opts) -> [MX]
dplesol(str name, str solver, dict:Sparsity st, dict opts) -> Function

Discrete periodic Lyapunov Equation solver Given matrices $A_k$ and symmetric $V_k, k = 0..K-1$

A_k in R^(n x n)
V_k in R^n

provides all of $P_k$ that satisfy:

P_0 = A_(K-1)*P_(K-1)*A_(K-1)' + V_k
P_k+1 = A_k*P_k*A_k' + V_k  for k = 1..K-1

General information

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

const_dim

OT_BOOL

Assume constant dimension of P

casadi::Dple

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

eps_unstable

OT_DOUBLE

A margin for unstability detection

casadi::Dple

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

error_unstable

OT_BOOL

Throw an exception when it is detected that Product(A_i, i=N..1)has eigenvalues greater than 1-eps_unstable

casadi::Dple

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

pos_def

OT_BOOL

Assume P positive definite

casadi::Dple

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

>Input scheme: casadi::DpleInput (DPLE_NUM_IN = 2)

Full name

Short

Description

DPLE_A

a

A matrices (horzcat when const_dim, diagcat otherwise) [a].

DPLE_V

v

V matrices (horzcat when const_dim, diagcat otherwise) [v].

>Output scheme: casadi::DpleOutput (DPLE_NUM_OUT = 1)

Full name

Short

Description

DPLE_P

p

Lyapunov matrix (horzcat when const_dim, diagcat otherwise) (Cholesky of P if pos_def) [p].

List of plugins - slicot

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Dple.doc("myextraplugin")


slicot

An efficient solver for Discrete Periodic Lyapunov Equations using SLICOT

Uses Periodic Schur Decomposition ('psd') and does not assume positive definiteness. Based on Periodic Lyapunov equations: some applications and new algorithms. Int. J. Control, vol. 67, pp. 69-87, 1997.

Overview of the method: J. Gillis Practical Methods for Approximate Robust Periodic Optimal Control ofNonlinear Mechanical Systems, PhD Thesis, KULeuven, 2015

>List of available options

Id

Type

Description

linear_solver

OT_STRING

User-defined linear solver class. Needed for sensitivities.

linear_solver_options

OT_DICT

Options to be passed to the linear solver.

psd_num_zero

OT_DOUBLE

Numerical zero used in Periodic Schur decomposition with slicot.This option is needed when your systems has Floquet multiplierszero or close to zero

Authors: Joris Gillis

Extra doc | Doc source | Implementation

dyn_in(...)

Get the name of a DAE function input by index.

dyn_in() -> [str]
dyn_in(int ind) -> str
Parameters:

ind -- Index in 0.. dyn_n_in() -1; any other value gives an empty string

>>> dyn_in(1), repr(dyn_in(5))
('x', "''")
>> dyn_in(1), isempty(dyn_in(5))
x
1
julia> ca.dyn_in(1), ca.dyn_in(5)
("x", "")

Get the input scheme of a DAE function.

Returns the names of the 5 inputs of a DAE Function as expected by integrator, in order: t, x, z, p, u. These are also the dictionary keys accepted by integrator.

>>> dyn_in()
['t', 'x', 'z', 'p', 'u']
>> dyn_in()
t
x
z
p
u
julia> ca.dyn_in()
5-element Vector{String}:
 "t"
 "x"
 "z"
 "p"
 "u"

See also: dyn_out, integrator

Extra doc | Doc source | Implementation

dyn_n_in(...)

Get the number of inputs of a DAE function.

dyn_n_in() -> int
>>> dyn_n_in()
5
>> dyn_n_in()
5
julia> ca.dyn_n_in()
5

Extra doc | Doc source | Implementation

dyn_n_out(...)

Get the number of outputs of a DAE function.

dyn_n_out() -> int
>>> dyn_n_out()
4
>> dyn_n_out()
4
julia> ca.dyn_n_out()
4

Extra doc | Doc source | Implementation

dyn_out(...)

Get the name of a DAE function output by index.

dyn_out() -> [str]
dyn_out(int ind) -> str
Parameters:

ind -- Index in 0.. dyn_n_out() -1; any other value gives an empty string

>>> dyn_out(0), repr(dyn_out(4))
('ode', "''")
>> dyn_out(0), isempty(dyn_out(4))
ode
1
julia> ca.dyn_out(0), ca.dyn_out(4)
("ode", "")

Get the output scheme of a DAE function.

Returns the names of the 4 outputs of a DAE Function as expected by integrator, in order: ode, alg, quad, zero.

>>> dyn_out()
['ode', 'alg', 'quad', 'zero']
>>> x = SX.sym("x"); t = SX.sym("t"); e = SX(0, 1)
>>> dae = Function("dae", [t, x, e, e, e], [-x, e, x, e], dyn_in(), dyn_out())
>>> integrator("F", "rk", dae)(x0=1)["xf"]
DM(0.3679)
>> dyn_out()
ode
alg
quad
zero
>> x = SX.sym('x'); t = SX.sym('t'); e = SX(0, 1);
>> dae = Function('dae', {t, x, e, e, e}, {-x, e, x, e}, dyn_in(), dyn_out());
>> F = integrator('F', 'rk', dae); r = F('x0', 1); r.xf
0.3679
julia> ca.dyn_out()
4-element Vector{String}:
 "ode"
 "alg"
 "quad"
 "zero"
julia> x = ca.SX.sym("x"); t = ca.SX.sym("t"); e = ca.SX(0, 1);
julia> dae = ca.Function("dae", [t, x, e, e, e], [-x, e, x, e], ca.dyn_in(), ca.dyn_out());
julia> ca.integrator("F", "rk", dae)(x0=1)["xf"]
DM(0.3679)

See also: dyn_in, integrator

Extra doc | Doc source | Implementation

eig_symbolic(...)

Eigenvalues of a square SX matrix in closed form.

eig_symbolic(DM m) -> DM
eig_symbolic(SX m) -> SX

Splits the matrix into its strongly connected (block diagonal) components and solves the characteristic polynomial of each block with poly_roots, so every block may be at most 4-by-4. Larger blocks raise an error. Eigenvalues are assumed real. Returns a column vector; the order follows the block structure, not the magnitude. Only defined for SX; pass SX(m) for a numeric matrix.

>>> evalf(eig_symbolic(SX([[2, 1], [1, 2]])))
DM([1, 3])
>>> M = SX.sym("M", 2, 2)
>>> eig_symbolic(M)
SX(@1=(M_3+M_0), @2=sqrt((sq(@1)-(4*((M_0*M_3)-(M_2*M_1))))), @3=2, [((@1-@2)/@3),
((@1+@2)/@3)])
>>> evalf(eig_symbolic(SX.eye(5) * 3)).T
DM([[3, 3, 3, 3, 3]])
>> evalf(eig_symbolic(SX([2 1; 1 2])))
[1, 3]
>> a = SX.sym('a'); b = SX.sym('b'); c = SX.sym('c'); d = SX.sym('d');
>> eig_symbolic([a b; c d])
@1=(d+a), @2=sqrt((sq(@1)-(4*((a*d)-(b*c))))), @3=2, [((@1-@2)/@3), ((@1+@2)/@3)]
>> evalf(eig_symbolic(SX.eye(5) * 3))'
[[3, 3, 3, 3, 3]]
julia> ca.evalf(ca.eig_symbolic(ca.SX([2 1; 1 2])))
DM([1, 3])
julia> M = ca.SX.sym("M", 2, 2);
julia> l = ca.eig_symbolic(M); size(l)
(2, 1)
julia> l[1]
SX(@1=(M_3+M_0), ((@1-sqrt((sq(@1)-(4*((M_0*M_3)-(M_2*M_1))))))/2))
julia> l[2]
SX(@1=(M_3+M_0), ((@1+sqrt((sq(@1)-(4*((M_0*M_3)-(M_2*M_1))))))/2))
julia> ca.evalf(ca.eig_symbolic(ca.SX.eye(5) * 3))'
DM([[3, 3, 3, 3, 3]])

See also: poly_roots, Sparsity.scc

Extra doc | Doc source | Implementation

einstein(...)

Compute a dense tensor contraction in Einstein notation.

einstein(DM A, DM B, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> DM
einstein(SX A, SX B, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> SX
einstein(MX A, MX B, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> MX
einstein(DM A, DM B, DM C, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> DM
einstein(SX A, SX B, SX C, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> SX
einstein(MX A, MX B, MX C, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> MX

Computes C_c += A_a * B_b, where a, b and c are index labels in Einstein notation: a label appearing in both a and b is summed over, the remaining labels index the result. Tensors are passed as flat column vectors in column-major (Fortran) order together with their dimensions. Labels are encoded as strictly negative integers. For the matrix product C_ij = A_ik B_kj one writes a = [-1, -3], b = [-3, -2], c = [-1, -2].

Parameters:
  • A -- Dense column vectors with product(dim_a), product(dim_b) entries

  • B -- Dense column vectors with product(dim_a), product(dim_b) entries

  • C -- Optional accumulator with product(dim_c) entries, added to the result; when omitted the result starts from zero

  • dim_a -- Tensor dimensions

  • dim_b -- Tensor dimensions

  • dim_c -- Tensor dimensions

  • a -- Negative labels, one per dimension

  • b -- Negative labels, one per dimension

  • c -- Negative labels, one per dimension

Returns:

Column vector with product(dim_c) entries

Inconsistent dimensions or labels are not validated with a user- facing message. Also available for SX and DM.

>>> A = MX.sym("A", 6)
>>> B = MX.sym("B", 6)
>>> C = einstein(A, B, [2, 3], [3, 2], [2, 2], [-1, -3], [-3, -2], [-1, -2])
>>> C.shape
(4, 1)
>>> f = Function("f", [A, B], [C])
>>> f(DM(range(1, 7)), DM(range(1, 7)))
DM([22, 28, 49, 64])
>>> reshape(DM(range(1, 7)), 2, 3) @ reshape(DM(range(1, 7)), 3, 2)
DM(
[[22, 49],
 [28, 64]])
>> A = MX.sym('A', 6); B = MX.sym('B', 6);
>> C = einstein(A, B, [2 3], [3 2], [2 2], [-1 -3], [-3 -2], [-1 -2]);
>> size(C)
4 1
>> f = Function('f', {A, B}, {C});
>> f(DM((1:6)'), DM((1:6)'))
[22, 28, 49, 64]
>> reshape(DM((1:6)'), 2, 3) * reshape(DM((1:6)'), 3, 2)
[[22, 49],
[28, 64]]
julia> A = ca.MX.sym("A", 6); B = ca.MX.sym("B", 6);
julia> C = ca.einstein(A, B, [2, 3], [3, 2], [2, 2], [-1, -3], [-3, -2], [-1, -2]);
julia> size(C)
(4, 1)
julia> f = ca.Function("f", [A, B], [C]);
julia> f(1:6, 1:6)
DM([22, 28, 49, 64])
julia> reshape(ca.DM(1:6), 2, 3) * reshape(ca.DM(1:6), 3, 2)
DM(
[[22, 49],
 [28, 64]])

Extra doc | Doc source | Implementation

eq(...)

Logical equal to: (x,y) -> x == y.

eq(float x, float y) -> float
eq(DM x, DM y) -> DM
eq(SX x, SX y) -> SX
eq(MX x, MX y) -> MX

Elementwise comparison with 0/1 result, see lt: this is value equality of the entries, not identity of expressions; use is_equal to test whether two symbolic expressions are the same. For symbolic operands x == x with the same node simplifies to 1. NaN is not equal to anything, including itself.

>>> eq(DM([1, 2, 3]), 2)
DM([0, 1, 0])
>>> DM.eye(2) == DM([[1, 0], [0, 1]])
DM(
[[1, 1],
 [1, 1]])
>>> x = SX.sym("x")
>>> x == x, x == SX.sym("x")
(SX(1), SX((x==x)))
>>> DM(float("nan")) == DM(float("nan"))
DM(0)
>> eq(DM([1; 2; 3]), 2)
[0, 1, 0]
>> DM.eye(2) == DM([1 0; 0 1])
[[1, 1],
[1, 1]]
>> x = SX.sym('x');
>> x == x, x == SX.sym('x')
1
(x==x)
>> DM(nan) == DM(nan)
0
julia> ca.eq(ca.DM([1, 2, 3]), 2)
DM([0, 1, 0])
julia> ca.DM.eye(2) == ca.DM([1 0; 0 1])
DM(
[[1, 1],
 [1, 1]])
julia> x = ca.SX.sym("x");
julia> x == x, x == ca.SX.sym("x")
(1, (x==x))
julia> ca.DM(NaN) == ca.DM(NaN)
DM(0)

See also: ne, is_equal

Extra doc | Doc source | Implementation

erf(...)

Error function: x -> erf(x)

erf(float x) -> float
erf(DM x) -> DM
erf(SX x) -> SX
erf(MX x) -> MX

Elementwise; sparsity preserved (erf(0) == 0). Range (-1, 1).

>>> erf(DM([0, 1]))
DM([0, 0.842701])
>> erf(DM([0; 1]))
[0, 0.842701]
julia> ca.erf(ca.DM([0, 1]))
DM([0, 0.842701])

See also: erfinv

Extra doc | Doc source | Implementation

erfinv(...)

Inverse error function: x -> erfinv(x)

erfinv(float x) -> float
erfinv(DM x) -> DM
erfinv(SX x) -> SX
erfinv(MX x) -> MX

Elementwise; sparsity preserved. Defined on [-1, 1] with erfinv(+-1) infinite; arguments outside give NaN.

>>> erfinv(DM([0, 0.5, 1]))
DM([0, 0.476936, inf])
>> erfinv(DM([0; 0.5; 1]))
[0, 0.476936, inf]
julia> ca.erfinv(ca.DM([0, 0.5, 1]))
DM([0, 0.476936, inf])

See also: erf

Extra doc | Doc source | Implementation

evalf(...)

Evaluate an expression without free symbols numerically.

evalf(DM x) -> DM
evalf(SX x) -> DM
evalf(MX x) -> DM

Builds a Function without inputs around expr and evaluates it. Function calls, solver calls and sparse constants are handled. An error is raised when the expression depends on a symbolic primitive.

>>> evalf(MX(DM([[1, 2], [3, 4]])) @ MX([1, 1]))
DM([3, 7])
>>> evalf(MX(Sparsity.lower(2)) * 2)
DM(
[[2, 00],
 [2, 2]])
>>> try:
...   evalf(MX.sym("x") + 1)
... except Exception as e:
...   print("are free" in str(e))
True
>> evalf(MX(DM([1 2; 3 4])) * MX([1; 1]))
[3, 7]
>> evalf(MX(Sparsity.lower(2)) * 2)
[[2, 00],
[2, 2]]
>> try, evalf(MX.sym('x') + 1); catch e, disp('free variables'); end
free variables
julia> ca.evalf(ca.MX([1 2; 3 4]) * ca.MX([1, 1]))
DM([3, 7])
julia> ca.evalf(ca.MX(ca.Sparsity.lower(2)) * 2)
DM(
[[2, 00],
 [2, 2]])
julia> try
           ca.evalf(ca.MX.sym("x") + 1)
       catch e
           println(occursin("are free", sprint(showerror, e)))
       end
true

See also: to_DM, Function

Extra doc | Doc source | Implementation

event_in(...)

Get the input scheme of an event transition function.

event_in() -> [str]

Returns the names of the inputs of the Function passed as option "transition" to integrator: index (of the triggered "zero" indicator), t, x, z, p, u.

>>> event_in()
['index', 't', 'x', 'z', 'p', 'u']
>> event_in()
index
t
x
z
p
u
julia> ca.event_in()
6-element Vector{String}:
 "index"
 "t"
 "x"
 "z"
 "p"
 "u"

See also: event_out

Extra doc | Doc source | Implementation

event_out(...)

Get the output scheme of an event transition function.

event_out() -> [str]

Returns the names of the outputs of a transition Function: post_x, post_z, the values of x and z right after the event.

>>> event_out()
['post_x', 'post_z']
>> event_out()
post_x
post_z
julia> ca.event_out()
2-element Vector{String}:
 "post_x"
 "post_z"

See also: event_in

Extra doc | Doc source | Implementation

exp(...)

Elementwise exponential: x -> exp(x)

exp(float x) -> float
exp(DM x) -> DM
exp(SX x) -> SX
exp(MX x) -> MX

Elementwise; the result is dense (exp(0) == 1).

>>> exp(DM.eye(2))
DM(
[[2.71828, 1],
 [1, 2.71828]])
>>> exp(MX.sym("m", Sparsity.diag(2)))
MX(exp(dense(m)))
>> exp(DM.eye(2))
[[2.71828, 1],
[1, 2.71828]]
>> exp(MX.sym('m', Sparsity.diag(2)))
exp(dense(m))
julia> exp.(ca.DM.eye(2))
DM(
[[2.71828, 1],
 [1, 2.71828]])
julia> exp.(ca.MX.sym("m", ca.Sparsity.diag(2)))
MX(exp(dense(m)))

See also: log, expm1

Extra doc | Doc source | Implementation

expand(...)

Expand a scalar SX expression as a weighted sum of terms with constant

expand(DM ex) -> (DM, DM)
expand(SX ex) -> (SX, SX)

weights.

Collects additions, subtractions and multiplications by constants so that ex == dot(weights, terms), merging repeated terms. Any other operation (a product of two non-constant factors, a function call, ...) is kept as a single term with weight 1. The input must be a scalar SX; DM is not supported.

Returns:

weights and terms, both column vectors (a tuple in Python)

>>> x = SX.sym("x"); y = SX.sym("y")
>>> w, t = expand(3*x - x + 5*y)
>>> w, t
(SX([2, 5]), SX([x, y]))
>>> w, t = expand(3*(x + y) + 1)
>>> t
SX([x, y, 1])
>> x = SX.sym('x'); y = SX.sym('y');
>> [w, t] = expand(3*x - x + 5*y);
>> w, t
[2, 5]
[x, y]
>> [w, t] = expand(3*(x + y) + 1);
>> t
[x, y, 1]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> w, t = ca.expand(3*x - x + 5*y);
julia> w
SX([2, 5])
julia> t
SX([x, y])
julia> w, t = ca.expand(3*(x + y) + 1);
julia> t
SX([x, y, 1])

See also: linear_coeff

Extra doc | Doc source | Implementation

expm(...)

Calculate Matrix exponential.

expm(DM A) -> DM
expm(SX A) -> SX
expm(MX A) -> MX

Computes expm(A) for a square matrix through the 'slicot' expm plugin, which must be available in the build. Only defined for DM and MX (SX raises an error).

See also: expm_const, expmsol, mpower

Extra doc | Doc source | Implementation

expm1(...)

Precision variant for elementwise exponential: x -> exp(x)-1.

expm1(float x) -> float
expm1(DM x) -> DM
expm1(SX x) -> SX
expm1(MX x) -> MX

Elementwise; accurate for small x where exp(x) - 1 would lose digits. Sparsity preserved (expm1(0) == 0).

>>> expm1(DM([0, 1e-10]))
DM([0, 1e-10])
>> expm1(DM([0; 1e-10]))
[0, 1e-10]
julia> expm1.(ca.DM([0, 1e-10]))
DM([0, 1e-10])

See also: exp, log1p

Extra doc | Doc source | Implementation

expm_const(...)

Calculate Matrix exponential.

expm_const(DM A, DM t) -> DM
expm_const(SX A, SX t) -> SX
expm_const(MX A, MX t) -> MX

Computes expm(A*t) with A constant, through the 'slicot' expm plugin, which must be available in the build. Only defined for DM and MX (SX raises an error).

Parameters:
  • A -- Square matrix

  • t -- Scalar

See also: expm, expmsol

Extra doc | Doc source | Implementation

expm_n_in(...)

Get the number of expm solver inputs.

expm_n_in() -> int

Extra doc | Doc source | Implementation

expm_n_out(...)

Get the number of expm solver outputs.

expm_n_out() -> int

Extra doc | Doc source | Implementation

expmsol(...)

Performs a matrix exponentiation expm(A) General information

expmsol(str name, str solver, Sparsity A, dict opts) -> Function

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

const_A

OT_BOOL

Assume A is constant. Default: false.

casadi::Expm

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

List of plugins - slicot

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Expm.doc("myextraplugin")


slicot

Authors: Joris Gillis

Extra doc | Doc source | Implementation

export_graph(...)
export_graph([SX] expressions, dict opts) -> str
export_graph(SX expression, dict opts) -> str
export_graph(MX expression, dict opts) -> str
export_graph([MX] expressions, dict opts) -> str
export_graph([SX] expressions, str fname, dict opts)
export_graph(SX expression, str fname, dict opts)
export_graph(MX expression, str fname, dict opts)
export_graph([MX] expressions, str fname, dict opts)
external(...)

Load a just-in-time compiled external function.

external(str name, dict opts) -> Function
external(str name, Importer li, dict opts) -> Function
external(str name, str bin_name, dict opts) -> Function

File name given

Overload: external(str name, dict opts)

Load an external function from a shared library.

Parameters:

name -- Name as in the label assigned to a CasADi Function object: Function(name,...,...) Will be used to look up symbols/functions named eg. <name>_eval Use nm (linux/osx) or depends.exe (win) to check which symbols are present in your shared library

File name is assumed to be ./<name>.so

Overload: external(str name, str bin_name, dict opts)

Load an external function from a shared library.

Parameters:
  • name -- Name as in the label assigned to a CasADi Function object: Function(name,...,...) Will be used to look up symbols/functions named eg. <name>_eval Use nm (linux/osx) or depends.exe (win) to check which symbols are present in your shared library

  • bin_name -- File name of the shared library

Extra doc | Doc source | Implementation

external_transform(...)

Apply a transformation defined externally.

external_transform(str name, str op, Function f, dict opts) -> Function
Parameters:

Doc source | Implementation

extract(...)

Introduce intermediate variables for selected nodes in a graph.

extract([DM] ex, dict opts) -> ([DM], [DM], [DM])
extract([SX] ex, dict opts) -> ([SX], [SX], [SX])
extract([MX] ex, dict opts) -> ([MX], [MX], [MX])

Rewrites the expressions ex so that selected intermediate results are replaced by new symbols v with definitions vdef (ex, v and vdef are outputs; in Python the call is extract(ex, opts) -> (ex, v, vdef)). Substituting vdef for v in the result gives back the original expressions. Only nodes that are physically shared in the graph are detected: two separately constructed copies of x+y are distinct nodes (apply cse first to merge them). Not defined for DM.

Options:

  • lift_shared (bool), default true: extract nodes used more than once

  • lift_calls (bool), default false: extract every Function call and its arguments (MX only; SX raises for lift_calls true or lift_shared false)

  • prefix (str), default 'v_', suffix (str), default '', offset (int), default 0: naming of the new symbols

>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = x + y
>>> extract([sin(e), cos(e)])
([SX(sin(v_0)), SX(cos(v_0))], [SX(v_0)], [SX((x+y))])
>>> extract([sin(e), cos(e)], {"prefix": "w_", "offset": 3})
([SX(sin(w_3)), SX(cos(w_3))], [SX(w_3)], [SX((x+y))])
>>> extract([sin(x + y), cos(x + y)])
([SX(sin((x+y))), SX(cos((x+y)))], [], [])
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> f = Function("f", [X], [sin(X)]); E = X + Y
>>> extract([f(E)*f(E)], {"lift_shared": False, "lift_calls": True})
([MX((v_1*v_2))], [MX(v_0), MX(v_1), MX(v_2)], [MX((X+Y)), MX(f(v_0){0}), MX(f(v_0){0})])
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x + y;
>> [ex, v, vdef] = extract({sin(e), cos(e)});
>> ex{1}, ex{2}, v{1}, vdef{1}
sin(v_0)
cos(v_0)
v_0
(x+y)
>> [ex, v, vdef] = extract({sin(e), cos(e)}, struct('prefix', 'w_', 'offset', 3));
>> ex{1}, v{1}
sin(w_3)
w_3
>> [ex, v, vdef] = extract({sin(x + y), cos(x + y)});
>> ex{1}, numel(v)
sin((x+y))
0
>> X = MX.sym('X'); Y = MX.sym('Y');
>> f = Function('f', {X}, {sin(X)}); E = X + Y;
>> opts = struct('lift_shared', false, 'lift_calls', true);
>> [ex, v, vdef] = extract({f(E)*f(E)}, opts);
>> ex{1}, numel(v), vdef{2}
(v_1*v_2)
3
f(v_0){0}
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = x + y;
julia> ca.extract([sin(e), cos(e)])
(SX[sin(v_0), cos(v_0)], SX[v_0], SX[(x+y)])
julia> ca.extract([sin(e), cos(e)], Dict("prefix" => "w_", "offset" => 3))
(SX[sin(w_3), cos(w_3)], SX[w_3], SX[(x+y)])
julia> ca.extract([sin(x + y), cos(x + y)])
(SX[sin((x+y)), cos((x+y))], SX[], SX[])
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> f = ca.Function("f", [X], [sin(X)]); E = X + Y;
julia> ca.extract([f(E) * f(E)], Dict("lift_shared" => false, "lift_calls" => true))
(MX[(v_1*v_2)], MX[v_0, v_1, v_2], MX[(X+Y), f(v_0){0}, f(v_0){0}])

See also: shared, cse, substitute

Extra doc | Doc source | Implementation

extract_parametric(...)

Extract purely parametric parts from an expression graph.

extract_parametric(DM expr, DM par, dict opts) -> (DM, [DM], [DM])
extract_parametric(DM expr, [DM] par, dict opts) -> (DM, [DM], [DM])
extract_parametric([DM] expr, DM par, dict opts) -> ([DM], [DM], [DM])
extract_parametric([DM] expr, [DM] par, dict opts) -> ([DM], [DM], [DM])
extract_parametric(SX expr, SX par, dict opts) -> (SX, [SX], [SX])
extract_parametric(SX expr, [SX] par, dict opts) -> (SX, [SX], [SX])
extract_parametric([SX] expr, SX par, dict opts) -> ([SX], [SX], [SX])
extract_parametric([SX] expr, [SX] par, dict opts) -> ([SX], [SX], [SX])
extract_parametric(MX expr, MX par, dict opts) -> (MX, [MX], [MX])
extract_parametric(MX expr, [MX] par, dict opts) -> (MX, [MX], [MX])
extract_parametric([MX] expr, MX par, dict opts) -> ([MX], [MX], [MX])
extract_parametric([MX] expr, [MX] par, dict opts) -> ([MX], [MX], [MX])

The purpose of extract_parametric is ultimately to save on evaluation time of an expression, by extracting out the parts that are only solely dependent on parameters.

For any: [expr_ret, symbols, parametric] = extract_parametric(expr, par) It holds that: substitute(expr_ret,symbols,parametric) == expr

parametric is only dependant on par expr_ret is not dependant on par, but is dependant on symbols

Example: [expr_ret, symbols, parametric] = extract_parametric((x-sqrt(p))*y+cos(p)**2, p)

expr_ret: (((x-extracted1)*y)+extracted2) symbols: [extracted1, extracted2] parametric: [sqrt(p),cos(p)**2]

Options to control the name of new symbols:

  • offset (int), default 0: Offset for new symbol counter

  • prefix (str), default 'e_': Prefix for new symbols

  • suffix (str), default '': Suffix for new symbols

Option 'extract_trivial' controls the behaviour for extracted parts that consist of pure symbols. If false (default), these parts are not extracted.

expr may also be a list of expressions and par a list of parameter symbols (concatenated internally). An unknown option raises an error. Not defined for DM.

>>> x = SX.sym("x"); y = SX.sym("y"); p = SX.sym("p")
>>> expr_ret, symbols, parametric = extract_parametric((x - sqrt(p))*y + cos(p)**2, p)
>>> expr_ret
SX((((x-e_0)*y)+e_1))
>>> symbols, parametric
([SX(e_0), SX(e_1)], [SX(sqrt(p)), SX(sq(cos(p)))])
>>> extract_parametric(x*p, p)
(SX((x*p)), [], [])
>>> extract_parametric(x*p, p, {"extract_trivial": True})
(SX((x*e_0)), [SX(e_0)], [SX(p)])
>> x = SX.sym('x'); y = SX.sym('y'); p = SX.sym('p');
>> [expr_ret, symbols, parametric] = extract_parametric((x - sqrt(p))*y + cos(p)^2, p);
>> expr_ret
(((x-e_0)*y)+e_1)
>> vertcat(symbols{:}), vertcat(parametric{:})
[e_0, e_1]
[sqrt(p), sq(cos(p))]
>> [expr_ret, symbols, parametric] = extract_parametric(x*p, p);
>> expr_ret, numel(symbols)
(x*p)
0
>> opts = struct('extract_trivial', true);
>> [expr_ret, symbols, parametric] = extract_parametric(x*p, p, opts);
>> expr_ret, symbols{1}, parametric{1}
(x*e_0)
e_0
p
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); p = ca.SX.sym("p");
julia> e = (x - sqrt(p)) * y + cos(p)^2;
julia> expr_ret, symbols, parametric = ca.extract_parametric(e, p);
julia> expr_ret
SX((((x-e_0)*y)+e_1))
julia> symbols, parametric
(SX[e_0, e_1], SX[sqrt(p), sq(cos(p))])
julia> ca.extract_parametric(x * p, p)
((x*p), SX[], SX[])
julia> ca.extract_parametric(x * p, p, Dict("extract_trivial" => true))
((x*e_0), SX[e_0], SX[p])

See also: separate_linear, substitute

Extra doc | Doc source | Implementation

fabs(...)

Absolute value: x -> abs(x)

fabs(float x) -> float
fabs(DM x) -> DM
fabs(SX x) -> SX
fabs(MX x) -> MX

Elementwise; structural zeros are preserved. The unary functions of this group operate on every entry, keep the shape and build a symbolic expression for SX and MX. Those that map 0 to 0 (abs, sqrt, sin, tan, atan, asin, sinh, tanh, asinh, atanh, floor, ceil, sign, erf, erfinv, log1p, expm1) keep the sparsity pattern; the others (cos, cosh, exp, log, log10, acos, acosh, logic_not) return a dense result. Named fabs in Python, where the built-in abs also applies.

>>> fabs(DM([-1, 0, 2]))
DM([1, 0, 2])
>>> fabs(DM.eye(2) * -1)
DM(
[[1, 00],
 [00, 1]])
>>> abs(SX.sym("x"))
SX(fabs(x))
>> abs(DM([-1; 0; 2]))
[1, 0, 2]
>> abs(-DM.eye(2))
[[1, 00],
[00, 1]]
>> abs(SX.sym('x'))
fabs(x)
julia> abs.(ca.DM([-1, 0, 2]))
DM([1, 0, 2])
julia> abs(-ca.DM.eye(2))
DM(
[[1, 00],
 [00, 1]])
julia> abs(ca.SX.sym("x"))
SX(fabs(x))

See also: sign, copysign

Extra doc | Doc source | Implementation

find(...)

Find the index of the first nonzero entry of a vector.

find(MX x) -> MX

Returns a 1-by-1 expression that evaluates to the index of the first entry of x whose value is not zero, or to the length of x when all entries are zero. Structural zeros are skipped. The result is piecewise constant, so its derivative is zero. x must be a column or row vector; matrices raise an error.

>>> v = MX.sym("v", 3)
>>> f = Function("f", [v], [find(v)])
>>> find(v).shape, f(DM([0, 3, 1])), f(DM([0, 0, 0]))
((1, 1), DM(1), DM(3))
>>> evalf(find(MX(DM(Sparsity.unit(3, 2), [1]))))
DM(2)
>>> try:
...   find(MX.sym("A", 2, 2))
... except Exception as e:
...   print("Argument must be vector" in str(e))
True
>> v = MX.sym('v', 3);
>> f = Function('f', {v}, {find(v)});
>> size(find(v)), f(DM([0; 3; 1])), f(DM([0; 0; 0]))
1 1
1
3
>> evalf(find(MX(DM(Sparsity.unit(3, 2), 1))))
2
>> try, find(MX.sym('A', 2, 2)); catch e, disp('argument must be vector'); end
argument must be vector
julia> v = ca.MX.sym("v", 3);
julia> f = ca.Function("f", [v], [ca.find(v)]);
julia> size(ca.find(v)), f([0, 3, 1]), f([0, 0, 0])
((1, 1), 1, 3)
julia> ca.evalf(ca.find(ca.MX(ca.DM(ca.Sparsity.unit(3, 2), [1]))))
DM(2)
julia> try
           ca.find(ca.MX.sym("A", 2, 2))
       catch e
           println(occursin("Argument must be vector", sprint(showerror, e)))
       end
true

See also: low

Extra doc | Doc source | Implementation

floor(...)

Round down to nearest integer: x -> floor(x)

floor(float x) -> float
floor(DM x) -> DM
floor(SX x) -> SX
floor(MX x) -> MX

Elementwise, towards minus infinity; sparsity preserved. The derivative is zero everywhere. Floor division x // y in Python is floor(x / y).

>>> floor(DM([-1.5, 1.5]))
DM([-2, 1])
>>> DM([7, -7]) // 2
DM([3, -4])
>>> SX.sym("x") // 2
SX(floor((x/2)))
>> floor(DM([-1.5; 1.5]))
[-2, 1]
>> floor(DM([7; -7]) ./ 2)
[3, -4]
>> floor(SX.sym('x') / 2)
floor((x/2))
julia> floor.(ca.DM([-1.5, 1.5]))
DM([-2, 1])
julia> fld.(ca.DM([7, -7]), 2)
DM([3, -4])
julia> floor(ca.SX.sym("x") / 2)
SX(floor((x/2)))

See also: ceil, sign

Extra doc | Doc source | Implementation

fmax(...)

Largest of two values: (x,y) -> max(x,y)

fmax(float x, float y) -> float
fmax(DM x, DM y) -> DM
fmax(SX x, SX y) -> SX
fmax(MX x, MX y) -> MX

Elementwise maximum; shape rules as for plus. Follows C fmax: when one operand is NaN the other is returned. The derivative is 1 with respect to the larger operand (split evenly on ties). For the maximum over the entries of one matrix use mmax.

>>> fmax(DM([1, 5]), DM([3, 2]))
DM([3, 5])
>>> fmax(DM([1, 5]), 3)
DM([3, 5])
>>> fmax(DM([1, float("nan")]), DM([float("nan"), 2]))
DM([1, 2])
>>> fmax(MX.sym("x"), MX.sym("y"))
MX(fmax(x,y))
>> fmax(DM([1; 5]), DM([3; 2]))
[3, 5]
>> max(DM([1; 5]), 3)
[3, 5]
>> fmax(DM([1; nan]), DM([nan; 2]))
[1, 2]
>> max(MX.sym('x'), MX.sym('y'))
fmax(x,y)
julia> max.(ca.DM([1, 5]), ca.DM([3, 2]))
DM([3, 5])
julia> max.(ca.DM([1, 5]), 3)
DM([3, 5])
julia> max.(ca.DM([1, NaN]), ca.DM([NaN, 2]))
DM([1, 2])
julia> max(ca.MX.sym("x"), ca.MX.sym("y"))
MX(fmax(x,y))

See also: fmin, mmax

Extra doc | Doc source | Implementation

fmin(...)

Smallest of two values: (x,y) -> min(x,y)

fmin(float x, float y) -> float
fmin(DM x, DM y) -> DM
fmin(SX x, SX y) -> SX
fmin(MX x, MX y) -> MX

Elementwise minimum; shape rules as for plus. Follows C fmin: when one operand is NaN the other is returned, NaN results only when both are NaN. The derivative is 1 with respect to the smaller operand (split evenly on ties). The sparsity pattern is kept where both operands are structurally zero; fmin with a negative scalar densifies. For the minimum over the entries of one matrix use mmin.

>>> fmin(DM([1, 5]), DM([3, 2]))
DM([1, 2])
>>> fmin(DM([1, float("nan")]), DM([float("nan"), 2]))
DM([1, 2])
>>> fmin(DM.eye(2), 1)
DM(
[[1, 00],
 [00, 1]])
>>> fmin(SX.sym("x"), SX.sym("y"))
SX(fmin(x,y))
>> fmin(DM([1; 5]), DM([3; 2]))
[1, 2]
>> min(DM([1; 5]), DM([3; 2]))
[1, 2]
>> fmin(DM([1; nan]), DM([nan; 2]))
[1, 2]
>> fmin(DM.eye(2), 1)
[[1, 00],
[00, 1]]
>> min(SX.sym('x'), SX.sym('y'))
fmin(x,y)
julia> min.(ca.DM([1, 5]), ca.DM([3, 2]))
DM([1, 2])
julia> min.(ca.DM([1, NaN]), ca.DM([NaN, 2]))
DM([1, 2])
julia> min.(ca.DM.eye(2), 1)
DM(
[[1, 00],
 [00, 1]])
julia> min(ca.SX.sym("x"), ca.SX.sym("y"))
SX(fmin(x,y))

See also: fmax, mmin

Extra doc | Doc source | Implementation

fmod(...)

Remainder after division: (x,y) -> fmod(x,y)

fmod(float x, float y) -> float
fmod(DM x, DM y) -> DM
fmod(SX x, SX y) -> SX
fmod(MX x, MX y) -> MX

This Function follows the convention of https://en.cppreference.com/w/c/numeric/math/fmod: the result has the sign of x and magnitude below |y|.

This is equivalent to Python's numpy.fmod and Matlab's rem. It differs from the Python operator x % y on these objects, which follows the Python convention x - y*floor(x/y) (result with the sign of y). Elementwise, shape rules as for plus; structural zeros of x stay zero. A zero divisor gives NaN.

>>> fmod(DM([5, 5, -5, -5]), DM([3, -3, 3, -3]))
DM([2, 2, -2, -2])
>>> DM([5, 5, -5, -5]) % DM([3, -3, 3, -3])
DM([2, -1, 1, -2])
>>> fmod(SX.sym("x"), 2), SX.sym("x") % 2
(SX(fmod(x,2)), SX((x-(2.*floor((x/2))))))
>> x = DM([5; 5; -5; -5]); y = DM([3; -3; 3; -3]);
>> fmod(x, y)
[2, 2, -2, -2]
>> rem(x, y)
[2, 2, -2, -2]
>> x - y .* floor(x ./ y)
[2, -1, 1, -2]
>> rem(SX.sym('x'), 2)
fmod(x,2)
julia> ca.fmod(ca.DM([5, 5, -5, -5]), ca.DM([3, -3, 3, -3]))
DM([2, 2, -2, -2])
julia> mod.(ca.DM([5, 5, -5, -5]), ca.DM([3, -3, 3, -3]))
DM([2, -1, 1, -2])
julia> ca.fmod(ca.SX.sym("x"), 2)
SX(fmod(x,2))

See also: remainder, floor  Extra doc: https://github.com/casadi/casadi/wiki/L_pq

Doc source | Implementation

forward(...)

Forward directional derivative.

forward([DM] ex, [DM] arg, [[DM]] v, dict opts) -> [[DM]]
forward([SX] ex, [SX] arg, [[SX]] v, dict opts) -> [[SX]]
forward([MX] ex, [MX] arg, [[MX]] v, dict opts) -> [[MX]]

For each seed direction v[d] (a list with one seed per entry of arg, with matching shapes), computes the forward sensitivities of every entry of ex: the result is a list over directions of lists over ex, containing jtimes(ex[i], arg, v[d]) summed over all arguments. Not defined for DM.

Parameters:
  • ex -- List of expressions

  • arg -- List of symbolic expressions

  • v -- List of directions, each a list of seeds matching arg

  • opts -- Options, see jacobian

>>> x = SX.sym("x"); y = SX.sym("y")
>>> forward([x*y, x**2], [x, y], [[1, 0]])
[[SX(y), SX((2.*x))]]
>>> forward([x*y, x**2], [x, y], [[1, 0], [0, 1]])
[[SX(y), SX((2.*x))], [SX(x), SX(0)]]
>> x = SX.sym('x'); y = SX.sym('y');
>> r = forward({x*y, x^2}, {x, y}, {{1, 0}});
>> r{1}{1}, r{1}{2}
y
(2.*x)
>> r = forward({x*y, x^2}, {x, y}, {{1, 0}, {0, 1}});
>> r{2}{1}, r{2}{2}
x
0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.forward([x*y, x^2], [x, y], [[ca.SX(1), ca.SX(0)]])
1-element Vector{Vector{SX}}:
 SX[y, (2.*x)]
julia> ca.forward([x*y, x^2], [x, y], [[ca.SX(1), ca.SX(0)], [ca.SX(0), ca.SX(1)]])
2-element Vector{Vector{SX}}:
 SX[y, (2.*x)]
 SX[x, 0]

See also: reverse, jtimes, Function.forward

Extra doc | Doc source | Implementation

gauss_quadrature(...)

Integrate a scalar SX expression over [a, b] with 5-point Gauss- Legendre

gauss_quadrature(DM f, DM x, DM a, DM b, int order) -> DM
gauss_quadrature(SX f, SX x, SX a, SX b, int order) -> SX
gauss_quadrature(DM f, DM x, DM a, DM b, int order, DM w) -> DM
gauss_quadrature(SX f, SX x, SX a, SX b, int order, SX w) -> SX

quadrature.

Evaluates f at the five Gauss points of [a, b] and returns the weighted sum, which is exact for polynomials in x up to degree 9. Only defined for SX.

Parameters:
  • f -- Scalar expression to integrate; it may depend only on x

  • x -- Scalar symbolic integration variable

  • a -- Lower bound, a numeric constant

  • b -- Upper bound, a numeric constant

  • order -- Must be 5; any other value raises an error

  • w -- Reserved; must be empty

>>> x = SX.sym("x")
>>> try: gauss_quadrature(x**2, x, 0, 1, 3)
... except Exception as e: print("error")
error
>> x = SX.sym('x');
>> try, gauss_quadrature(x^2, x, 0, 1, 3); catch e, disp('error'); end
error
julia> x = ca.SX.sym("x");
julia> try ca.gauss_quadrature(x^2, x, 0, 1, 3); catch; println("error") end
error

See also: integrator

Extra doc | Doc source | Implementation

ge(...)

Logical greater or equal to: (x,y) -> x >= y.

ge(float x, float y) -> float
ge(DM x, DM y) -> DM
ge(SX x, SX y) -> SX
ge(MX x, MX y) -> MX

Elementwise comparison with 0/1 result, see lt. Implemented as y <= x.

>>> ge(DM([1, 2, 3]), 2)
DM([0, 1, 1])
>>> ge(MX.sym("x"), MX.sym("y"))
MX((y<=x))
>> ge(DM([1; 2; 3]), 2)
[0, 1, 1]
>> MX.sym('x') >= MX.sym('y')
(y<=x)
julia> ca.ge(ca.DM([1, 2, 3]), 2)
DM([0, 1, 1])
julia> ca.ge(ca.MX.sym("x"), ca.MX.sym("y"))
MX((y<=x))

See also: lt

Extra doc | Doc source | Implementation

gradient(...)

Calculate the gradient of an expression.

gradient(DM ex, DM arg, dict opts) -> DM
gradient(SX ex, SX arg, dict opts) -> SX
gradient(MX ex, MX arg, dict opts) -> MX

Computed with one reverse-mode sweep (jtimes with tr true) and projected onto the sparsity of arg: the result has the shape and pattern of arg, also for a matrix arg. A non-scalar ex raises an error (use jacobian).

Parameters:
  • ex -- Scalar expression to take the gradient of

  • arg -- Symbolic expression (any shape)

  • opts -- Options, see jacobian

Returns:

Matrix with the sparsity of arg

>>> x = SX.sym("x"); y = SX.sym("y")
>>> gradient(x*y + x**2, vertcat(x, y))
SX([((2.*x)+y), x])
>>> gradient(x**2, vertcat(x, y))
SX([(2.*x), 0])
>>> A = SX.sym("A", 2, 2)
>>> gradient(sumsqr(A), A)
SX(
[[(2.*A_0), (2.*A_2)],
 [(2.*A_1), (2.*A_3)]])
>> x = SX.sym('x'); y = SX.sym('y');
>> gradient(x*y + x^2, vertcat(x, y))
[((2.*x)+y), x]
>> gradient(x^2, vertcat(x, y))
[(2.*x), 0]
>> A = SX.sym('A', 2, 2);
>> gradient(sumsqr(A), A)
[[(2.*A_0), (2.*A_2)],
[(2.*A_1), (2.*A_3)]]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.gradient(x * y + x^2, [x; y])
SX([((2.*x)+y), x])
julia> ca.gradient(x^2, [x; y])
SX([(2.*x), 0])
julia> A = ca.SX.sym("A", 2, 2);
julia> ca.gradient(ca.sumsqr(A), A)
SX(
[[(2.*A_0), (2.*A_2)],
 [(2.*A_1), (2.*A_3)]])

See also: jacobian, hessian, jtimes

Extra doc | Doc source | Implementation

graph_substitute(...)

Substitute nodes in the expression graph, by node identity.

graph_substitute(MX ex, [MX] v, [MX] vdef) -> MX
graph_substitute([MX] ex, [MX] v, [MX] vdef) -> [MX]

Replaces every occurrence of the node v[i] in ex by vdef[i]. Unlike substitute, which only accepts symbolic primitives for v, graph_substitute matches any node, so intermediate results and Function call results can be replaced. Matching is by identity: an expression that was rebuilt (x + y created twice) is a different node and is not matched. Nodes that do not depend on any substituted node are reused, not copied. Shapes of v[i] and vdef[i] must agree.

Parameters:
  • ex -- Expression to substitute in

  • v -- Nodes to replace

  • vdef -- Replacements, same length as v

  • updated -- Set to true if any substitution took place (C++ only)

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> s = x + y
>>> e = sin(s) + s
>>> graph_substitute(e, [s], [MX(3)])
MX(3.14112)
>>> graph_substitute(e, [x + y], [MX(3)])
MX(@1=(x+y), (sin(@1)+@1))
>>> try:
...   substitute(e, s, MX(3))
... except Exception as err:
...   print("not symbolic" in str(err))
True
>>> try:
...   graph_substitute(e, [s], [MX.sym("z", 2)])
... except Exception as err:
...   print("Inconsistent shapes" in str(err))
True
>> x = MX.sym('x'); y = MX.sym('y');
>> s = x + y;
>> e = sin(s) + s;
>> graph_substitute(e, {s}, {MX(3)})
3.14112
>> graph_substitute(e, {x + y}, {MX(3)})
@1=(x+y), (sin(@1)+@1)
>> try, substitute(e, s, MX(3)); catch err, disp('not symbolic'); end
not symbolic
>> z = MX.sym('z', 2);
>> try, graph_substitute(e, {s}, {z}); catch err, disp('inconsistent shapes'); end
inconsistent shapes
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> s = x + y;
julia> e = sin(s) + s;
julia> ca.graph_substitute(e, [s], [ca.MX(3)])
MX(3.14112)
julia> ca.graph_substitute(e, [x + y], [ca.MX(3)])
MX(@1=(x+y), (sin(@1)+@1))
julia> try
           ca.substitute(e, s, ca.MX(3))
       catch err
           println(occursin("not symbolic", sprint(showerror, err)))
       end
true
julia> try
           ca.graph_substitute(e, [s], [ca.MX.sym("z", 2)])
       catch err
           println(occursin("Inconsistent shapes", sprint(showerror, err)))
       end
true

See also: substitute

Extra doc | Doc source | Implementation

gt(...)

Logical greater than: (x,y) -> x > y.

gt(float x, float y) -> float
gt(DM x, DM y) -> DM
gt(SX x, SX y) -> SX
gt(MX x, MX y) -> MX

Elementwise comparison with 0/1 result, see lt. Implemented as y < x, which is how a symbolic expression prints.

>>> gt(DM([1, 2, 3]), 2)
DM([0, 0, 1])
>>> gt(SX.sym("x"), SX.sym("y"))
SX((y<x))
>> gt(DM([1; 2; 3]), 2)
[0, 0, 1]
>> SX.sym('x') > SX.sym('y')
(y<x)
julia> ca.gt(ca.DM([1, 2, 3]), 2)
DM([0, 0, 1])
julia> ca.gt(ca.SX.sym("x"), ca.SX.sym("y"))
SX((y<x))

See also: lt

Extra doc | Doc source | Implementation

has_archiver(...)

Check if a particular plugin is available.

has_archiver(str name) -> bool

Doc source | Implementation

has_blas(...)
has_blas(str name) -> bool
has_conic(...)

Check if a QP solver plugin is available.

has_conic(str name) -> bool

Tries to load the plugin name if it is not loaded yet; false when it is not found.

>>> has_conic("qrqp"), has_conic("no_such_plugin")
(True, False)
>> has_conic('qrqp'), has_conic('no_such_plugin')
1
0
julia> ca.has_conic("qrqp"), ca.has_conic("no_such_plugin")
(true, false)

Extra doc | Doc source | Implementation

has_dple(...)

Check if a particular plugin is available.

has_dple(str name) -> bool

Doc source | Implementation

has_expm(...)

Check if a particular plugin is available.

has_expm(str name) -> bool

Doc source | Implementation

has_filesystem(...)

Check if a particular plugin is available.

has_filesystem(str name) -> bool

Doc source | Implementation

has_graphmodel(...)

Check if a graph-model format plugin is available.

has_graphmodel(str name) -> bool

Doc source | Implementation

has_integrator(...)

Check if an integrator plugin is available.

has_integrator(str name) -> bool

Tries to load the plugin name if it is not loaded yet; false when it is not found.

>>> has_integrator("rk"), has_integrator("no_such_plugin")
(True, False)
>> has_integrator('rk'), has_integrator('no_such_plugin')
1
0
julia> ca.has_integrator("rk"), ca.has_integrator("no_such_plugin")
(true, false)

Extra doc | Doc source | Implementation

has_interpolant(...)

Check if a particular plugin is available.

has_interpolant(str name) -> bool

Doc source | Implementation

has_linsol(...)

Check if a linear solver plugin is available.

has_linsol(str name) -> bool

Tries to load the plugin name if it is not loaded yet; false when it is not found.

>>> has_linsol("qr"), has_linsol("no_such_plugin")
(True, False)
>> has_linsol('qr'), has_linsol('no_such_plugin')
1
0
julia> ca.has_linsol("qr"), ca.has_linsol("no_such_plugin")
(true, false)

Extra doc | Doc source | Implementation

has_modelicaparser(...)

Check if a particular plugin is available.

has_modelicaparser(str name) -> bool

Doc source | Implementation

has_nlpsol(...)

Check if an NLP solver plugin is available.

has_nlpsol(str name) -> bool

Tries to load the plugin name if it is not loaded yet; false when it is not found.

>>> has_nlpsol("ipopt"), has_nlpsol("no_such_plugin")
(True, False)
>> has_nlpsol('ipopt'), has_nlpsol('no_such_plugin')
1
0
julia> ca.has_nlpsol("ipopt"), ca.has_nlpsol("no_such_plugin")
(true, false)

Extra doc | Doc source | Implementation

has_onnxbackend(...)

Check if a given ONNX runtime backend is available.

has_onnxbackend(str solver) -> bool

Extra doc | Doc source | Implementation

has_rootfinder(...)

Check if a rootfinder plugin is available.

has_rootfinder(str name) -> bool

Tries to load the plugin name if it is not loaded yet; false when it is not found.

>>> has_rootfinder("newton"), has_rootfinder("no_such_plugin")
(True, False)
>> has_rootfinder('newton'), has_rootfinder('no_such_plugin')
1
0
julia> ca.has_rootfinder("newton"), ca.has_rootfinder("no_such_plugin")
(true, false)

Extra doc | Doc source | Implementation

hash_sparsity(...)
hash_sparsity(int nrow, int ncol, casadi_int const * colind, casadi_int const * row) -> std::size_t
hash_sparsity(int nrow, int ncol, [int] colind, [int] row) -> std::size_t

Hash a sparsity pattern.

Extra doc | Doc source | Implementation

heaviside(...)

Heaviside step function, elementwise.

heaviside(DM x) -> DM
heaviside(SX x) -> SX

H(x) = 0 for x < 0, 1/2 for x == 0 and 1 for x > 0, computed as (1 + sign(x))/2. Structural zeros of a sparse input become 1/2. Not defined for MX.

>>> heaviside(DM([-1, 0, 1]))
DM([0, 0.5, 1])
>>> heaviside(SX.sym("x"))
SX(((1+sign(x))/2))
>> heaviside(DM([-1; 0; 1]))
[0, 0.5, 1]
>> heaviside(SX.sym('x'))
((1+sign(x))/2)
julia> ca.heaviside(ca.DM([-1, 0, 1]))
DM([0, 0.5, 1])
julia> ca.heaviside(ca.SX.sym("x"))
SX(((1+sign(x))/2))

See also: ramp, rectangle, sign

Extra doc | Doc source | Implementation

hessian(...)

Hessian and (optionally) gradient.

hessian(DM ex, DM arg, dict opts) -> (DM, DM)
hessian(SX ex, SX arg, dict opts) -> (SX, SX)
hessian(MX ex, MX arg, dict opts) -> (MX, MX)

Computes the gradient g = gradient(ex, arg) and the Hessian jacobian(g, arg), an arg.numel()-by-arg.numel() symmetric matrix; the "symmetric" option is set unless given in opts. ex must be scalar. The overload with output_g also returns the gradient; in Python, MATLAB and Julia this is the variant that is exposed, so the result is always the pair (H, g). Not defined for DM.

Parameters:

opts -- Options, see jacobian

>>> x = SX.sym("x"); y = SX.sym("y")
>>> H, g = hessian(x**2*y, vertcat(x, y))
>>> H
SX(@1=(2.*x),
[[(2.*y), @1],
 [@1, 00]])
>>> g
SX([((2.*x)*y), sq(x)])
>> x = SX.sym('x'); y = SX.sym('y');
>> [H, g] = hessian(x^2*y, vertcat(x, y));
>> H
@1=(2.*x),
[[(2.*y), @1],
[@1, 00]]
>> g
[((2.*x)*y), sq(x)]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> H, g = ca.hessian(x^2 * y, [x; y]);
julia> H
SX(@1=(2.*x),
[[(2.*y), @1],
 [@1, 00]])
julia> g
SX([((2.*x)*y), sq(x)])

See also: gradient, jacobian, Function.hessian

Extra doc | Doc source | Implementation

horzcat(...)

Concatenate a list of matrices horizontally.

_horzcat([Sparsity] v) -> Sparsity
_horzcat([DM] v) -> DM
_horzcat([SX] v) -> SX
_horzcat([MX] v) -> MX

Places the matrices side by side, in order: the result has the row count of the inputs and a column count equal to the sum of the column counts. All inputs must have the same number of rows; a 0-by-0 matrix is ignored. The result is of the type of the arguments, numeric arguments are converted to the symbolic type (DM mixes with SX or MX, but SX and MX cannot be mixed). The sparsity pattern of each block is preserved. With no arguments the result is a 1-by-0 matrix.

Alternative terminology: horizontal stack, hstack, horizontal append, [a b]. Inverse of horzsplit: horzcat(horzsplit(x, ...)) == x.

Parameters:

v -- List of matrices with matching row count

Returns:

Matrix with the blocks of v side by side

>>> horzcat(DM([1, 2]), DM([3, 4]), DM([5, 6]))
DM(
[[1, 3, 5],
 [2, 4, 6]])
>>> horzcat(SX.sym("x", 2), DM.ones(2, 1))
SX(@1=1,
[[x_0, @1],
 [x_1, @1]])
>>> horzcat(MX.sym("x", 2, 2), MX.sym("y", 2, 0))
MX(x)
>>> horzcat().shape, horzcat(DM(2, 3), DM(0, 0)).shape
((1, 0), (2, 3))
>>> horzcat(DM.ones(2, 2), DM.ones(3, 1))
Traceback (most recent call last):
  ...
RuntimeError: ...Mismatching number of rows...
>> [DM([1; 2]), DM([3; 4]), DM([5; 6])]
[[1, 3, 5],
[2, 4, 6]]
>> horzcat(SX.sym('x', 2), DM.ones(2, 1))
@1=1,
[[x_0, @1],
[x_1, @1]]
>> [MX.sym('x', 2, 2), MX.sym('y', 2, 0)]
x
>> size([DM(2, 3), DM(0, 0)])
2 3
>> try, [DM.ones(2, 2), DM.ones(3, 1)]; catch e, disp(e.message); end
...Mismatching number of rows
julia> [ca.DM([1, 2]) ca.DM([3, 4]) ca.DM([5, 6])]
DM(
[[1, 3, 5],
 [2, 4, 6]])
julia> [ca.SX.sym("x", 2) ca.DM.ones(2, 1)]
SX(@1=1,
[[x_0, @1],
 [x_1, @1]])
julia> [ca.MX.sym("x", 2, 2) ca.MX.sym("y", 2, 0)]
MX(x)
julia> size([ca.DM(2, 3) ca.DM(0, 0)])
(2, 3)
julia> try
           [ca.DM.ones(2, 2) ca.DM.ones(3, 1)]
       catch err
           println(occursin("dimension mismatch", sprint(showerror, err)))
       end
false

See also: vertcat, diagcat, veccat, horzsplit

Extra doc | Doc source | Implementation

horzsplit(...)

Split a matrix horizontally into groups of columns.

horzsplit(Sparsity v, int incr) -> [Sparsity]
horzsplit(DM v, int incr) -> [DM]
horzsplit(SX v, int incr) -> [SX]
horzsplit(MX v, int incr) -> [MX]
horzsplit(Sparsity v, [int] offset) -> [Sparsity]
horzsplit(DM v, [int] offset) -> [DM]
horzsplit(SX v, [int] offset) -> [SX]
horzsplit(MX v, [int] offset) -> [MX]

Returns the column blocks x``[:, offset[i]:offset[i+1]], in order. The offsets must start at 0, be non-decreasing and end at the number of columns of ``x, otherwise an error is raised. Two equal consecutive offsets give an empty block. Each block carries the corresponding part of the sparsity pattern. Inverse of horzcat: horzcat(horzsplit(x, offset)) == x.

Parameters:
  • x -- Matrix (or Sparsity) to split; any shape

  • offset -- Start column of every block followed by the column count of x

Returns:

List of matrices of the same type as x, one per block

>>> x = DM([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]])
>>> horzsplit(x, [0, 2, 5])
[DM(
[[1, 2],
 [6, 7]]), DM(
[[3, 4, 5],
 [8, 9, 10]])]
>>> horzsplit(x, [0, 0, 5])[0].shape
(2, 0)
>>> horzsplit(x, [0, 2])
Traceback (most recent call last):
  ...
RuntimeError: ...must start at 0, be nondecreasing and end at 5...
>> x = DM([1 2 3 4 5; 6 7 8 9 10]);
>> v = horzsplit(x, [0, 2, 5]); disp(numel(v)), disp(v{1}), disp(v{2})
2
[[1, 2],
[6, 7]]
[[3, 4, 5],
[8, 9, 10]]
>> v = horzsplit(x, [0, 0, 5]); disp(size(v{1}))
2 0
>> try, horzsplit(x, [0, 2]); catch e, disp(e.message); end
...must start at 0, be nondecreasing and end at 5...
julia> x = ca.DM([1 2 3 4 5; 6 7 8 9 10]);
julia> v = ca.horzsplit(x, [0, 2, 5]);
julia> length(v)
2
julia> v[1]
DM(
[[1, 2],
 [6, 7]])
julia> v[2]
DM(
[[3, 4, 5],
 [8, 9, 10]])
julia> size(ca.horzsplit(x, [0, 0, 5])[1])
(2, 0)
julia> try
           ca.horzsplit(x, [0, 2])
       catch err
           println(occursin("end at 5", sprint(showerror, err)))
       end
true

See also: horzsplit_n, vertsplit, offset

Extra doc | Doc source | Implementation

horzsplit_n(...)

Split a matrix horizontally into a given number of equal groups of columns.

horzsplit_n(Sparsity v, int n) -> [Sparsity]
horzsplit_n(DM v, int n) -> [DM]
horzsplit_n(SX v, int n) -> [SX]
horzsplit_n(MX v, int n) -> [MX]

Returns n column blocks of equal width, in order. An error is raised when the column count of x is not a multiple of n or n is negative. A matrix without columns gives n copies of itself. Inverse of horzcat: horzcat(horzsplit_n(x, n)) == x.

Parameters:
  • x -- Matrix (or Sparsity) to split; any shape

  • n -- Number of blocks

Returns:

List of n matrices of the same type as x

>>> horzsplit_n(DM([[1, 2, 3, 4]]), 2)
[DM([[1, 2]]), DM([[3, 4]])]
>>> horzsplit_n(DM(2, 0), 3)
[DM(2x0), DM(2x0), DM(2x0)]
>>> horzsplit_n(DM([[1, 2, 3]]), 2)
Traceback (most recent call last):
  ...
RuntimeError: ...must be a multiple of n...
>> v = horzsplit_n(DM([1 2 3 4]), 2); disp(v{1}), disp(v{2})
[[1, 2]]
[[3, 4]]
>> v = horzsplit_n(DM(2, 0), 3); disp(numel(v)), disp(size(v{1}))
3
2 0
>> try, horzsplit_n(DM([1 2 3]), 2); catch e, disp(e.message); end
...must be a multiple of n...
julia> ca.horzsplit_n(ca.DM([1 2 3 4]), 2)
2-element Vector{DM}:
 DM([[1, 2]])
 DM([[3, 4]])
julia> ca.horzsplit_n(ca.DM(2, 0), 3)
3-element Vector{DM}:
 DM(2x0)
 DM(2x0)
 DM(2x0)
julia> try
           ca.horzsplit_n(ca.DM([1 2 3]), 2)
       catch err
           println(occursin("must be a multiple of n", sprint(showerror, err)))
       end
true

See also: horzsplit, vertsplit_n

Extra doc | Doc source | Implementation

hypot(...)

Precision variant for 2 norm: (x,y) -> sqrt(x^2+y^2)

hypot(float x, float y) -> float
hypot(DM x, DM y) -> DM
hypot(SX x, SX y) -> SX
hypot(MX x, MX y) -> MX

Elementwise; avoids the overflow and underflow of forming the squares, as C hypot. Shape rules as for plus; the result is structurally zero where both operands are.

>>> hypot(DM(3), DM(4))
DM(5)
>>> hypot(DM(1e200), DM(1e200))
DM(1.41421e+200)
>>> hypot(SX.sym("x"), SX.sym("y"))
SX(hypot(x,y))
>> hypot(DM(3), DM(4))
5
>> hypot(DM(1e200), DM(1e200))
1.41421e+200
>> hypot(SX.sym('x'), SX.sym('y'))
hypot(x,y)
julia> hypot(ca.DM(3), ca.DM(4))
DM(5)
julia> hypot(ca.DM(1e200), ca.DM(1e200))
DM(1.41421e+200)
julia> hypot(ca.SX.sym("x"), ca.SX.sym("y"))
SX(hypot(x,y))

See also: norm_2

Extra doc | Doc source | Implementation

if_else(...)

Branching on MX nodes.

if_else(DM cond, DM if_true, DM if_false, bool short_circuit) -> DM
if_else(SX cond, SX if_true, SX if_false, bool short_circuit) -> SX
if_else(MX cond, MX if_true, MX if_false, bool short_circuit) -> MX

Ternary operator, "cond ? if_true : if_false"

Selects if_true where cond is nonzero and if_false elsewhere. cond may be a scalar or have the shape of the branches (elementwise selection); a scalar branch is broadcast. By default the result is if_else_zero(cond, if_true) + if_else_zero(!cond, if_false): both branches are part of the expression and are evaluated, but the value of the unselected branch is discarded, so a nan or inf there does not propagate. With short_circuit true (MX only; ignored for SX and DM) the branches are wrapped in functions and only the selected one is evaluated.

>>> if_else(DM(1), DM(10), DM(20)), if_else(DM(0), DM(10), DM(20))
(DM(10), DM(20))
>>> if_else(DM([1, 0]), DM([1, 2]), DM([3, 4]))
DM([1, 4])
>>> x = SX.sym("x")
>>> if_else(x > 0, x, -x)
SX(@1=(0<x), ((@1?x:0)+((!@1)?(-x):0)))
>>> f = Function("f", [x], [if_else(x >= 0, sqrt(x), 0)])
>>> f(-1)
DM(0)
>>> X = MX.sym("X")
>>> if_else(X > 0, X, -X, True)
MX(switch((0<X), X){0})
>> if_else(DM(1), DM(10), DM(20)), if_else(DM(0), DM(10), DM(20))
10
20
>> if_else(DM([1; 0]), DM([1; 2]), DM([3; 4]))
[1, 4]
>> x = SX.sym('x');
>> if_else(x > 0, x, -x)
@1=(0<x), ((@1?x:0)+((!@1)?(-x):0))
>> f = Function('f', {x}, {if_else(x >= 0, sqrt(x), 0)});
>> f(-1)
0
>> X = MX.sym('X');
>> if_else(X > 0, X, -X, true)
switch((0<X), X){0}
julia> a = ca.DM(10); b = ca.DM(20);
julia> ca.if_else(ca.DM(1), a, b), ca.if_else(ca.DM(0), a, b)
(10, 20)
julia> ca.if_else(ca.DM([1, 0]), ca.DM([1, 2]), ca.DM([3, 4]))
DM([1, 4])
julia> x = ca.SX.sym("x");
julia> ca.if_else(x > 0, x, -x)
SX(@1=(0<x), ((@1?x:0)+((!@1)?(-x):0)))
julia> f = ca.Function("f", [x], [ca.if_else(x >= 0, sqrt(x), 0)]);
julia> f(-1)
DM(0)
julia> X = ca.MX.sym("X");
julia> ca.if_else(X > 0, X, -X, true)
MX(switch((0<X), X){0})

See also: conditional, if_else_zero, Function.if_else

Extra doc | Doc source | Implementation

index_interp1d(...)
index_interp1d([float] x, float xq, bool equidistant) -> float
integrator_in(...)

Get the name of an integrator input by index.

integrator_in() -> [str]
integrator_in(int ind) -> str
Parameters:

ind -- Index in 0.. integrator_n_in() -1; any other value gives an empty string

>>> integrator_in(0), integrator_in(6), repr(integrator_in(7))
('x0', 'adj_qf', "''")
>> integrator_in(0), integrator_in(6), isempty(integrator_in(7))
x0
adj_qf
1
julia> ca.integrator_in(0), ca.integrator_in(6), ca.integrator_in(7)
("x0", "adj_qf", "")

Get the input scheme of integrators.

Returns the names of the 7 inputs of a Function created by integrator, in order: x0, z0, p, u, adj_xf, adj_zf, adj_qf.

>>> integrator_in()
['x0', 'z0', 'p', 'u', 'adj_xf', 'adj_zf', 'adj_qf']
>> integrator_in()
x0
z0
p
u
adj_xf
adj_zf
adj_qf
julia> ca.integrator_in()
7-element Vector{String}:
 "x0"
 "z0"
 "p"
 "u"
 "adj_xf"
 "adj_zf"
 "adj_qf"

See also: integrator_out, integrator_n_in

Extra doc | Doc source | Implementation

integrator_n_in(...)

Get the number of integrator inputs.

integrator_n_in() -> int
>>> integrator_n_in()
7
>> integrator_n_in()
7
julia> ca.integrator_n_in()
7

Extra doc | Doc source | Implementation

integrator_n_out(...)

Get the number of integrator outputs.

integrator_n_out() -> int
>>> integrator_n_out()
7
>> integrator_n_out()
7
julia> ca.integrator_n_out()
7

Extra doc | Doc source | Implementation

integrator_out(...)

Get the name of an integrator output by index.

integrator_out() -> [str]
integrator_out(int ind) -> str
Parameters:

ind -- Index in 0.. integrator_n_out() -1; any other value gives an empty string

>>> integrator_out(0), integrator_out(6), repr(integrator_out(7))
('xf', 'adj_u', "''")
>> integrator_out(0), integrator_out(6), isempty(integrator_out(7))
xf
adj_u
1
julia> ca.integrator_out(0), ca.integrator_out(6), ca.integrator_out(7)
("xf", "adj_u", "")

Get the output scheme of integrators.

Returns the names of the 7 outputs of a Function created by integrator, in order: xf, zf, qf, adj_x0, adj_z0, adj_p, adj_u.

>>> integrator_out()
['xf', 'zf', 'qf', 'adj_x0', 'adj_z0', 'adj_p', 'adj_u']
>> integrator_out()
xf
zf
qf
adj_x0
adj_z0
adj_p
adj_u
julia> ca.integrator_out()
7-element Vector{String}:
 "xf"
 "zf"
 "qf"
 "adj_x0"
 "adj_z0"
 "adj_p"
 "adj_u"

See also: integrator_in, integrator_n_out

Extra doc | Doc source | Implementation

interp1d(...)

Performs 1d linear interpolation.

interp1d([float] x, DM v, [float] xq, str mode, bool equidistant) -> DM
interp1d([float] x, SX v, [float] xq, str mode, bool equidistant) -> SX
interp1d([float] x, MX v, [float] xq, str mode, bool equidistant) -> MX

The data points are (x[i], v[i, :]): row i of v holds the values at abscissa x[i], so v has as many rows as x has entries and every column is interpolated independently. The result has one row per query point xq[j].

Queries outside the range of x are clamped to the first or last data point (no extrapolation). The result is a constant sparse matrix times v, so for symbolic v the expression is linear in v.

Parameters:
  • x -- Abscissae, strictly increasing, at least two entries

  • v -- Data values, x.size()-by-m

  • xq -- Query abscissae, any order

  • mode -- "linear" (interpolate), "floor" (value at the data point at or below the query) or "ceil" (at or above); any other string raises an error

  • equidistant -- When true, x is assumed uniformly spaced and the interval is located arithmetically from x[0] and x[1] instead of by search

Returns:

Matrix of size xq.size()-by-m

>>> interp1d([0, 1, 2], DM([0, 10, 20]), [0.5, 1.5])
DM([5, 15])
>>> interp1d([0, 1, 2], DM([0, 10, 20]), [0.5, 1.5], "floor")
DM([0, 10])
>>> interp1d([0, 1, 2], DM([[0, 1], [10, 11], [20, 21]]), [0.5, 2])
DM(
[[5, 6],
 [20, 21]])
>>> interp1d([0, 1, 2], DM([0, 10, 20]), [-1, 3])
DM([0, 20])
>>> interp1d([0, 1, 2], SX.sym("v", 3), [0.5])
SX(@1=0.5, ((@1*v_0)+(@1*v_1)))
>> interp1d([0, 1, 2], DM([0; 10; 20]), [0.5, 1.5])
[5, 15]
>> interp1d([0, 1, 2], DM([0; 10; 20]), [0.5, 1.5], 'floor')
[0, 10]
>> interp1d([0, 1, 2], DM([0 1; 10 11; 20 21]), [0.5, 2])
[[5, 6],
[20, 21]]
>> interp1d([0, 1, 2], DM([0; 10; 20]), [-1, 3])
[0, 20]
>> interp1d([0, 1, 2], SX.sym('v', 3), 0.5)
@1=0.5, ((@1*v_0)+(@1*v_1))
julia> ca.interp1d([0, 1, 2], ca.DM([0, 10, 20]), [0.5, 1.5])
DM([5, 15])
julia> ca.interp1d([0, 1, 2], ca.DM([0, 10, 20]), [0.5, 1.5], "floor")
DM([0, 10])
julia> ca.interp1d([0, 1, 2], ca.DM([0 1; 10 11; 20 21]), [0.5, 2])
DM(
[[5, 6],
 [20, 21]])
julia> ca.interp1d([0, 1, 2], ca.DM([0, 10, 20]), [-1, 3])
DM([0, 20])
julia> ca.interp1d([0, 1, 2], ca.SX.sym("v", 3), [0.5])
SX(@1=0.5, ((@1*v_0)+(@1*v_1)))

See also: interpolant

Extra doc | Doc source | Implementation

interpolant(...)

Parametric variant of interpolant.

interpolant(str name, str solver, [[float]] grid, int m, dict opts) -> Function
interpolant(str name, str solver, [int] grid_dims, int m, dict opts) -> Function
interpolant(str name, str solver, [[float]] grid, [float] values, dict opts) -> Function
interpolant(str name, str solver, [int] grid_dims, [float] values, dict opts) -> Function

The resulting function will have an additional argument for the grid

By default, derivatives wrt the coefficients are not supported (zero). Some interpolant plugins may support the inline=true which enables correct derivatives

Overload: interpolant(str name, str solver, [[float]] grid, int m, dict opts)

Parametric variant of interpolant.

The resulting function will have an additional argument for the coefficients

By default, derivatives wrt the coefficients are not supported (zero). Some interpolant plugins may support the inline=true which enables correct derivatives

Overload: interpolant(str name, str solver, [int] grid_dims, int m, dict opts)

Parametric variant of interpolant.

The resulting function will have additional arguments for the grid and coefficients

By default, derivatives wrt the coefficients are not supported (zero). Some interpolant plugins may support the inline=true which enables correct derivatives

Overload: interpolant(str name, str solver, [[float]] grid, [float] values, dict opts)

An interpolant function for lookup table data

Parameters:
  • name -- label for the resulting Function

  • solver -- name of the plugin

  • grid -- collection of 1D grids whose outer product defines the full N-D rectangular grid

  • values -- flattened vector of all values for all gridpoints

Examples in 1D and 2D; the values of a 2D grid are flattened in column-major order.

>>> xgrid = np.linspace(1, 6, 6)
>>> V = [-1, -1, -2, -3, 0, 2]
>>> LUT = interpolant("LUT", "bspline", [xgrid], V)
>>> print(LUT(2.5))
-1.35
>>> xgrid = np.linspace(-5, 5, 11)
>>> ygrid = np.linspace(-4, 4, 9)
>>> X, Y = np.meshgrid(xgrid, ygrid, indexing="ij")
>>> R = np.sqrt(5*X**2 + Y**2) + 1
>>> V = np.sin(R)/R
>>> LUT = interpolant("LUT", "bspline", [xgrid, ygrid], V.ravel(order="F"))
>>> print(LUT([0.5, 1]))
0.245507
>> xgrid = 1:6;
>> V = [-1 -1 -2 -3 0 2];
>> LUT = interpolant('LUT', 'bspline', {xgrid}, V);
>> LUT(2.5)
-1.35
>> xgrid = -5:5;
>> ygrid = -4:4;
>> [X, Y] = ndgrid(xgrid, ygrid);
>> R = sqrt(5*X.^2 + Y.^2) + 1;
>> V = sin(R)./R;
>> LUT = interpolant('LUT', 'bspline', {xgrid, ygrid}, V(:));
>> LUT([0.5 1])
0.245507
julia> xgrid = collect(1.0:6.0);
julia> V = [-1, -1, -2, -3, 0, 2];
julia> LUT = ca.interpolant("LUT", "bspline", [xgrid], V);
julia> LUT(2.5)
DM(-1.35)
julia> xgrid = collect(-5.0:5.0);
julia> ygrid = collect(-4.0:4.0);
julia> R = [sqrt(5x^2 + y^2) + 1 for x in xgrid, y in ygrid];
julia> V = sin.(R) ./ R;
julia> LUT = ca.interpolant("LUT", "bspline", [xgrid, ygrid], vec(V));
julia> LUT([0.5, 1])
DM(0.245507)

General information

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

batch_x

OT_INT

Evaluate a batch of different inputs at once (default 1).

casadi::Interpol ant

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

inline

OT_BOOL

Implement the lookup table in MX primitives. Useful when you need derivatives with respect to grid and/or coefficients. Such derivatives are fundamentally dense, so use with caution.

casadi::Interpol ant

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

lookup_mode

OT_STRINGVECTOR

Specifies, for each grid dimension, the lookup algorithm used to find the correct index. 'linear' uses a for-loop + break; (default when #knots<=100), 'exact' uses floored division (only for uniform grids), 'binary' uses a binary search. (default when #knots>100).

casadi::Interpol ant

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

List of plugins - bspline

  • linear

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Interpolant.doc("myextraplugin")


bspline

>List of available options

Id

Type

Description

algorithm

OT_STRING

Algorithm used for fitting the data: 'not_a_knot' (default, same as Matlab), 'smooth_linear'.

degree

OT_INTVECTOR

Sets, for each grid dimension, the degree of the spline.

linear_solver

OT_STRING

Solver used for constructing the coefficient tensor.

linear_solver_options

OT_DICT

Options to be passed to the linear solver.

smooth_linear_frac

OT_DOUBLE

When 'smooth_linear' algorithm is active, determines sharpness between 0 (sharp, as linear interpolation) and 0.5 (smooth).Default value is 0.1.


linear

>List of available options

Id

Type

Description

lookup_mode

OT_STRINGVECTOR

Sets, for each grid dimenion, the lookup algorithm used to find the correct index. 'linear' uses a for-loop + break; 'exact' uses floored division (only for uniform grids).

Authors: Joel Andersson

Extra doc | Doc source | Implementation

inv(...)

Element-wise inverse, 1/x.

inv(DM A) -> DM
inv(SX A) -> SX
inv(MX A) -> MX
inv(DM A, str lsolver, dict opts) -> DM
inv(SX A, str lsolver, dict opts) -> SX
inv(MX A, str lsolver, dict opts) -> MX

Not the matrix inverse: use inv or inv_node for that. Applied twice it returns the original node. Not available in MATLAB and Julia, where inv is the matrix inverse; use 1./x there.

>>> A = MX.sym("A", 2, 2)
>>> A.inv(), A.inv().inv()
(MX((1./A)), MX(A))
>>> evalf(MX(4).inv())
DM(0.25)

See also: inv, inv_node

Extra doc | Doc source | Implementation

inv_minor(...)

Matrix inverse by the adjugate (experimental)

inv_minor(DM A) -> DM
inv_minor(SX A) -> SX
inv_minor(MX A) -> MX

Computes adj(A)/det(A) by minor expansion. Available for DM and SX; MX raises "Not implemented". Use inv for the general case.

>>> inv_minor(DM([[1, 2], [3, 4]]))
DM(
[[-2, 1],
 [1.5, -0.5]])
>> inv_minor(DM([1 2; 3 4]))
[[-2, 1],
[1.5, -0.5]]
julia> ca.inv_minor(ca.DM([1 2; 3 4]))
DM(
[[-2, 1],
 [1.5, -0.5]])

See also: inv, det

Extra doc | Doc source | Implementation

inv_node(...)

Symbolic matrix inverse node.

inv_node(MX x) -> MX

Creates a single node representing the inverse of the square matrix x. The node defines its derivatives (via -inv(x) dx inv(x)) but cannot be evaluated numerically or expanded to SX; it is meant as a placeholder in symbolic manipulations. For an inverse that can be evaluated use inv or solve.

>>> A = MX.sym("A", 2, 2)
>>> inv_node(A), inv_node(A).is_op(OP_INVERSE), jacobian(inv_node(A), A).shape
(MX(inv(A)), True, (4, 4))
>>> try:
...   inv_node(MX.sym("B", 2, 3))
... except Exception as e:
...   print("must be square" in str(e))
True
>> A = MX.sym('A', 2, 2);
>> e = inv_node(A); J = jacobian(e, A);
>> e, e.is_op(OP_INVERSE), size(J)
inv(A)
1
4 4
>> try, inv_node(MX.sym('B', 2, 3)); catch e, disp('must be square'); end
must be square
julia> A = ca.MX.sym("A", 2, 2);
julia> B = ca.inv_node(A);
julia> B, ca.is_op(B, ca.OP_INVERSE), size(ca.jacobian(B, A))
(inv(A), true, (4, 4))
julia> try
           ca.inv_node(ca.MX.sym("B", 2, 3))
       catch e
           println(occursin("must be square", sprint(showerror, e)))
       end
true

See also: inv, solve

Extra doc | Doc source | Implementation

inv_skew(...)

Generate the 3-vector progenitor of a skew symmetric matrix.

inv_skew(DM a) -> DM
inv_skew(SX a) -> SX
inv_skew(MX a) -> MX

Inverse of skew: for a 3-by-3 matrix S, returns 0.5*[S(2,1)-S(1,2); S(0,2)-S(2,0); S(1,0)-S(0,1)], which recovers a from skew(a). A non-3-by-3 argument raises an error.

See also: skew

Extra doc | Doc source | Implementation

is_equal(...)

Check if two nodes are equivalent up to a given depth.

is_equal(float x, float y, int depth) -> bool
is_equal(DM x, DM y, int depth) -> bool
is_equal(SX x, SX y, int depth) -> bool
is_equal(MX x, MX y, int depth) -> bool

Depth=0 checks if the expressions are identical, i.e. points to the same node.

a = x*x b = x*x

is_equal(a,b,0) will return false, but is_equal(a,b,1) will return true

Returns a plain boolean, unlike the elementwise comparison eq. With depth > 0 two different nodes are equivalent when they have the same operation and their dependencies are equivalent up to depth-1. For SX and DM matrices the test is applied entry by entry; matrices of different shape raise an error, and for DM it is value equality. Both arguments must be of the same type.

Parameters:
  • x -- First expression

  • y -- Second expression

  • depth -- Number of levels of the expression graph to compare, 0 for identity

>>> x = SX.sym("x")
>>> is_equal(x, x), is_equal(x, SX.sym("x"))
(True, False)
>>> is_equal(x*x, x*x), is_equal(x*x, x*x, 1)
(False, True)
>>> is_equal(DM([1, 2]), DM([1, 2])), is_equal(DM([1, 2]), DM([1, 3]))
(True, False)
>>> y = MX.sym("y")
>>> is_equal(y * y, y * y), is_equal(y * y, y * y, 1)
(False, True)
>> x = SX.sym('x');
>> is_equal(x, x), is_equal(x, SX.sym('x'))
1
0
>> is_equal(x*x, x*x), is_equal(x*x, x*x, 1)
0
1
>> is_equal(DM([1; 2]), DM([1; 2])), is_equal(DM([1; 2]), DM([1; 3]))
1
0
>> y = MX.sym('y');
>> is_equal(y * y, y * y), is_equal(y * y, y * y, 1)
0
1
julia> x = ca.SX.sym("x");
julia> ca.is_equal(x, x), ca.is_equal(x, ca.SX.sym("x"))
(true, false)
julia> ca.is_equal(x*x, x*x), ca.is_equal(x*x, x*x, 1)
(false, true)
julia> ca.is_equal(ca.DM([1, 2]), ca.DM([1, 2])), ca.is_equal(ca.DM([1, 2]), ca.DM([1, 3]))
(true, false)
julia> y = ca.MX.sym("y");
julia> ca.is_equal(y * y, y * y), ca.is_equal(y * y, y * y, 1)
(false, true)

See also: eq

Extra doc | Doc source | Implementation

is_linear(...)

Is expr linear in var?

is_linear(DM expr, DM var) -> bool
is_linear(SX expr, SX var) -> bool
is_linear(MX expr, MX var) -> bool

Defined as: no entry of expr depends on var with order 2 (see which_depends). Only the structure of the graph is inspected, not the values: false negatives are possible (an expression may not be recognised as linear while it really is, e.g. x*x/x). Operations whose derivative is structurally zero, such as floor, sign or comparisons, are treated as linear. A constant expression counts as linear.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> is_linear(2*x + y, vertcat(x, y)), is_linear(x*y, vertcat(x, y))
(True, False)
>>> is_linear(sin(y)*x, x), is_linear(x*x/x, x)
(True, False)
>> x = SX.sym('x'); y = SX.sym('y');
>> fprintf('%d %d\n', is_linear(2*x + y, vertcat(x, y)), is_linear(x*y, vertcat(x, y)))
1 0
>> fprintf('%d %d\n', is_linear(sin(y)*x, x), is_linear(x*x/x, x))
1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.is_linear(2 * x + y, [x; y]), ca.is_linear(x * y, [x; y])
(true, false)
julia> ca.is_linear(sin(y) * x, x), ca.is_linear(x * x / x, x)
(true, false)

See also: is_quadratic, linear_coeff, which_depends

Extra doc | Doc source | Implementation

is_quadratic(...)

Is expr quadratic in var?

is_quadratic(DM expr, DM var) -> bool
is_quadratic(SX expr, SX var) -> bool
is_quadratic(MX expr, MX var) -> bool

Defined as: gradient(expr, var) is linear in var; hence expr must be scalar. False negatives are possible (an expression may not be recognised as quadratic while it really is), see is_linear for the structural nature of the check. Linear and constant expressions count as quadratic.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> is_quadratic(x*y + x**2, vertcat(x, y)), is_quadratic(x**3, x)
(True, False)
>>> is_quadratic(x, x)
True
>> x = SX.sym('x'); y = SX.sym('y');
>> fprintf('%d %d\n', is_quadratic(x*y + x^2, vertcat(x, y)), is_quadratic(x^3, x))
1 0
>> is_quadratic(x, x)
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.is_quadratic(x * y + x^2, [x; y]), ca.is_quadratic(x^3, x)
(true, false)
julia> ca.is_quadratic(x, x)
true

See also: is_linear, quadratic_coeff

Extra doc | Doc source | Implementation

is_slice(...)

Check if an index vector can be represented more efficiently as a slice.

is_slice([int] v, bool ind1) -> bool

Doc source | Implementation

is_slice2(...)

Check if an index vector can be represented more efficiently as two nested

is_slice2([int] v) -> bool

slices.

Doc source | Implementation

jacobian(...)

Calculate Jacobian.

jacobian(DM ex, DM arg, dict opts) -> DM
jacobian(SX ex, SX arg, dict opts) -> SX
jacobian(MX ex, MX arg, dict opts) -> MX

The derivative of ex with respect to arg, with both treated as column-major vectors of their elements: the result is ex.numel()-by- arg.numel(), one row per element of ex and one column per element of arg. Entries that are structurally zero are left out of the sparsity pattern.

arg must be symbolic (for MX: symbolic primitives as created by MX.sym, or a concatenation of them; elements of a primitive are rejected). Not defined for DM.

Parameters:

opts -- Options: "allow_forward" and "allow_reverse" (bool, default true) restrict the AD mode; "symmetric" (bool, default false) hints that the Jacobian is symmetric; "verbose"

Returns:

Sparse matrix

>>> x = SX.sym("x"); y = SX.sym("y")
>>> J = jacobian(vertcat(x*y, x**2), vertcat(x, y))
>>> J
SX(
[[y, x],
 [(2.*x), 00]])
>>> J.dim(True)
'2x2,3nz'
>>> A = SX.sym("A", 2, 2)
>>> jacobian(2*A, A).dim()
'4x4'
>>> jacobian(SX(0, 1), vertcat(x, y)).dim()
'0x2'
>> x = SX.sym('x'); y = SX.sym('y');
>> J = jacobian(vertcat(x*y, x^2), vertcat(x, y));
>> J
[[y, x],
[(2.*x), 00]]
>> J.dim(true)
2x2,3nz
>> A = SX.sym('A', 2, 2);
>> J = jacobian(2*A, A); disp(J.dim())
4x4
>> J = jacobian(SX(0, 1), vertcat(x, y)); disp(J.dim())
0x2
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> J = ca.jacobian([x * y; x^2], [x; y])
SX(
[[y, x],
 [(2.*x), 00]])
julia> ca.dim(J, true)
"2x2,3nz"
julia> A = ca.SX.sym("A", 2, 2);
julia> ca.dim(ca.jacobian(2 * A, A))
"4x4"
julia> ca.dim(ca.jacobian(ca.SX(0, 1), [x; y]))
"0x2"

See also: gradient, hessian, jtimes, jacobian_sparsity, Function.jacobian

Extra doc | Doc source | Implementation

jacobian_sparsity(...)

Get the sparsity pattern of a jacobian.

jacobian_sparsity(DM f, DM x) -> Sparsity
jacobian_sparsity(SX f, SX x) -> Sparsity
jacobian_sparsity(MX f, MX x) -> Sparsity

Equivalent to, but cheaper to compute than, jacobian(f,x).sparsity()

>>> x = SX.sym("x"); y = SX.sym("y")
>>> jacobian_sparsity(vertcat(x*y, x**2, 3), vertcat(x, y))
Sparsity(3x2,3nz)
>> x = SX.sym('x'); y = SX.sym('y');
>> jacobian_sparsity(vertcat(x*y, x^2, 3), vertcat(x, y))
3x2,3nz
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.jacobian_sparsity([x * y; x^2; 3], [x; y])
Sparsity(3x2,3nz)

See also: jacobian, which_depends

Extra doc | Doc source | Implementation

jtimes(...)

Calculate the Jacobian and multiply by a vector from the right.

jtimes(DM ex, DM arg, DM v, bool tr, dict opts) -> DM
jtimes(SX ex, SX arg, SX v, bool tr, dict opts) -> SX
jtimes(MX ex, MX arg, MX v, bool tr, dict opts) -> MX

This is equivalent to mul(jacobian(ex, arg), v) or mul(jacobian(ex, arg).T, v) for tr set to false and true respectively. If contrast to these expressions, it will use directional derivatives which is typically (but not necessarily) more efficient if the complete Jacobian is not needed and v has few rows.

The matrix shapes of ex and arg are kept: v must have the shape of arg (or of ex when tr is true), and several directions can be passed at once by concatenating them horizontally, i.e. v.size2() a multiple of arg.size2(). The result is ex.size1()-by-ex.size2()*n_dir (arg.size1()-by-arg.size2()*n_dir when tr is true). An inconsistent shape of v raises an error.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> ex = vertcat(x*y, x**2); arg = vertcat(x, y)
>>> jtimes(ex, arg, DM([1, 0]))
SX([y, (2.*x)])
>>> jtimes(ex, arg, DM([1, 0]), True)
SX([y, x])
>>> jtimes(ex, arg, DM.eye(2))
SX(
[[y, x],
 [(2.*x), 0]])
>>> jtimes(ex, arg, SX.sym("v", 2))
SX([((y*v_0)+(x*v_1)), ((2.*x)*v_0)])
>> x = SX.sym('x'); y = SX.sym('y');
>> ex = vertcat(x*y, x^2); arg = vertcat(x, y);
>> jtimes(ex, arg, DM([1; 0]))
[y, (2.*x)]
>> jtimes(ex, arg, DM([1; 0]), true)
[y, x]
>> jtimes(ex, arg, DM.eye(2))
[[y, x],
[(2.*x), 0]]
>> jtimes(ex, arg, SX.sym('v', 2))
[((y*v_0)+(x*v_1)), ((2.*x)*v_0)]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ex = [x * y; x^2]; arg = [x; y];
julia> ca.jtimes(ex, arg, ca.DM([1, 0]))
SX([y, (2.*x)])
julia> ca.jtimes(ex, arg, ca.DM([1, 0]), true)
SX([y, x])
julia> ca.jtimes(ex, arg, ca.DM.eye(2))
SX(
[[y, x],
 [(2.*x), 0]])
julia> ca.jtimes(ex, arg, ca.SX.sym("v", 2))
SX([((y*v_0)+(x*v_1)), ((2.*x)*v_0)])

See also: jacobian, forward, reverse

Extra doc | Doc source | Implementation

kron(...)

Kronecker tensor product.

kron(Sparsity a, Sparsity b) -> Sparsity
kron(DM a, DM b) -> DM
kron(SX a, SX b) -> SX
kron(MX a, MX b) -> MX

Creates a block matrix in which block (i, j) is a_ij*b, for any shapes of a and b. The result is a.size1()*b.size1() by a.size2()*b.size2() with the Kronecker product of the sparsity patterns.

>>> kron(DM([[1, 2]]), DM([[1], [10]]))
DM(
[[1, 2],
 [10, 20]])
>>> kron(DM.eye(2), DM([[1, 2], [3, 4]]))
DM(
[[1, 2, 00, 00],
 [3, 4, 00, 00],
 [00, 00, 1, 2],
 [00, 00, 3, 4]])
>>> kron(MX.sym("a", 2, 2), MX.sym("b", 1, 2)).shape
(2, 4)
>> kron(DM([1 2]), DM([1; 10]))
[[1, 2],
[10, 20]]
>> kron(DM.eye(2), DM([1 2; 3 4]))
[[1, 2, 00, 00],
[3, 4, 00, 00],
[00, 00, 1, 2],
[00, 00, 3, 4]]
>> size(kron(MX.sym('a', 2, 2), MX.sym('b', 1, 2)))
2 4
julia> kron(ca.DM([1 2]), ca.DM([1; 10]))
DM(
[[1, 2],
 [10, 20]])
julia> kron(ca.DM.eye(2), ca.DM([1 2; 3 4]))
DM(
[[1, 2, 00, 00],
 [3, 4, 00, 00],
 [00, 00, 1, 2],
 [00, 00, 3, 4]])
julia> size(kron(ca.MX.sym("a", 2, 2), ca.MX.sym("b", 1, 2)))
(2, 4)

Extra doc | Doc source | Implementation

kron_contract(...)

Kronecker contraction, the adjoint of kron.

kron_contract(MX m, MX x, bool inner) -> MX

Contracts a matrix m whose dimensions are multiples of those of x (as produced by kron) against x. With mB-by-nB the shape of x and blocks M[i*mB+r, j*nB+s] of m:

  • inner true: Y[i, j] = sum over (r, s) of M[i*mB+r, j*nB+s] * X[r, s]

  • inner false: Y[r, s] = sum over (i, j) of X[i, j] * M[i*mB+r, j*nB+s]

Closes the AD algebra of kron under arbitrary-order differentiation. A shape that is not a multiple raises an error.

>>> M = MX.sym("M", 4, 4)
>>> X = MX.sym("X", 2, 2)
>>> f = Function("f", [M, X], [kron_contract(M, X, True), kron_contract(M, X, False)])
>>> f(DM(np.arange(16).reshape(4, 4)), DM.eye(2))
(DM(
[[5, 9],
 [21, 25]]), DM(
[[10, 12],
 [18, 20]]))
>> M = MX.sym('M', 4, 4); X = MX.sym('X', 2, 2);
>> f = Function('f', {M, X}, {kron_contract(M, X, true), kron_contract(M, X, false)});
>> [a, b] = f(DM(reshape(0:15, 4, 4)'), DM.eye(2));
>> a, b
[[5, 9],
[21, 25]]
[[10, 12],
[18, 20]]
julia> M = ca.MX.sym("M", 4, 4); X = ca.MX.sym("X", 2, 2);
julia> f = ca.Function("f", [M, X], [ca.kron_contract(M, X, true),
                                     ca.kron_contract(M, X, false)]);
julia> P, Q = f(reshape(0:15, 4, 4)', ca.DM.eye(2));
julia> P
DM(
[[5, 9],
 [21, 25]])
julia> Q
DM(
[[10, 12],
 [18, 20]])

See also: kron

Extra doc | Doc source | Implementation

ldivide(...)
ldivide(float x, float y) -> float
ldivide(DM x, DM y) -> DM
ldivide(SX x, SX y) -> SX
ldivide(MX x, MX y) -> MX
ldl(...)

Sparse LDL^T factorization of a symmetric matrix.

ldl(DM A, bool amd) -> (DM, DM, [int])
ldl(SX A, bool amd) -> (SX, SX, [int])

Computes A(p, p) = L*diag(D)*L^T with L unit lower triangular. Returns D as a vector, LT holding the strictly upper triangular entries of L^T (the unit diagonal is omitted), and the permutation p. Only the upper triangle of A is referenced. The sparsity pattern of A must be symmetric. Only guaranteed to work for positive definite matrices (no pivoting). Works symbolically on SX.

Parameters:
  • A -- Square matrix with symmetric sparsity pattern

  • amd -- Use an approximate minimum degree ordering to reduce fill-in

Returns:

D, LT, p (a tuple in Python)

>>> D, LT, p = ldl(DM([[4, 2], [2, 3]]))
>>> D, p
(DM([4, 2]), [0, 1])
>>> LT
DM(
[[00, 0.5],
 [00, 00]])
>>> L = DM.eye(2) + LT.T
>>> mtimes(mtimes(L, diag(D)), L.T)
DM(
[[4, 2],
 [2, 3]])
>> [D, LT, p] = ldl(DM([4 2; 2 3]));
>> D, p
[4, 2]
0 1
>> LT
[[00, 0.5],
[00, 00]]
>> L = DM.eye(2) + LT';
>> L*diag(D)*L'
[[4, 2],
[2, 3]]
julia> D, LT, p = ca.ldl(ca.DM([4 2; 2 3]));
julia> D
DM([4, 2])
julia> p
2-element Vector{Int64}:
 0
 1
julia> LT
DM(
[[00, 0.5],
 [00, 00]])
julia> L = ca.DM.eye(2) + LT';
julia> L * ca.diag(D) * L'
DM(
[[4, 2],
 [2, 3]])

See also: ldl_solve, chol, Sparsity.ldl

Extra doc | Doc source | Implementation

ldl_solve(...)

Solve A*x = b with the factors returned by ldl.

ldl_solve(DM b, DM D, DM LT, [int] p) -> DM
ldl_solve(SX b, SX D, SX LT, [int] p) -> SX
Parameters:
  • b -- Right-hand side, one column per system; a sparse b is densified

  • D -- Output of ldl(A)

  • LT -- Output of ldl(A)

  • p -- Output of ldl(A)

Returns:

Dense solution with the shape of b

>>> A = DM([[4, 2], [2, 3]])
>>> D, LT, p = ldl(A)
>>> ldl_solve(DM([1, 2]), D, LT, p)
DM([-0.125, 0.75])
>>> solve(A, DM([1, 2]))
DM([-0.125, 0.75])
>> A = DM([4 2; 2 3]);
>> [D, LT, p] = ldl(A);
>> ldl_solve(DM([1; 2]), D, LT, p)
[-0.125, 0.75]
>> solve(A, DM([1; 2]))
[-0.125, 0.75]
julia> A = ca.DM([4 2; 2 3]);
julia> D, LT, p = ca.ldl(A);
julia> ca.ldl_solve(ca.DM([1, 2]), D, LT, p)
DM([-0.125, 0.75])
julia> A \ [1, 2]
DM([-0.125, 0.75])

See also: ldl, solve

Extra doc | Doc source | Implementation

le(...)

Logical less or equal to: (x,y) -> x <= y.

le(float x, float y) -> float
le(DM x, DM y) -> DM
le(SX x, SX y) -> SX
le(MX x, MX y) -> MX

Elementwise comparison with 0/1 result, see lt. Chained inequalities such as lb <= (x <= ub) are recognised by Opti as bound constraints.

>>> le(DM([1, 2, 3]), 2)
DM([1, 1, 0])
>>> x = SX.sym("x")
>>> x <= x
SX(1)
>> le(DM([1; 2; 3]), 2)
[1, 1, 0]
>> x = SX.sym('x');
>> x <= x
1
julia> ca.le(ca.DM([1, 2, 3]), 2)
DM([1, 1, 0])
julia> x = ca.SX.sym("x");
julia> x <= x
SX(1)

See also: lt

Extra doc | Doc source | Implementation

linear_coeff(...)

Recognizes linear form in vector expression.

linear_coeff(DM ex, DM arg, bool check) -> (DM, DM)
linear_coeff(SX ex, SX arg, bool check) -> (SX, SX)
linear_coeff(MX ex, MX arg, bool check) -> (MX, MX)

A x + b

Returns A = jacobian(expr, var) at var = 0 and b = vec(expr) at var = 0. expr must be a vector (a matrix raises an error).

Parameters:

check[in] -- When true (default), expr is checked to be linear in var (is_linear) and an error is raised otherwise. Provided to deal with false positive dependency checks.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> A, b = linear_coeff(vertcat(2*x + y + 1, 3*y), vertcat(x, y))
>>> A
SX(
[[2, 1],
 [00, 3]])
>>> b
SX([1, 0])
>> x = SX.sym('x'); y = SX.sym('y');
>> [A, b] = linear_coeff(vertcat(2*x + y + 1, 3*y), vertcat(x, y));
>> A
[[2, 1],
 [00, 3]]
>> b
[1, 0]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> A, b = ca.linear_coeff([2 * x + y + 1; 3 * y], [x; y]);
julia> A
SX(
[[2, 1],
 [00, 3]])
julia> b
SX([1, 0])

See also: quadratic_coeff, is_linear, jacobian

Extra doc | Doc source | Implementation

linearize(...)

Linearize an expression.

linearize(DM f, DM x, DM x0) -> DM
linearize(SX f, SX x, SX x0) -> SX
linearize(MX f, MX x, MX x0) -> MX

[DEPRECATED] confusing behaviour

This function linearizes an expression around a point x0, using x as delta around that point:

linearize(sin(x),x,x0) -> sin(x0)+cos(x0)*x

x0 must have the shape of x or be a scalar (broadcast). For a variant that returns sin(x0)+cos(x0)*(x-x0), see taylor.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> linearize(sin(x), x, y)
SX((sin(y)+(cos(y)*x)))
>> x = SX.sym('x'); y = SX.sym('y');
>> linearize(sin(x), x, y)
(sin(y)+(cos(y)*x))
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.linearize(sin(x), x, y)
SX((sin(y)+(cos(y)*x)))

See also: taylor, linear_coeff

Extra doc | Doc source | Implementation

linspace(...)

Matlab's linspace command.

linspace(DM a, DM b, int nsteps) -> DM
linspace(SX a, SX b, int nsteps) -> SX
linspace(MX a, MX b, int nsteps) -> MX

Returns the column vector [a, a + (b-a)/(nsteps-1), ..., b] with nsteps entries, the endpoints included. For nsteps == 1 the result is b. When a and b are matrices, the nsteps intermediate matrices are stacked vertically (vertcat). nsteps must be at least 1.

>>> linspace(0, 1, 5)
DM([0, 0.25, 0.5, 0.75, 1])
>>> linspace(SX.sym("a"), SX.sym("b"), 3)
SX([a, (a+((b-a)/2)), b])
>>> linspace(DM([0, 0]), DM([1, 2]), 3)
DM([0, 0, 0.5, 1, 1, 2])
>> linspace(DM(0), DM(1), 5)
[0, 0.25, 0.5, 0.75, 1]
>> linspace(SX.sym('a'), SX.sym('b'), 3)
[a, (a+((b-a)/2)), b]
>> linspace(DM([0; 0]), DM([1; 2]), 3)
[0, 0, 0.5, 1, 1, 2]
julia> ca.linspace(0, 1, 5)
DM([0, 0.25, 0.5, 0.75, 1])
julia> ca.linspace(ca.SX.sym("a"), ca.SX.sym("b"), 3)
SX([a, (a+((b-a)/2)), b])
julia> ca.linspace(ca.DM([0, 0]), ca.DM([1, 2]), 3)
DM([0, 0, 0.5, 1, 1, 2])

Extra doc | Doc source | Implementation

load_archiver(...)

Explicitly load a plugin dynamically.

load_archiver(str name)

Doc source | Implementation

load_blas(...)
load_blas(str name)
load_conic(...)

Explicitly load a QP solver plugin.

load_conic(str name)

Normally plugins are loaded on first use; this raises an error when the plugin cannot be found.

>>> try:
...     load_conic("no_such_plugin")
... except RuntimeError as e:
...     print("no_such_plugin" in str(e))
True
>> try, load_conic('no_such_plugin'); catch e, msg = e.message; end
>> contains(msg, 'no_such_plugin')
1
julia> try
           ca.load_conic("no_such_plugin")
       catch e
           println(occursin("no_such_plugin", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

load_dple(...)

Explicitly load a plugin dynamically.

load_dple(str name)

Doc source | Implementation

load_expm(...)

Explicitly load a plugin dynamically.

load_expm(str name)

Doc source | Implementation

load_filesystem(...)

Explicitly load a plugin dynamically.

load_filesystem(str name)

Doc source | Implementation

load_graphmodel(...)

Explicitly load a graph-model format plugin.

load_graphmodel(str name)

Doc source | Implementation

load_integrator(...)

Explicitly load an integrator plugin.

load_integrator(str name)

Normally plugins are loaded on first use; this raises an error when the plugin cannot be found.

>>> try:
...     load_integrator("no_such_plugin")
... except RuntimeError as e:
...     print("no_such_plugin" in str(e))
True
>> try, load_integrator('no_such_plugin'); catch e, msg = e.message; end
>> contains(msg, 'no_such_plugin')
1
julia> try
           ca.load_integrator("no_such_plugin")
       catch e
           println(occursin("no_such_plugin", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

load_interpolant(...)

Explicitly load a plugin dynamically.

load_interpolant(str name)

Doc source | Implementation

load_linsol(...)

Explicitly load a linear solver plugin.

load_linsol(str name)

Normally plugins are loaded on first use; this raises an error when the plugin cannot be found.

>>> try:
...     load_linsol("no_such_plugin")
... except RuntimeError as e:
...     print("no_such_plugin" in str(e))
True
>> try, load_linsol('no_such_plugin'); catch e, msg = e.message; end
>> contains(msg, 'no_such_plugin')
1
julia> try
           ca.load_linsol("no_such_plugin")
       catch e
           println(occursin("no_such_plugin", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

load_modelicaparser(...)

Explicitly load a plugin dynamically.

load_modelicaparser(str name)

Doc source | Implementation

load_nlpsol(...)

Explicitly load an NLP solver plugin.

load_nlpsol(str name)

Normally plugins are loaded on first use; this raises an error when the plugin cannot be found.

>>> try:
...     load_nlpsol("no_such_plugin")
... except RuntimeError as e:
...     print("no_such_plugin" in str(e))
True
>> try, load_nlpsol('no_such_plugin'); catch e, msg = e.message; end
>> contains(msg, 'no_such_plugin')
1
julia> try
           ca.load_nlpsol("no_such_plugin")
       catch e
           println(occursin("no_such_plugin", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

load_onnxbackend(...)

Load an ONNX runtime backend.

load_onnxbackend(str solver)

Extra doc | Doc source | Implementation

load_rootfinder(...)

Explicitly load a rootfinder plugin.

load_rootfinder(str name)

Normally plugins are loaded on first use; this raises an error when the plugin cannot be found.

>>> try:
...     load_rootfinder("no_such_plugin")
... except RuntimeError as e:
...     print("no_such_plugin" in str(e))
True
>> try, load_rootfinder('no_such_plugin'); catch e, msg = e.message; end
>> contains(msg, 'no_such_plugin')
1
julia> try
           ca.load_rootfinder("no_such_plugin")
       catch e
           println(occursin("no_such_plugin", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

log(...)

Natural logarithm: x -> log(x)

log(float x) -> float
log(DM x) -> DM
log(SX x) -> SX
log(MX x) -> MX

Elementwise; the result is dense with -inf at structural zeros. Negative arguments give NaN; no error is raised.

>>> log(DM([1, 0]))
DM([0, -inf])
>>> log(SX.sym("x"))
SX(log(x))
>> log(DM([1; 0]))
[0, -inf]
>> log(SX.sym('x'))
log(x)
julia> log.(ca.DM([1, 0]))
DM([0, -inf])
julia> log(ca.SX.sym("x"))
SX(log(x))

See also: exp, log10, log1p

Extra doc | Doc source | Implementation

log10(...)

Base-10 logarithm: x -> log10(x)

log10(float x) -> float
log10(DM x) -> DM
log10(SX x) -> SX
log10(MX x) -> MX

Computed as log(x) * (1 / log(10)); there is no dedicated operation, which is visible in symbolic expressions. Dense result like log.

>>> log10(DM([1, 10, 1000]))
DM([0, 1, 3])
>>> log10(SX.sym("x"))
SX((0.434294*log(x)))
>> log10(DM([1; 10; 1000]))
[0, 1, 3]
>> log10(SX.sym('x'))
(0.434294*log(x))
julia> log10.(ca.DM([1, 10, 1000]))
DM([0, 1, 3])
julia> log10(ca.SX.sym("x"))
SX((0.434294*log(x)))

See also: log

Extra doc | Doc source | Implementation

log1p(...)

Precision variant for natural logarithm: x -> log(x+1)

log1p(float x) -> float
log1p(DM x) -> DM
log1p(SX x) -> SX
log1p(MX x) -> MX

Elementwise; accurate for small x where log(1 + x) would lose digits. Sparsity preserved (log1p(0) == 0).

>>> log1p(DM([0, 1e-10]))
DM([0, 1e-10])
>>> log1p(SX.sym("x"))
SX(log1p(x))
>> log1p(DM([0; 1e-10]))
[0, 1e-10]
>> log1p(SX.sym('x'))
log1p(x)
julia> log1p.(ca.DM([0, 1e-10]))
DM([0, 1e-10])
julia> log1p(ca.SX.sym("x"))
SX(log1p(x))

See also: log, expm1

Extra doc | Doc source | Implementation

logic_all(...)

True if every entry equals one.

logic_all(DM x) -> DM
logic_all(SX x) -> SX

Returns a 1-by-1 matrix. A matrix with structural zeros gives false. Not available in Python (shadowed by the builtin); use logic_all.

See also: any, logic_all

Extra doc | Doc source | Implementation

logic_and(...)

Logical and

logic_and(float x, float y) -> float
logic_and(DM x, DM y) -> DM
logic_and(SX x, SX y) -> SX
logic_and(MX x, MX y) -> MX

Returns (an expression evaluating to) 1 where both entries are nonzero and 0 otherwise, elementwise

Any nonzero value, including NaN, counts as true. Shape rules as for plus; the result is structurally zero wherever either operand is. The Python keyword and does not work on matrices (it needs a single truth value); use this function.

>>> logic_and(DM([1, 2, 0]), DM([3, 0, 0]))
DM([1, 0, 0])
>>> logic_and(SX.sym("x"), SX.sym("y"))
SX((x&&y))
>>> logic_and(DM.eye(2), DM.ones(2, 2))
DM(
[[1, 00],
 [00, 1]])
>> DM([1; 2; 0]) & DM([3; 0; 0])
[1, 0, 0]
>> SX.sym('x') & SX.sym('y')
(x&&y)
>> and(DM.eye(2), DM.ones(2, 2))
[[1, 00],
[00, 1]]
julia> ca.logic_and(ca.DM([1, 2, 0]), ca.DM([3, 0, 0]))
DM([1, 0, 0])
julia> ca.logic_and(ca.SX.sym("x"), ca.SX.sym("y"))
SX((x&&y))
julia> ca.logic_and(ca.DM.eye(2), ca.DM.ones(2, 2))
DM(
[[1, 00],
 [00, 1]])

See also: logic_or, logic_not

Extra doc | Doc source | Implementation

logic_any(...)

True if any entry equals one.

logic_any(DM x) -> DM
logic_any(SX x) -> SX

Returns a 1-by-1 matrix. A matrix with structural zeros gives false. Not available in Python (shadowed by the builtin); use logic_any or sum1/sum2.

See also: all, logic_any

Extra doc | Doc source | Implementation

logic_not(...)

Logical not x -> !x.

logic_not(float x) -> float
logic_not(DM x) -> DM
logic_not(SX x) -> SX
logic_not(MX x) -> MX

Returns (an expression evaluating to) 1 where the entry is zero and 0 otherwise, elementwise

Structural zeros map to 1, so a sparse input gives a dense result. The Python keyword not does not work on matrices; use this function.

>>> logic_not(DM([1, 0, -1]))
DM([0, 1, 0])
>>> logic_not(DM.eye(2))
DM(
[[0, 1],
 [1, 0]])
>>> logic_not(SX.sym("x"))
SX((!x))
>> ~DM([1; 0; -1])
[0, 1, 0]
>> not(DM.eye(2))
[[0, 1],
[1, 0]]
>> ~SX.sym('x')
(!x)
julia> ca.logic_not(ca.DM([1, 0, -1]))
DM([0, 1, 0])
julia> ca.logic_not(ca.DM.eye(2))
DM(
[[0, 1],
 [1, 0]])
julia> ca.logic_not(ca.SX.sym("x"))
SX((!x))

See also: logic_and, logic_or

Extra doc | Doc source | Implementation

logic_or(...)

Logical or

logic_or(float x, float y) -> float
logic_or(DM x, DM y) -> DM
logic_or(SX x, SX y) -> SX
logic_or(MX x, MX y) -> MX

returns (an expression evaluating to) 1 where at least one entry is nonzero and 0 otherwise, elementwise

Shape rules as for plus; the result is structurally zero where both operands are.

>>> logic_or(DM([1, 0, 0]), DM([0, 0, 2]))
DM([1, 0, 1])
>>> logic_or(MX.sym("x"), MX.sym("y"))
MX((x||y))
>> DM([1; 0; 0]) | DM([0; 0; 2])
[1, 0, 1]
>> or(MX.sym('x'), MX.sym('y'))
(x||y)
julia> ca.logic_or(ca.DM([1, 0, 0]), ca.DM([0, 0, 2]))
DM([1, 0, 1])
julia> ca.logic_or(ca.MX.sym("x"), ca.MX.sym("y"))
MX((x||y))

See also: logic_and, logic_not

Extra doc | Doc source | Implementation

logsumexp(...)

x -> log(sum_i exp(x_i))

logsumexp(DM a) -> DM
logsumexp(SX a) -> SX
logsumexp(MX a) -> MX
logsumexp(DM a, DM margin) -> DM
logsumexp(SX a, SX margin) -> SX
logsumexp(MX a, MX margin) -> MX

Can be used to achieve a smooth max.

The argument must be a dense column vector; a scalar is returned unchanged. Implementations for DM/SX/MX are hardened against overflow by shifting with the largest entry. Implementations for DM/MX are more accurate with log1p (*).

(*) https://nhigham.com/2021/01/05/what-is-the-log-sum-exp-function/

>>> logsumexp(DM([1, 2, 3]))
DM(3.40761)
>>> logsumexp(DM([1000, 1000]))
DM(1000.69)
>>> logsumexp(MX.sym("x", 3))
MX(logsumexp(x))
>>> try: logsumexp(DM([1, 2, 3]).T)
... except Exception as e: print("error")
error
>> logsumexp(DM([1; 2; 3]))
3.40761
>> logsumexp(DM([1000; 1000]))
1000.69
>> logsumexp(MX.sym('x', 3))
logsumexp(x)
>> try, logsumexp(DM([1; 2; 3])'); catch e, disp('error'); end
error
julia> ca.logsumexp(ca.DM([1, 2, 3]))
DM(3.40761)
julia> ca.logsumexp(ca.DM([1000, 1000]))
DM(1000.69)
julia> ca.logsumexp(ca.MX.sym("x", 3))
MX(logsumexp(x))
julia> try ca.logsumexp(ca.DM([1, 2, 3])') catch e; println("error") end
error

See also: mmax

Extra doc | Doc source | Implementation

lookupvector(...)
lookupvector([int] v) -> [int]
lookupvector([int] v, int size) -> [int]

Returns a vector for quickly looking up entries of supplied list.

lookupvector[i]!=-1 <=> v contains i v[lookupvector[i]] == i <=> v contains i

Duplicates are treated by looking up last occurrence

Extra doc | Doc source | Implementation

low(...)

Find the interval of a sorted grid that contains each query value.

low(MX v, MX p, dict options) -> MX

For each entry p_i of p, returns the index k such that v[k] <= p_i < v[k+1] for the ascending grid v, clipped to [0, len(v)-2] so that values outside the grid map to the first or last interval. This is the lookup step of linear interpolation. The result has the shape of p and is piecewise constant, so its derivative is zero.

Parameters:
  • v -- Dense ascending grid, vector

  • p -- Query values, dense vector

  • options -- "lookup_mode": "linear" (scan), "binary" (bisection), "exact" (assumes an equidistant grid and computes the index arithmetically) or "auto" (default: "binary" for grids longer than 100 entries, else "linear"). Any other key or mode raises an error.

>>> g = MX.sym("g", 4)
>>> p = MX.sym("p", 5)
>>> f = Function("f", [g, p], [low(g, p)])
>>> f(DM([0, 1, 2, 3]), DM([-1, 0, 1.5, 3, 4]))
DM([0, 0, 1, 2, 2])
>>> jacobian(low(g, p), p).nnz()
0
>>> try:
...   low(g, p, {"lookup_mode": "foo"})
... except Exception as e:
...   print("Invalid lookup mode" in str(e))
True
>> g = MX.sym('g', 4); p = MX.sym('p', 5);
>> f = Function('f', {g, p}, {low(g, p)});
>> f(DM([0; 1; 2; 3]), DM([-1; 0; 1.5; 3; 4]))
[0, 0, 1, 2, 2]
>> J = jacobian(low(g, p), p);
>> J.nnz()
0
>> try, low(g, p, struct('lookup_mode', 'foo')); catch e, disp('invalid lookup mode'); end
invalid lookup mode
julia> g = ca.MX.sym("g", 4); p = ca.MX.sym("p", 5);
julia> f = ca.Function("f", [g, p], [ca.low(g, p)]);
julia> f([0, 1, 2, 3], [-1, 0, 1.5, 3, 4])
DM([0, 0, 1, 2, 2])
julia> ca.nnz(ca.jacobian(ca.low(g, p), p))
0
julia> try
           ca.low(g, p, Dict("lookup_mode" => "foo"))
       catch e
           println(occursin("Invalid lookup mode", sprint(showerror, e)))
       end
true

See also: find, interpn_linear, interpolant

Extra doc | Doc source | Implementation

lt(...)

Logical less than: (x,y) -> x < y.

lt(float x, float y) -> float
lt(DM x, DM y) -> DM
lt(SX x, SX y) -> SX
lt(MX x, MX y) -> MX

Elementwise comparison; shape rules as for plus. Every comparison in this group returns a matrix of the same type as the operands with entries 1 (true) and 0 (false): for DM a numeric 0/1 matrix, not a boolean, and for SX and MX a symbolic expression that is only decided at evaluation time. Comparisons with NaN are false. The result is sparse where both operands are structurally zero (0 < 0 is false).

>>> lt(DM([1, 2, 3]), 2)
DM([1, 0, 0])
>>> DM([1, 2, 3]) < DM([3, 2, 1])
DM([1, 0, 0])
>>> SX.sym("x", 2) < SX.sym("y", 2)
SX([(x_0<y_0), (x_1<y_1)])
>>> DM.eye(2) < 1
DM(
[[0, 1],
 [1, 0]])
>> lt(DM([1; 2; 3]), 2)
[1, 0, 0]
>> DM([1; 2; 3]) < DM([3; 2; 1])
[1, 0, 0]
>> SX.sym('x', 2) < SX.sym('y', 2)
[(x_0<y_0), (x_1<y_1)]
>> DM.eye(2) < 1
[[0, 1],
[1, 0]]
julia> ca.lt(ca.DM([1, 2, 3]), 2)
DM([1, 0, 0])
julia> ca.DM([1, 2, 3]) < ca.DM([3, 2, 1])
DM([1, 0, 0])
julia> ca.SX.sym("x", 2) < ca.SX.sym("y", 2)
SX([(x_0<y_0), (x_1<y_1)])
julia> ca.DM.eye(2) < 1
DM(
[[0, 1],
 [1, 0]])

See also: le, gt, ge, eq, ne, if_else

Extra doc | Doc source | Implementation

mac(...)

Multiply-accumulate operation.

mac(Sparsity X, Sparsity Y, Sparsity Z, str blas) -> Sparsity
mac(DM X, DM Y, DM Z, str blas) -> DM
mac(SX X, SX Y, SX Z, str blas) -> SX
mac(MX X, MX Y, MX Z, str blas) -> MX

Matrix product of two matrices (x and y), adding the result to a third matrix z. The result has the same sparsity pattern as z, meaning that other entries of the product are ignored. The operation is equivalent to z + project(mtimes(x, y), z.sparsity()). The dimensions of z must match the product, otherwise an error is raised. When x or y is a scalar the result is z + x*y. See mtimes for the meaning of the blas argument.

mtimes is implemented as mac with a structurally zero z of the product pattern.

Parameters:
  • x -- Left factor

  • y -- Right factor

  • z -- Matrix to add to; its sparsity pattern selects the computed entries

Returns:

Matrix with the sparsity pattern of z

>>> A = DM([[1, 2], [3, 4]])
>>> mac(A, A, DM.eye(2))
DM(
[[8, 00],
 [00, 23]])
>>> mac(A, A, DM.ones(2, 2))
DM(
[[8, 11],
 [16, 23]])
>>> mac(MX.sym("x", 2, 3), MX.sym("y", 3, 2), MX.sym("z", Sparsity.diag(2)))
MX(mac(x,y,z))
>> A = DM([1 2; 3 4]);
>> mac(A, A, DM.eye(2))
[[8, 00],
[00, 23]]
>> mac(A, A, DM.ones(2, 2))
[[8, 11],
[16, 23]]
>> mac(MX.sym('x', 2, 3), MX.sym('y', 3, 2), MX.sym('z', Sparsity.diag(2)))
mac(x,y,z)
julia> A = ca.DM([1 2; 3 4]);
julia> ca.mac(A, A, ca.DM.eye(2))
DM(
[[8, 00],
 [00, 23]])
julia> ca.mac(A, A, ca.DM.ones(2, 2))
DM(
[[8, 11],
 [16, 23]])
julia> x, y = ca.MX.sym("x", 2, 3), ca.MX.sym("y", 3, 2);
julia> ca.mac(x, y, ca.MX.sym("z", ca.Sparsity.diag(2)))
MX(mac(x,y,z))

See also: mtimes

Extra doc | Doc source | Implementation

matrix_expand(...)

Expand an MX expression into a call to an SX Function.

matrix_expand(MX e, [MX] boundary, dict options) -> MX
matrix_expand([MX] e, [MX] boundary, dict options) -> [MX]

Converts the whole matrix graph of e to scalar SX operations (including inlined Function calls, as Function.expand does) and returns a call to the resulting SXFunction, with the free symbols of e as arguments. Expressions listed in boundary are not expanded: they stay as MX inputs of the call.

Parameters:
  • e -- Expression to expand

  • boundary -- Sub-expressions at which the expansion stops

  • options -- Options for the SXFunction, forwarded to Function.expand

Returns:

An OutputNode of the SXFunction call

>>> x = MX.sym("x")
>>> g = Function("g", [x], [x**2 + 1])
>>> sx = sin(x)
>>> e = g(x) + sx
>>> r = matrix_expand(e)
>>> r, r.is_output(), r.dep(0).which_function()
(MX(expand_tmp_matrix_expand(x){0}), True, Function(expand_tmp_matrix_expand:(i0)->(o0)
SXFunction))
>>> Function("f", [x], [r])(2)
DM(5.9093)
>>> matrix_expand(e, [sx]).dep(0).which_function()
Function(expand_tmp_matrix_expand:(i0,i1)->(o0) SXFunction)
>> x = MX.sym('x');
>> g = Function('g', {x}, {x^2 + 1});
>> sx = sin(x);
>> e = g(x) + sx;
>> r = matrix_expand(e);
>> r, r.is_output(), r.dep(0).which_function()
expand_tmp_matrix_expand(x){0}
1
expand_tmp_matrix_expand:(i0)->(o0) SXFunction
>> f = Function('f', {x}, {r});
>> f(2)
5.9093
>> r = matrix_expand(e, {sx});
>> r.dep(0).which_function()
expand_tmp_matrix_expand:(i0,i1)->(o0) SXFunction
julia> x = ca.MX.sym("x");
julia> g = ca.Function("g", [x], [x^2 + 1]);
julia> sx = sin(x);
julia> e = g(x) + sx;
julia> r = ca.matrix_expand(e);
julia> r, ca.is_output(r)
(expand_tmp_matrix_expand(x){0}, true)
julia> ca.which_function(ca.dep(r, 0))
Function(expand_tmp_matrix_expand:(i0)->(o0) SXFunction)
julia> ca.Function("f", [x], [r])(2)
DM(5.9093)
julia> ca.which_function(ca.dep(ca.matrix_expand(e, [sx]), 0))
Function(expand_tmp_matrix_expand:(i0,i1)->(o0) SXFunction)

See also: Function.expand

Extra doc | Doc source | Implementation

minor(...)

Minor of a square matrix: determinant with one column and one row removed.

minor(DM x, int i, int j) -> DM
minor(SX x, int i, int j) -> SX

Note the argument order: i is the column that is removed, j the row. The input must be square; a 1-by-1 input gives 1.

Parameters:
  • x -- Square matrix

  • i -- Column index to remove (zero-based)

  • j -- Row index to remove (zero-based)

>>> A = DM([[1, 2, 3], [0, 1, 4], [5, 6, 0]])
>>> minor(A, 0, 1)
DM(-18)
>>> X = SX.sym("X", 2, 2)
>>> minor(X, 0, 1)
SX(X_2)
>> A = DM([1 2 3; 0 1 4; 5 6 0]);
>> minor(A, 0, 1)
-18
>> X = SX.sym('X', 2, 2);
>> minor(X, 0, 1)
X_2
julia> A = ca.DM([1 2 3; 0 1 4; 5 6 0]);
julia> ca.minor(A, 0, 1)
DM(-18)
julia> X = ca.SX.sym("X", 2, 2);
julia> ca.minor(X, 0, 1)
SX(X_2)

See also: cofactor, adj, det

Extra doc | Doc source | Implementation

minus(...)

Subtraction: (x,y) -> x - y.

minus(float x, float y) -> float
minus(DM x, DM y) -> DM
minus(SX x, SX y) -> SX
minus(MX x, MX y) -> MX

Elementwise difference; shape and sparsity rules as for plus. For symbolic arguments, x - x with the same node simplifies to 0.

>>> minus(DM([5, 6]), DM([1, 2]))
DM([4, 4])
>>> DM.eye(2) - 1
DM(
[[0, -1],
 [-1, 0]])
>>> x = SX.sym("x")
>>> x - x
SX(0)
>> minus(DM([5; 6]), DM([1; 2]))
[4, 4]
>> DM.eye(2) - 1
[[0, -1],
[-1, 0]]
>> x = SX.sym('x');
>> x - x
0
julia> ca.minus(ca.DM([5, 6]), ca.DM([1, 2]))
DM([4, 4])
julia> ca.DM.eye(2) - 1
DM(
[[0, -1],
 [-1, 0]])
julia> x = ca.SX.sym("x");
julia> x - x
SX(0)

Extra doc | Doc source | Implementation

mldivide(...)

Matrix left divide, Ab (cf. backslash '' in MATLAB)

mldivide(DM x, DM y) -> DM
mldivide(SX x, SX y) -> SX
mldivide(MX x, MX y) -> MX

Computes inv(A)*b as solve(A, b). If either argument is scalar, the elementwise division b/A is returned instead.

>>> A = DM([[1, 2], [3, 4]])
>>> mldivide(A, DM([1, 2]))
DM([0, 0.5])
>> A = DM([1 2; 3 4]);
>> A\DM([1; 2])
[0, 0.5]
julia> A = ca.DM([1 2; 3 4]);
julia> A \ ca.DM([1, 2])
DM([0, 0.5])

See also: mrdivide, solve, inv

Extra doc | Doc source | Implementation

mmax(...)

Largest element in a matrix.

mmax(DM x) -> DM
mmax(SX x) -> SX
mmax(MX x) -> MX

Over all entries, structural zeros included. See mmin.

>>> mmax(DM(Sparsity.diag(2), [-3, -4]))
DM(0)
>>> mmax(MX.sym("x", 3))
MX(max(x))
>> mmax(DM(Sparsity.diag(2), [-3; -4]))
0
>> mmax(MX.sym('x', 3))
max(x)
julia> ca.mmax(ca.DM(ca.Sparsity.diag(2), [-3, -4]))
DM(0)
julia> ca.mmax(ca.MX.sym("x", 3))
MX(max(x))

See also: mmin, fmax, logsumexp

Extra doc | Doc source | Implementation

mmin(...)

Smallest element in a matrix.

mmin(DM x) -> DM
mmin(SX x) -> SX
mmin(MX x) -> MX

Over all entries, structural zeros included (so a sparse matrix with only positive nonzeros has minimum 0). An empty matrix gives an empty 0-by-0 result. For SX a chain of fmin operations is built; for MX a single node.

>>> mmin(DM([[3, -1], [2, 5]])), mmax(DM([[3, -1], [2, 5]]))
(DM(-1), DM(5))
>>> mmin(DM(Sparsity.diag(2), [3, 4]))
DM(0)
>>> mmin(SX.sym("x", 3))
SX(fmin(fmin(x_0,x_1),x_2))
>> mmin(DM([3 -1; 2 5])), mmax(DM([3 -1; 2 5]))
-1
5
>> mmin(DM(Sparsity.diag(2), [3; 4]))
0
>> mmin(SX.sym('x', 3))
fmin(fmin(x_0,x_1),x_2)
julia> ca.mmin(ca.DM([3 -1; 2 5])), ca.mmax(ca.DM([3 -1; 2 5]))
(-1, 5)
julia> minimum(ca.DM([3 -1; 2 5])), maximum(ca.DM([3 -1; 2 5]))
(-1, 5)
julia> ca.mmin(ca.DM(ca.Sparsity.diag(2), [3, 4]))
DM(0)
julia> ca.mmin(ca.SX.sym("x", 3))
SX(fmin(fmin(x_0,x_1),x_2))

See also: mmax, fmin, norm_inf

Extra doc | Doc source | Implementation

mpower(...)

Matrix power x^n.

mpower(DM x, DM n) -> DM
mpower(SX x, SX n) -> SX
mpower(MX x, MX n) -> MX

For a square matrix x and a constant integer scalar n, computes the repeated matrix product by squaring. n == 0 gives the (sparse) identity, negative n gives the inverse of the positive power (via inv). If both arguments are scalar, this is the elementwise pow. A non-integer or symbolic n for a matrix raises an error.

>>> A = DM([[1, 2], [3, 4]])
>>> mpower(A, 2)
DM(
[[7, 10],
 [15, 22]])
>>> mpower(A, 0)
DM(
[[1, 00],
 [00, 1]])
>>> mpower(A, -1)
DM(
[[-2, 1],
 [1.5, -0.5]])
>>> mpower(DM(2), 0.5)
DM(1.41421)
>>> try: mpower(A, 0.5)
... except Exception as e: print("error")
error
>> A = DM([1 2; 3 4]);
>> A^2
[[7, 10],
[15, 22]]
>> A^0
[[1, 00],
[00, 1]]
>> mpower(A, -1)
[[-2, 1],
[1.5, -0.5]]
>> DM(2)^0.5
1.41421
>> try, A^0.5; catch e, disp('error'); end
error
julia> A = ca.DM([1 2; 3 4]);
julia> A^2
DM(
[[7, 10],
 [15, 22]])
julia> A^0
DM(
[[1, 00],
 [00, 1]])
julia> A^-1
DM(
[[-2, 1],
 [1.5, -0.5]])
julia> ca.DM(2)^0.5
DM(1.41421)
julia> try A^0.5 catch e; println("error") end
error

See also: mtimes, inv, expm

Extra doc | Doc source | Implementation

mrdivide(...)

Matrix right divide, x/A (cf. slash '/' in MATLAB)

mrdivide(DM x, DM y) -> DM
mrdivide(SX x, SX y) -> SX
mrdivide(MX x, MX y) -> MX

Computes x*inv(A) as solve(A', x')'. If either argument is scalar, the elementwise division x/A is returned instead.

>>> A = DM([[1, 2], [3, 4]])
>>> mrdivide(DM([[1, 2]]), A)
DM([[1, 0]])
>> A = DM([1 2; 3 4]);
>> DM([1 2])/A
[[1, 0]]
julia> A = ca.DM([1 2; 3 4]);
julia> ca.DM([1 2]) / A
DM([[1, 0]])

See also: mldivide, solve, inv

Extra doc | Doc source | Implementation

mtaylor(...)

Multivariate Taylor series expansion.

mtaylor(DM ex, DM x, DM a, int order) -> DM
mtaylor(SX ex, SX x, SX a, int order) -> SX
mtaylor(DM ex, DM x, DM a, int order, [int] order_contributions) -> DM
mtaylor(SX ex, SX x, SX a, int order, [int] order_contributions) -> SX

Expands ex around the point a with respect to the symbols in x, keeping all terms whose total degree is at most order. The total degree of x^n*y^m is n+m. ex and x must be dense; a must have the same number of entries as x. Only defined for SX.

Parameters:
  • ex -- Dense SX expression to expand

  • x -- Vector of SX symbols

  • a -- Expansion point, a vector of the same length as x

  • order -- Maximum total degree, default 1 (linearization)

>>> x = SX.sym("x"); y = SX.sym("y"); a = SX.sym("a"); b = SX.sym("b")
>>> mtaylor(sin(x + y), vertcat(x, y), vertcat(a, b), 1)
SX(((sin((a+b))+(cos((a+b))*(x-a)))+(cos((a+b))*(y-b))))
>>> mtaylor(exp(x * y), vertcat(x, y), DM([0, 0]), 2)
SX(@1=2, ((1+((x*y)/@1))+((y*x)/@1)))
>> x = SX.sym('x'); y = SX.sym('y'); a = SX.sym('a'); b = SX.sym('b');
>> mtaylor(sin(x + y), [x; y], [a; b], 1)
((sin((a+b))+(cos((a+b))*(x-a)))+(cos((a+b))*(y-b)))
>> mtaylor(exp(x * y), [x; y], DM([0; 0]), 2)
@1=2, ((1+((x*y)/@1))+((y*x)/@1))
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); a = ca.SX.sym("a"); b = ca.SX.sym("b");
julia> ca.mtaylor(sin(x + y), [x; y], [a; b], 1)
SX(((sin((a+b))+(cos((a+b))*(x-a)))+(cos((a+b))*(y-b))))
julia> ca.mtaylor(exp(x * y), [x; y], ca.DM([0, 0]), 2)
SX(@1=2, ((1+((x*y)/@1))+((y*x)/@1)))

See also: taylor

Extra doc | Doc source | Implementation

mtimes(...)

Matrix product of two matrices.

mtimes([Sparsity] args) -> Sparsity
mtimes([DM] args) -> DM
mtimes([SX] args) -> SX
mtimes([MX] args) -> MX
mtimes(Sparsity x, Sparsity y, str blas) -> Sparsity
mtimes([Sparsity] args, str blas) -> Sparsity
mtimes(DM x, DM y, str blas) -> DM
mtimes([DM] args, str blas) -> DM
mtimes(SX x, SX y, str blas) -> SX
mtimes([SX] args, str blas) -> SX
mtimes(MX x, MX y, str blas) -> MX
mtimes([MX] args, str blas) -> MX

Computes x*y in the linear-algebra sense; the column count of x must equal the row count of y, otherwise an error is raised. When either argument is a scalar the result is the elementwise product instead. The sparsity pattern of the result is the structural product of the patterns (entries that are structurally zero in every term stay structural zeros). For Sparsity arguments only the pattern of the product is computed.

Optional blas selects the BLAS plugin used for dense numeric kernels. The choice only takes effect on numeric DM / MX dense * dense; symbolic types (Sparsity, SX) and the sparse fallback path ignore it.

Values of blas:

  • reference (default): built-in reference kernel (triple loop)

  • classic: whatever BLAS was built into casadi via WITH_LAPACK (typically OpenBLAS)

  • blasfeo: BLASFEO

Plugins (classic, blasfeo) are loaded lazily on first use; if the corresponding plugin DLL isn't present in the build, calling them raises an error.

Parameters:
  • x -- Left factor

  • y -- Right factor

  • blas -- Name of the BLAS plugin for dense numeric products

Returns:

Matrix of size x.size1() by y.size2()

>>> A = DM([[1, 2], [3, 4]])
>>> mtimes(A, A)
DM(
[[7, 10],
 [15, 22]])
>>> mtimes(A, 2)
DM(
[[2, 4],
 [6, 8]])
>>> mtimes(Sparsity.diag(2), Sparsity.dense(2, 1))
Sparsity(2x1)
>>> mtimes(MX.sym("x", 2, 3), MX.sym("y", 3, 1))
MX(mac(x,y,zeros(2x1)))
>>> mtimes(A, DM.ones(3, 1))
Traceback (most recent call last):
  ...
RuntimeError: ...incompatible dimensions...
>> A = DM([1 2; 3 4]);
>> A * A
[[7, 10],
[15, 22]]
>> mtimes(A, 2)
[[2, 4],
[6, 8]]
>> MX.sym('x', 2, 3) * MX.sym('y', 3, 1)
mac(x,y,zeros(2x1))
>> try, A * DM.ones(3, 1); catch e, disp(e.message); end
...incompatible dimensions...
julia> A = ca.DM([1 2; 3 4]);
julia> A * A
DM(
[[7, 10],
 [15, 22]])
julia> A * 2
DM(
[[2, 4],
 [6, 8]])
julia> ca.mtimes(ca.Sparsity.diag(2), ca.Sparsity.dense(2, 1))
Sparsity(2x1)
julia> ca.MX.sym("x", 2, 3) * ca.MX.sym("y", 3, 1)
MX(mac(x,y,zeros(2x1)))
julia> try
           A * ca.DM.ones(3, 1)
       catch err
           println(occursin("incompatible dimensions", sprint(showerror, err)))
       end
true

See also: mac, times, norm_0_mul

Extra doc | Doc source | Implementation

n_nodes(...)

Count the number of nodes in an expression graph.

n_nodes(DM A) -> int
n_nodes(SX A) -> int
n_nodes(MX A) -> int

The number of nodes of the Function that evaluates the expression, which for SX includes symbols and constants and for MX also output nodes. Shared subexpressions are counted once; identical subexpressions built separately are counted separately (use cse to merge them). Not defined for DM.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> n_nodes(x), n_nodes(x + y), n_nodes(vertcat(x + y, x + y))
(1, 3, 4)
>>> n_nodes(SX(0, 1))
0
>> x = SX.sym('x'); y = SX.sym('y');
>> fprintf('%d %d %d\n', n_nodes(x), n_nodes(x + y), n_nodes(vertcat(x + y, x + y)))
1 3 4
>> n_nodes(SX(0, 1))
0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.n_nodes(x), ca.n_nodes(x + y), ca.n_nodes([x + y; x + y])
(1, 3, 4)
julia> ca.n_nodes(ca.SX(0, 1))
0

See also: cse, Function.n_nodes

Extra doc | Doc source | Implementation

ne(...)

Logical not equal to: (x,y) -> x != y.

ne(float x, float y) -> float
ne(DM x, DM y) -> DM
ne(SX x, SX y) -> SX
ne(MX x, MX y) -> MX

Elementwise comparison with 0/1 result, see lt and eq. For symbolic operands x != x with the same node simplifies to 0, so it cannot be used to detect NaN symbolically.

>>> ne(DM([1, 2, 3]), 2)
DM([1, 0, 1])
>>> x = MX.sym("x")
>>> x != x
MX(0)
>> ne(DM([1; 2; 3]), 2)
[1, 0, 1]
>> x = MX.sym('x');
>> x ~= x
0
julia> ca.ne(ca.DM([1, 2, 3]), 2)
DM([1, 0, 1])
julia> x = ca.MX.sym("x");
julia> x != x
MX(0)

See also: eq

Extra doc | Doc source | Implementation

nlpsol_default_in(...)
nlpsol_default_in() -> [float]
nlpsol_default_in(int ind) -> float

Default value of an NLP solver input.

The value used for an input that is not passed when calling an NLP solver Function: -inf for lbx and lbg, +inf for ubx and ubg, 0 for x0, p, lam_x0 and lam_g0.

Parameters:

ind -- Input index as in nlpsol_in; without argument, the list of all 8 defaults

>>> nlpsol_default_in()
[0.0, 0.0, -inf, inf, -inf, inf, 0.0, 0.0]
>>> nlpsol_default_in(3)
inf
>> nlpsol_default_in()
0 0 -Inf Inf -Inf Inf 0 0
>> nlpsol_default_in(3)
Inf
julia> ca.nlpsol_default_in()
8-element Vector{Float64}:
   0.0
   0.0
 -Inf
  Inf
 -Inf
  Inf
   0.0
   0.0
julia> ca.nlpsol_default_in(3)
Inf

Extra doc | Doc source | Implementation

nlpsol_in(...)

Get the name of an NLP solver input by index.

nlpsol_in() -> [str]
nlpsol_in(int ind) -> str
Parameters:

ind -- Index in 0.. nlpsol_n_in() -1; any other value gives an empty string

>Input scheme: casadi::NlpsolInput (NLPSOL_NUM_IN = 8)

Full name

Short

Description

NLPSOL_X0

x0

Decision variables, initial guess (nx x 1), default 0.

NLPSOL_P

p

Value of fixed parameters (np x 1), default 0.

NLPSOL_LBX

lbx

Decision variables lower bound (nx x 1), default -inf.

NLPSOL_UBX

ubx

Decision variables upper bound (nx x 1), default +inf.

NLPSOL_LBG

lbg

Constraints lower bound (ng x 1), default -inf.

NLPSOL_UBG

ubg

Constraints upper bound (ng x 1), default +inf.

NLPSOL_LAM_X0

lam_x0

Lagrange multipliers for bounds on X, initial guess (nx x 1), default 0.

NLPSOL_LAM_G0

lam_g0

Lagrange multipliers for bounds on G, initial guess (ng x 1), default 0.

>>> nlpsol_in(0), nlpsol_in(7), repr(nlpsol_in(8))
('x0', 'lam_g0', "''")
>> nlpsol_in(0), nlpsol_in(7), isempty(nlpsol_in(8))
x0
lam_g0
1
julia> ca.nlpsol_in(0), ca.nlpsol_in(7), ca.nlpsol_in(8)
("x0", "lam_g0", "")

Get the input scheme of NLP solvers.

Returns the names of the 8 inputs of a Function created by nlpsol, in order: x0, p, lbx, ubx, lbg, ubg, lam_x0, lam_g0.

>Input scheme: casadi::NlpsolInput (NLPSOL_NUM_IN = 8)

Full name

Short

Description

NLPSOL_X0

x0

Decision variables, initial guess (nx x 1), default 0.

NLPSOL_P

p

Value of fixed parameters (np x 1), default 0.

NLPSOL_LBX

lbx

Decision variables lower bound (nx x 1), default -inf.

NLPSOL_UBX

ubx

Decision variables upper bound (nx x 1), default +inf.

NLPSOL_LBG

lbg

Constraints lower bound (ng x 1), default -inf.

NLPSOL_UBG

ubg

Constraints upper bound (ng x 1), default +inf.

NLPSOL_LAM_X0

lam_x0

Lagrange multipliers for bounds on X, initial guess (nx x 1), default 0.

NLPSOL_LAM_G0

lam_g0

Lagrange multipliers for bounds on G, initial guess (ng x 1), default 0.

>>> nlpsol_in()
['x0', 'p', 'lbx', 'ubx', 'lbg', 'ubg', 'lam_x0', 'lam_g0']
>> nlpsol_in()
x0
p
lbx
ubx
lbg
ubg
lam_x0
lam_g0
julia> ca.nlpsol_in()
8-element Vector{String}:
 "x0"
 "p"
 "lbx"
 "ubx"
 "lbg"
 "ubg"
 "lam_x0"
 "lam_g0"

See also: nlpsol_out, nlpsol_n_in, nlpsol_default_in

Extra doc | Doc source | Implementation

nlpsol_n_in(...)

Number of NLP solver inputs.

nlpsol_n_in() -> int
>>> nlpsol_n_in(), len(nlpsol_in())
(8, 8)
>> fprintf('%d %d\n', nlpsol_n_in(), numel(cellstr(nlpsol_in())))
8 8
julia> ca.nlpsol_n_in(), length(ca.nlpsol_in())
(8, 8)

Extra doc | Doc source | Implementation

nlpsol_n_out(...)

Number of NLP solver outputs.

nlpsol_n_out() -> int
>>> nlpsol_n_out(), len(nlpsol_out())
(6, 6)
>> fprintf('%d %d\n', nlpsol_n_out(), numel(cellstr(nlpsol_out())))
6 6
julia> ca.nlpsol_n_out(), length(ca.nlpsol_out())
(6, 6)

Extra doc | Doc source | Implementation

nlpsol_option_info(...)

Get the documentation string of an option of an NLP solver plugin.

nlpsol_option_info(str name, str op) -> str
Parameters:
  • name -- Plugin name

  • op -- Option name; an unknown option raises an error

>>> nlpsol_option_info("sqpmethod", "max_iter")
'Maximum number of SQP iterations'
>> nlpsol_option_info('sqpmethod', 'max_iter')
Maximum number of SQP iterations
julia> ca.nlpsol_option_info("sqpmethod", "max_iter")
"Maximum number of SQP iterations"

Extra doc | Doc source | Implementation

nlpsol_option_type(...)

Get the type of an option of an NLP solver plugin.

nlpsol_option_type(str name, str op) -> str
Parameters:
  • name -- Plugin name

  • op -- Option name; an unknown option raises an error

Returns:

Type name such as "OT_INT", "OT_BOOL", "OT_DICT"

>>> nlpsol_option_type("sqpmethod", "max_iter"), nlpsol_option_type("ipopt", "ipopt")
('OT_INT', 'OT_DICT')
>> nlpsol_option_type('sqpmethod', 'max_iter')
OT_INT
>> nlpsol_option_type('ipopt', 'ipopt')
OT_DICT
julia> ca.nlpsol_option_type("sqpmethod", "max_iter"), ca.nlpsol_option_type("ipopt", "ipopt")
("OT_INT", "OT_DICT")

Extra doc | Doc source | Implementation

nlpsol_options(...)

Get all options of an NLP solver plugin.

nlpsol_options(str name) -> [str]

Returns the names of the plugin-specific options only; the options shared by all plugins (e.g. "print_time", "calc_lam_x") are not included. Raises an error for an unknown plugin.

>>> opts = nlpsol_options("sqpmethod")
>>> "max_iter" in opts, "qpsol" in opts, "print_time" in opts
(True, True, False)
>> opts = cellstr(nlpsol_options('sqpmethod'));
>> ismember({'max_iter', 'qpsol', 'print_time'}, opts)
1 1 0
julia> opts = ca.nlpsol_options("sqpmethod");
julia> "max_iter" in opts, "qpsol" in opts, "print_time" in opts
(true, true, false)

See also: nlpsol_option_type, nlpsol_option_info

Extra doc | Doc source | Implementation

nlpsol_out(...)

Get the name of an NLP solver output by index.

nlpsol_out() -> [str]
nlpsol_out(int ind) -> str
Parameters:

ind -- Index in 0.. nlpsol_n_out() -1; any other value gives an empty string

>Output scheme: casadi::NlpsolOutput (NLPSOL_NUM_OUT = 6)

Full name

Short

Description

NLPSOL_X

x

Decision variables at the optimal solution (nx x 1)

NLPSOL_F

f

Cost function value at the optimal solution (1 x 1)

NLPSOL_G

g

Constraints function at the optimal solution (ng x 1)

NLPSOL_LAM_X

lam_x

Lagrange multipliers for bounds on X at the solution (nx x 1); negative for an active lower bound, positive for an active upper bound

NLPSOL_LAM_G

lam_g

Lagrange multipliers for bounds on G at the solution (ng x 1); same sign convention.

NLPSOL_LAM_P

lam_p

Lagrange multipliers for p == P at the solution (np x 1): minus the gradient of the optimal cost with respect to p

>>> nlpsol_out(0), nlpsol_out(5), repr(nlpsol_out(6))
('x', 'lam_p', "''")
>> nlpsol_out(0), nlpsol_out(5), isempty(nlpsol_out(6))
x
lam_p
1
julia> ca.nlpsol_out(0), ca.nlpsol_out(5), ca.nlpsol_out(6)
("x", "lam_p", "")

Get the output scheme of NLP solvers.

Returns the names of the 6 outputs of a Function created by nlpsol, in order: x, f, g, lam_x, lam_g, lam_p.

>Output scheme: casadi::NlpsolOutput (NLPSOL_NUM_OUT = 6)

Full name

Short

Description

NLPSOL_X

x

Decision variables at the optimal solution (nx x 1)

NLPSOL_F

f

Cost function value at the optimal solution (1 x 1)

NLPSOL_G

g

Constraints function at the optimal solution (ng x 1)

NLPSOL_LAM_X

lam_x

Lagrange multipliers for bounds on X at the solution (nx x 1); negative for an active lower bound, positive for an active upper bound

NLPSOL_LAM_G

lam_g

Lagrange multipliers for bounds on G at the solution (ng x 1); same sign convention.

NLPSOL_LAM_P

lam_p

Lagrange multipliers for p == P at the solution (np x 1): minus the gradient of the optimal cost with respect to p

>>> nlpsol_out()
['x', 'f', 'g', 'lam_x', 'lam_g', 'lam_p']
>> nlpsol_out()
x
f
g
lam_x
lam_g
lam_p
julia> ca.nlpsol_out()
6-element Vector{String}:
 "x"
 "f"
 "g"
 "lam_x"
 "lam_g"
 "lam_p"

See also: nlpsol_in, nlpsol_n_out

Extra doc | Doc source | Implementation

no_grad(...)

Treat an expression as constant for differentiation (stop first derivatives)

no_grad(MX expr) -> MX

Same as stop_diff(expr, 1): the value is unchanged but all derivatives with respect to the symbols in expr are zero.

>>> x = MX.sym("x")
>>> y = no_grad(x**2)
>>> Function("f", [x], [y])(3), jacobian(y, x).nnz()
(DM(9), 0)
>>> Function("f", [x], [jacobian(x * y, x)])(3)
DM(9)
>> x = MX.sym('x');
>> y = no_grad(x^2); J = jacobian(y, x);
>> f = Function('f', {x}, {y});
>> f(3), J.nnz()
9
0
>> f = Function('f', {x}, {jacobian(x * y, x)});
>> f(3)
9
julia> x = ca.MX.sym("x");
julia> y = ca.no_grad(x^2);
julia> ca.Function("f", [x], [y])(3), ca.nnz(ca.jacobian(y, x))
(9, 0)
julia> ca.Function("f", [x], [ca.jacobian(x * y, x)])(3)
DM(9)

See also: stop_diff, no_hess

Extra doc | Doc source | Implementation

no_hess(...)

Stop second derivatives of an expression wrt all its symbolic variables.

no_hess(MX expr) -> MX

Same as stop_diff(expr, 2): first derivatives are exact, the Hessian contribution is zero. Useful for Gauss-Newton-type Hessians.

>>> x = MX.sym("x")
>>> y = no_hess(x**3)
>>> Function("f", [x], [jacobian(y, x)])(2), hessian(y, x)[0].nnz()
(DM(12), 0)
>> x = MX.sym('x');
>> y = no_hess(x^3);
>> f = Function('f', {x}, {jacobian(y, x)});
>> [H, g] = hessian(y, x);
>> f(2), H.nnz()
12
0
julia> x = ca.MX.sym("x");
julia> y = ca.no_hess(x^3);
julia> ca.Function("f", [x], [ca.jacobian(y, x)])(2), ca.nnz(first(ca.hessian(y, x)))
(12, 0)

See also: stop_diff, no_grad

Extra doc | Doc source | Implementation

norm_0_mul(...)

0-norm (nonzero count) of a Matrix-matrix product

norm_0_mul(Sparsity x, Sparsity y) -> int
norm_0_mul(DM x, DM y) -> int
norm_0_mul(SX x, SX y) -> int
norm_0_mul(MX x, MX y) -> int

Number of structural nonzeros that mtimes(x, y) would have, computed from the sparsity patterns without forming the product. The inner dimensions must match, otherwise an error is raised.

>>> norm_0_mul(DM.eye(3), DM.ones(3, 2))
6
>>> norm_0_mul(Sparsity.diag(3), Sparsity.diag(3))
3
>>> norm_0_mul(DM.ones(2, 3), DM.ones(2, 3))
Traceback (most recent call last):
  ...
RuntimeError: ...Dimension error...
>> norm_0_mul(DM.eye(3), DM.ones(3, 2))
6
>> norm_0_mul(Sparsity.diag(3), Sparsity.diag(3))
3
>> try, norm_0_mul(DM.ones(2, 3), DM.ones(2, 3)); catch e, disp(e.message); end
...Dimension error...
julia> ca.norm_0_mul(ca.DM.eye(3), ca.DM.ones(3, 2))
6
julia> ca.norm_0_mul(ca.Sparsity.diag(3), ca.Sparsity.diag(3))
3
julia> try
           ca.norm_0_mul(ca.DM.ones(2, 3), ca.DM.ones(2, 3))
       catch err
           println(occursin("Dimension error", sprint(showerror, err)))
       end
true

See also: mtimes

Extra doc | Doc source | Implementation

norm_1(...)

1-norm

norm_1(DM x) -> DM
norm_1(SX x) -> SX
norm_1(MX x) -> MX

Sum of the absolute values of all entries. For a matrix this is the entrywise norm, not the induced (maximum column sum) matrix norm. Nonsmooth at zero entries.

>>> norm_1(DM([[1, -2], [3, 4]]))
DM(10)
>>> norm_1(SX.sym("x", 2))
SX((fabs(x_0)+fabs(x_1)))
>> norm_1(DM([1 -2; 3 4]))
10
>> norm_1(SX.sym('x', 2))
(fabs(x_0)+fabs(x_1))
julia> ca.norm_1(ca.DM([1 -2; 3 4]))
DM(10)
julia> ca.norm_1(ca.SX.sym("x", 2))
SX((fabs(x_0)+fabs(x_1)))

See also: norm_inf, norm_2, norm_fro

Extra doc | Doc source | Implementation

norm_2(...)

2-norm

norm_2(DM x) -> DM
norm_2(SX x) -> SX
norm_2(MX x) -> MX

For a vector (row or column) this is the Euclidean norm, identical to norm_fro. For a matrix argument DM and SX raise an error (use norm_fro if that is what you meant); MX creates a spectral-norm node that cannot be evaluated. Not differentiable at x == 0; use sumsqr in objectives where possible.

>>> norm_2(DM([3, 4]))
DM(5)
>>> norm_2(MX.sym("x", 2))
MX(||x||_F)
>>> try: norm_2(DM([[1, 2], [3, 4]]))
... except Exception as e: print("error")
error
>> norm_2(DM([3; 4]))
5
>> norm_2(MX.sym('x', 2))
||x||_F
>> try, norm_2(DM([1 2; 3 4])); catch e, disp('error'); end
error
julia> ca.norm_2(ca.DM([3, 4]))
DM(5)
julia> ca.norm_2(ca.MX.sym("x", 2))
MX(||x||_F)
julia> try ca.norm_2(ca.DM([1 2; 3 4])) catch e; println("error") end
error

See also: norm_fro, norm_1, norm_inf, sumsqr

Extra doc | Doc source | Implementation

norm_fro(...)

Frobenius norm.

norm_fro(DM x) -> DM
norm_fro(SX x) -> SX
norm_fro(MX x) -> MX

sqrt(sum_ij x_ij^2) over all entries, for a matrix of any shape. Not differentiable at x == 0 (the derivative evaluates to nan there); use sumsqr in objectives where possible.

>>> norm_fro(DM([[1, -2], [3, 4]]))
DM(5.47723)
>>> norm_fro(SX.sym("x", 2))
SX(sqrt((sq(x_0)+sq(x_1))))
>> norm_fro(DM([1 -2; 3 4]))
5.47723
>> norm_fro(SX.sym('x', 2))
sqrt((sq(x_0)+sq(x_1)))
julia> ca.norm_fro(ca.DM([1 -2; 3 4]))
DM(5.47723)
julia> ca.norm_fro(ca.SX.sym("x", 2))
SX(sqrt((sq(x_0)+sq(x_1))))

See also: norm_2, norm_1, norm_inf, sumsqr

Extra doc | Doc source | Implementation

norm_inf(...)

Infinity-norm.

norm_inf(DM x) -> DM
norm_inf(SX x) -> SX
norm_inf(MX x) -> MX

Largest absolute value among all entries. For a matrix this is the entrywise norm, not the induced (maximum row sum) matrix norm. Nonsmooth.

>>> norm_inf(DM([[1, -2], [3, 4]]))
DM(4)
>>> norm_inf(SX.sym("x", 2))
SX(fmax(fmax(0,fabs(x_0)),fabs(x_1)))
>> norm_inf(DM([1 -2; 3 4]))
4
>> norm_inf(SX.sym('x', 2))
fmax(fmax(0,fabs(x_0)),fabs(x_1))
julia> ca.norm_inf(ca.DM([1 -2; 3 4]))
DM(4)
julia> ca.norm_inf(ca.SX.sym("x", 2))
SX(fmax(fmax(0,fabs(x_0)),fabs(x_1)))

See also: norm_1, norm_2, norm_fro, mmax

Extra doc | Doc source | Implementation

norm_inf_mul(...)

Infinity norm of a matrix product, without forming the product.

norm_inf_mul(DM x, DM y) -> DM
norm_inf_mul(SX x, SX y) -> SX

Equals norm_inf(mtimes(x, y)): the largest absolute entry of x*y. Exploits sparsity; a shape mismatch raises an error. Works symbolically on SX.

>>> A = DM([[1, 2], [3, 4]])
>>> norm_inf_mul(A, A), norm_inf(mtimes(A, A))
(DM(22), DM(22))
>> A = DM([1 2; 3 4]);
>> norm_inf_mul(A, A), norm_inf(A*A)
22
22
julia> A = ca.DM([1 2; 3 4]);
julia> ca.norm_inf_mul(A, A), ca.norm_inf(A * A)
(22, 22)

See also: norm_inf, mtimes

Extra doc | Doc source | Implementation

normalized_in(...)
normalized_in(std::istream & stream, double & ret) -> int
normalized_out(...)
normalized_out(float val)
normalized_setup(...)
normalized_setup()
normalized_setup(std::istream & stream)
nullspace(...)

Computes the nullspace of a matrix A.

nullspace(DM A) -> DM
nullspace(SX A) -> SX
nullspace(MX A) -> MX

Finds Z m-by-(m-n) such that AZ = 0 with A n-by-m with m >= n (a matrix with more rows than columns raises an error).

Assumes A is full rank. Computed with Householder reflections, dense; for MX the SX algorithm is embedded as a function call node.

Inspired by Numerical Methods in Scientific Computing by Ake Bjorck

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> Z = nullspace(A)
>>> Z.dim(), norm_1(mtimes(A, Z))
('3x1', DM(0))
>> A = DM([1 2 3; 4 5 6]);
>> Z = nullspace(A);
>> Z.dim(), norm_1(A*Z)
3x1
0
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> Z = ca.nullspace(A);
julia> ca.dim(Z), ca.norm_1(A * Z)
("3x1", 0)

See also: qr, pinv

Extra doc | Doc source | Implementation

offset(...)

Get the block offsets of a list of matrices.

offset([Sparsity] v, bool vert) -> [int]
offset([DM] v, bool vert) -> [int]
offset([SX] v, bool vert) -> [int]
offset([MX] v, bool vert) -> [int]

Returns the cumulative row counts (or column counts when vert is false) of the matrices in v, starting with 0. The result has one entry more than v and is the offset list that vertsplit (or horzsplit) needs to undo a vertcat (or horzcat) of v.

Parameters:
  • v -- List of matrices (or Sparsity patterns)

  • vert -- True for row offsets, false for column offsets

Returns:

List of offsets of length len(v)+1

>>> offset([DM(2, 3), DM(4, 3)])
[0, 2, 6]
>>> offset([DM(2, 3), DM(2, 4)], False)
[0, 3, 7]
>>> offset([])
[0]
julia> ca.offset([ca.DM(2, 3), ca.DM(4, 3)])
3-element Vector{Int64}:
 0
 2
 6
julia> ca.offset([ca.DM(2, 3), ca.DM(2, 4)], false)
3-element Vector{Int64}:
 0
 3
 7
julia> ca.offset(ca.DM[])
1-element Vector{Int64}:
 0

See also: vertsplit, horzsplit

Extra doc | Doc source | Implementation

onnxbackend_doc(...)

Get documentation for an ONNX runtime backend.

onnxbackend_doc(str solver) -> str

Extra doc | Doc source | Implementation

onnxbackend_solvers(...)

List available ONNX runtime backends.

onnxbackend_solvers() -> [str]

Extra doc | Doc source | Implementation

pinv(...)

Computes the Moore-Penrose pseudo-inverse.

pinv(DM A) -> DM
pinv(SX A) -> SX
pinv(MX A) -> MX
pinv(DM A, str lsolver, dict opts) -> DM
pinv(SX A, str lsolver, dict opts) -> SX
pinv(MX A, str lsolver, dict opts) -> MX

If the matrix A is fat (size1<size2), mul(A, pinv(A)) is unity.

pinv(A)' = (AA')^(-1) A

If the matrix A is slender (size1>size2), mul(pinv(A), A) is unity.

pinv(A) = (A'A)^(-1) A'

The normal equations are solved with solve, so A is assumed to have full rank. For a square matrix this is the inverse.

>>> A = DM([[1, 0, 0], [0, 2, 0]])
>>> pinv(A)
DM(
[[1, 0],
 [0, 0.5],
 [0, 0]])
>>> mtimes(A, pinv(A))
DM(
[[1, 0],
 [0, 1]])
>>> pinv(SX.sym("A", 1, 2))
SX(@1=(sq(A_0)+sq(A_1)), [(A_0/@1), (A_1/@1)])
>> A = DM([1 0 0; 0 2 0]);
>> pinv(A)
[[1, 0],
[0, 0.5],
[0, 0]]
>> A*pinv(A)
[[1, 0],
[0, 1]]
>> pinv(SX.sym('A', 1, 2))
@1=(sq(A_0)+sq(A_1)), [(A_0/@1), (A_1/@1)]
julia> A = ca.DM([1 0 0; 0 2 0]);
julia> ca.pinv(A)
DM(
[[1, 0],
 [0, 0.5],
 [0, 0]])
julia> A * ca.pinv(A)
DM(
[[1, 0],
 [0, 1]])
julia> ca.pinv(ca.SX.sym("A", 1, 2))
SX(@1=(sq(A_0)+sq(A_1)), [(A_0/@1), (A_1/@1)])

See also: inv, solve, nullspace

Extra doc | Doc source | Implementation

plus(...)

Addition: (x,y) -> x + y.

plus(float x, float y) -> float
plus(DM x, DM y) -> DM
plus(SX x, SX y) -> SX
plus(MX x, MX y) -> MX

Elementwise sum. The shape rules below hold for every binary operation in this group (minus, times, rdivide, the comparisons, logic_and, ...):

  • both operands have the same shape, or

  • one operand is a scalar (1-by-1), which is combined with every element, or

  • the operands have the same number of rows and the column count of one is a multiple of the other's; the narrower one is repeated horizontally (so a column vector can be added to every column of a matrix, but a row vector cannot be added to every row). Any other combination raises an error; there is no further broadcasting. Empty matrices follow the same rules and give an empty result.

The result is sparse where both operands are structurally zero; an entry that is a structural zero in only one operand becomes an explicit value. Operations that map (0, y) or (x, 0) to a nonzero, such as x + 1 or cos, densify the result. Numeric (DM) operands are evaluated, symbolic ones (SX, MX) build an expression; DM and SX or MX can be mixed, SX and MX cannot.

>>> plus(DM([1, 2]), DM([10, 20]))
DM([11, 22])
>>> DM([1, 2]) + 1
DM([2, 3])
>>> DM.eye(2) + DM.eye(2)
DM(
[[2, 00],
 [00, 2]])
>>> DM.eye(2) + 1
DM(
[[2, 1],
 [1, 2]])
>>> SX.sym("x", 2, 2) + SX.sym("y", 2)
SX(
[[(x_0+y_0), (x_2+y_0)],
 [(x_1+y_1), (x_3+y_1)]])
>>> (MX.sym("x", 2, 0) + 1).shape
(2, 0)
>>> DM.ones(2, 2) + DM.ones(1, 2)
Traceback (most recent call last):
  ...
RuntimeError: ...Dimension mismatch...
>> plus(DM([1; 2]), DM([10; 20]))
[11, 22]
>> DM([1; 2]) + 1
[2, 3]
>> DM.eye(2) + DM.eye(2)
[[2, 00],
[00, 2]]
>> DM.eye(2) + 1
[[2, 1],
[1, 2]]
>> SX.sym('x', 2, 2) + SX.sym('y', 2)
[[(x_0+y_0), (x_2+y_0)],
[(x_1+y_1), (x_3+y_1)]]
>> size(MX.sym('x', 2, 0) + 1)
2 0
>> try, DM.ones(2, 2) + DM.ones(1, 2); catch e, disp(e.message); end
...Dimension mismatch...
julia> ca.plus(ca.DM([1, 2]), ca.DM([10, 20]))
DM([11, 22])
julia> ca.DM([1, 2]) + 1
DM([2, 3])
julia> ca.DM.eye(2) + ca.DM.eye(2)
DM(
[[2, 00],
 [00, 2]])
julia> ca.DM.eye(2) + 1
DM(
[[2, 1],
 [1, 2]])
julia> ca.SX.sym("x", 2, 2) + ca.SX.sym("y", 2)
SX(
[[(x_0+y_0), (x_2+y_0)],
 [(x_1+y_1), (x_3+y_1)]])
julia> size(ca.MX.sym("x", 2, 0) + 1)
(2, 0)
julia> try
           ca.DM.ones(2, 2) + ca.DM.ones(1, 2)
       catch e
           println(occursin("Dimension mismatch", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

poly_coeff(...)

Extract the polynomial coefficients of a scalar expression in one symbol.

poly_coeff(DM ex, DM x) -> DM
poly_coeff(SX ex, SX x) -> SX

Returns the coefficients in decreasing power order (highest degree first), as a column vector; the constant term is last. Coefficients may be symbolic in other variables. Found by repeated differentiation, so an expression that is not polynomial in x raises an error. Only defined for SX.

Parameters:
  • ex -- Scalar SX expression that is a polynomial in x

  • x -- Scalar SX symbol

>>> x = SX.sym("x"); a = SX.sym("a")
>>> poly_coeff(3*x**2 + 2*x + 1, x)
SX([3, 2, 1])
>>> poly_coeff((x - a)*(x + a), x)
SX([1, 0, (-sq(a))])
>>> try: poly_coeff(sin(x), x)
... except Exception as e: print("error")
error
>> x = SX.sym('x'); a = SX.sym('a');
>> poly_coeff(3*x^2 + 2*x + 1, x)
[3, 2, 1]
>> poly_coeff((x - a)*(x + a), x)
[1, 0, (-sq(a))]
>> try, poly_coeff(sin(x), x); catch e, disp('error'); end
error
julia> x = ca.SX.sym("x"); a = ca.SX.sym("a");
julia> ca.poly_coeff(3*x^2 + 2*x + 1, x)
SX([3, 2, 1])
julia> ca.poly_coeff((x - a)*(x + a), x)
SX([1, 0, (-sq(a))])
julia> try ca.poly_coeff(sin(x), x); catch; println("error") end
error

See also: poly_roots, polyval

Extra doc | Doc source | Implementation

poly_roots(...)

Roots of a polynomial given by its coefficients, in closed form.

poly_roots(DM p) -> DM
poly_roots(SX p) -> SX

p is a dense column vector of coefficients in decreasing power order, as returned by poly_coeff. Closed-form formulas are used for degrees 1 to 4; a zero constant term is split off as a root 0 first. Higher degrees raise an error. All roots are assumed real: complex roots give nan. The result stays symbolic for symbolic coefficients. Only defined for SX; pass SX(p) for numeric coefficients.

>>> poly_roots(SX([1, -3, 2]))
SX([1, 2])
>>> evalf(poly_roots(SX([1, -6, 11, -6])))
DM([3, 1, 2])
>>> a = SX.sym("a")
>>> poly_roots(vertcat(a, 2))
SX((-2/a))
>>> try: poly_roots(SX([1, 1, 1, 1, 1, 1]))
... except Exception as e: print("error")
error
>> poly_roots(SX([1; -3; 2]))
[1, 2]
>> evalf(poly_roots(SX([1; -6; 11; -6])))
[3, 1, 2]
>> a = SX.sym('a');
>> poly_roots([a; 2])
(-2/a)
>> try, poly_roots(SX([1; 1; 1; 1; 1; 1])); catch e, disp('error'); end
error
julia> ca.poly_roots(ca.SX([1, -3, 2]))
SX([1, 2])
julia> ca.evalf(ca.poly_roots(ca.SX([1, -6, 11, -6])))
DM([3, 1, 2])
julia> a = ca.SX.sym("a");
julia> ca.poly_roots([a; 2])
SX((-2/a))
julia> try ca.poly_roots(ca.SX([1, 1, 1, 1, 1, 1])); catch; println("error") end
error

See also: poly_coeff, eig_symbolic

Extra doc | Doc source | Implementation

polyval(...)

Evaluate a polynomial with coefficients p in x.

polyval(DM p, DM x) -> DM
polyval(SX p, SX x) -> SX
polyval(MX p, MX x) -> MX

Horner evaluation of p[0]*x^(n-1) + ... + p[n-2]*x + p[n-1]: the first coefficient belongs to the highest power, as in MATLAB's polyval. The polynomial is applied to every structurally nonzero entry of x; the result keeps the shape and sparsity of x (structural zeros stay zero even when p[n-1] != 0).

Parameters:
  • p -- Dense column vector of coefficients, at least one entry

  • x -- Point(s) of evaluation, any shape

>>> polyval(DM([1, 2, 3]), 2)
DM(11)
>>> polyval(DM([1, 0, -1]), DM([0, 1, 2]))
DM([-1, 0, 3])
>>> polyval(SX.sym("p", 3), SX.sym("x"))
SX(((((p_0*x)+p_1)*x)+p_2))
>> polyval(DM([1; 2; 3]), 2)
11
>> polyval(DM([1; 0; -1]), DM([0; 1; 2]))
[-1, 0, 3]
>> polyval(SX.sym('p', 3), SX.sym('x'))
((((p_0*x)+p_1)*x)+p_2)
julia> ca.polyval(ca.DM([1, 2, 3]), 2)
DM(11)
julia> ca.polyval(ca.DM([1, 0, -1]), ca.DM([0, 1, 2]))
DM([-1, 0, 3])
julia> ca.polyval(ca.SX.sym("p", 3), ca.SX.sym("x"))
SX(((((p_0*x)+p_1)*x)+p_2))

Extra doc | Doc source | Implementation

power(...)

Elementwise power: (x,y) -> x.^y.

power(float x, float n) -> float
power(DM x, DM n) -> DM
power(SX x, SX n) -> SX
power(MX x, MX n) -> MX

Elementwise; shape rules as for plus. Named power in Python, where the ** operator maps to it as well. A constant exponent is simplified symbolically: integer powers become repeated squaring and multiplication, 0.5 becomes sqrt, -1 a reciprocal, other constants a constpow operation. Structural zeros of x stay zero for a nonzero exponent; x**0 is dense (0**0 == 1).

>>> power(DM([1, 2, 3]), 2)
DM([1, 4, 9])
>>> DM([1, 2, 3])**DM([3, 2, 1]), 2**DM([1, 2, 3])
(DM([1, 4, 3]), DM([2, 4, 8]))
>>> x = SX.sym("x")
>>> x**2, x**3, x**-1, x**x
(SX(sq(x)), SX((x*sq(x))), SX((1./x)), SX(pow(x,x)))
>>> x**2.5
SX(pow(x,2.5))
>> power(DM([1; 2; 3]), 2)
[1, 4, 9]
>> DM([1; 2; 3]).^DM([3; 2; 1]), 2.^DM([1; 2; 3])
[1, 4, 3]
[2, 4, 8]
>> x = SX.sym('x');
>> x.^2, x.^3, x.^-1, x.^x
sq(x)
(x*sq(x))
(1./x)
pow(x,x)
>> x.^2.5
pow(x,2.5)
julia> ca.power(ca.DM([1, 2, 3]), 2)
DM([1, 4, 9])
julia> ca.DM([1, 2, 3]) .^ ca.DM([3, 2, 1]), 2 .^ ca.DM([1, 2, 3])
([1, 4, 3], [2, 4, 8])
julia> x = ca.SX.sym("x");
julia> x^2, x^3, x^-1, x^x
(sq(x), (x*sq(x)), (1./x), pow(x,x))
julia> x^2.5
SX(pow(x,2.5))

See also: sq, sqrt, constpow, mpower

Extra doc | Doc source | Implementation

print_operator(...)

Get a string representation for a binary MatType, using custom arguments.

print_operator(DM xb, [str] args) -> str
print_operator(SX xb, [str] args) -> str
print_operator(MX xb, [str] args) -> str

Prints the operation at the root of a scalar expression with the given strings in place of its operands. xb must be a unary or binary operation (a symbol or constant raises an error for SX) and args must have one entry per operand.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> print_operator(x + y, ["a", "b"]), print_operator(sin(x), ["a"])
('(a+b)', 'sin(a)')
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> print_operator(vertcat(X, Y), ["a", "b"])
'vertcat(a, b)'
>> x = SX.sym('x'); y = SX.sym('y');
>> print_operator(x + y, {'a', 'b'}), print_operator(sin(x), {'a'})
(a+b)
sin(a)
>> X = MX.sym('X'); Y = MX.sym('Y');
>> print_operator(vertcat(X, Y), {'a', 'b'})
vertcat(a, b)
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.print_operator(x + y, ["a", "b"]), ca.print_operator(sin(x), ["a"])
("(a+b)", "sin(a)")
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.print_operator([X; Y], ["a", "b"])
"vertcat(a, b)"

Extra doc | Doc source | Implementation

project(...)

Create a new matrix with a given sparsity pattern but with the.

project(DM A, Sparsity sp, bool intersect) -> DM
project(SX A, Sparsity sp, bool intersect) -> SX
project(MX A, Sparsity sp, bool intersect) -> MX

nonzeros taken from an existing matrix

Entries of A outside sp are dropped; entries of sp not present in A become numerical zeros. The shape of sp must equal that of A. With intersect true, the target pattern is the intersection of sp and the pattern of A, so the result only ever loses entries.

>>> project(DM([[1, 2], [3, 4]]), Sparsity.diag(2))
DM(
[[1, 00],
 [00, 4]])
>>> project(DM.eye(2), Sparsity.dense(2, 2))
DM(
[[1, 0],
 [0, 1]])
>>> project(DM(Sparsity.diag(2), [1, 2]), Sparsity.upper(2), True)
DM(
[[1, 00],
 [00, 2]])
>> project(DM([1 2; 3 4]), Sparsity.diag(2))
[[1, 00],
[00, 4]]
>> project(DM.eye(2), Sparsity.dense(2, 2))
[[1, 0],
[0, 1]]
>> project(DM(Sparsity.diag(2), [1; 2]), Sparsity.upper(2), true)
[[1, 00],
[00, 2]]
julia> ca.project(ca.DM([1 2; 3 4]), ca.Sparsity.diag(2))
DM(
[[1, 00],
 [00, 4]])
julia> ca.project(ca.DM.eye(2), ca.Sparsity.dense(2, 2))
DM(
[[1, 0],
 [0, 1]])
julia> ca.project(ca.DM(ca.Sparsity.diag(2), [1, 2]), ca.Sparsity.upper(2), true)
DM(
[[1, 00],
 [00, 2]])

See also: densify, sparsify, unite

Extra doc | Doc source | Implementation

pw_const(...)

Piecewise constant function of a scalar symbolic variable.

pw_const(DM t, DM tval, DM val) -> DM
pw_const(SX t, SX tval, SX val) -> SX

Builds an SX expression that equals val[0] for t < tval[0], val[k] for tval[k-1] <= t < tval[k] and val[n-1] for t >= tval[n-2], with n = val.numel(). tval must be increasing. The result is a sum of step functions, so it is not smooth; its derivative with respect to t is zero almost everywhere. Only defined for SX.

Parameters:
  • t -- Scalar SX variable (e.g. time)

  • tval -- Breakpoints, length n-1; a length mismatch raises an error

  • val -- Function value on each interval, length n

>>> t = SX.sym("t")
>>> e = pw_const(t, [0, 2], [7, 1, 3])
>>> f = Function("f", [t], [e])
>>> [float(f(v)) for v in [-1, 0, 1, 2, 5]]
[7.0, 1.0, 1.0, 3.0, 3.0]
>>> try: pw_const(t, [0], [7, 1, 3])
... except Exception as e: print("error")
error
>> t = SX.sym('t');
>> e = pw_const(t, [0 2], [7 1 3]);
>> f = Function('f', {t}, {e});
>> f([-1; 0; 1; 2; 5])
[7, 1, 1, 3, 3]
>> try, pw_const(t, 0, [7 1 3]); catch e, disp('error'); end
error
julia> t = ca.SX.sym("t");
julia> e = ca.pw_const(t, [0, 2], [7, 1, 3]);
julia> f = ca.Function("f", [t], [e]);
julia> [Float64(f(v)) for v in [-1, 0, 1, 2, 5]]
5-element Vector{Float64}:
 7.0
 1.0
 1.0
 3.0
 3.0
julia> try ca.pw_const(t, [0], [7, 1, 3]); catch; println("error") end
error

See also: pw_lin, if_else, interpolant

Extra doc | Doc source | Implementation

pw_lin(...)

Piecewise linear function of a scalar symbolic variable.

pw_lin(DM t, DM tval, DM val) -> DM
pw_lin(SX t, SX tval, SX val) -> SX

Builds an SX expression that interpolates linearly between the points (tval[k], val[k]). Outside [tval[0], tval[N-1]] the first and last segments are extrapolated. Only defined for SX.

Parameters:
  • t -- Scalar SX variable (e.g. time)

  • tval -- Breakpoints, increasing, at least two

  • val -- Function values at the breakpoints, same length as tval

>>> t = SX.sym("t")
>>> f = Function("f", [t], [pw_lin(t, [0, 1, 3], [0, 2, 1])])
>>> [float(f(v)) for v in [-1, 0, 0.5, 1, 2, 3, 4]]
[-2.0, 0.0, 1.0, 2.0, 1.5, 1.0, 0.5]
>>> try: pw_lin(t, [0], [7])
... except Exception as e: print("error")
error
>> t = SX.sym('t');
>> f = Function('f', {t}, {pw_lin(t, [0 1 3], [0 2 1])});
>> f([-1; 0; 0.5; 1; 2; 3; 4])
[-2, 0, 1, 2, 1.5, 1, 0.5]
>> try, pw_lin(t, 0, 7); catch e, disp('error'); end
error
julia> t = ca.SX.sym("t");
julia> f = ca.Function("f", [t], [ca.pw_lin(t, [0, 1, 3], [0, 2, 1])]);
julia> [Float64(f(v)) for v in [-1, 0, 0.5, 1, 2, 3, 4]]
7-element Vector{Float64}:
 -2.0
  0.0
  1.0
  2.0
  1.5
  1.0
  0.5
julia> try ca.pw_lin(t, [0], [7]); catch; println("error") end
error

See also: pw_const, interpolant

Extra doc | Doc source | Implementation

qr(...)

Dense QR factorization using the modified Gram-Schmidt algorithm.

qr(DM A) -> (DM, DM)
qr(SX A) -> (SX, SX)

Factorizes A = Q*R with Q of the same shape as A (orthonormal columns) and R square upper triangular. More stable than classical Gram- Schmidt, but breaks down (nan entries, no error) when the columns of A are (nearly) linearly dependent. A must have at least as many rows as columns. Works symbolically on SX. See J. Demmel: Applied Numerical Linear Algebra (algorithm 3.1). In Python and MATLAB, Q and R are returned as a tuple.

>>> Q, R = qr(DM([[3, 1], [4, 2]]))
>>> Q
DM(
[[0.6, -0.8],
 [0.8, 0.6]])
>>> R
DM(
[[5, 2.2],
 [00, 0.4]])
>>> mtimes(Q, R)
DM(
[[3, 1],
 [4, 2]])
>>> try: qr(DM([[1, 2, 3]]))
... except Exception as e: print("error")
error
>> [Q, R] = qr(DM([3 1; 4 2]));
>> Q
[[0.6, -0.8],
[0.8, 0.6]]
>> R
[[5, 2.2],
[00, 0.4]]
>> Q*R
[[3, 1],
[4, 2]]
>> try, [Q, R] = qr(DM([1 2 3])); catch e, disp('error'); end
error
julia> Q, R = ca.qr(ca.DM([3 1; 4 2]));
julia> Q
DM(
[[0.6, -0.8],
 [0.8, 0.6]])
julia> R
DM(
[[5, 2.2],
 [00, 0.4]])
julia> Q * R
DM(
[[3, 1],
 [4, 2]])
julia> try ca.qr(ca.DM([1 2 3])); catch; println("error") end
error

See also: qr_sparse, chol, ldl

Extra doc | Doc source | Implementation

qr_solve(...)

Solve A*x = b (or A^T*x = b) with the factors returned by qr_sparse.

qr_solve(DM b, DM v, DM r, DM beta, [int] prinv, [int] pc, bool tr) -> DM
qr_solve(SX b, SX v, SX r, SX beta, [int] prinv, [int] pc, bool tr) -> SX
Parameters:
  • b -- Right-hand side, one column per system; a sparse b is densified

  • v -- Output of qr_sparse(A)

  • r -- Output of qr_sparse(A)

  • beta -- Output of qr_sparse(A)

  • prinv -- Output of qr_sparse(A)

  • pc -- Output of qr_sparse(A)

  • tr -- Solve with the transpose of A instead

Returns:

Dense solution with the shape of b

>>> A = DM([[3, 1], [4, 2]])
>>> V, R, beta, prinv, pc = qr_sparse(A)
>>> qr_solve(DM([1, 2]), V, R, beta, prinv, pc, True)
DM([-3, 2.5])
>>> solve(A.T, DM([1, 2]))
DM([-3, 2.5])
>> A = DM([3 1; 4 2]);
>> [V, R, beta, prinv, pc] = qr_sparse(A);
>> qr_solve(DM([1; 2]), V, R, beta, prinv, pc, true)
[-3, 2.5]
>> solve(A', DM([1; 2]))
[-3, 2.5]
julia> A = ca.DM([3 1; 4 2]);
julia> V, R, beta, prinv, pc = ca.qr_sparse(A);
julia> ca.qr_solve(ca.DM([1, 2]), V, R, beta, prinv, pc, true)
DM([-3, 2.5])
julia> A' \ [1, 2]
DM([-3, 2.5])

See also: qr_sparse, solve

Extra doc | Doc source | Implementation

qr_sparse(...)

Sparse direct QR factorization with Householder reflections.

qr_sparse(DM A, bool amd) -> (DM, DM, DM, [int], [int])
qr_sparse(SX A, bool amd) -> (SX, SX, SX, [int], [int])

Computes a compact representation of Q (Householder vectors V and scaling factors beta), the upper triangular factor R and the row and column permutations prinv and pc that were applied, so that the factors can be reused by qr_solve. See T. Davis: Direct Methods for Sparse Linear Systems. Works symbolically on SX.

Parameters:
  • A -- Matrix to factorize

  • amd -- Use an approximate minimum degree column ordering to reduce fill-in

Returns:

V, R, beta, prinv, pc (a tuple in Python)

>>> A = DM([[3, 1], [4, 2]])
>>> V, R, beta, prinv, pc = qr_sparse(A)
>>> R
DM(
[[5, 2.2],
 [00, 0.4]])
>>> qr_solve(DM([1, 2]), V, R, beta, prinv, pc)
DM([0, 1])
>> A = DM([3 1; 4 2]);
>> [V, R, beta, prinv, pc] = qr_sparse(A);
>> R
[[5, 2.2],
[00, 0.4]]
>> qr_solve(DM([1; 2]), V, R, beta, prinv, pc)
[0, 1]
julia> A = ca.DM([3 1; 4 2]);
julia> V, R, beta, prinv, pc = ca.qr_sparse(A);
julia> R
DM(
[[5, 2.2],
 [00, 0.4]])
julia> ca.qr_solve(ca.DM([1, 2]), V, R, beta, prinv, pc)
DM([0, 1])

See also: qr_solve, Sparsity.qr_sparse, qr

Extra doc | Doc source | Implementation

quadratic_coeff(...)

Recognizes quadratic form in scalar expression.

quadratic_coeff(DM ex, DM arg, bool check) -> (DM, DM, DM)
quadratic_coeff(SX ex, SX arg, bool check) -> (SX, SX, SX)
quadratic_coeff(MX ex, MX arg, bool check) -> (MX, MX, MX)

1/2*x' A x + b' x + c

e = 0.5*bilin(A,x,x)+dot(b,x)+c

Returns A = hessian(expr, var), b = jacobian(expr, var) at var = 0 as a column, and c = expr at var = 0. A non-scalar expr raises an error.

Parameters:

check[in] -- When true (default), A is checked to be independent of x and an error is raised otherwise ("called on non-quadratic expression"). Provided to deal with false positive dependency checks.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> A, b, c = quadratic_coeff(x**2 + 2*x*y + 3*x + 4, vertcat(x, y))
>>> A
SX(@1=2,
[[@1, @1],
 [@1, 00]])
>>> b, c
(SX([3, 0]), SX(4))
>>> try: quadratic_coeff(x**3, x)
... except Exception as e: print("error")
error
>> x = SX.sym('x'); y = SX.sym('y');
>> [A, b, c] = quadratic_coeff(x^2 + 2*x*y + 3*x + 4, vertcat(x, y));
>> A
@1=2,
[[@1, @1],
 [@1, 00]]
>> b, c
[3, 0]
4
>> try, [A, b, c] = quadratic_coeff(x^3, x); catch e, disp('error'); end
error
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> A, b, c = ca.quadratic_coeff(x^2 + 2 * x * y + 3 * x + 4, [x; y]);
julia> A
SX(@1=2,
[[@1, @1],
 [@1, 00]])
julia> b, c
([3, 0], 4)
julia> try ca.quadratic_coeff(x^3, x) catch e; println("error") end
error

See also: linear_coeff, is_quadratic, hessian

Extra doc | Doc source | Implementation

ramp(...)

Ramp function, elementwise.

ramp(DM x) -> DM
ramp(SX x) -> SX

x for x > 0 and 0 for x <= 0, computed as x*heaviside(x). Also called the slope function or relu. Not defined for MX; use fmax(x, 0) for an MX- compatible alternative.

>>> ramp(DM([0, 0.5, 3]))
DM([0, 0.5, 3])
>>> ramp(SX.sym("x"))
SX((x*((1+sign(x))/2)))
>> ramp(DM([0; 0.5; 3]))
[0, 0.5, 3]
>> ramp(SX.sym('x'))
(x*((1+sign(x))/2))
julia> ca.ramp(ca.DM([0, 0.5, 3]))
DM([0, 0.5, 3])
julia> ca.ramp(ca.SX.sym("x"))
SX((x*((1+sign(x))/2)))

See also: heaviside, fmax

Extra doc | Doc source | Implementation

rank1(...)

Make a rank-1 update to a matrix A.

rank1(DM A, DM alpha, DM x, DM y) -> DM
rank1(SX A, SX alpha, SX x, SX y) -> SX
rank1(MX A, MX alpha, MX x, MX y) -> MX

Calculates A + alpha * x*y'

Parameters:
  • alpha -- Scalar; if it is a structural zero, A is returned unchanged

  • x -- Vector with x.numel() == A.size1() (row vectors are transposed)

  • y -- Vector with y.numel() == A.size2()

>>> A = DM([[1, 2], [3, 4]])
>>> rank1(A, 2, DM([1, 0]), DM([0, 1]))
DM(
[[1, 4],
 [3, 4]])
>>> rank1(MX.sym("A", 2, 2), MX.sym("a"), MX.sym("x", 2), MX.sym("y", 2))
MX(rank1(A, a, x, y))
>> A = DM([1 2; 3 4]);
>> rank1(A, 2, DM([1; 0]), DM([0; 1]))
[[1, 4],
[3, 4]]
>> rank1(MX.sym('A', 2, 2), MX.sym('a'), MX.sym('x', 2), MX.sym('y', 2))
rank1(A, a, x, y)
julia> A = ca.DM([1 2; 3 4]);
julia> ca.rank1(A, 2, ca.DM([1, 0]), ca.DM([0, 1]))
DM(
[[1, 4],
 [3, 4]])
julia> ca.rank1(ca.MX.sym("A", 2, 2), ca.MX.sym("a"), ca.MX.sym("x", 2), ca.MX.sym("y", 2))
MX(rank1(A, a, x, y))

See also: bilin, mtimes

Extra doc | Doc source

rdivide(...)

Elementwise division: (x,y) -> x ./ y.

rdivide(float x, float y) -> float
rdivide(DM x, DM y) -> DM
rdivide(SX x, SX y) -> SX
rdivide(MX x, MX y) -> MX

Elementwise quotient, not a linear solve; use solve or mldivide for that. Shape rules as for plus. Division by zero follows IEEE arithmetic (inf or nan), no error is raised. Structural zeros of x stay structural zeros; dividing by a sparse y densifies.

>>> rdivide(DM([1, 2]), 4)
DM([0.25, 0.5])
>>> DM([1, 2]) / DM([4, 8])
DM([0.25, 0.25])
>>> 1 / DM.eye(2)
DM(
[[1, inf],
 [inf, 1]])
>>> DM.eye(2) / 2
DM(
[[0.5, 00],
 [00, 0.5]])
>> rdivide(DM([1; 2]), 4)
[0.25, 0.5]
>> DM([1; 2]) ./ DM([4; 8])
[0.25, 0.25]
>> 1 ./ DM.eye(2)
[[1, inf],
[inf, 1]]
>> DM.eye(2) ./ 2
[[0.5, 00],
[00, 0.5]]
julia> ca.rdivide(ca.DM([1, 2]), 4)
DM([0.25, 0.5])
julia> ca.DM([1, 2]) ./ ca.DM([4, 8])
DM([0.25, 0.25])
julia> 1 ./ ca.DM.eye(2)
DM(
[[1, inf],
 [inf, 1]])
julia> ca.DM.eye(2) / 2
DM(
[[0.5, 00],
 [00, 0.5]])

See also: mldivide, mrdivide, solve

Extra doc | Doc source | Implementation

rectangle(...)

Rectangle (gate, pulse, window) function, elementwise.

rectangle(DM x) -> DM
rectangle(SX x) -> SX

1 for |x| < 1/2, 1/2 for |x| == 1/2 and 0 for |x| > 1/2, built from sign. Not defined for MX.

>>> rectangle(DM([-1, -0.5, 0, 0.5, 1]))
DM([0, 0.5, 1, 0.5, 0])
>> rectangle(DM([-1; -0.5; 0; 0.5; 1]))
[0, 0.5, 1, 0.5, 0]
julia> ca.rectangle(ca.DM([-1, -0.5, 0, 0.5, 1]))
DM([0, 0.5, 1, 0.5, 0])

See also: triangle, heaviside

Extra doc | Doc source | Implementation

remainder(...)

Remainder after division: (x,y) -> remainder(x,y)

remainder(float x, float y) -> float
remainder(DM x, DM y) -> DM
remainder(SX x, SX y) -> SX
remainder(MX x, MX y) -> MX

This Function follows the convention of https://en.cppreference.com/w/c/numeric/math/remainder: x - n*y with n the integer nearest to x/y (ties to even), so the result lies in [-|y|/2, |y|/2].

Notably:

  • remainder(5,3) -> -1

  • remainder(5,-3) -> -1

  • remainder(-5,3) -> 1

  • remainder(-5,-3) -> 1

This is equivalent to Python's math.remainder. There is no equivalence in Matlab. Elementwise, shape rules as for plus; structural zeros of x stay zero.

>>> remainder(DM([5, 5, -5, -5]), DM([3, -3, 3, -3]))
DM([-1, -1, 1, 1])
>>> remainder(DM([2.5, 3.5]), 2)
DM([0.5, -0.5])
>>> remainder(MX.sym("x"), 2)
MX(remainder(x,2))
>> remainder(DM([5; 5; -5; -5]), DM([3; -3; 3; -3]))
[-1, -1, 1, 1]
>> remainder(DM([2.5; 3.5]), 2)
[0.5, -0.5]
>> remainder(MX.sym('x'), 2)
remainder(x,2)
julia> ca.remainder(ca.DM([5, 5, -5, -5]), ca.DM([3, -3, 3, -3]))
DM([-1, -1, 1, 1])
julia> ca.remainder(ca.DM([2.5, 3.5]), 2)
DM([0.5, -0.5])
julia> ca.remainder(ca.MX.sym("x"), 2)
MX(remainder(x,2))

See also: fmod  Extra doc: https://github.com/casadi/casadi/wiki/L_24x

Doc source | Implementation

repmat(...)

Repeat matrix A n times vertically and m times horizontally.

repmat(Sparsity A, int n, int m) -> Sparsity
repmat(Sparsity A, (int,int) rc) -> Sparsity
repmat(DM A, int n, int m) -> DM
repmat(DM A, (int,int) rc) -> DM
repmat(SX A, int n, int m) -> SX
repmat(SX A, (int,int) rc) -> SX
repmat(MX A, int n, int m) -> MX
repmat(MX A, (int,int) rc) -> MX

Tiles A into an n-by-m grid of copies; the sparsity pattern is tiled along. A zero count gives an empty matrix with the remaining dimension kept. For MX the horizontal repetition is a single node, the vertical one a vertcat of n references.

Parameters:
  • A -- Matrix (or Sparsity) to tile; any shape

  • n -- Number of vertical repetitions, non-negative

  • m -- Number of horizontal repetitions, non-negative

>>> repmat(DM([[1, 2]]), 2, 2)
DM(
[[1, 2, 1, 2],
 [1, 2, 1, 2]])
>>> repmat(DM.eye(2), 1, 2)
DM(
[[1, 00, 1, 00],
 [00, 1, 00, 1]])
>>> repmat(MX.sym("x", 2), 1, 3)
MX(repmat(x, 3))
>>> repmat(MX.sym("x", 2), 3, 1)
MX(vertcat(x, x, x))
>>> repmat(DM.ones(2, 3), 0, 2).shape
(0, 6)
>> repmat(DM([1 2]), 2, 2)
[[1, 2, 1, 2],
[1, 2, 1, 2]]
>> repmat(DM.eye(2), 1, 2)
[[1, 00, 1, 00],
[00, 1, 00, 1]]
>> repmat(MX.sym('x', 2), 1, 3)
repmat(x, 3)
>> repmat(MX.sym('x', 2), 3, 1)
vertcat(x, x, x)
>> size(repmat(DM.ones(2, 3), 0, 2))
0 6
julia> repeat(ca.DM([1 2]), 2, 2)
DM(
[[1, 2, 1, 2],
 [1, 2, 1, 2]])
julia> repeat(ca.DM.eye(2), 1, 2)
DM(
[[1, 00, 1, 00],
 [00, 1, 00, 1]])
julia> repeat(ca.MX.sym("x", 2), 1, 3)
MX(repmat(x, 3))
julia> repeat(ca.MX.sym("x", 2), 3, 1)
MX(vertcat(x, x, x))
julia> size(repeat(ca.DM.ones(2, 3), 0, 2))
(0, 6)

Extra doc | Doc source | Implementation

repsum(...)

Given a repeated matrix, computes the sum of repeated parts.

repsum(DM A, int n, int m) -> DM
repsum(SX A, int n, int m) -> SX
repsum(MX A, int n, int m) -> MX

Splits A into an n-by-m grid of equally sized blocks and returns their sum, a matrix of size A.size1()/n by A.size2()/m. The inverse of repmat(x, n, m) in the sense that repsum(repmat(x, n, m), n, m) == n*m*x. The dimensions of A must be multiples of n and m.

>>> repsum(DM([[1, 2, 3, 4], [5, 6, 7, 8]]), 1, 2)
DM(
[[4, 6],
 [12, 14]])
>>> repsum(SX.sym("x", 4), 2)
SX([(x_0+x_2), (x_1+x_3)])
>> repsum(DM([1 2 3 4; 5 6 7 8]), 1, 2)
[[4, 6],
[12, 14]]
>> repsum(SX.sym('x', 4), 2)
[(x_0+x_2), (x_1+x_3)]
julia> ca.repsum(ca.DM([1 2 3 4; 5 6 7 8]), 1, 2)
DM(
[[4, 6],
 [12, 14]])
julia> ca.repsum(ca.SX.sym("x", 4), 2)
SX([(x_0+x_2), (x_1+x_3)])

See also: repmat, blocksplit

Extra doc | Doc source | Implementation

reshape(...)

Returns a reshaped version of the matrix.

reshape(Sparsity a, (int,int) rc) -> Sparsity
reshape(Sparsity a, Sparsity sp) -> Sparsity
reshape(DM a, (int,int) rc) -> DM
reshape(DM a, Sparsity sp) -> DM
reshape(SX a, (int,int) rc) -> SX
reshape(SX a, Sparsity sp) -> SX
reshape(MX a, (int,int) rc) -> MX
reshape(MX a, Sparsity sp) -> MX
reshape(Sparsity a, int nrow, int ncol) -> Sparsity
reshape(DM a, int nrow, int ncol) -> DM
reshape(SX a, int nrow, int ncol) -> SX
reshape(MX a, int nrow, int ncol) -> MX

Reinterprets the entries of x in column-major order as a matrix of nrow by ncol, as reshape does in MATLAB and numpy with order='F'. The number of elements must not change, otherwise an error is raised. One of the dimensions can be -1, it is then inferred from the other. The sparsity pattern is reshaped along; no entries are densified. For MX this is a cheap reordering node.

Parameters:
  • x -- Matrix (or Sparsity) to reshape; any shape

  • nrow -- Number of rows of the result, or -1

  • ncol -- Number of columns of the result, or -1

>>> x = DM([[1, 2, 3], [4, 5, 6]])
>>> reshape(x, 3, 2)
DM(
[[1, 5],
 [4, 3],
 [2, 6]])
>>> reshape(x, -1, 1)
DM([1, 4, 2, 5, 3, 6])
>>> reshape(DM.eye(2), 1, 4)
DM([[1, 00, 00, 1]])
>>> reshape(MX.sym("x", 2, 3), 3, 2)
MX(reshape(x))
>>> reshape(x, 4, 2)
Traceback (most recent call last):
  ...
RuntimeError: ...number of elements must remain the same...
>> x = DM([1 2 3; 4 5 6]);
>> reshape(x, 3, 2)
[[1, 5],
[4, 3],
[2, 6]]
>> reshape(x, -1, 1)
[1, 4, 2, 5, 3, 6]
>> reshape(DM.eye(2), 1, 4)
[[1, 00, 00, 1]]
>> reshape(MX.sym('x', 2, 3), 3, 2)
reshape(x)
>> try, reshape(x, 4, 2); catch e, disp(e.message); end
...number of elements must remain the same...
julia> x = ca.DM([1 2 3; 4 5 6]);
julia> reshape(x, 3, 2)
DM(
[[1, 5],
 [4, 3],
 [2, 6]])
julia> reshape(x, :, 1)
DM([1, 4, 2, 5, 3, 6])
julia> reshape(ca.DM.eye(2), 1, 4)
DM([[1, 00, 00, 1]])
julia> reshape(ca.MX.sym("x", 2, 3), 3, 2)
MX(reshape(x))
julia> try
           reshape(x, 4, 2)
       catch err
           println(occursin("number of elements must remain", sprint(showerror, err)))
       end
true

See also: vec, sparsity_cast, transpose

Extra doc | Doc source | Implementation

reverse(...)

Reverse directional derivative.

reverse([DM] ex, [DM] arg, [[DM]] v, dict opts) -> [[DM]]
reverse([SX] ex, [SX] arg, [[SX]] v, dict opts) -> [[SX]]
reverse([MX] ex, [MX] arg, [[MX]] v, dict opts) -> [[MX]]

For each adjoint seed v[d] (a list with one seed per entry of ex, with matching shapes), computes the adjoint sensitivities with respect to every entry of arg: the result is a list over directions of lists over arg. Not defined for DM.

Parameters:
  • ex -- List of expressions

  • arg -- List of symbolic expressions

  • v -- List of directions, each a list of seeds matching ex

  • opts -- Options, see jacobian

>>> x = SX.sym("x"); y = SX.sym("y")
>>> reverse([x*y, x**2], [x, y], [[1, 0]])
[[SX(y), SX(x)]]
>>> reverse([x*y, x**2], [x, y], [[1, 1]])
[[SX(((2.*x)+y)), SX(x)]]
>> x = SX.sym('x'); y = SX.sym('y');
>> r = reverse({x*y, x^2}, {x, y}, {{1, 0}});
>> r{1}{1}, r{1}{2}
y
x
>> r = reverse({x*y, x^2}, {x, y}, {{1, 1}});
>> r{1}{1}, r{1}{2}
((2.*x)+y)
x
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.reverse([x*y, x^2], [x, y], [[ca.SX(1), ca.SX(0)]])
1-element Vector{Vector{SX}}:
 SX[y, x]
julia> ca.reverse([x*y, x^2], [x, y], [[ca.SX(1), ca.SX(1)]])
1-element Vector{Vector{SX}}:
 SX[((2.*x)+y), x]

See also: forward, jtimes, gradient, Function.reverse

Extra doc | Doc source | Implementation

rootfinder_in(...)

Get the name of a rootfinder input by index.

rootfinder_in() -> [str]
rootfinder_in(int ind) -> str
Parameters:

ind -- Index in 0.. rootfinder_n_in() -1; any other value gives an empty string

>>> rootfinder_in(0), rootfinder_in(1), repr(rootfinder_in(2))
('x0', 'p', "''")
>> rootfinder_in(0), rootfinder_in(1), isempty(rootfinder_in(2))
x0
p
1
julia> ca.rootfinder_in(0), ca.rootfinder_in(1), ca.rootfinder_in(2)
("x0", "p", "")

Get the rootfinder input scheme.

Returns the names of the 2 inputs of a Function created by rootfinder from a dictionary, in order: x0, p. A Function created from a general Function keeps that Function's input names, with "0" appended to the unknown.

>>> rootfinder_in()
['x0', 'p']
>> rootfinder_in()
x0
p
julia> ca.rootfinder_in()
2-element Vector{String}:
 "x0"
 "p"

See also: rootfinder_out, rootfinder_n_in

Extra doc | Doc source | Implementation

rootfinder_n_in(...)

Number of rootfinder inputs.

rootfinder_n_in() -> int
>>> rootfinder_n_in()
2
>> rootfinder_n_in()
2
julia> ca.rootfinder_n_in()
2

Extra doc | Doc source | Implementation

rootfinder_n_out(...)

Number of rootfinder outputs.

rootfinder_n_out() -> int
>>> rootfinder_n_out()
1
>> rootfinder_n_out()
1
julia> ca.rootfinder_n_out()
1

Extra doc | Doc source | Implementation

rootfinder_option_info(...)

Get the documentation string of an option of a rootfinder plugin.

rootfinder_option_info(str name, str op) -> str
Parameters:
  • name -- Plugin name

  • op -- Option name; an unknown option raises an error

>>> rootfinder_option_info("newton", "abstol")
'Stopping criterion tolerance on max(|F|)'
>> rootfinder_option_info('newton', 'abstol')
Stopping criterion tolerance on max(|F|)
julia> ca.rootfinder_option_info("newton", "abstol")
"Stopping criterion tolerance on max(|F|)"

Extra doc | Doc source | Implementation

rootfinder_option_type(...)

Get the type of an option of a rootfinder plugin.

rootfinder_option_type(str name, str op) -> str
Parameters:
  • name -- Plugin name

  • op -- Option name; an unknown option raises an error

Returns:

Type name such as "OT_INT", "OT_DOUBLE", "OT_BOOL"

>>> rootfinder_option_type("newton", "max_iter")
'OT_INT'
>>> rootfinder_option_type("newton", "abstol")
'OT_DOUBLE'
>> rootfinder_option_type('newton', 'max_iter')
OT_INT
>> rootfinder_option_type('newton', 'abstol')
OT_DOUBLE
julia> ca.rootfinder_option_type("newton", "max_iter")
"OT_INT"
julia> ca.rootfinder_option_type("newton", "abstol")
"OT_DOUBLE"

Extra doc | Doc source | Implementation

rootfinder_options(...)

Get all options of a rootfinder plugin.

rootfinder_options(str name) -> [str]

Returns the names of the plugin-specific options only; the options shared by all plugins (e.g. "linear_solver", "error_on_fail") are not included. Raises an error for an unknown plugin.

>>> opts = rootfinder_options("newton")
>>> "max_iter" in opts, "abstol" in opts, "linear_solver" in opts
(True, True, False)
>> opts = cellstr(rootfinder_options('newton'));
>> ismember({'max_iter', 'abstol', 'linear_solver'}, opts)
1 1 0
julia> opts = ca.rootfinder_options("newton");
julia> "max_iter" in opts, "abstol" in opts, "linear_solver" in opts
(true, true, false)

See also: rootfinder_option_type, rootfinder_option_info

Extra doc | Doc source | Implementation

rootfinder_out(...)

Get the name of a rootfinder output by index.

rootfinder_out() -> [str]
rootfinder_out(int ind) -> str
Parameters:

ind -- Index in 0.. rootfinder_n_out() -1; any other value gives an empty string

>>> rootfinder_out(0), repr(rootfinder_out(1))
('x', "''")
>> rootfinder_out(0), isempty(rootfinder_out(1))
x
1
julia> ca.rootfinder_out(0), ca.rootfinder_out(1)
("x", "")

Get the rootfinder output scheme.

Returns the name of the single output of a Function created by rootfinder from a dictionary: x.

>>> rootfinder_out()
['x']
>> rootfinder_out()
x
julia> ca.rootfinder_out()
1-element Vector{String}:
 "x"

See also: rootfinder_in, rootfinder_n_out

Extra doc | Doc source | Implementation

separate_linear(...)

Separate an expression into subexpressions that are constant, linear and

separate_linear(DM expr, DM sym_lin, DM sym_const) -> (DM, DM, DM)
separate_linear(DM expr, [DM] sym_lin, [DM] sym_const) -> (DM, DM, DM)
separate_linear(SX expr, SX sym_lin, SX sym_const) -> (SX, SX, SX)
separate_linear(SX expr, [SX] sym_lin, [SX] sym_const) -> (SX, SX, SX)
separate_linear(MX expr, MX sym_lin, MX sym_const) -> (MX, MX, MX)
separate_linear(MX expr, [MX] sym_lin, [MX] sym_const) -> (MX, MX, MX)

nonlinear.

Parameters:
  • expr[in] -- The expression to be separated

  • sym_lin[in] -- The symbolic variables w.r.t. which linearity should be checked

  • sym_const[in] -- The symbolic variables that are deemed constant

  • expr_const[out] -- The constant part of the expression

  • expr_lin[out] -- The linear part of the expression

  • expr_nonlin[out] -- The nonlinear part of the expression

Every symbol in expr must be listed in sym_lin or sym_const; otherwise an error about free variables is raised.

A post condition is that the following holds: expr = expr_const + expr_lin + expr_nonlin

Here, expr_const is only dependant on sym_const, expr_lin is linear in sym_lin (with coefficients that may depend on sym_const)

Example:

[expr_const,expr_lin,expr_nonlin] = separate_linear(cos(p)+7*x+x*y, vertcat(x,y), p)

expr_const: cos(p) expr_lin: 7*x expr_nonlin: x*y

sym_lin and sym_const may also be lists of symbols. Not defined for DM.

>>> x = SX.sym("x"); y = SX.sym("y"); p = SX.sym("p")
>>> separate_linear(cos(p) + 7*x + x*y, vertcat(x, y), p)
(SX(cos(p)), SX((7*x)), SX((x*y)))
>>> separate_linear(p*x, x, p)
(SX(0), SX((p*x)), SX(0))
>> x = SX.sym('x'); y = SX.sym('y'); p = SX.sym('p');
>> [c, l, n] = separate_linear(cos(p) + 7*x + x*y, vertcat(x, y), p);
>> c, l, n
cos(p)
(7*x)
(x*y)
>> [c, l, n] = separate_linear(p*x, x, p);
>> c, l, n
0
(p*x)
0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); p = ca.SX.sym("p");
julia> ca.separate_linear(cos(p) + 7 * x + x * y, [x; y], p)
(cos(p), (7*x), (x*y))
julia> ca.separate_linear(p * x, x, p)
(0, (p*x), 0)

See also: extract_parametric, linear_coeff

Extra doc | Doc source | Implementation

shared(...)

Extract shared subexpressions from an set of expressions.

shared([DM] ex, str v_prefix, str v_suffix) -> ([DM], [DM], [DM])
shared([SX] ex, str v_prefix, str v_suffix) -> ([SX], [SX], [SX])
shared([MX] ex, str v_prefix, str v_suffix) -> ([MX], [MX], [MX])

Same as extract with the options lift_shared true and lift_calls false: every node that is used more than once is replaced by a new symbol named v_prefix + counter

  • v_suffix. In Python the call is shared(ex, v_prefix, v_suffix) -> (ex,

v, vdef).

>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = x + y
>>> shared([sin(e)*cos(e) + e])
([SX(((sin(v_0)*cos(v_0))+v_0))], [SX(v_0)], [SX((x+y))])
>>> shared([sin(e), cos(e)], "w_", "_s")
([SX(sin(w_0_s)), SX(cos(w_0_s))], [SX(w_0_s)], [SX((x+y))])
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x + y;
>> [ex, v, vdef] = shared({sin(e)*cos(e) + e});
>> ex{1}, v{1}, vdef{1}
((sin(v_0)*cos(v_0))+v_0)
v_0
(x+y)
>> [ex, v, vdef] = shared({sin(e), cos(e)}, 'w_', '_s');
>> ex{1}, ex{2}, v{1}
sin(w_0_s)
cos(w_0_s)
w_0_s
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = x + y;
julia> ca.shared([sin(e) * cos(e) + e])
(SX[((sin(v_0)*cos(v_0))+v_0)], SX[v_0], SX[(x+y)])
julia> ca.shared([sin(e), cos(e)], "w_", "_s")
(SX[sin(w_0_s), cos(w_0_s)], SX[w_0_s], SX[(x+y)])

See also: extract, cse

Extra doc | Doc source | Implementation

sign(...)

Sign function:

sign(float x) -> float
sign(DM x) -> DM
sign(SX x) -> SX
sign(MX x) -> MX

sign(x) := -1 for x<0 sign(x) := 1 for x>0, sign(0) := 0 sign(NaN) := NaN

Elementwise; sparsity preserved. The derivative is zero everywhere.

>>> sign(DM([-2, 0, 3]))
DM([-1, 0, 1])
>>> sign(SX.sym("x"))
SX(sign(x))
>> sign(DM([-2; 0; 3]))
[-1, 0, 1]
>> sign(SX.sym('x'))
sign(x)
julia> sign.(ca.DM([-2, 0, 3]))
DM([-1, 0, 1])
julia> sign(ca.SX.sym("x"))
SX(sign(x))

See also: abs, copysign

Extra doc | Doc source | Implementation

simpleIRK(...)

Construct an implicit Runge-Kutta integrator using a collocation scheme.

simpleIRK(Function f, int N, int order, str scheme, str solver, dict solver_options) -> Function

The constructed function has three inputs, corresponding to initial state (x0), parameter (p) and integration time (h) and one output, corresponding to final state (xf).

Parameters:
  • f -- ODE function with two inputs (x and p) and one output (xdot)

  • N -- Number of integrator steps

  • order -- Order of interpolating polynomials

  • scheme -- Collocation scheme, as excepted by collocationPoints function.

  • solver -- Solver plugin

  • solver_options -- Options to be passed to the solver plugin

Extra doc | Doc source | Implementation

simpleIntegrator(...)

Simplified wrapper for the Integrator class.

simpleIntegrator(Function f, str integrator, dict integrator_options) -> Function

Extra doc | Doc source | Implementation

simpleRK(...)

Construct an explicit Runge-Kutta integrator.

simpleRK(Function f, int N, int order) -> Function

The constructed function has three inputs, corresponding to initial state (x0), parameter (p) and integration time (h) and one output, corresponding to final state (xf).

Parameters:
  • f -- ODE function with two inputs (x and p) and one output (xdot)

  • N -- Number of integrator steps

  • order -- Order of interpolating polynomials

Extra doc | Doc source | Implementation

simplify(...)

Simplify an expression.

simplify(float x) -> float
simplify(DM x) -> DM
simplify(SX x) -> SX
simplify(MX x) -> MX

For SX, applies simplification passes such as constant folding and removal of trivial operations. For MX and DM the expression is returned unchanged.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> simplify(x*2*3), simplify(x*0 + y*1)
(SX((6*x)), SX(y))
>> x = SX.sym('x'); y = SX.sym('y');
>> simplify(x*2*3), simplify(x*0 + y*1)
(6*x)
y
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.simplify(x * 2 * 3), ca.simplify(x * 0 + y * 1)
((6*x), y)

See also: transform, cse

Extra doc | Doc source | Implementation

sin(...)

Sine: x -> sin(x)

sin(float x) -> float
sin(DM x) -> DM
sin(SX x) -> SX
sin(MX x) -> MX

Elementwise; sparsity preserved (sin(0) == 0).

>>> sin(DM.eye(2))
DM(
[[0.841471, 00],
 [00, 0.841471]])
>>> sin(MX.sym("x", 2))
MX(sin(x))
>> sin(DM.eye(2))
[[0.841471, 00],
[00, 0.841471]]
>> sin(MX.sym('x', 2))
sin(x)
julia> sin.(ca.DM.eye(2))
DM(
[[0.841471, 00],
 [00, 0.841471]])
julia> sin.(ca.MX.sym("x", 2))
MX(sin(x))

See also: cos, tan, asin

Extra doc | Doc source | Implementation

sinh(...)

Hyperbolic sin: x -> sinh(x)

sinh(float x) -> float
sinh(DM x) -> DM
sinh(SX x) -> SX
sinh(MX x) -> MX

Elementwise; sparsity preserved.

>>> sinh(DM([0, 1]))
DM([0, 1.1752])
>> sinh(DM([0; 1]))
[0, 1.1752]
julia> sinh.(ca.DM([0, 1]))
DM([0, 1.1752])

See also: asinh, cosh, tanh

Extra doc | Doc source | Implementation

skew(...)

Generate a skew symmetric matrix from a 3-vector.

skew(DM a) -> DM
skew(SX a) -> SX
skew(MX a) -> MX

skew(a) is the 3-by-3 matrix S with S*b == cross(a, b).

>>> skew(DM([1, 2, 3]))
DM(
[[0, -3, 2],
 [3, 0, -1],
 [-2, 1, 0]])
>>> inv_skew(skew(DM([1, 2, 3])))
DM([1, 2, 3])
>> skew(DM([1; 2; 3]))
[[0, -3, 2],
[3, 0, -1],
[-2, 1, 0]]
>> inv_skew(skew(DM([1; 2; 3])))
[1, 2, 3]
julia> ca.skew(ca.DM([1, 2, 3]))
DM(
[[0, -3, 2],
 [3, 0, -1],
 [-2, 1, 0]])
julia> ca.inv_skew(ca.skew(ca.DM([1, 2, 3])))
DM([1, 2, 3])

See also: inv_skew, cross

Extra doc | Doc source | Implementation

soc(...)

Construct second-order-cone matrix.

soc(DM x, DM y) -> DM
soc(SX x, SX y) -> SX
soc(MX x, MX y) -> MX

soc(x, y) computes the (n+1)-by-(n+1) matrix [y*eye(n) x; x' y]. This matrix is positive semidefinite if and only if norm_2(x) <= y, which makes it a way to express a second-order cone constraint as a semidefinite constraint.

Parameters:
  • x -- Vector expression of size n (row or column; sparse entries are densified)

  • y -- Scalar expression

>>> soc(DM([1, 2]), 3)
DM(
[[3, 00, 1],
 [00, 3, 2],
 [1, 2, 3]])
>> soc(DM([1; 2]), 3)
[[3, 00, 1],
[00, 3, 2],
[1, 2, 3]]
julia> ca.soc(ca.DM([1, 2]), 3)
DM(
[[3, 00, 1],
 [00, 3, 2],
 [1, 2, 3]])

See also: norm_2

Extra doc | Doc source | Implementation

solve(...)

Solve a system of equations: A*x = b.

solve(DM A, DM b) -> DM
solve(SX A, SX b) -> SX
solve(MX A, MX b) -> MX
solve(DM A, DM b, str lsolver, dict opts) -> DM
solve(SX A, SX b, str lsolver, dict opts) -> SX
solve(MX A, MX b, str lsolver, dict opts) -> MX

The solve routine works similar to Matlab's backslash when A is square and nonsingular. The algorithm used is the following:

  1. A simple forward or backward substitution if A is upper or lower triangular

  2. If the linear system is at most 3-by-3, form the inverse via minor expansion and multiply

  3. Permute the variables and equations as to get a (structurally) nonzero diagonal, then perform a QR factorization without pivoting and solve the factorized system.

Note 1: If there are entries of the linear system known to be zero, these will be removed. Elements that are very small, or will evaluate to be zero, can still cause numerical errors, due to the lack of pivoting (which is not possible since cannot compare the size of entries)

Note 2: When permuting the linear system, a BLT (block lower triangular) transformation is formed. Only the permutation part of this is however used. An improvement would be to solve block-by-block if there are multiple BLT blocks.

The description above applies to DM and SX. For MX, triangular systems give dedicated solve nodes, an orthonormal pattern is inverted by transposition, and everything else falls back to solve(A, b, "qr"). A scalar A gives the elementwise division b/A. b may have several columns (one right-hand side each). A non-square A or a row count mismatch raises an error; a numerically singular DM returns nan or inf.

>>> A = DM([[1, 2], [3, 4]])
>>> solve(A, DM([1, 2]))
DM([0, 0.5])
>>> solve(A, DM.eye(2))
DM(
[[-2, 1],
 [1.5, -0.5]])
>>> solve(SX.sym("A", 2, 2), SX.sym("b", 2))
SX(@1=((A_0*A_3)-(A_2*A_1)), [(((A_3/@1)*b_0)-((A_2/@1)*b_1)),
(((A_0/@1)*b_1)-((A_1/@1)*b_0))])
>>> solve(MX.sym("A", 2, 2), MX.sym("b", 2))
MX((A\b))
>>> solve(DM(2), DM([1, 2]))
DM([0.5, 1])
>> A = DM([1 2; 3 4]);
>> solve(A, DM([1; 2]))
[0, 0.5]
>> solve(A, DM.eye(2))
[[-2, 1],
[1.5, -0.5]]
>> solve(SX.sym('A', 2, 2), SX.sym('b', 2))
@1=((A_0*A_3)-(A_2*A_1)), [(((A_3/@1)*b_0)-((A_2/@1)*b_1)), (((A_0/@1)*b_1)-((A_1/@1)*b_0))]
>> solve(MX.sym('A', 2, 2), MX.sym('b', 2))
(A\b)
>> solve(DM(2), DM([1; 2]))
[0.5, 1]
julia> A = ca.DM([1 2; 3 4]);
julia> ca.solve(A, ca.DM([1, 2]))
DM([0, 0.5])
julia> ca.solve(A, ca.DM.eye(2))
DM(
[[-2, 1],
 [1.5, -0.5]])
julia> ca.solve(ca.SX.sym("A", 2, 2), ca.SX.sym("b", 2))
SX(@1=((A_0*A_3)-(A_2*A_1)), [(((A_3/@1)*b_0)-((A_2/@1)*b_1)), (((A_0/@1)*b_1)-((A_1/@1)*b_0))])
julia> ca.solve(ca.MX.sym("A", 2, 2), ca.MX.sym("b", 2))
MX((A\b))
julia> ca.solve(ca.DM(2), ca.DM([1, 2]))
DM([0.5, 1])

See also: inv, mldivide, Linsol, qr

Extra doc | Doc source | Implementation

sparsify(...)

Make a matrix sparse by turning numerical zeros into structural zeros.

sparsify(DM A, float tol) -> DM
sparsify(SX A, float tol) -> SX

Every stored entry with absolute value at most tol is dropped from the sparsity pattern. With the default tol=0 only exact zeros are removed; SX entries that the symbolic simplifications already reduced to the constant 0 count as zeros. Returns a new matrix; the input is unchanged.

Parameters:
  • A -- Matrix to compact

  • tol -- Absolute threshold below which an entry counts as zero

>>> sparsify(DM([[1, 0], [0, 2]]))
DM(
[[1, 00],
 [00, 2]])
>>> A = DM([[1, 0], [1e-9, 2]])
>>> sparsify(A).nnz(), sparsify(A, 1e-6).nnz()
(3, 2)
>>> x = SX.sym("x")
>>> sparsify(vertcat(x, 0, x * 0))
SX([x, 00, 00])
>> sparsify(DM([1 0; 0 2]))
[[1, 00],
[00, 2]]
>> A = DM([1 0; 1e-9 2]);
>> fprintf('%d %d\n', sparsify(A).nnz(), sparsify(A, 1e-6).nnz())
3 2
>> x = SX.sym('x');
>> sparsify([x; 0; x * 0])
[x, 00, 00]
julia> ca.sparsify(ca.DM([1 0; 0 2]))
DM(
[[1, 00],
 [00, 2]])
julia> A = ca.DM([1 0; 1e-9 2]);
julia> ca.nnz(ca.sparsify(A)), ca.nnz(ca.sparsify(A, 1e-6))
(3, 2)
julia> x = ca.SX.sym("x");
julia> ca.sparsify([x; 0; x * 0])
SX([x, 00, 00])

See also: densify, has_zeros

Extra doc | Doc source | Implementation

sparsity_cast(...)

Cast matrix nonzeros to different Sparsity.

sparsity_cast(Sparsity a, Sparsity sp) -> Sparsity
sparsity_cast(DM a, Sparsity sp) -> DM
sparsity_cast(SX a, Sparsity sp) -> SX
sparsity_cast(MX a, Sparsity sp) -> MX

Keeps the nonzero values of x in storage order and gives them the pattern sp, which must have the same number of nonzeros (an error is raised otherwise). Unlike reshape, the dimensions and the positions of the nonzeros can change freely; only the nonzero count is preserved. This is how the nonzeros of a sparse matrix are extracted as a dense vector.

Parameters:
  • x -- Matrix (or Sparsity) whose nonzeros are reused

  • sp -- Target pattern with x.nnz() nonzeros

Returns:

Matrix of the same type as x with pattern sp

>>> sparsity_cast(DM([[1, 2], [3, 4]]), Sparsity.dense(1, 4))
DM([[1, 3, 2, 4]])
>>> sparsity_cast(DM.eye(3), Sparsity.dense(3, 1))
DM([1, 1, 1])
>>> sparsity_cast(MX.sym("x", Sparsity.diag(3)), Sparsity.dense(3, 1))
MX(nonzeros(x))
>>> sparsity_cast(MX.sym("x", 2, 2), Sparsity.dense(3, 1))
Traceback (most recent call last):
  ...
RuntimeError: ...Mismatching nonzero count...
>> sparsity_cast(DM([1 2; 3 4]), Sparsity.dense(1, 4))
[[1, 3, 2, 4]]
>> sparsity_cast(DM.eye(3), Sparsity.dense(3, 1))
[1, 1, 1]
>> sparsity_cast(MX.sym('x', Sparsity.diag(3)), Sparsity.dense(3, 1))
nonzeros(x)
>> x = MX.sym('x', 2, 2);
>> try, sparsity_cast(x, Sparsity.dense(3, 1)); catch e, disp(e.message); end
...Mismatching nonzero count...
julia> ca.sparsity_cast(ca.DM([1 2; 3 4]), ca.Sparsity.dense(1, 4))
DM([[1, 3, 2, 4]])
julia> ca.sparsity_cast(ca.DM.eye(3), ca.Sparsity.dense(3, 1))
DM([1, 1, 1])
julia> ca.sparsity_cast(ca.MX.sym("x", ca.Sparsity.diag(3)), ca.Sparsity.dense(3, 1))
MX(nonzeros(x))
julia> try
           ca.sparsity_cast(ca.MX.sym("x", 2, 2), ca.Sparsity.dense(3, 1))
       catch err
           println(occursin("Mismatching nonzero count", sprint(showerror, err)))
       end
true

See also: reshape

Extra doc | Doc source | Implementation

sprank(...)

Obtain the structural rank of a sparsity-pattern.

sprank(Sparsity A) -> int
sprank(DM A) -> int
sprank(SX A) -> int
sprank(MX A) -> int

The structural rank is the size of a maximum matching between rows and columns of the pattern (via the Dulmage-Mendelsohn decomposition): an upper bound on the numerical rank that depends only on which entries are structurally nonzero, not on their values. A dense matrix always has full structural rank, even when it is numerically singular.

Parameters:

x -- Matrix (or Sparsity); only x.sparsity() is used

Returns:

Structural rank, at most min(size1, size2)

>>> sprank(Sparsity.diag(3))
3
>>> sprank(Sparsity.triplet(3, 3, [0, 1, 2], [0, 0, 0]))
1
>>> sprank(DM([[1, 2], [2, 4]]))
2
>>> sprank(DM(2, 3))
0
>> sprank(Sparsity.diag(3))
3
>> sprank(Sparsity.triplet(3, 3, [0, 1, 2], [0, 0, 0]))
1
>> sprank(DM([1 2; 2 4]))
2
>> sprank(DM(2, 3))
0
julia> ca.sprank(ca.Sparsity.diag(3))
3
julia> ca.sprank(ca.Sparsity.triplet(3, 3, [0, 1, 2], [0, 0, 0]))
1
julia> ca.sprank(ca.DM([1 2; 2 4]))
2
julia> ca.sprank(ca.DM(2, 3))
0

Extra doc | Doc source | Implementation

sqrt(...)

Square root: x -> sqrt(x)

sqrt(float x) -> float
sqrt(DM x) -> DM
sqrt(SX x) -> SX
sqrt(MX x) -> MX

Elementwise; sparsity preserved. A negative argument gives NaN, no error is raised. A symbolic power x**0.5 simplifies to sqrt(x).

>>> sqrt(DM([4, 9]))
DM([2, 3])
>>> SX.sym("x")**0.5
SX(sqrt(x))
>> sqrt(DM([4; 9]))
[2, 3]
>> SX.sym('x').^0.5
sqrt(x)
julia> sqrt.(ca.DM([4, 9]))
DM([2, 3])
julia> ca.SX.sym("x")^0.5
SX(sqrt(x))

See also: sq, pow

Extra doc | Doc source | Implementation

stop_diff(...)

Stop derivatives of an expression with respect to all its symbolic

stop_diff(MX expr, int order) -> MX
stop_diff(MX expr, MX var, int order) -> MX

variables.

Wraps expr in a non-inlined Function call whose derivatives of the given order are declared zero. The value is unchanged. With order 1 the expression is treated as a constant by all differentiation; with order 2 first derivatives are propagated normally but second derivatives are zero. Other orders raise an error.

>>> x = MX.sym("x")
>>> e = x * stop_diff(x**2, 1)
>>> Function("f", [x], [e, jacobian(e, x)])(3)
(DM(27), DM(9))
>> x = MX.sym('x');
>> e = x * stop_diff(x^2, 1);
>> f = Function('f', {x}, {e, jacobian(e, x)});
>> [v, J] = f(3);
>> v, J
27
9
julia> x = ca.MX.sym("x");
julia> e = x * ca.stop_diff(x^2, 1);
julia> ca.Function("f", [x], [e, ca.jacobian(e, x)])(3)
(27, 9)

See also: no_grad, no_hess

Extra doc | Doc source | Implementation

substitute(...)

Substitute variable v with expression vdef in an expression ex.

substitute(DM ex, DM v, DM vdef) -> DM
substitute([DM] ex, [DM] v, [DM] vdef) -> [DM]
substitute(SX ex, SX v, SX vdef) -> SX
substitute([SX] ex, [SX] v, [SX] vdef) -> [SX]
substitute(MX ex, MX v, MX vdef) -> MX
substitute([MX] ex, [MX] v, [MX] vdef) -> [MX]

v must be symbolic and have the same shape as vdef (for SX also the same sparsity). For MX, v must be a symbolic primitive as created by MX.sym; an element of such a primitive is rejected. Substituting a symbol that does not occur in ex is a no-op. Not defined for DM.

>>> x = SX.sym("x"); y = SX.sym("y"); z = SX.sym("z")
>>> substitute(x*y + x, x, 2)
SX(((2.*y)+2))
>>> substitute(x*y + x, x, z**2)
SX(@1=sq(z), ((@1*y)+@1))
>>> p = SX.sym("p", 2)
>>> substitute(sumsqr(p), p, DM([1, 2]))
SX(5)
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> substitute(X*Y + X, X, Y)
MX((sq(Y)+Y))
>> x = SX.sym('x'); y = SX.sym('y'); z = SX.sym('z');
>> substitute(x*y + x, x, 2)
((2.*y)+2)
>> substitute(x*y + x, x, z^2)
@1=sq(z), ((@1*y)+@1)
>> p = SX.sym('p', 2);
>> substitute(sumsqr(p), p, DM([1; 2]))
5
>> X = MX.sym('X'); Y = MX.sym('Y');
>> substitute(X*Y + X, X, Y)
(sq(Y)+Y)
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); z = ca.SX.sym("z");
julia> ca.substitute(x * y + x, x, 2)
SX(((2.*y)+2))
julia> ca.substitute(x * y + x, x, z^2)
SX(@1=sq(z), ((@1*y)+@1))
julia> p = ca.SX.sym("p", 2);
julia> ca.substitute(ca.sumsqr(p), p, ca.DM([1, 2]))
SX(5)
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.substitute(X * Y + X, X, Y)
MX((sq(Y)+Y))

See also: substitute_inplace, graph_substitute, Function

Extra doc | Doc source | Implementation

substitute_inplace(...)

Inplace substitution with piggyback expressions.

substitute_inplace([DM] v, bool reverse) -> ([DM] INOUT1, [DM] INOUT2)
substitute_inplace([SX] v, bool reverse) -> ([SX] INOUT1, [SX] INOUT2)
substitute_inplace([MX] v, bool reverse) -> ([MX] INOUT1, [MX] INOUT2)

Substitute variables v out of the expressions vdef sequentially, as well as out of a number of other expressions piggyback

Interprets vdef[k] as the definition of the symbol v[k] and resolves the definitions into each other, so that afterwards neither vdef nor ex contain any of the symbols v. Both vdef and ex are modified in place (and returned, in Python). v must consist of symbolic primitives with the shapes of vdef. reverse is only accepted for SX; MX raises "Not implemented".

>>> x = SX.sym("x"); y = SX.sym("y")
>>> substitute_inplace([x, y], [y + 1, 3], [x*y])
([SX(4), SX(3)], [SX(12)])
>>> X = MX.sym("X"); Y = MX.sym("Y")
>>> substitute_inplace([X, Y], [Y + 1, 3], [X*Y])
([MX(1), MX(3)], [MX(00)])
>> x = SX.sym('x'); y = SX.sym('y');
>> [vdef, ex] = substitute_inplace({x, y}, {y + 1, 3}, {x*y});
>> vdef{1}, vdef{2}, ex{1}
4
3
12
>> X = MX.sym('X'); Y = MX.sym('Y');
>> [vdef, ex] = substitute_inplace({X, Y}, {Y + 1, 3}, {X*Y});
>> vdef{1}, vdef{2}, ex{1}
1
3
00
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.substitute_inplace([x, y], [y + 1, ca.SX(3)], [x*y])
(SX[4, 3], SX[12])
julia> X = ca.MX.sym("X"); Y = ca.MX.sym("Y");
julia> ca.substitute_inplace([X, Y], [Y + 1, ca.MX(3)], [X*Y])
(MX[1, 3], MX[00])

See also: substitute

Extra doc | Doc source | Implementation

sum(...)

Sum all elements.

sum(Sparsity x) -> Sparsity
sum(DM x) -> DM
sum(SX x) -> SX
sum(MX x) -> MX
sum(Sparsity x, int dim) -> Sparsity
sum(DM x, int dim) -> DM
sum(SX x, int dim) -> SX
sum(MX x, int dim) -> MX

Returns a 1-by-1 matrix with the sum of all elements, combining sum1 and sum2. An empty matrix sums to a structural zero.

sum also accepts an axis argument: sum(x, 0) is sum1(x) and sum(x, 1) is sum2(x).

>>> sum(DM([[1, 2, 3], [4, 5, 6]]))
DM(21)
>>> sum(DM([[1, 2, 3], [4, 5, 6]]), 0)
DM([[5, 7, 9]])
>>> sum(SX.sym("x", 3))
SX(((x_0+x_1)+x_2))
>>> sum(DM(3, 0))
DM(00)
>> sum(DM([1 2 3; 4 5 6]), 'all')
21
>> sum(DM([1 2 3; 4 5 6]))
[[5, 7, 9]]
>> sum(SX.sym('x', 3))
((x_0+x_1)+x_2)
>> sum(DM(3, 0), 'all')
00
julia> sum(ca.DM([1 2 3; 4 5 6]))
DM(21)
julia> sum(ca.DM([1 2 3; 4 5 6]), dims=1)
DM([[5, 7, 9]])
julia> sum(ca.SX.sym("x", 3))
SX(((x_0+x_1)+x_2))
julia> sum(ca.DM(3, 0))
DM(00)

See also: sum1, sum2

Extra doc | Doc source | Implementation

sum1(...)

Sum the elements of every column.

sum1(Sparsity x) -> Sparsity
sum1(DM x) -> DM
sum1(SX x) -> SX
sum1(MX x) -> MX

Returns a row vector with the sum over the rows, as MATLAB sum(x, 1); implemented as the product ones(1, size1) * x, so it is a mtimes node for MX. A column of structural zeros sums to a structural zero. For Sparsity only the pattern is computed.

>>> sum1(DM([[1, 2, 3], [4, 5, 6]]))
DM([[5, 7, 9]])
>>> sum1(SX.sym("x", 2, 2))
SX([[(x_0+x_1), (x_2+x_3)]])
>>> sum1(MX.sym("x", 2, 3))
MX(mac(ones(1x2),x,zeros(1x3)))
>>> sum1(DM(0, 3))
DM([[00, 00, 00]])
>> sum1(DM([1 2 3; 4 5 6]))
[[5, 7, 9]]
>> sum(DM([1 2 3; 4 5 6]), 1)
[[5, 7, 9]]
>> sum1(SX.sym('x', 2, 2))
[[(x_0+x_1), (x_2+x_3)]]
>> sum1(MX.sym('x', 2, 3))
mac(ones(1x2),x,zeros(1x3))
>> sum1(DM(0, 3))
[[00, 00, 00]]
julia> ca.sum1(ca.DM([1 2 3; 4 5 6]))
DM([[5, 7, 9]])
julia> ca.sum1(ca.SX.sym("x", 2, 2))
SX([[(x_0+x_1), (x_2+x_3)]])
julia> ca.sum1(ca.MX.sym("x", 2, 3))
MX(mac(ones(1x2),x,zeros(1x3)))
julia> ca.sum1(ca.DM(0, 3))
DM([[00, 00, 00]])

See also: sum2, sum

Extra doc | Doc source | Implementation

sum2(...)

Sum the elements of every row.

sum2(Sparsity x) -> Sparsity
sum2(DM x) -> DM
sum2(SX x) -> SX
sum2(MX x) -> MX

Returns a column vector with the sum over the columns, as MATLAB sum(x, 2); implemented as the product x * ones(size2, 1). A row of structural zeros sums to a structural zero.

>>> sum2(DM([[1, 2, 3], [4, 5, 6]]))
DM([6, 15])
>>> sum2(SX.sym("x", 2, 2))
SX([(x_0+x_2), (x_1+x_3)])
>>> sum2(DM(3, 3))
DM([00, 00, 00])
>> sum2(DM([1 2 3; 4 5 6]))
[6, 15]
>> sum(DM([1 2 3; 4 5 6]), 2)
[6, 15]
>> sum2(SX.sym('x', 2, 2))
[(x_0+x_2), (x_1+x_3)]
>> sum2(DM(3, 3))
[00, 00, 00]
julia> ca.sum2(ca.DM([1 2 3; 4 5 6]))
DM([6, 15])
julia> ca.sum2(ca.SX.sym("x", 2, 2))
SX([(x_0+x_2), (x_1+x_3)])
julia> ca.sum2(ca.DM(3, 3))
DM([00, 00, 00])

See also: sum1, sum

Extra doc | Doc source | Implementation

sumsqr(...)

Calculate sum of squares: sum_ij X_ij^2.

sumsqr(DM X) -> DM
sumsqr(SX X) -> SX
sumsqr(MX X) -> MX

Defined as dot(x, x) for a matrix of any shape; structural zeros contribute nothing. Prefer this over norm_2(x)**2 in objectives: it is smooth everywhere.

>>> sumsqr(DM([[1, 2], [3, 4]]))
DM(30)
>>> sumsqr(SX.sym("x", 2))
SX((sq(x_0)+sq(x_1)))
>>> sumsqr(MX.sym("x", 2))
MX(dot(x, x))
>> sumsqr(DM([1 2; 3 4]))
30
>> sumsqr(SX.sym('x', 2))
(sq(x_0)+sq(x_1))
>> sumsqr(MX.sym('x', 2))
dot(x, x)
julia> ca.sumsqr(ca.DM([1 2; 3 4]))
DM(30)
julia> ca.sumsqr(ca.SX.sym("x", 2))
SX((sq(x_0)+sq(x_1)))
julia> ca.sumsqr(ca.MX.sym("x", 2))
MX(dot(x, x))

See also: dot, norm_2, norm_fro

Extra doc | Doc source | Implementation

symvar(...)

Get all symbolic primitives present in an expression.

symvar(DM x) -> [DM]
symvar(SX x) -> [SX]
symvar(MX x) -> [MX]

Returns the symbols the expression was built from, in order of first appearance, each once. For SX every scalar symbol is a separate entry; for MX the entries are the symbolic matrices as created by MX.sym, even if only part of such a matrix is used. Presence in the graph is a structural notion; an expression like 0*x still lists x. Use depends_on for mathematical dependency. Not defined for DM.

>>> x = SX.sym("x"); y = SX.sym("y"); z = SX.sym("z")
>>> symvar(vertcat(z*x, y))
[SX(z), SX(x), SX(y)]
>>> symvar(SX.sym("v", 2)*3)
[SX(v_0), SX(v_1)]
>>> v = MX.sym("v", 2)
>>> symvar(v[0]*3)
[MX(v)]
>>> symvar(SX(3))
[]
>> x = SX.sym('x'); y = SX.sym('y'); z = SX.sym('z');
>> v = symvar(vertcat(z*x, y));
>> numel(v), vertcat(v{:})
3
[z, x, y]
>> v = symvar(SX.sym('v', 2)*3); disp(vertcat(v{:}))
[v_0, v_1]
>> v = MX.sym('v', 2);
>> s = symvar(v(1)*3); disp(numel(s)), disp(s{1})
1
v
>> numel(symvar(SX(3)))
0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); z = ca.SX.sym("z");
julia> ca.symvar([z*x; y])
3-element Vector{SX}:
 SX(z)
 SX(x)
 SX(y)
julia> ca.symvar(ca.SX.sym("v", 2) * 3)
2-element Vector{SX}:
 SX(v_0)
 SX(v_1)
julia> v = ca.MX.sym("v", 2);
julia> ca.symvar(v[1] * 3)
1-element Vector{MX}:
 MX(v)
julia> ca.symvar(ca.SX(3))
SX[]

See also: depends_on, contains

Extra doc | Doc source | Implementation

tan(...)

Tangent: x -> tan(x)

tan(float x) -> float
tan(DM x) -> DM
tan(SX x) -> SX
tan(MX x) -> MX

Elementwise; sparsity preserved.

>>> tan(DM([0, 1]))
DM([0, 1.55741])
>> tan(DM([0; 1]))
[0, 1.55741]
julia> tan.(ca.DM([0, 1]))
DM([0, 1.55741])

See also: atan, sin, cos

Extra doc | Doc source | Implementation

tangent(...)

Calculate the tangent of an expression.

tangent(DM ex, DM arg, dict opts) -> DM
tangent(SX ex, SX arg, dict opts) -> SX
tangent(MX ex, MX arg, dict opts) -> MX

Derivative of ex with respect to a scalar arg, computed with one forward-mode sweep and projected onto the sparsity of ex: the result has the shape and pattern of ex. A non-scalar arg raises an error (use jacobian).

>>> x = SX.sym("x")
>>> tangent(vertcat(x**2, 3*x), x)
SX([(2.*x), 3])
>> x = SX.sym('x');
>> tangent(vertcat(x^2, 3*x), x)
[(2.*x), 3]
julia> x = ca.SX.sym("x");
julia> ca.tangent([x^2; 3 * x], x)
SX([(2.*x), 3])

See also: gradient, jacobian, jtimes

Extra doc | Doc source | Implementation

tanh(...)

Hyperbolic tangent: x -> tanh(x)

tanh(float x) -> float
tanh(DM x) -> DM
tanh(SX x) -> SX
tanh(MX x) -> MX

Elementwise; sparsity preserved.

>>> tanh(DM([0, 1]))
DM([0, 0.761594])
>> tanh(DM([0; 1]))
[0, 0.761594]
julia> tanh.(ca.DM([0, 1]))
DM([0, 0.761594])

See also: atanh, sinh, cosh

Extra doc | Doc source | Implementation

taylor(...)

Univariate Taylor series expansion.

taylor(DM ex, DM x, DM a, int order) -> DM
taylor(SX ex, SX x, SX a, int order) -> SX

Expands ex around a with respect to the scalar symbol x up to the given order: ex(a) + ex'(a)*(x-a) + ex''(a)*(x-a)^2/2! + ... + ex^(order)(a)*(x-a)^order/order! The expansion is done entrywise for a dense matrix ex; sparse ex raises an error. a may itself be symbolic. The two-argument form expands around 0 to first order. Only defined for SX.

Parameters:
  • ex -- Dense SX expression to expand

  • x -- Scalar SX symbol

  • a -- Scalar expansion point, default 0

  • order -- Highest power of (x-a) kept, default 1; 0 gives ex(a)

>>> x = SX.sym("x"); a = SX.sym("a")
>>> taylor(sin(x), x)
SX(x)
>>> taylor(sin(x), x, a, 1)
SX((sin(a)+(cos(a)*(x-a))))
>>> taylor(exp(x), x, 0, 3)
SX(@1=sq(x), (((1+x)+(0.5*@1))+(0.166667*(@1*x))))
>>> taylor(vertcat(sin(x), cos(x)), x, 0, 2)
SX([x, (1+(-0.5*sq(x)))])
>> x = SX.sym('x'); a = SX.sym('a');
>> taylor(sin(x), x)
x
>> taylor(sin(x), x, a, 1)
(sin(a)+(cos(a)*(x-a)))
>> taylor(exp(x), x, 0, 3)
@1=sq(x), (((1+x)+(0.5*@1))+(0.166667*(@1*x)))
>> taylor([sin(x); cos(x)], x, 0, 2)
[x, (1+(-0.5*sq(x)))]
julia> x = ca.SX.sym("x"); a = ca.SX.sym("a");
julia> ca.taylor(sin(x), x)
SX(x)
julia> ca.taylor(sin(x), x, a, 1)
SX((sin(a)+(cos(a)*(x-a))))
julia> ca.taylor(exp(x), x, 0, 3)
SX(@1=sq(x), (((1+x)+(0.5*@1))+(0.166667*(@1*x))))
julia> ca.taylor([sin(x); cos(x)], x, 0, 2)
SX([x, (1+(-0.5*sq(x)))])

See also: mtaylor, linearize, linear_coeff

Extra doc | Doc source | Implementation

temporary_file(...)
temporary_file(str prefix, str suffix, str directory) -> str
times(...)

Elementwise multiplication: (x,y) -> x .* y.

times(float x, float y) -> float
times(DM x, DM y) -> DM
times(SX x, SX y) -> SX
times(MX x, MX y) -> MX

Elementwise (Hadamard) product, not the matrix product; use mtimes for that. Shape rules as for plus. The result is structurally zero wherever either operand is, so the sparsity pattern is the intersection of the patterns.

>>> times(DM([1, 2]), DM([3, 4]))
DM([3, 8])
>>> DM([[1, 2], [3, 4]]) * DM([[1, 2], [3, 4]])
DM(
[[1, 4],
 [9, 16]])
>>> DM.eye(2) * DM.ones(2, 2)
DM(
[[1, 00],
 [00, 1]])
>> times(DM([1; 2]), DM([3; 4]))
[3, 8]
>> DM([1 2; 3 4]) .* DM([1 2; 3 4])
[[1, 4],
[9, 16]]
>> DM([1 2; 3 4]) * DM([1 2; 3 4])
[[7, 10],
[15, 22]]
>> DM.eye(2) .* DM.ones(2, 2)
[[1, 00],
[00, 1]]
julia> ca.times(ca.DM([1, 2]), ca.DM([3, 4]))
DM([3, 8])
julia> ca.DM([1 2; 3 4]) .* ca.DM([1 2; 3 4])
DM(
[[1, 4],
 [9, 16]])
julia> ca.DM.eye(2) .* ca.DM.ones(2, 2)
DM(
[[1, 00],
 [00, 1]])

See also: mtimes

Extra doc | Doc source | Implementation

to_slice(...)

Construct from an index vector (requires is_slice(v) to be true)

to_slice([int] v, bool ind1) -> Slice

Doc source | Implementation

to_slice2(...)

Construct nested slices from an index vector (requires is_slice2(v) to be

to_slice2([int] v) -> std::pair< casadi::Slice,casadi::Slice >

true)

Doc source | Implementation

trace(...)

Matrix trace.

trace(DM a) -> DM
trace(SX a) -> SX
trace(MX a) -> MX

Sum of the diagonal entries of a square matrix (structural zeros contribute nothing). A non-square argument raises an error.

>>> trace(DM([[1, 2], [3, 4]]))
DM(5)
>>> trace(SX.sym("A", 2, 2))
SX((A_0+A_3))
>> trace(DM([1 2; 3 4]))
5
>> trace(SX.sym('A', 2, 2))
(A_0+A_3)
julia> ca.tr(ca.DM([1 2; 3 4]))
DM(5)
julia> ca.tr(ca.SX.sym("A", 2, 2))
SX((A_0+A_3))

See also: diag

Extra doc | Doc source | Implementation

transform(...)

Apply transformation passes to an expression.

transform(DM x, dict opts) -> DM
transform([DM] x, dict opts) -> [DM]
transform(SX x, dict opts) -> SX
transform([SX] x, dict opts) -> [SX]
transform(MX x, dict opts) -> MX
transform([MX] x, dict opts) -> [MX]
transform(DM x, [[GenericType]] passes, dict opts) -> DM
transform([DM] x, [[GenericType]] passes, dict opts) -> [DM]
transform(SX x, [[GenericType]] passes, dict opts) -> SX
transform([SX] x, [[GenericType]] passes, dict opts) -> [SX]
transform(MX x, [[GenericType]] passes, dict opts) -> MX
transform([MX] x, [[GenericType]] passes, dict opts) -> [MX]

Wraps the expression in a Function of its free symbols, applies Function::transform and re-evaluates it on the original symbols. Each pass is a list starting with a verb: "simplify" (followed by task names), "expand" or "external"; an unknown verb raises an error. Without passes a default set of simplification passes is applied.

>>> x = SX.sym("x")
>>> transform(x*2*3)
SX((6*x))
>> x = SX.sym('x');
>> transform(x*2*3)
(6*x)
julia> x = ca.SX.sym("x");
julia> ca.transform(x * 2 * 3)
SX((6*x))

See also: simplify, Function.transform

Extra doc | Doc source | Implementation

transpose(...)

Transpose.

transpose(Sparsity X) -> Sparsity
transpose(DM X) -> DM
transpose(SX X) -> SX
transpose(MX X) -> MX

Returns the transpose of X; the sparsity pattern is transposed along. Same as X.T().

>>> transpose(DM([[1, 2, 3]]))
DM([1, 2, 3])
>>> transpose(MX.sym("x", 2, 3))
MX(x')
>>> transpose(Sparsity.lower(2)) == Sparsity.upper(2)
True
>> DM([1 2 3])'
[1, 2, 3]
>> MX.sym('x', 2, 3)'
x'
>> transpose(Sparsity.lower(2)) == Sparsity.upper(2)
1
julia> ca.DM([1 2 3])'
DM([1, 2, 3])
julia> ca.MX.sym("x", 2, 3)'
MX(x')
julia> ca.is_equal(ca.transpose(ca.Sparsity.lower(2)), ca.Sparsity.upper(2))
true

Extra doc | Doc source | Implementation

triangle(...)

Triangle (hat) function, elementwise.

triangle(DM x) -> DM
triangle(SX x) -> SX

1 - |x| for |x| < 1 and 0 otherwise, built from rectangle and fabs. Not defined for MX.

>>> triangle(DM([-1, -0.5, 0, 0.5, 1]))
DM([0, 0.5, 1, 0.5, 0])
>> triangle(DM([-1; -0.5; 0; 0.5; 1]))
[0, 0.5, 1, 0.5, 0]
julia> ca.triangle(ca.DM([-1, -0.5, 0, 0.5, 1]))
DM([0, 0.5, 1, 0.5, 0])

See also: rectangle, ramp

Extra doc | Doc source | Implementation

tril(...)

Get the lower triangular part of a matrix.

tril(Sparsity a, bool includeDiagonal) -> Sparsity
tril(DM a, bool includeDiagonal) -> DM
tril(SX a, bool includeDiagonal) -> SX
tril(MX a, bool includeDiagonal) -> MX

Entries above the diagonal become structural zeros; the matrix need not be square.

Parameters:
  • x -- Matrix (or Sparsity); any shape

  • includeDiagonal -- False to drop the diagonal as well

>>> x = DM([[1, 2, 3], [4, 5, 6]])
>>> tril(x)
DM(
[[1, 00, 00],
 [4, 5, 00]])
>>> tril(x, False)
DM(
[[00, 00, 00],
 [4, 00, 00]])
>> x = DM([1 2 3; 4 5 6]);
>> tril(x)
[[1, 00, 00],
[4, 5, 00]]
>> tril(x, false)
[[00, 00, 00],
[4, 00, 00]]
julia> x = ca.DM([1 2 3; 4 5 6]);
julia> ca.tril(x)
DM(
[[1, 00, 00],
 [4, 5, 00]])
julia> ca.tril(x, false)
DM(
[[00, 00, 00],
 [4, 00, 00]])

See also: triu

Extra doc | Doc source | Implementation

tril2symm(...)

Convert a lower triangular matrix to a symmetric one.

tril2symm(DM a) -> DM
tril2symm(SX a) -> SX
tril2symm(MX a) -> MX

Returns a + a' - diag(diag(a)), i.e. mirrors the strictly lower part to the upper part. The argument must be square and have no structural nonzeros above the diagonal (a dense matrix is rejected even if numerically lower triangular).

>>> L = DM(Sparsity.lower(3), [1, 2, 3, 4, 5, 6])
>>> tril2symm(L)
DM(
[[1, 2, 3],
 [2, 4, 5],
 [3, 5, 6]])
>>> tril2symm(SX.sym("L", Sparsity.lower(2)))
SX(
[[L_0, L_1],
 [L_1, L_2]])
>> L = DM(Sparsity.lower(3), [1; 2; 3; 4; 5; 6]);
>> tril2symm(L)
[[1, 2, 3],
[2, 4, 5],
[3, 5, 6]]
>> tril2symm(SX.sym('L', Sparsity.lower(2)))
[[L_0, L_1],
[L_1, L_2]]
julia> L = ca.DM(ca.Sparsity.lower(3), [1, 2, 3, 4, 5, 6]);
julia> ca.tril2symm(L)
DM(
[[1, 2, 3],
 [2, 4, 5],
 [3, 5, 6]])
julia> ca.tril2symm(ca.SX.sym("L", ca.Sparsity.lower(2)))
SX(
[[L_0, L_1],
 [L_1, L_2]])

See also: triu2symm, tril, is_tril

Extra doc | Doc source | Implementation

triu(...)

Get the upper triangular part of a matrix.

triu(Sparsity a, bool includeDiagonal) -> Sparsity
triu(DM a, bool includeDiagonal) -> DM
triu(SX a, bool includeDiagonal) -> SX
triu(MX a, bool includeDiagonal) -> MX

Entries below the diagonal become structural zeros; the matrix need not be square. For MX this is a projection node.

Parameters:
  • x -- Matrix (or Sparsity); any shape

  • includeDiagonal -- False to drop the diagonal as well

>>> x = DM([[1, 2, 3], [4, 5, 6]])
>>> triu(x)
DM(
[[1, 2, 3],
 [00, 5, 6]])
>>> triu(x, False)
DM(
[[00, 2, 3],
 [00, 00, 6]])
>>> triu(MX.sym("x", 2, 2))
MX(project(x))
>> x = DM([1 2 3; 4 5 6]);
>> triu(x)
[[1, 2, 3],
[00, 5, 6]]
>> triu(x, false)
[[00, 2, 3],
[00, 00, 6]]
>> triu(MX.sym('x', 2, 2))
project(x)
julia> x = ca.DM([1 2 3; 4 5 6]);
julia> ca.triu(x)
DM(
[[1, 2, 3],
 [00, 5, 6]])
julia> ca.triu(x, false)
DM(
[[00, 2, 3],
 [00, 00, 6]])
julia> ca.triu(ca.MX.sym("x", 2, 2))
MX(project(x))

See also: tril

Extra doc | Doc source | Implementation

triu2symm(...)

Convert a upper triangular matrix to a symmetric one.

triu2symm(DM a) -> DM
triu2symm(SX a) -> SX
triu2symm(MX a) -> MX

Mirror image of tril2symm: the argument must be square without structural nonzeros below the diagonal.

>>> U = DM(Sparsity.upper(2), [1, 2, 3])
>>> triu2symm(U)
DM(
[[1, 2],
 [2, 3]])
>> U = DM(Sparsity.upper(2), [1; 2; 3]);
>> triu2symm(U)
[[1, 2],
[2, 3]]
julia> U = ca.DM(ca.Sparsity.upper(2), [1, 2, 3]);
julia> ca.triu2symm(U)
DM(
[[1, 2],
 [2, 3]])

See also: tril2symm, triu, is_triu

Extra doc | Doc source | Implementation

unite(...)

Unite two matrices with non-overlapping sparsity patterns.

unite(DM A, DM B) -> DM
unite(SX A, SX B) -> SX
unite(MX A, MX B) -> MX

The result has the union of both patterns with the nonzeros of A and B at their positions. Both must have the same shape; a shared structural nonzero raises "Pattern intersection not empty".

>>> A = DM(Sparsity.upper(2), [1, 2, 3])
>>> B = DM(Sparsity.triplet(2, 2, [1], [0]), [4])
>>> unite(A, B)
DM(
[[1, 2],
 [4, 3]])
>>> try: unite(DM.eye(2), DM.eye(2))
... except Exception as e: print("error")
error
>> A = DM(Sparsity.upper(2), [1; 2; 3]);
>> B = DM(Sparsity.triplet(2, 2, 1, 0), 4);
>> unite(A, B)
[[1, 2],
[4, 3]]
>> try, unite(DM.eye(2), DM.eye(2)); catch e, disp('error'); end
error
julia> A = ca.DM(ca.Sparsity.upper(2), [1, 2, 3]);
julia> B = ca.DM(ca.Sparsity.triplet(2, 2, [1], [0]), [4]);
julia> ca.unite(A, B)
DM(
[[1, 2],
 [4, 3]])
julia> try ca.unite(ca.DM.eye(2), ca.DM.eye(2)) catch e; println("error") end
error

See also: project, Sparsity.unite

Extra doc | Doc source | Implementation

vec(...)

Reshape a matrix into a column vector.

vec(Sparsity a) -> Sparsity
vec(DM a) -> DM
vec(SX a) -> SX
vec(MX a) -> MX

Stacks the columns of x on top of each other (column-major order), giving a column of length x.numel(). Same as reshape(x, x.numel(), 1); a column is returned unchanged. The sparsity pattern is carried along: no entries are densified.

a c b d turns into

a b c d

>>> vec(DM([[1, 2], [3, 4]]))
DM([1, 3, 2, 4])
>>> vec(DM.eye(2))
DM([1, 00, 00, 1])
>>> vec(MX.sym("x", 1, 3))
MX(x')
>> vec(DM([1 2; 3 4]))
[1, 3, 2, 4]
>> vec(DM.eye(2))
[1, 00, 00, 1]
>> vec(MX.sym('x', 1, 3))
x'
julia> vec(ca.DM([1 2; 3 4]))
DM([1, 3, 2, 4])
julia> vec(ca.DM.eye(2))
DM([1, 00, 00, 1])
julia> vec(ca.MX.sym("x", 1, 3))
MX(x')

See also: veccat, reshape

Extra doc | Doc source | Implementation

veccat(...)

Concatenate vertically after vectorizing every argument.

_veccat([Sparsity] x) -> Sparsity
_veccat([DM] x) -> DM
_veccat([SX] x) -> SX
_veccat([MX] x) -> MX

Every argument is first turned into a column with vec (column-major), then the columns are stacked. Arguments can have any shape, so this is the common way to collect decision variables into one vector. With no arguments the result is a 0-by-1 matrix.

Parameters:

x -- List of matrices of any shape

Returns:

Column vector of the same type as the arguments

>>> veccat(DM([[1, 2], [3, 4]]), 5)
DM([1, 3, 2, 4, 5])
>>> veccat(MX.sym("x", 2, 2), MX.sym("y", 1, 3))
MX(vertcat(vec(x), y'))
>>> veccat().shape
(0, 1)
>> veccat(DM([1 2; 3 4]), 5)
[1, 3, 2, 4, 5]
>> veccat(MX.sym('x', 2, 2), MX.sym('y', 1, 3))
vertcat(vec(x), y')
julia> ca.veccat([ca.MX.sym("x", 2, 2), ca.MX.sym("y", 1, 3)])
MX(vertcat(vec(x), y'))
julia> [vec(ca.DM([1 2; 3 4])); 5]
DM([1, 3, 2, 4, 5])

See also: vec, vertcat

Extra doc | Doc source | Implementation

vertcat(...)

Concatenate a list of matrices vertically.

_vertcat([Sparsity] v) -> Sparsity
_vertcat([DM] v) -> DM
_vertcat([SX] v) -> SX
_vertcat([MX] v) -> MX

Stacks the matrices on top of each other, in order: the result has the column count of the inputs and a row count equal to the sum of the row counts. All inputs must have the same number of columns; a 0-by-0 matrix is ignored. Type and sparsity rules are those of horzcat. With no arguments the result is a 0-by-1 matrix.

Column vectors stack cheaply; for MX, stacking matrices with more than one column is rewritten as a horizontal concatenation of the transposes.

Alternative terminology: vertical stack, vstack, vertical append, [a;b]. Inverse of vertsplit: vertcat(vertsplit(x, ...)) == x.

Parameters:

v -- List of matrices with matching column count

Returns:

Matrix with the blocks of v stacked vertically

>>> vertcat(SX.sym("x", 2), 3)
SX([x_0, x_1, 3])
>>> vertcat(DM([[1, 2]]), DM.eye(2))
DM(
[[1, 2],
 [1, 00],
 [00, 1]])
>>> vertcat(MX.sym("a", 2, 3), MX.sym("b", 1, 3))
MX(horzcat(a', b')')
>>> vertcat().shape
(0, 1)
>>> vertcat(MX.sym("a", 2, 2), MX.sym("b", 2, 3))
Traceback (most recent call last):
  ...
RuntimeError: ...vertcat dimension mismatch...
>> [SX.sym('x', 2); 3]
[x_0, x_1, 3]
>> vertcat(DM([1 2]), DM.eye(2))
[[1, 2],
[1, 00],
[00, 1]]
>> [MX.sym('a', 2, 3); MX.sym('b', 1, 3)]
horzcat(a', b')'
>> try, [MX.sym('a', 2, 2); MX.sym('b', 2, 3)]; catch e, disp(e.message); end
...vertcat dimension mismatch...
julia> [ca.SX.sym("x", 2); 3]
SX([x_0, x_1, 3])
julia> [ca.DM([1 2]); ca.DM.eye(2)]
DM(
[[1, 2],
 [1, 00],
 [00, 1]])
julia> print([ca.MX.sym("a", 2, 3); ca.MX.sym("b", 1, 3)])
horzcat(a', b')'
julia> try
           [ca.MX.sym("a", 2, 2); ca.MX.sym("b", 2, 3)]
       catch err
           println(occursin("vertcat dimension mismatch", sprint(showerror, err)))
       end
false

See also: horzcat, diagcat, veccat, vertsplit

Extra doc | Doc source | Implementation

vertsplit(...)

Split a matrix vertically into groups of rows.

vertsplit(Sparsity v, int incr) -> [Sparsity]
vertsplit(DM v, int incr) -> [DM]
vertsplit(SX v, int incr) -> [SX]
vertsplit(MX v, int incr) -> [MX]
vertsplit(Sparsity v, [int] offset) -> [Sparsity]
vertsplit(DM v, [int] offset) -> [DM]
vertsplit(SX v, [int] offset) -> [SX]
vertsplit(MX v, [int] offset) -> [MX]

Returns the row blocks x``[offset[i]:offset[i+1], :], in order. The offsets must start at 0, be non-decreasing and end at the number of rows of ``x, otherwise an error is raised. Each block carries the corresponding part of the sparsity pattern. The offsets of a list of matrices that were stacked with vertcat can be recovered with offset. Inverse of vertcat: vertcat(vertsplit(x, offset)) == x.

Parameters:
  • x -- Matrix (or Sparsity) to split; any shape

  • offset -- Start row of every block followed by the row count of x

Returns:

List of matrices of the same type as x, one per block

>>> x = SX.sym("x", 5)
>>> vertsplit(x, [0, 2, 5])
[SX([x_0, x_1]), SX([x_2, x_3, x_4])]
>>> parts = [DM.ones(2, 1), DM.ones(3, 1)]
>>> vertsplit(x, offset(parts))
[SX([x_0, x_1]), SX([x_2, x_3, x_4])]
>>> vertsplit(DM([[1, 2], [3, 4]]), [0, 1, 2])
[DM([[1, 2]]), DM([[3, 4]])]
>> x = SX.sym('x', 5);
>> v = vertsplit(x, [0, 2, 5]); disp(numel(v)), disp(v{1}), disp(v{2})
2
[x_0, x_1]
[x_2, x_3, x_4]
>> v = vertsplit(DM([1 2; 3 4]), [0, 1, 2]); disp(v{1}), disp(v{2})
[[1, 2]]
[[3, 4]]
julia> x = ca.SX.sym("x", 5);
julia> ca.vertsplit(x, [0, 2, 5])
2-element Vector{SX}:
 SX([x_0, x_1])
 SX([x_2, x_3, x_4])
julia> parts = [ca.DM.ones(2, 1), ca.DM.ones(3, 1)];
julia> ca.vertsplit(x, ca.offset(parts))
2-element Vector{SX}:
 SX([x_0, x_1])
 SX([x_2, x_3, x_4])
julia> ca.vertsplit(ca.DM([1 2; 3 4]), [0, 1, 2])
2-element Vector{DM}:
 DM([[1, 2]])
 DM([[3, 4]])

See also: vertsplit_n, horzsplit, offset

Extra doc | Doc source | Implementation

vertsplit_n(...)

Split a matrix vertically into a given number of equal groups of rows.

vertsplit_n(Sparsity v, int n) -> [Sparsity]
vertsplit_n(DM v, int n) -> [DM]
vertsplit_n(SX v, int n) -> [SX]
vertsplit_n(MX v, int n) -> [MX]

Returns n row blocks of equal height, in order. An error is raised when the row count of x is not a multiple of n or n is negative. A matrix without rows gives n copies of itself. Inverse of vertcat: vertcat(vertsplit_n(x, n)) == x.

Parameters:
  • x -- Matrix (or Sparsity) to split; any shape

  • n -- Number of blocks

Returns:

List of n matrices of the same type as x

>>> vertsplit_n(DM([1, 2, 3, 4]), 2)
[DM([1, 2]), DM([3, 4])]
>>> vertsplit_n(DM([1, 2, 3]), 2)
Traceback (most recent call last):
  ...
RuntimeError: ...must be a multiple of n...
>> v = vertsplit_n(DM([1; 2; 3; 4]), 2); disp(v{1}), disp(v{2})
[1, 2]
[3, 4]
>> try, vertsplit_n(DM([1; 2; 3]), 2); catch e, disp(e.message); end
...must be a multiple of n...
julia> ca.vertsplit_n(ca.DM([1, 2, 3, 4]), 2)
2-element Vector{DM}:
 DM([1, 2])
 DM([3, 4])
julia> try
           ca.vertsplit_n(ca.DM([1, 2, 3]), 2)
       catch err
           println(occursin("must be a multiple of n", sprint(showerror, err)))
       end
true

See also: vertsplit, horzsplit_n

Extra doc | Doc source | Implementation

which_depends(...)

Find out which variables enter with some order.

which_depends(DM expr, DM var, int order, bool tr) -> [bool]
which_depends(SX expr, SX var, int order, bool tr) -> [bool]
which_depends(MX expr, MX var, int order, bool tr) -> [bool]

Structural dependency check by sparsity propagation, without forming derivatives. With order 1, an entry depends if the corresponding Jacobian entry is structurally nonzero; with order 2, if it enters nonlinearly (second derivative structurally nonzero). Operations whose derivative is structurally zero, such as floor or sign, count as not depending.

Parameters:
  • expr -- Expression

  • var -- Symbolic expression

  • order -- 1 or 2; other values raise an error

  • tr -- When false, the result has one entry per element of var: does any element of expr depend on it. When true, one entry per element of expr: does it depend on any element of var.

Returns:

List of booleans

>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = vertcat(x*y, x**2, 3*x)
>>> which_depends(e, vertcat(x, y), 1, False)
[True, True]
>>> which_depends(e, vertcat(x, y), 1, True)
[True, True, True]
>>> which_depends(e, vertcat(x, y), 2, True)
[True, True, False]
>> x = SX.sym('x'); y = SX.sym('y');
>> e = vertcat(x*y, x^2, 3*x);
>> which_depends(e, vertcat(x, y), 1, false)
1 1
>> which_depends(e, vertcat(x, y), 1, true)
1 1 1
>> which_depends(e, vertcat(x, y), 2, true)
1 1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = [x * y; x^2; 3 * x];
julia> ca.which_depends(e, [x; y], 1, false)
2-element Vector{Bool}:
 1
 1
julia> ca.which_depends(e, [x; y], 1, true)
3-element Vector{Bool}:
 1
 1
 1
julia> ca.which_depends(e, [x; y], 2, true)
3-element Vector{Bool}:
 1
 1
 0

See also: depends_on, is_linear, jacobian_sparsity

Extra doc | Doc source | Implementation

Classes

DM

class DM(...)
assign(...)
assign(self, DM rhs)
static binary(...)
binary(int op, DM x, DM y) -> DM
static call(...)
call(Function f, [float] x) -> [float]
call(Function f, [DM] x) -> [DM]
clear(...)

Reset to an empty 0-by-0 matrix, in place.

clear(self)

Doc source

colind(...)
colind(self) -> [int]
colind(self, int col) -> int

Get the sparsity pattern. See the Sparsity class for details.

The pattern is stored in compressed column format: colind has size2()+1 entries, the nonzeros of column j are the entries colind(j) up to colind(j+1) (exclusive), and row(el) is the row index of nonzero el. Without argument, the full vectors are returned. Out-of-range indices raise an error.

>>> x = DM(Sparsity.diag(2), [5, 6])
>>> x.row(), x.colind()
([0, 1], [0, 1, 2])
>>> x.row(1), x.colind(2)
(1, 2)
>> x = DM(Sparsity.diag(2), [5; 6]);
>> x.row(), x.colind()
0 1
0 1 2
>> fprintf('%d %d\n', x.row(1), x.colind(2))
1 2
julia> x = ca.DM(ca.Sparsity.diag(2), [5, 6]);
julia> ca.row(x), ca.colind(x)
([0, 1], [0, 1, 2])
julia> ca.row(x, 1), ca.colind(x, 2)
(1, 2)

Extra doc | Doc source | Implementation

columns(...)

Get the number of columns, Octave-style syntax (same as size2())

columns(self) -> int

Extra doc | Doc source | Implementation

dep(...)

Get operand ch of a 1-by-1 SX expression.

dep(self, int ch) -> DM

Only defined for a scalar SX that is the result of an operation; a symbol, a constant or a DM raises an error.

Parameters:

ch -- Operand index, 0 or 1

>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = x * y
>>> e.dep(0), e.dep(1), e.n_dep()
(SX(x), SX(y), 2)
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x * y;
>> e.dep(0), e.dep(1), e.n_dep()
x
y
2
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = x * y;
julia> ca.dep(e, 0), ca.dep(e, 1), ca.n_dep(e)
(x, y, 2)

See also: n_dep, op

Extra doc | Doc source | Implementation

static deserialize(...)
deserialize(std::istream & stream) -> DM
deserialize(casadi::DeserializingStream & s) -> DM
deserialize(str s) -> DM

Overload: deserialize(std::istream & stream)

Build a matrix from a serialization stream.

Overload: deserialize(str s)

Build a matrix from a string produced by serialize.

A string that is not a CasADi serialization raises an error.

See also: serialize

Extra doc | Doc source

dim(...)

Get string representation of dimensions.

dim(self, bool with_nz) -> str

The representation is e.g. "4x5" or, with with_nz true, "4x5,10nz".

>>> DM.eye(3).dim(), DM.eye(3).dim(True), DM.ones(3, 3).dim(True)
('3x3', '3x3,3nz', '3x3,9nz')
>> fprintf('%s %s %s\n', DM.eye(3).dim(), DM.eye(3).dim(true), DM.ones(3, 3).dim(true))
3x3 3x3,3nz 3x3,9nz
julia> ca.dim(ca.DM.eye(3)), ca.dim(ca.DM.eye(3), true), ca.dim(ca.DM.ones(3, 3), true)
("3x3", "3x3,3nz", "3x3,9nz")

See also: size, nnz

Extra doc | Doc source | Implementation

disp(...)

Print a representation of the object to a stream.

disp(self, bool more)

Picks the layout automatically: scalar, vector, dense matrix (small or at least half full) or sparse coordinate list. This is what str() and print() use. more has no effect for matrices.

Extra doc | Doc source

element_hash(...)

Hash of the node of a 1-by-1 SX expression.

element_hash(self) -> int

Equal expressions (same node) have the same hash. Only defined for a scalar SX; a vector or a DM raises an error.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> x.element_hash() == x.element_hash(), x.element_hash() == y.element_hash()
(True, False)
>> x = SX.sym('x'); y = SX.sym('y');
>> h = x.element_hash();
>> fprintf('%d %d\n', h == x.element_hash(), h == y.element_hash())
1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.element_hash(x) == ca.element_hash(x), ca.element_hash(x) == ca.element_hash(y)
(true, false)

Extra doc | Doc source | Implementation

elements(...)

Get all elements as a flat list in column-major order (Python: elements())

elements(self) -> [float]

Like nonzeros, but structural zeros are included as 0, so the list has numel() entries.

>>> DM(Sparsity.diag(2)).elements()
[1.0, 0.0, 0.0, 1.0]
>> DM(Sparsity.diag(2)).elements()
1 0 0 1
julia> ca.elements(ca.DM(ca.Sparsity.diag(2)))
4-element Vector{Float64}:
 1.0
 0.0
 0.0
 1.0

See also: nonzeros, densify

Extra doc | Doc source

enlarge(...)

Enlarge the matrix in place, moving the existing rows and columns to new

enlarge(self, int nrow, int ncol, [int] rr, [int] cc, bool ind1)

positions.

The new shape is nrow-by-ncol. rr lists, for every existing row, its index in the enlarged matrix; cc does the same for the columns. Both must have exactly size1() and size2() entries. All other rows and columns are structurally zero.

Parameters:
  • nrow -- New number of rows

  • ncol -- New number of columns

  • rr -- New position of each existing row, length size1()

  • cc -- New position of each existing column, length size2()

  • ind1 -- True for one-based indices

>>> A = DM([[1, 2], [3, 4]])
>>> A.enlarge(3, 4, [0, 2], [0, 1])
>>> A
DM(
[[1, 2, 00, 00],
 [00, 00, 00, 00],
 [3, 4, 00, 00]])
>>> try: A.enlarge(4, 4, [0, 1], [0, 1])
... except Exception as e: print("error")
error
>> A = DM([1 2; 3 4]);
>> A.enlarge(3, 4, [1 3], [1 2], true);
>> A
[[1, 2, 00, 00],
[00, 00, 00, 00],
[3, 4, 00, 00]]
>> try, A.enlarge(4, 4, [1 2], [1 2], true); catch e, disp('error'); end
error
julia> A = ca.DM([1 2; 3 4]);
julia> ca.enlarge(A, 3, 4, [0, 2], [0, 1])
julia> A
DM(
[[1, 2, 00, 00],
 [00, 00, 00, 00],
 [3, 4, 00, 00]])
julia> try ca.enlarge(A, 4, 4, [0, 1], [0, 1]); catch; println("error") end
error

See also: resize, Sparsity.enlarge

Extra doc | Doc source

erase(...)

Erase the elements at the given linear indices, leaving structural zeros.

erase(self, [int] rr, bool ind1)
erase(self, [int] rr, [int] cc, bool ind1)

Column-major linear indices, as in get. The shape is unchanged.

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A.erase([0, -1])
>>> A
DM(
[[00, 2, 3],
 [4, 5, 00]])
>> A = DM([1 2 3; 4 5 6]);
>> A.erase([1 6], true);
>> A
[[00, 2, 3],
[4, 5, 00]]
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> ca.erase(A, [0, 5])
julia> A
DM(
[[00, 2, 3],
 [4, 5, 00]])

Erase the block at the given rows and columns, leaving structural zeros.

The shape is unchanged; the entries of the submatrix rr x cc are removed from the sparsity pattern. Negative indices count from the end; out-of-range indices raise an error.

Parameters:
  • rr -- Row indices

  • cc -- Column indices

  • ind1 -- True for one-based indices

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A.erase([0], [1])
>>> A
DM(
[[1, 00, 3],
 [4, 5, 6]])
>>> A.dim(), A.nnz()
('2x3', 5)
>> A = DM([1 2 3; 4 5 6]);
>> A.erase(1, 2, true);
>> A
[[1, 00, 3],
[4, 5, 6]]
>> fprintf('%s %d\n', A.dim(), A.nnz())
2x3 5
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> ca.erase(A, [0], [1])
julia> A
DM(
[[1, 00, 3],
 [4, 5, 6]])
julia> ca.dim(A), ca.nnz(A)
("2x3", 5)

See also: remove, sparsify

Extra doc | Doc source

export_code(...)

Export matrix in specific language.

export_code(self, str lang, dict options)

lang: only 'matlab' supported for now

options:
  inline: Indicates if you want everything on a single line (default: False)
  name: Name of exported variable (default: 'm')
  indent_level: Level of indentation (default: 0)
  spoof_zero: Replace numerical zero by a 1e-200 (default: false)
              might be needed for matlab sparse construct,
              which doesn't allow numerical zero

Extra doc | Doc source

static eye(...)

Create an n-by-n identity matrix.

eye(int n) -> DM

The result is sparse: only the n diagonal entries are structural nonzeros.

>>> DM.eye(2)
DM(
[[1, 00],
 [00, 1]])
>>> DM.eye(3).nnz(), DM.eye(0).dim()
(3, '0x0')
>> DM.eye(2)
[[1, 00],
[00, 1]]
>> fprintf('%d %s\n', DM.eye(3).nnz(), DM.eye(0).dim())
3 0x0
julia> ca.DM.eye(2)
DM(
[[1, 00],
 [00, 1]])
julia> ca.nnz(ca.DM.eye(3)), ca.dim(ca.DM.eye(0))
(3, "0x0")

See also: is_eye, Sparsity.diag

Extra doc | Doc source

static from_file(...)

Read a numerical matrix from a text file written by to_file (DM only)

from_file(str filename, str format_hint) -> DM

Same formats as to_file. In txt format, lines starting with #, % or / and empty lines are skipped, 00 marks a structural zero and a plain 0 a stored zero; every row must have the same number of columns, otherwise an error is raised. An empty file gives a 0-by-0 matrix. A missing file raises an error.

Parameters:
  • filename -- Input path

  • format_hint -- "mtx" or "txt"; empty means deduce from the extension

>>> import os, tempfile
>>> fn = os.path.join(tempfile.mkdtemp(), "a.txt")
>>> with open(fn, "w") as f: n = f.write("# comment\n1 00\n0 2\n")
>>> A = DM.from_file(fn)
>>> A
DM(
[[1, 00],
 [0, 2]])
>>> A.nnz()
3
>>> os.remove(fn); os.rmdir(os.path.dirname(fn))
>> fn = [tempname '.txt'];
>> fid = fopen(fn, 'w'); fprintf(fid, '# comment\n1 00\n0 2\n'); fclose(fid);
>> A = DM.from_file(fn);
>> A
[[1, 00],
[0, 2]]
>> A.nnz()
3
>> delete(fn);
julia> fn = joinpath(mktempdir(), "a.txt");
julia> write(fn, "# comment\n1 00\n0 2\n");
julia> A = ca.DM.from_file(fn)
DM(
[[1, 00],
 [0, 2]])
julia> ca.nnz(A)
3
julia> rm(dirname(fn), recursive=true)

See also: to_file

Extra doc | Doc source

full(...)
full(self) -> PyObject *
get(...)
get(self, bool ind1, Sparsity sp) -> DM
get(self, bool ind1, Slice rr) -> DM
get(self, bool ind1, IM rr) -> DM
get(self, bool ind1, Slice rr, Slice cc) -> DM
get(self, bool ind1, Slice rr, IM cc) -> DM
get(self, bool ind1, IM rr, Slice cc) -> DM
get(self, bool ind1, IM rr, IM cc) -> DM

Overload: get(self, bool ind1, Slice rr)

Get elements by a single (linear) index.

Backs the Python expressions x[k] and x[sp]. The index addresses elements, not nonzeros, in column-major order: element (i, j) has linear index i + j*size1(). Negative indices count from the end; out- of-range indices raise an error.

  • A scalar index returns a 1-by-1 matrix. If that element is a structural zero, the result is structurally empty (prints 00).

  • A Slice (Python slice) or a list of indices returns a column vector, except that indexing a row vector gives a row vector.

  • A matrix of indices (IM) returns a matrix of the same shape.

  • A Sparsity pattern must have the same shape as the matrix; the result is the projection of the matrix onto that pattern (entries outside it are dropped).

Note that the result of a comparison such as A > 2 is a DM of zeros and ones, not a boolean mask: indexing with it uses those values as linear indices. Use a Sparsity pattern or the nz accessor for masking.

Parameters:
  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Linear index, Slice or list/matrix of indices

  • sp -- Sparsity pattern of the same shape as the matrix

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A[1], A[2], A[-1]
(DM(4), DM(2), DM(6))
>>> A[[0, 5]]
DM([1, 6])
>>> A[Sparsity.diag(2, 3)]
DM(
[[1, 00, 00],
 [00, 5, 00]])
>>> S = DM(Sparsity.diag(2))
>>> S[1]
DM(00)
>>> A.get(False, Slice(0, 2))
DM([1, 4])
>>> try: A[6]
... except Exception as e: print("error")
error
>> A = DM([1 2 3; 4 5 6]);
>> A(2), A(3), A(end)
4
2
6
>> A([1 6])
[[1, 6]]
>> A(Sparsity.diag(2, 3))
[[1, 00, 00],
[00, 5, 00]]
>> S = DM(Sparsity.diag(2));
>> S(2)
00
>> A.get(true, [1; 2])
[1, 4]
>> try, A(7); catch e, disp('error'); end
error
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> A[2], A[3], A[end]
(4, 2, 6)
julia> A[[1, 6]]
DM([1, 6])
julia> S = ca.DM(ca.Sparsity.diag(2));
julia> S[2]
DM(00)
julia> try A[7]; catch; println("error") end
error

See also: set, get_nz, Sparsity.sub

Overload: get(self, bool ind1, Slice rr, Slice cc)

Get a submatrix by row and column indices.

Backs the Python expression x[i, j]. Each of rr and cc is a scalar, a Slice or a list/vector of indices (any order, repetitions allowed, negative counts from the end). The result has len(rr) rows and len(cc) columns and keeps the sparsity of the selected entries. Two scalar indices give a 1-by-1 matrix (structurally empty when the entry is a structural zero). Out-of-range indices raise an error.

Parameters:
  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Row index, Slice or list/matrix of row indices

  • cc -- Column index, Slice or list/matrix of column indices

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A[0, 1], A[1, -1]
(DM(2), DM(6))
>>> A[:, 1]
DM([2, 5])
>>> A[[1, 0], [0, 2]]
DM(
[[4, 6],
 [1, 3]])
>>> A[1:1, :].dim()
'0x3'
>>> x = SX.sym("x", 2, 2)
>>> x[0, :]
SX([[x_0, x_2]])
>>> DM(Sparsity.diag(2))[1, 0]
DM(00)
>>> try: A[2, 0]
... except Exception as e: print("error")
error
>> A = DM([1 2 3; 4 5 6]);
>> A(1, 2), A(2, end)
2
6
>> A(:, 2)
[2, 5]
>> A([2 1], [1 3])
[[4, 6],
[1, 3]]
>> B = A(2:1, :); disp(B.dim())
0x3
>> x = SX.sym('x', 2, 2);
>> x(1, :)
[[x_0, x_2]]
>> S = DM(Sparsity.diag(2));
>> S(2, 1)
00
>> try, A(3, 1); catch e, disp('error'); end
error
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> A[1, 2], A[2, end]
(2, 6)
julia> A[:, 2]
DM([2, 5])
julia> A[[2, 1], [1, 3]]
DM(
[[4, 6],
 [1, 3]])
julia> ca.dim(A[2:1, :])
"0x3"
julia> x = ca.SX.sym("x", 2, 2);
julia> x[1, :]
SX([[x_0, x_2]])
julia> ca.DM(ca.Sparsity.diag(2))[2, 1]
DM(00)
julia> try A[3, 1]; catch; println("error") end
error

See also: set

Extra doc | Doc source | Implementation

static get_free(...)

Get the free symbols of an SX Function.

get_free(Function f) -> [DM]

Same as Function::free_sx. Only defined for SX.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> SX.get_free(Function("f", [x], [x + y], {"allow_free": True}))
[SX(y)]
>> x = SX.sym('x'); y = SX.sym('y');
>> v = SX.get_free(Function('f', {x}, {x + y}, struct('allow_free', true)));
>> v{1}
y
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.SX.get_free(ca.Function("f", [x], [x + y], Dict("allow_free" => true)))
1-element Vector{SX}:
 SX(y)

See also: Function.free_sx, get_input

Extra doc | Doc source | Implementation

static get_input(...)

Get the symbolic input expressions of an SX Function.

get_input(Function f) -> [DM]

Same as Function::sx_in. Only defined for SX.

>>> x = SX.sym("x")
>>> SX.get_input(Function("f", [x], [x + 1]))
[SX(x)]
>> x = SX.sym('x');
>> v = SX.get_input(Function('f', {x}, {x + 1}));
>> numel(v), v{1}
1
x
julia> x = ca.SX.sym("x");
julia> ca.SX.get_input(ca.Function("f", [x], [x + 1]))
1-element Vector{SX}:
 SX(x)

See also: Function.sx_in, get_free

Extra doc | Doc source | Implementation

static get_max_depth(...)

Get the depth to which SX subexpressions are compared during simplification.

get_max_depth() -> int

See also: set_max_depth

Extra doc | Doc source | Implementation

get_nz(...)
get_nz(self, bool ind1, Slice k) -> DM
get_nz(self, bool ind1, IM k) -> DM

Get structural nonzeros by their position in the nonzero storage.

Backs the Python expression x.nz[k]. Index k runs over the nonzeros in column-major order, 0 <= k < nnz(); negative values count from the end and out-of-range values raise an error. Structural zeros are skipped, so for a dense matrix this coincides with linear indexing. The result is a column vector shaped like the index (a row vector when indexing a row vector; a matrix for a matrix index). Iterating over x.nz in Python yields the nonzeros one by one.

Parameters:
  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • k -- Nonzero index, Slice or list/matrix of indices

>>> S = DM(Sparsity.diag(3)); S[0, 2] = 7
>>> S.nz[:]
DM([1, 1, 7, 1])
>>> S.nz[2], S.nz[-1], len(S.nz)
(DM(7), DM(1), 4)
>>> x = SX.sym("x", Sparsity.lower(2))
>>> x.nz[[0, 2]]
SX([x_0, x_2])
>>> SX.sym("e", 2, 0).nz[:].dim()
'0x1'
>>> try: S.nz[4]
... except Exception as e: print("error")
error
>> S = DM(Sparsity.diag(3)); S(1, 3) = 7;
>> S.get_nz(true, Slice())
[1, 1, 7, 1]
>> S.get_nz(true, 3), S.get_nz(true, [1; 3])
7
[1, 7]
>> x = SX.sym('x', Sparsity.lower(2));
>> x.get_nz(true, [1; 3])
[x_0, x_2]
>> SX.sym('e', 2, 0).get_nz(true, Slice()).dim()
0x1
>> try, S.get_nz(true, 5); catch e, disp('error'); end
error
julia> S = ca.DM(ca.Sparsity.diag(3)); S[1, 3] = 7;
julia> S.nz[:]
DM([1, 1, 7, 1])
julia> S.nz[3], S.nz[end], length(S.nz)
(7, 1, 4)
julia> x = ca.SX.sym("x", ca.Sparsity.lower(2));
julia> x.nz[[1, 3]]
SX([x_0, x_2])
julia> ca.dim(ca.SX.sym("e", 2, 0).nz[:])
"0x1"
julia> try S.nz[5]; catch e; println(typeof(e)) end
BoundsError

See also: set_nz, get, nonzeros

Extra doc | Doc source | Implementation

get_output(...)

Get an output.

get_output(self, int oind) -> DM

Extra doc | Doc source | Implementation

static get_precision(...)

Get the precision, field width and scientific flag used when printing

get_precision() -> int

nonzeros.

Doc source | Implementation

static get_scientific(...)
get_scientific() -> bool
static get_width(...)
get_width() -> int
has_duplicates(...)
has_duplicates(self) -> bool
has_nz(...)

Check whether element (rr, cc) is a structural nonzero.

has_nz(self, int rr, int cc) -> bool

Looks only at the sparsity pattern; a stored numerical zero still counts as a nonzero. Negative indices count from the end. An index past the end raises an error.

>>> S = DM(Sparsity.diag(2))
>>> S.has_nz(0, 0), S.has_nz(0, 1), DM([0, 1]).has_nz(0, 0)
(True, False, True)
>> S = DM(Sparsity.diag(2));
>> fprintf('%d %d %d\n', S.has_nz(0, 0), S.has_nz(0, 1), DM([0; 1]).has_nz(0, 0))
1 0 1
julia> S = ca.DM(ca.Sparsity.diag(2));
julia> ca.has_nz(S, 0, 0), ca.has_nz(S, 0, 1), ca.has_nz(ca.DM([0, 1]), 0, 0)
(true, false, true)

See also: has_zeros, Sparsity.has_nz

Extra doc | Doc source | Implementation

has_output(...)

Check if a multiple output node.

has_output(self) -> bool

Extra doc | Doc source | Implementation

has_zeros(...)

Check if any structural nonzero is known to be numerically zero.

has_zeros(self) -> bool

For SX only entries that are the constant 0 count. Use sparsify to remove them.

>>> DM([1, 0]).has_zeros(), DM([1, 2]).has_zeros(), DM(2, 2).has_zeros()
(True, False, False)
>>> x = SX.sym("x")
>>> vertcat(x, 0).has_zeros(), vertcat(x, x * 0).has_zeros()
(True, True)
>> fprintf('%d %d\n', DM([1; 0]).has_zeros(), DM([1; 2]).has_zeros())
1 0
>> DM(2, 2).has_zeros()
0
>> x = SX.sym('x');
>> fprintf('%d %d\n', vertcat(x, 0).has_zeros(), vertcat(x, x * 0).has_zeros())
1 1
julia> ca.has_zeros(ca.DM([1, 0])), ca.has_zeros(ca.DM([1, 2])), ca.has_zeros(ca.DM(2, 2))
(true, false, false)
julia> x = ca.SX.sym("x");
julia> ca.has_zeros([x; 0]), ca.has_zeros([x; x * 0])
(true, true)

See also: sparsify, has_nz

Extra doc | Doc source

static inf(...)
inf(int nrow, int ncol) -> DM
inf((int,int) rc) -> DM
inf(Sparsity sp) -> DM

Create a matrix with every nonzero equal to +inf.

Takes a shape (dense result, default 1-by-1) or a sparsity pattern.

>>> DM.inf(), DM.inf(2, 1).is_inf()
(DM(inf), True)
>>> DM.inf(Sparsity.diag(2))
DM(
[[inf, 00],
 [00, inf]])
>> DM.inf(), DM.inf(2, 1).is_inf()
inf
1
>> DM.inf(Sparsity.diag(2))
[[inf, 00],
[00, inf]]
julia> ca.DM.inf(), ca.is_inf(ca.DM.inf(2, 1))
(inf, true)
julia> ca.DM.inf(ca.Sparsity.diag(2))
DM(
[[inf, 00],
 [00, inf]])

See also: nan, is_inf

Extra doc | Doc source

info(...)

Dictionary with the sparsity pattern and the nonzeros (DM only)

info(self) -> dict
>>> sorted(DM([1, 2]).info().keys())
['data', 'sparsity']
>> s = DM([1; 2]).info();
>> strjoin(sort(fieldnames(s))', ' ')
data sparsity
julia> sort(collect(keys(ca.info(ca.DM([1, 2])))))
2-element Vector{String}:
 "data"
 "sparsity"

Extra doc | Doc source | Implementation

is_call(...)

Check if function call.

is_call(self) -> bool

Extra doc | Doc source | Implementation

is_column(...)

Check if the matrix is a column vector (i.e. size2()==1)

is_column(self) -> bool

Extra doc | Doc source | Implementation

is_commutative(...)

Check whether a binary SX is commutative.

is_commutative(self) -> bool

Only defined if symbolic scalar.

Extra doc | Doc source | Implementation

is_constant(...)

Check if every entry is a numerical constant (no symbols)

is_constant(self) -> bool

Always true for DM. For SX, true when no entry depends on a symbol; the simplifications make x*0 and x-x constant. A false negative is possible for expressions that are constant only in value, e.g. x - x after other operations.

>>> x = SX.sym("x")
>>> SX([1, 2]).is_constant(), x.is_constant(), (x * 0).is_constant()
(True, False, True)
>>> vertcat(x, 1).is_constant(), SX.sym("e", 2, 0).is_constant()
(False, True)
>> x = SX.sym('x'); z = x * 0;
>> fprintf('%d %d %d\n', SX([1; 2]).is_constant(), x.is_constant(), z.is_constant())
1 0 1
>> fprintf('%d %d\n', vertcat(x, 1).is_constant(), SX.sym('e', 2, 0).is_constant())
0 1
julia> x = ca.SX.sym("x");
julia> ca.is_constant(ca.SX([1, 2])), ca.is_constant(x), ca.is_constant(x * 0)
(true, false, true)
julia> ca.is_constant([x; 1]), ca.is_constant(ca.SX.sym("e", 2, 0))
(false, true)

See also: is_symbolic, evalf

Extra doc | Doc source

is_dense(...)

Check if the matrix is dense, i.e. nnz() equals numel()

is_dense(self) -> bool

Based on the sparsity pattern only: stored numerical zeros still count as nonzeros. Empty matrices are dense.

>>> DM.zeros(2, 2).is_dense(), DM(2, 2).is_dense(), DM(0, 3).is_dense()
(True, False, True)
>> Z = DM.zeros(2, 2);
>> fprintf('%d %d %d\n', Z.is_dense(), DM(2, 2).is_dense(), DM(0, 3).is_dense())
1 0 1
julia> ca.is_dense(ca.DM.zeros(2, 2)), ca.is_dense(ca.DM(2, 2)), ca.is_dense(ca.DM(0, 3))
(true, false, true)

See also: nnz, numel, densify

Extra doc | Doc source | Implementation

is_empty(...)

Check if the matrix is empty, i.e. if one of the dimensions is zero.

is_empty(self, bool both) -> bool

With both true, only a 0-by-0 matrix counts as empty.

>>> DM(0, 3).is_empty(), DM(0, 3).is_empty(True), DM(0, 0).is_empty(True)
(True, False, True)
>>> DM(1, 1).is_empty()
False
>> E = DM(0, 3);
>> fprintf('%d %d %d\n', E.is_empty(), E.is_empty(true), DM(0, 0).is_empty(true))
1 0 1
>> DM(1, 1).is_empty()
0
julia> E = ca.DM(0, 3);
julia> ca.is_empty(E), ca.is_empty(E, true), ca.is_empty(ca.DM(0, 0), true)
(true, false, true)
julia> ca.is_empty(ca.DM(1, 1))
false

Extra doc | Doc source | Implementation

is_eye(...)

check if the matrix is an identity matrix (note that false negative answers

is_eye(self) -> bool

are possible)

Extra doc | Doc source

is_half(...)

check if the matrix is 0.5 (note that false negative answers are possible)

is_half(self) -> bool

Extra doc | Doc source

is_inf(...)

check if the matrix is inf (note that false negative answers are possible)

is_inf(self) -> bool

Extra doc | Doc source

is_integer(...)

Check if the matrix is integer-valued.

is_integer(self) -> bool

(note that false negative answers are possible)

Extra doc | Doc source

is_leaf(...)

Check if SX is a leaf of the SX graph.

is_leaf(self) -> bool

Only defined if symbolic scalar.

Extra doc | Doc source | Implementation

is_minus_inf(...)

check if the matrix is -inf (note that false negative answers are possible)

is_minus_inf(self) -> bool

Extra doc | Doc source

is_minus_one(...)

check if the matrix is -1 (note that false negative answers are possible)

is_minus_one(self) -> bool

Extra doc | Doc source

is_nonnegative(...)

check if the matrix is not negative

is_nonnegative(self) -> bool

(note that false negative answers are possible)

Extra doc | Doc source

is_one(...)

check if the matrix is 1 (note that false negative answers are possible)

is_one(self) -> bool

Extra doc | Doc source

is_op(...)

Is it a certain operation.

is_op(self, int op) -> bool

Doc source | Implementation

is_output(...)

Check if evaluation output.

is_output(self) -> bool

Extra doc | Doc source | Implementation

is_regular(...)

Check that no entry is nan, inf or -inf.

is_regular(self) -> bool

Structural zeros are ignored. For SX, every entry must be a constant: the check raises an error when it reaches a symbolic entry (an infinite constant found before it still gives false).

>>> DM([1, 2]).is_regular(), DM([1, inf]).is_regular(), DM.nan(2, 2).is_regular()
(True, False, False)
>>> DM(2, 2).is_regular(), SX([1, 2]).is_regular()
(True, True)
>>> try: SX.sym("x").is_regular()
... except Exception as e: print("error")
error
>> fprintf('%d %d\n', DM([1; 2]).is_regular(), DM([1; inf]).is_regular())
1 0
>> fprintf('%d %d\n', DM.nan(2, 2).is_regular(), DM(2, 2).is_regular())
0 1
>> SX([1; 2]).is_regular()
1
>> try, SX.sym('x').is_regular(); catch e, disp('error'); end
error
julia> ca.is_regular(ca.DM([1, 2])), ca.is_regular(ca.DM([1, Inf]))
(true, false)
julia> ca.is_regular(ca.DM.nan(2, 2))
false
julia> ca.is_regular(ca.DM(2, 2)), ca.is_regular(ca.SX([1, 2]))
(true, true)
julia> try ca.is_regular(ca.SX.sym("x")); catch; println("error") end
error

See also: nan, inf

Extra doc | Doc source | Implementation

is_row(...)

Check if the matrix is a row vector (i.e. size1()==1)

is_row(self) -> bool

Extra doc | Doc source | Implementation

is_scalar(...)

Check if the matrix is scalar, i.e. 1-by-1.

is_scalar(self, bool scalar_and_dense) -> bool
Parameters:

scalar_and_dense -- When true, a 1-by-1 matrix with a structural zero does not count

>>> x = SX.sym("x", Sparsity(1, 1))
>>> x.is_scalar(), x.is_scalar(True), SX.sym("y").is_scalar(True)
(True, False, True)
>> x = SX.sym('x', Sparsity(1, 1));
>> fprintf('%d %d %d\n', x.is_scalar(), x.is_scalar(true), SX.sym('y').is_scalar(true))
1 0 1
julia> x = ca.SX.sym("x", ca.Sparsity(1, 1));
julia> ca.is_scalar(x), ca.is_scalar(x, true), ca.is_scalar(ca.SX.sym("y"), true)
(true, false, true)

Extra doc | Doc source | Implementation

is_smooth(...)

Check whether an SX expression contains only smooth operations.

is_smooth(self) -> bool

False when any node is a non-smooth operation such as floor, ceil, sign, a comparison or if_else. Operations such as fabs, fmin and fmax count as smooth. Always true for DM.

>>> x = SX.sym("x")
>>> sin(x).is_smooth(), fabs(x).is_smooth(), floor(x).is_smooth()
(True, True, False)
>>> if_else(x > 0, x, 0).is_smooth(), (x > 0).is_smooth(), DM(1).is_smooth()
(False, False, True)
>> x = SX.sym('x');
>> fprintf('%d %d %d\n', sin(x).is_smooth(), abs(x).is_smooth(), floor(x).is_smooth())
1 1 0
>> c = x > 0; b = if_else(c, x, 0);
>> fprintf('%d %d %d\n', b.is_smooth(), c.is_smooth(), DM(1).is_smooth())
0 0 1
julia> x = ca.SX.sym("x");
julia> ca.is_smooth(sin(x)), ca.is_smooth(abs(x)), ca.is_smooth(floor(x))
(true, true, false)
julia> ca.is_smooth(ifelse(x > 0, x, 0)), ca.is_smooth(x > 0), ca.is_smooth(ca.DM(1))
(false, false, true)

Extra doc | Doc source | Implementation

is_square(...)

Check if the matrix is square, i.e. size1() equals size2()

is_square(self) -> bool

Extra doc | Doc source | Implementation

is_symbolic(...)

Check if symbolic (Dense)

is_symbolic(self) -> bool

Check if an expression is a pure symbol. Pure means that no operations should happen on the symbol (not even vec, transpose, index, concatenation, ...) By consequence, a slice of a vector-shaped MX symbol is not a symbol. However, the SX type is really a container format with scalar entries. Therefore, a slice of a vector-shaped SX symbol is still a symbol.

Sparse matrices invariable return false

seealso is_valid_input

Extra doc | Doc source | Implementation

is_tril(...)

Check if the matrix is lower triangular.

is_tril(self) -> bool

Decided on the sparsity pattern alone, see is_triu.

See also: is_triu, tril, tril2symm

Extra doc | Doc source | Implementation

is_triu(...)

Check if the matrix is upper triangular.

is_triu(self) -> bool

Decided on the sparsity pattern alone: all structural nonzeros must lie on or above the diagonal. A dense matrix with numerical zeros below the diagonal is not upper triangular. Also defined for non- square matrices.

>>> DM(Sparsity.upper(3), 1).is_triu(), DM.zeros(2, 2).is_triu(), DM(2, 2).is_triu()
(True, False, True)
>> U = DM(Sparsity.upper(3), 1);
>> fprintf('%d %d %d\n', U.is_triu(), DM.zeros(2, 2).is_triu(), DM(2, 2).is_triu())
1 0 1
julia> U = ca.DM(ca.Sparsity.upper(3), 1);
julia> ca.is_triu(U), ca.is_triu(ca.DM.zeros(2, 2)), ca.is_triu(ca.DM(2, 2))
(true, false, true)

See also: is_tril, triu, triu2symm

Extra doc | Doc source | Implementation

is_valid_input(...)

Check if matrix can be used to define function inputs.

is_valid_input(self) -> bool

is_valid_input is more forgiving than is_symbolic. Some compositions are allowed: vec, vertcat.

Sparse matrices can return true if all non-zero elements are symbolic

seealso is_symbolic

Extra doc | Doc source | Implementation

is_value(...)

check if the matrix is value

is_value(self, float val) -> bool

Extra doc | Doc source

is_vector(...)

Check if the matrix is a row or column vector.

is_vector(self) -> bool

True when size1() or size2() is one, so scalars and n-by-1 or 1-by-n empties count. A 0-by-0 matrix does not.

>>> DM(3, 1).is_vector(), DM(1, 3).is_vector(), DM(1, 1).is_vector()
(True, True, True)
>>> DM(3, 3).is_vector(), DM(0, 1).is_vector(), DM(0, 0).is_vector()
(False, True, False)
>> fprintf('%d %d %d\n', DM(3, 1).is_vector(), DM(1, 3).is_vector(), DM(1, 1).is_vector())
1 1 1
>> fprintf('%d %d %d\n', DM(3, 3).is_vector(), DM(0, 1).is_vector(), DM(0, 0).is_vector())
0 1 0
julia> ca.is_vector(ca.DM(3, 1)), ca.is_vector(ca.DM(1, 3)), ca.is_vector(ca.DM(1, 1))
(true, true, true)
julia> ca.is_vector(ca.DM(3, 3)), ca.is_vector(ca.DM(0, 1)), ca.is_vector(ca.DM(0, 0))
(false, true, false)

See also: is_row, is_column

Extra doc | Doc source | Implementation

is_zero(...)

check if the matrix is 0 (note that false negative answers are possible)

is_zero(self) -> bool

Extra doc | Doc source

static matrix_matrix(...)
matrix_matrix(int op, DM x, DM y) -> DM
static matrix_scalar(...)
matrix_scalar(int op, DM x, DM y) -> DM
n_dep(...)

Number of operands of a 1-by-1 SX expression (0 for symbols and constants)

n_dep(self) -> int

See also: dep

Extra doc | Doc source | Implementation

name(...)

Name of a 1-by-1 symbolic SX primitive.

name(self) -> str

Raises an error for a non-scalar, for an expression that is not a pure symbol, and for DM.

>>> SX.sym("x").name(), SX.sym("v", 2)[1].name()
('x', 'v_1')
>> v = SX.sym('v', 2); v2 = v(2);
>> fprintf('%s %s\n', SX.sym('x').name(), v2.name())
x v_1
julia> ca.name(ca.SX.sym("x")), ca.name(ca.SX.sym("v", 2)[2])
("x", "v_1")

See also: is_symbolic

Extra doc | Doc source | Implementation

static nan(...)
nan(int nrow, int ncol) -> DM
nan((int,int) rc) -> DM
nan(Sparsity sp) -> DM

Create a matrix with every nonzero equal to nan.

Takes a shape (dense result, default 1-by-1) or a sparsity pattern. Useful as a placeholder that is easy to detect with is_regular.

>>> DM.nan(), DM.nan((2, 1)).dim()
(DM(nan), '2x1')
>>> DM.nan(2, 2).is_regular()
False
>> DM.nan(), DM.nan([2 1]).dim()
nan
2x1
>> DM.nan(2, 2).is_regular()
0
julia> ca.DM.nan(), ca.dim(ca.DM.nan(2, 1))
(nan, "2x1")
julia> ca.is_regular(ca.DM.nan(2, 2))
false

See also: inf, is_regular

Extra doc | Doc source

nnz(...)

Get the number of structural nonzeros.

nnz(self) -> int

Counts the entries present in the sparsity pattern. Entries that are stored but numerically zero still count; structural zeros (not stored) do not. For a dense matrix this equals numel().

>>> DM.eye(3).nnz(), DM.ones(3, 3).nnz(), DM(3, 3).nnz()
(3, 9, 0)
>>> DM([[1, 0], [0, 2]]).nnz()
4
>>> MX.sym("x", 2, 0).nnz()
0
>> fprintf('%d %d %d\n', DM.eye(3).nnz(), DM.ones(3, 3).nnz(), DM(3, 3).nnz())
3 9 0
>> DM([1 0; 0 2]).nnz()
4
>> MX.sym('x', 2, 0).nnz()
0
julia> ca.nnz(ca.DM.eye(3)), ca.nnz(ca.DM.ones(3, 3)), ca.nnz(ca.DM(3, 3))
(3, 9, 0)
julia> ca.nnz(ca.DM([1 0; 0 2]))
4
julia> ca.nnz(ca.MX.sym("x", 2, 0))
0

See also: numel, nnz_lower, nnz_upper, nnz_diag, sparsity

Extra doc | Doc source | Implementation

nnz_diag(...)

Get the number of structural nonzeros on the diagonal.

nnz_diag(self) -> int

Also defined for non-square matrices.

>>> DM.ones(3, 3).nnz_diag(), DM.eye(3).nnz_diag(), DM.ones(2, 3).nnz_diag()
(3, 3, 2)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_diag(), I.nnz_diag(), B.nnz_diag())
3 3 2
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_diag(A), ca.nnz_diag(I), ca.nnz_diag(B)
(3, 3, 2)

See also: nnz, nnz_lower, nnz_upper

Extra doc | Doc source | Implementation

nnz_lower(...)

Get the number of structural nonzeros on or below the diagonal.

nnz_lower(self) -> int
>>> DM.ones(3, 3).nnz_lower(), DM.eye(3).nnz_lower(), DM.ones(2, 3).nnz_lower()
(6, 3, 3)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_lower(), I.nnz_lower(), B.nnz_lower())
6 3 3
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_lower(A), ca.nnz_lower(I), ca.nnz_lower(B)
(6, 3, 3)

See also: nnz, nnz_upper, nnz_diag

Extra doc | Doc source | Implementation

nnz_upper(...)

Get the number of structural nonzeros on or above the diagonal.

nnz_upper(self) -> int
>>> DM.ones(3, 3).nnz_upper(), DM.eye(3).nnz_upper(), DM.ones(2, 3).nnz_upper()
(6, 3, 5)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_upper(), I.nnz_upper(), B.nnz_upper())
6 3 5
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_upper(A), ca.nnz_upper(I), ca.nnz_upper(B)
(6, 3, 5)

See also: nnz, nnz_lower, nnz_diag

Extra doc | Doc source | Implementation

nonzeros(...)

Get all nonzeros.

nonzeros(self) -> [float]

Extra doc | Doc source

numel(...)

Get the number of elements, size1()*size2()

numel(self) -> int

Counts all entries, structural zeros included.

>>> DM.eye(3).numel(), MX.sym("x", 2, 0).numel(), SX.sym("x").numel()
(9, 0, 1)
>> fprintf('%d %d %d\n', DM.eye(3).numel(), MX.sym('x', 2, 0).numel(), SX.sym('x').numel())
9 0 1
julia> ca.numel(ca.DM.eye(3)), ca.numel(ca.MX.sym("x", 2, 0)), ca.numel(ca.SX.sym("x"))
(9, 0, 1)
julia> length(ca.DM.eye(3))
9

See also: nnz, size

Extra doc | Doc source | Implementation

static ones(...)
ones(int nrow, int ncol) -> DM
ones((int,int) rc) -> DM
ones(Sparsity sp) -> DM

Create a dense matrix or a matrix with specified sparsity with all entries one.

ones(sp) sets every structural nonzero of sp to one; other entries stay structurally zero.

>>> DM.ones(2, 3)
DM(
[[1, 1, 1],
 [1, 1, 1]])
>>> DM.ones(Sparsity.diag(2))
DM(
[[1, 00],
 [00, 1]])
>> DM.ones(2, 3)
[[1, 1, 1],
[1, 1, 1]]
>> DM.ones(Sparsity.diag(2))
[[1, 00],
[00, 1]]
julia> ca.DM.ones(2, 3)
DM(
[[1, 1, 1],
 [1, 1, 1]])
julia> ca.DM.ones(ca.Sparsity.diag(2))
DM(
[[1, 00],
 [00, 1]])

See also: zeros, Sparsity

Extra doc | Doc source | Implementation

op(...)

Get operation type.

op(self) -> int

Doc source | Implementation

print_dense(...)

Print as a dense matrix, one row per line, structural zeros as 00.

print_dense(self, bool truncate)

Shared SX subexpressions are printed first as @1=..., @2=....

Parameters:

truncate -- Print only 3 leading and trailing rows and columns when the matrix has more than 1000 elements and at least 7 rows or columns

>>> DM(Sparsity.diag(2)).print_dense()
[[1, 00],
 [00, 1]]
julia> ca.print_dense(ca.DM(ca.Sparsity.diag(2)))
[[1, 00],
 [00, 1]]

See also: print_sparse

Extra doc | Doc source | Implementation

print_scalar(...)

Print a 1-by-1 matrix as a bare number or expression.

print_scalar(self)

A structurally empty 1-by-1 matrix prints as 00; other shapes raise an error.

>>> DM(3).print_scalar()
3
>>> DM(1, 1).print_scalar()
00
julia> ca.print_scalar(ca.DM(3))
3
julia> ca.print_scalar(ca.DM(1, 1))
00

Extra doc | Doc source | Implementation

print_sparse(...)

Print as a list of (row, col) -> value triplets, column-major order.

print_sparse(self, bool truncate)
Parameters:

truncate -- Print only the first and last 3 nonzeros when there are more than 1000

>>> DM(Sparsity.diag(2)).print_sparse()
sparse: 2-by-2, 2 nnz
 (0, 0) -> 1
 (1, 1) -> 1
>>> DM(2, 2).print_sparse()
all zero sparse: 2-by-2
julia> ca.print_sparse(ca.DM(ca.Sparsity.diag(2)))
sparse: 2-by-2, 2 nnz
 (0, 0) -> 1
 (1, 1) -> 1
julia> ca.print_sparse(ca.DM(2, 2))
all zero sparse: 2-by-2

See also: print_dense

Extra doc | Doc source | Implementation

print_split(...)

String representation of each nonzero and of the shared subexpressions.

print_split(self) -> ([str], [str])

Returns two lists: one string per nonzero (in storage order) and the definitions of the intermediate expressions "@1", "@2", ... that the nonzero strings refer to (always empty for DM).

>>> DM([[1, 2], [3, 4]]).print_split()
(['1', '3', '2', '4'], [])
>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = x * y
>>> vertcat(e + 1, e - 1).print_split()
(['(@1+@2)', '(@1-@2)'], ['(x*y)', '1'])
>> [nz, inter] = DM([1 2; 3 4]).print_split();
>> disp(strjoin(cellstr(nz)', ' ')), disp(isempty(inter))
1 3 2 4
1
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x * y;
>> [nz, inter] = vertcat(e + 1, e - 1).print_split();
>> disp(strjoin(cellstr(nz)', ' ')), disp(strjoin(cellstr(inter)', ' '))
(@1+@2) (@1-@2)
(x*y) 1
julia> ca.print_split(ca.DM([1 2; 3 4]))
(["1", "3", "2", "4"], String[])
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = x * y;
julia> ca.print_split([e + 1; e - 1])
(["(@1+@2)", "(@1-@2)"], ["(x*y)", "1"])

Extra doc | Doc source | Implementation

print_vector(...)

Print a column vector as [a, b, ...], structural zeros as 00.

print_vector(self, bool truncate)

Only column vectors are accepted; a row vector raises an error.

Parameters:

truncate -- Print only the first and last 3 entries of vectors longer than 1000

>>> DM(Sparsity.unit(3, 1)).print_vector()
[00, 1, 00]
julia> ca.print_vector(ca.DM(ca.Sparsity.unit(3, 1)))
[00, 1, 00]

Extra doc | Doc source | Implementation

printme(...)
printme(self, DM y) -> DM
static rand(...)
rand(int nrow, int ncol) -> DM
rand((int,int) rc) -> DM
rand(Sparsity sp) -> DM

Create a matrix with uniformly distributed random numbers in [0, 1)

Takes a shape (dense result, default 1-by-1) or a sparsity pattern, in which case only the structural nonzeros get a random value. Only available for DM.

>>> DM.rand(2, 3).dim(), DM.rand().dim(), DM.rand(Sparsity.diag(3)).nnz()
('2x3', '1x1', 3)
>>> try: SX.rand(2)
... except Exception as e: print("error")
error
>> fprintf('%s %s\n', DM.rand(2, 3).dim(), DM.rand().dim())
2x3 1x1
>> DM.rand(Sparsity.diag(3)).nnz()
3
>> try, SX.rand(2); catch e, disp('error'); end
error
julia> ca.dim(ca.DM.rand(2, 3)), ca.dim(ca.DM.rand())
("2x3", "1x1")
julia> ca.nnz(ca.DM.rand(ca.Sparsity.diag(3)))
3
julia> try ca.SX.rand(2); catch; println("error") end
error

See also: rng

Extra doc | Doc source

remove(...)

Delete rows and columns, shrinking the matrix in place.

remove(self, [int] rr, [int] cc)

Both lists may be empty; duplicates are ignored, out-of-range indices raise an error.

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A.remove([0], [1])
>>> A
DM([[4, 6]])
>> A = DM([1 2 3; 4 5 6]);
>> A.remove(0, 1);
>> A
[[4, 6]]
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> ca.remove(A, [0], [1])
julia> A
DM([[4, 6]])

See also: erase

Extra doc | Doc source

reserve(...)
reserve(self, int nnz)
reserve(self, int nnz, int ncol)

Reserve storage for the given number of nonzeros (performance hint, no visible effect)

Doc source

reset_input(...)
reset_input(self)
resize(...)

Change the shape in place, keeping nonzeros that remain inside the new

resize(self, int nrow, int ncol)

bounds.

Growing appends structural zeros; shrinking drops the entries outside the new shape.

>>> A = DM([[1, 2], [3, 4]])
>>> A.resize(3, 3)
>>> A
DM(
[[1, 2, 00],
 [3, 4, 00],
 [00, 00, 00]])
>>> A.resize(1, 1)
>>> A
DM(1)
>> A = DM([1 2; 3 4]);
>> A.resize(3, 3);
>> A
[[1, 2, 00],
[3, 4, 00],
[00, 00, 00]]
>> A.resize(1, 1);
>> A
1
julia> A = ca.DM([1 2; 3 4]);
julia> ca.resize(A, 3, 3)
julia> A
DM(
[[1, 2, 00],
 [3, 4, 00],
 [00, 00, 00]])
julia> ca.resize(A, 1, 1)
julia> A
DM(1)

See also: enlarge, reshape

Extra doc | Doc source

static rng(...)

Seed the random number generator used by rand.

rng(int seed)

The generator is global to the class and is seeded from the clock at startup; seeding it makes subsequent rand calls reproducible.

>>> DM.rng(1); a = DM.rand(2, 2)
>>> DM.rng(1); b = DM.rand(2, 2)
>>> norm_inf(a - b)
DM(0)
>> DM.rng(1); a = DM.rand(2, 2);
>> DM.rng(1); b = DM.rand(2, 2);
>> norm_inf(a - b)
0
julia> ca.DM.rng(1); a = ca.DM.rand(2, 2);
julia> ca.DM.rng(1); b = ca.DM.rand(2, 2);
julia> ca.norm_inf(a - b)
DM(0)

See also: rand

Extra doc | Doc source | Implementation

row(...)
row(self) -> [int]
row(self, int el) -> int

Get the sparsity pattern. See the Sparsity class for details.

The pattern is stored in compressed column format: colind has size2()+1 entries, the nonzeros of column j are the entries colind(j) up to colind(j+1) (exclusive), and row(el) is the row index of nonzero el. Without argument, the full vectors are returned. Out-of-range indices raise an error.

>>> x = DM(Sparsity.diag(2), [5, 6])
>>> x.row(), x.colind()
([0, 1], [0, 1, 2])
>>> x.row(1), x.colind(2)
(1, 2)
>> x = DM(Sparsity.diag(2), [5; 6]);
>> x.row(), x.colind()
0 1
0 1 2
>> fprintf('%d %d\n', x.row(1), x.colind(2))
1 2
julia> x = ca.DM(ca.Sparsity.diag(2), [5, 6]);
julia> ca.row(x), ca.colind(x)
([0, 1], [0, 1, 2])
julia> ca.row(x, 1), ca.colind(x, 2)
(1, 2)

Extra doc | Doc source | Implementation

rows(...)

Get the number of rows, Octave-style syntax (same as size1())

rows(self) -> int

Extra doc | Doc source | Implementation

static scalar_matrix(...)
scalar_matrix(int op, DM x, DM y) -> DM
serialize(...)

Serialize an object.

serialize(self) -> str
serialize(self, casadi::SerializingStream & s)

Serialize to a string.

The string can be restored with deserialize of the same class (DM or SX). For SX the whole expression graph is stored, symbols included.

>>> s = DM([[1, 2], [3, 4]]).serialize()
>>> DM.deserialize(s)
DM(
[[1, 2],
 [3, 4]])
>>> x = SX.sym("x")
>>> SX.deserialize((sin(x) + x).serialize())
SX((sin(x)+x))
>> s = DM([1 2; 3 4]).serialize();
>> DM.deserialize(s)
[[1, 2],
[3, 4]]
>> x = SX.sym('x'); e = sin(x) + x;
>> SX.deserialize(e.serialize())
(sin(x)+x)
julia> s = ca.serialize(ca.DM([1 2; 3 4]));
julia> ca.DM.deserialize(s)
DM(
[[1, 2],
 [3, 4]])
julia> x = ca.SX.sym("x");
julia> ca.SX.deserialize(ca.serialize(sin(x) + x))
SX((sin(x)+x))

See also: deserialize, StringSerializer

Extra doc | Doc source

set(...)
set(self, DM m, bool ind1, Sparsity sp)
set(self, DM m, bool ind1, Slice rr)
set(self, DM m, bool ind1, IM rr)
set(self, DM m, bool ind1, Slice rr, Slice cc)
set(self, DM m, bool ind1, Slice rr, IM cc)
set(self, DM m, bool ind1, IM rr, Slice cc)
set(self, DM m, bool ind1, IM rr, IM cc)

Overload: set(self, DM m, bool ind1, Slice rr)

Assign elements by a single (linear) index.

Backs the Python statements x[k] = v and x[sp] = v. Indices are linear, column-major and zero-based (see get). The matrix is modified in place.

  • m must be a scalar (assigned to every selected element) or have as many entries as there are indices (a vector of the other orientation is transposed). Any other shape raises an error.

  • Assigning to a structural zero inserts a new nonzero; the sparsity pattern grows. Assigning a structurally empty value (e.g. DM(1, 1)) removes the entry instead.

  • With a Sparsity index of the same shape, the entries at the pattern's positions receive m (a scalar) or the corresponding entries of m (a matrix).

Parameters:
  • m -- Value(s) to assign

  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Linear index, Slice or list/matrix of indices

  • sp -- Sparsity pattern of the same shape as the matrix

>>> A = DM([[1, 2], [3, 4]])
>>> A[1] = 10; A[[0, 3]] = [7, 8]
>>> A
DM(
[[7, 2],
 [10, 8]])
>>> A[Sparsity.diag(2)] = 0
>>> A
DM(
[[0, 2],
 [10, 0]])
>>> S = DM(Sparsity.diag(2))
>>> S[1] = 5
>>> S.nnz(), S[0, 1]
(3, DM(00))
>>> try: A[[0, 1]] = [1, 2, 3]
... except Exception as e: print("error")
error
>> A = DM([1 2; 3 4]);
>> A(2) = 10; A([1 4]) = [7 8];
>> A
[[7, 2],
[10, 8]]
>> A(Sparsity.diag(2)) = 0;
>> A
[[0, 2],
[10, 0]]
>> S = DM(Sparsity.diag(2));
>> S(2) = 5;
>> S.nnz(), S(1, 2)
3
00
>> try, A([1 2]) = [1 2 3]; catch e, disp('error'); end
error
julia> A = ca.DM([1 2; 3 4]);
julia> A[2] = 10; A[[1, 4]] = [7, 8];
julia> A
DM(
[[7, 2],
 [10, 8]])
julia> S = ca.DM(ca.Sparsity.diag(2));
julia> S[2] = 5;
julia> ca.nnz(S), S[1, 2]
(3, 00)
julia> try A[[1, 2]] = [1, 2, 3]; catch; println("error") end
error

See also: get, set_nz, erase

Overload: set(self, DM m, bool ind1, Slice rr, Slice cc)

Assign a submatrix by row and column indices.

Backs the Python statement x[i, j] = v. The matrix is modified in place. m must be len(rr)-by-len(cc), a scalar (broadcast to all selected entries) or a vector of the transposed orientation (transposed automatically); other shapes raise an error. Assigning into structural zeros inserts nonzeros; assigning a sparse m first erases the selected block, so its structural zeros become structural zeros.

Parameters:
  • m -- Value(s) to assign

  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Row index, Slice or list/matrix of row indices

  • cc -- Column index, Slice or list/matrix of column indices

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A[0, 1] = 9; A[1, :] = 0
>>> A
DM(
[[1, 9, 3],
 [0, 0, 0]])
>>> A[0, :] = DM([7, 8, 9])
>>> A[0, :]
DM([[7, 8, 9]])
>>> A[:, 0] = DM(2, 1)
>>> A.nnz()
4
>>> x = SX.sym("x", 2, 2)
>>> x[0, 0] = 0
>>> x
SX(
[[0, x_2],
 [x_1, x_3]])
>>> try: A[0, :] = [1, 2]
... except Exception as e: print("error")
error
>> A = DM([1 2 3; 4 5 6]);
>> A(1, 2) = 9; A(2, :) = 0;
>> A
[[1, 9, 3],
[0, 0, 0]]
>> A(1, :) = DM([7; 8; 9]);
>> A(1, :)
[[7, 8, 9]]
>> A(:, 1) = DM(2, 1);
>> A.nnz()
4
>> x = SX.sym('x', 2, 2);
>> x(1, 1) = 0;
>> x
[[0, x_2],
[x_1, x_3]]
>> try, A(1, :) = [1 2]; catch e, disp('error'); end
error
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> A[1, 2] = 9; A[2, :] = 0;
julia> A
DM(
[[1, 9, 3],
 [0, 0, 0]])
julia> A[1, :] = ca.DM([7, 8, 9]);
julia> A[1, :]
DM([[7, 8, 9]])
julia> A[:, 1] = ca.DM(2, 1);
julia> ca.nnz(A)
4
julia> x = ca.SX.sym("x", 2, 2);
julia> x[1, 1] = 0;
julia> x
SX(
[[0, x_2],
 [x_1, x_3]])
julia> try A[1, :] = [1, 2]; catch; println("error") end
error

See also: get

Extra doc | Doc source | Implementation

static set_max_depth(...)

Set the depth to which SX subexpressions are compared during simplification.

set_max_depth(int eq_depth)

The on-the-fly simplifications (x - x -> 0, x/x -> 1, x == x -> 1, ...) recognise two operands as equal when they are the same node, or, up to this depth, when they are the same operation applied to equal operands. Depth 1 (the default) recognises (x+y) - (x+y); depth 2 also sin(x+y) - sin(x+y). Depth 0 compares nodes only. Global setting, SX only; calling without an argument restores the default.

Parameters:

eq_depth -- Comparison depth, default 1

>>> x = SX.sym("x"); y = SX.sym("y")
>>> sin(x + y) - sin(x + y)
SX((sin((x+y))-sin((x+y))))
>>> SX.set_max_depth(2)
>>> sin(x + y) - sin(x + y)
SX(0)
>>> SX.set_max_depth()
>>> SX.get_max_depth()
1
>> x = SX.sym('x'); y = SX.sym('y');
>> sin(x + y) - sin(x + y)
(sin((x+y))-sin((x+y)))
>> SX.set_max_depth(2);
>> sin(x + y) - sin(x + y)
0
>> SX.set_max_depth();
>> SX.get_max_depth()
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> sin(x + y) - sin(x + y)
SX((sin((x+y))-sin((x+y))))
julia> ca.SX.set_max_depth(2)
julia> sin(x + y) - sin(x + y)
SX(0)
julia> ca.SX.set_max_depth()
julia> ca.SX.get_max_depth()
1

See also: get_max_depth, is_equal

Extra doc | Doc source | Implementation

set_nz(...)
set_nz(self, DM m, bool ind1, Slice k)
set_nz(self, DM m, bool ind1, IM k)

Assign structural nonzeros by their position in the nonzero storage.

Backs the Python statement x.nz[k] = v. The sparsity pattern never changes: only stored values are overwritten (writing 0 keeps the entry as a structural nonzero). m must be a scalar (assigned to every selected nonzero) or have as many entries as there are indices; a mismatch raises an error.

Parameters:
  • m -- Value(s) to assign

  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • k -- Nonzero index, Slice or list/matrix of indices

>>> S = DM(Sparsity.diag(3))
>>> S.nz[:] = [4, 5, 6]; S.nz[0] = 0
>>> S
DM(
[[0, 00, 00],
 [00, 5, 00],
 [00, 00, 6]])
>>> S.nnz()
3
>>> try: S.nz[[0, 1]] = [1, 2, 3]
... except Exception as e: print("error")
error
>> S = DM(Sparsity.diag(3));
>> S.set_nz([4 5 6], true, 1:3); S.set_nz(0, true, 1);
>> S
[[0, 00, 00],
[00, 5, 00],
[00, 00, 6]]
>> S.nnz()
3
>> try, S.set_nz([1 2 3], true, [1 2]); catch e, disp('error'); end
error
julia> S = ca.DM(ca.Sparsity.diag(3));
julia> S.nz[:] = [4, 5, 6]; S.nz[1] = 0;
julia> S
DM(
[[0, 00, 00],
 [00, 5, 00],
 [00, 00, 6]])
julia> ca.nnz(S)
3
julia> try S.nz[[1, 2]] = [1, 2, 3]; catch; println("error") end
error

See also: get_nz, set

Extra doc | Doc source | Implementation

static set_precision(...)

Set the precision, field width and scientific flag used when printing

set_precision(int precision)

nonzeros.

Global settings per class (DM and SX each keep their own), applied by str(), print() and the print_* methods. Defaults: precision 6, width 0, scientific false.

>>> DM.set_precision(3)
>>> DM(1/3)
DM(0.333)
>>> DM.set_precision(6)
>>> DM(1/3)
DM(0.333333)
>> DM.set_precision(3);
>> DM(1/3)
0.333
>> DM.set_precision(6);
>> DM(1/3)
0.333333
julia> ca.DM.set_precision(3)
julia> ca.DM(1/3)
DM(0.333)
julia> ca.DM.set_precision(6)
julia> ca.DM(1/3)
DM(0.333333)

See also: get_precision

Extra doc | Doc source | Implementation

static set_scientific(...)
set_scientific(bool scientific)
static set_width(...)
set_width(int width)
size(...)

Get the size along a particular dimension.

size(self) -> (int,int)
size(self, int axis) -> int
Parameters:

axis -- 1 for the number of rows, 2 for the number of columns; any other value raises an error

Get the shape as a pair (number of rows, number of columns)

>>> x = MX.sym("x", 2, 3)
>>> x.size(), x.size(1), x.size(2)
((2, 3), 2, 3)
>> x = MX.sym('x', 2, 3);
>> size(x)
2 3
>> fprintf('%d %d\n', size(x, 1), size(x, 2))
2 3
julia> x = ca.MX.sym("x", 2, 3);
julia> size(x), size(x, 1), size(x, 2)
((2, 3), 2, 3)

See also: size1, size2, numel, dim

Extra doc | Doc source | Implementation

size1(...)

Get the first dimension (i.e. number of rows)

size1(self) -> int
>>> x = MX.sym("x", 2, 3)
>>> x.size1(), x.size2()
(2, 3)
>> x = MX.sym('x', 2, 3);
>> fprintf('%d %d\n', x.size1(), x.size2())
2 3
julia> x = ca.MX.sym("x", 2, 3);
julia> ca.size1(x), ca.size2(x)
(2, 3)

See also: size2, size, rows

Extra doc | Doc source | Implementation

size2(...)

Get the second dimension (i.e. number of columns)

size2(self) -> int

See also: size1, size, columns

Extra doc | Doc source | Implementation

sparse(...)
sparse(self) -> PyObject *
sparsity(...)

Get the sparsity pattern (Python: sparsity())

sparsity(self) -> Sparsity

Returns a copy of the Sparsity object; patterns are reference counted, so this is cheap.

>>> DM(Sparsity.diag(2)).sparsity()
Sparsity(2x2,2nz)
>> DM(Sparsity.diag(2)).sparsity()
2x2,2nz
julia> ca.sparsity(ca.DM(ca.Sparsity.diag(2)))
Sparsity(2x2,2nz)

See also: nonzeros

Extra doc | Doc source

str(...)

Get the string representation that disp prints.

str(self, bool more) -> str

Doc source

static sym(...)

Create a list of length r of lists of length p of nrow-by-ncol symbolic

sym(str name, int nrow, int ncol) -> DM
sym(str name, (int,int) rc) -> DM
sym(str name, Sparsity sp) -> DM
sym(str name, Sparsity sp, int p) -> [DM]
sym(str name, int nrow, int ncol, int p) -> [DM]
sym(str name, Sparsity sp, int p, int r) -> [[DM]]
sym(str name, int nrow, int ncol, int p, int r) -> [[DM]]

primitives.

>>> MX.sym("x", 1, 1, 2, 2)
[[MX(x_00), MX(x_01)], [MX(x_10), MX(x_11)]]
>> v = MX.sym('x', 1, 1, 2, 2);
>> numel(v), v{1}{2}, v{2}{1}
2
x_01
x_10
julia> ca.MX.sym("x", 1, 1, 2, 2)
2-element Vector{Vector{MX}}:
 MX[x_00, x_01]
 MX[x_10, x_11]

Overload: sym(str name, int nrow, int ncol)

Create an nrow-by-ncol symbolic primitive.

Creates a new, dense symbol; two symbols with the same name are still different symbols. For SX each entry is a separate scalar symbol named name_k (k the column-major index), while an MX symbol is a single node with the given name. Only SX and MX have symbols; DM.sym raises an error.

Parameters:
  • name -- Name used for printing. For SX, a name of the form "[a,b,c]" assigns individual names to the numel() entries.

  • nrow -- Number of rows, default 1

  • ncol -- Number of columns, default 1

>>> SX.sym("x"), MX.sym("x", 2, 3).dim()
(SX(x), '2x3')
>>> SX.sym("x", 2, 2)
SX(
[[x_0, x_2],
 [x_1, x_3]])
>>> SX.sym("[a,b,c]", 3)
SX([a, b, c])
>>> is_equal(SX.sym("x"), SX.sym("x"))
False
>> SX.sym('x'), MX.sym('x', 2, 3).dim()
x
2x3
>> SX.sym('x', 2, 2)
[[x_0, x_2],
[x_1, x_3]]
>> SX.sym('[a,b,c]', 3)
[a, b, c]
>> is_equal(SX.sym('x'), SX.sym('x'))
0
julia> ca.SX.sym("x"), ca.dim(ca.MX.sym("x", 2, 3))
(x, "2x3")
julia> ca.SX.sym("x", 2, 2)
SX(
[[x_0, x_2],
 [x_1, x_3]])
julia> ca.SX.sym("[a,b,c]", 3)
SX([a, b, c])
julia> isequal(ca.SX.sym("x"), ca.SX.sym("x"))
false

See also: symvar, zeros, ones

Overload: sym(str name, (int,int) rc)

Construct a symbolic primitive with given dimensions, as a pair (nrow, ncol)

Overload: sym(str name, Sparsity sp)

Create symbolic primitive with a given sparsity pattern.

Only the structural nonzeros of sp become symbolic entries; for SX they are numbered by nonzero index.

>>> SX.sym("p", Sparsity.diag(2))
SX(
[[p_0, 00],
 [00, p_1]])
>>> MX.sym("p", Sparsity.diag(2)).dim(True)
'2x2,2nz'
>> SX.sym('p', Sparsity.diag(2))
[[p_0, 00],
[00, p_1]]
>> MX.sym('p', Sparsity.diag(2)).dim(true)
2x2,2nz
julia> ca.SX.sym("p", ca.Sparsity.diag(2))
SX(
[[p_0, 00],
 [00, p_1]])
julia> ca.dim(ca.MX.sym("p", ca.Sparsity.diag(2)), true)
"2x2,2nz"

Overload: sym(str name, Sparsity sp, int p)

Create a list of length p of symbolic primitives with a given sparsity.

The k-th symbol is named name followed by k (no separator).

>>> MX.sym("x", Sparsity.dense(2, 1), 3)
[MX(x0), MX(x1), MX(x2)]
>> v = MX.sym('x', Sparsity.dense(2, 1), 3);
>> numel(v), v{1}, v{3}
3
x0
x2
julia> ca.MX.sym("x", ca.Sparsity.dense(2, 1), 3)
3-element Vector{MX}:
 MX(x0)
 MX(x1)
 MX(x2)

Overload: sym(str name, int nrow, int ncol, int p)

Create a list of length p of nrow-by-ncol symbolic primitives.

>>> SX.sym("x", 1, 1, 2)
[SX(x0), SX(x1)]
>> v = SX.sym('x', 1, 1, 2);
>> v{1}, v{2}
x0
x1
julia> ca.SX.sym("x", 1, 1, 2)
2-element Vector{SX}:
 SX(x0)
 SX(x1)

Overload: sym(str name, Sparsity sp, int p, int r)

Create a list of length r of lists of length p of symbolic primitives.

with given sparsity. The symbol at outer index i and inner index k is named name_ik.

Extra doc | Doc source | Implementation

to_file(...)

Write a numerical matrix to a text file (DM only)

to_file(self, str filename, str format)

Supported formats, selected by the file extension unless format is given:

  • mtx: Matrix Market coordinate format (sparse, one-based row/col/value triplets)

  • txt: one line per row, whitespace separated, aligned columns, full precision, structural zeros written as 00. Does not scale to large sparse matrices. Values are written with the C locale; nan and inf round-trip. An unknown extension or format raises an error. SX is not supported.

Parameters:
  • filename -- Output path

  • format -- "mtx" or "txt"; empty means deduce from the extension

>>> import os, tempfile
>>> fn = os.path.join(tempfile.mkdtemp(), "a.txt")
>>> A = DM(Sparsity.diag(2)) * 2.5
>>> A.to_file(fn)
>>> DM.from_file(fn)
DM(
[[2.5, 00],
 [00, 2.5]])
>>> os.remove(fn); os.rmdir(os.path.dirname(fn))
>> fn = [tempname '.txt'];
>> A = DM(Sparsity.diag(2)) * 2.5;
>> A.to_file(fn);
>> DM.from_file(fn)
[[2.5, 00],
[00, 2.5]]
>> delete(fn);
julia> fn = joinpath(mktempdir(), "a.txt");
julia> A = ca.DM(ca.Sparsity.diag(2)) * 2.5;
julia> ca.to_file(A, fn)
julia> ca.DM.from_file(fn)
DM(
[[2.5, 00],
 [00, 2.5]])
julia> rm(dirname(fn), recursive=true)

See also: from_file, Sparsity.to_file

Extra doc | Doc source

static triplet(...)
triplet([int] row, [int] col, DM d) -> DM
triplet([int] row, [int] col, DM d, (int,int) rc) -> DM
triplet([int] row, [int] col, DM d, int nrow, int ncol) -> DM

Construct a sparse matrix from triplet form (row indices, column indices, values)

Entry k of the result is at (row[k], col[k]) with value d[k]. The three lists must have the same length; indices are zero-based and must be within the matrix bounds. The nonzeros are reordered into column- major order. When the same (row, col) pair appears more than once, only the first value is kept; duplicates are not summed.

Parameters:
  • row -- Row index of each entry

  • col -- Column index of each entry

  • d -- Dense vector of values, one per entry

  • nrow -- Number of rows of the result [default: largest row index plus one]

  • ncol -- Number of columns of the result [default: largest column index plus one]

>>> DM.triplet([0, 1], [1, 0], [5, 6], 3, 3)
DM(
[[00, 5, 00],
 [6, 00, 00],
 [00, 00, 00]])
>>> DM.triplet([0, 1], [1, 0], [5, 6], (3, 3)).nonzeros()
[6.0, 5.0]
>>> SX.triplet([0, 1], [0, 1], SX.sym("v", 2), 2, 2)
SX(
[[v_0, 00],
 [00, v_1]])
>>> DM.triplet([], [], [], 2, 2).nnz()
0
>>> try: DM.triplet([0, 1], [1, 0], [5], 3, 3)
... except Exception as e: print("error")
error
>> DM.triplet([0 1], [1 0], [5 6], 3, 3)
[[00, 5, 00],
[6, 00, 00],
[00, 00, 00]]
>> DM.triplet([0 1], [1 0], [5 6], [3 3]).nonzeros()
6 5
>> SX.triplet([0 1], [0 1], SX.sym('v', 2), 2, 2)
[[v_0, 00],
[00, v_1]]
>> DM.triplet([], [], [], 2, 2).nnz()
0
>> try, DM.triplet([0 1], [1 0], 5, 3, 3); catch e, disp('error'); end
error
julia> ca.DM.triplet([0, 1], [1, 0], [5, 6], 3, 3)
DM(
[[00, 5, 00],
 [6, 00, 00],
 [00, 00, 00]])
julia> ca.SX.triplet([0, 1], [0, 1], ca.SX.sym("v", 2), 2, 2)
SX(
[[v_0, 00],
 [00, v_1]])
julia> ca.nnz(ca.DM.triplet([], [], [], 2, 2))
0
julia> try ca.DM.triplet([0, 1], [1, 0], [5], 3, 3); catch; println("error") end
error

See also: Sparsity.triplet

Extra doc | Doc source

static type_name(...)

Name of the class: "DM" or "SX".

type_name() -> str
>>> DM.type_name(), SX.type_name()
('DM', 'SX')
>> fprintf('%s %s\n', DM.type_name(), SX.type_name())
DM SX
julia> ca.DM.type_name(), ca.SX.type_name()
("DM", "SX")

Extra doc | Doc source | Implementation

static unary(...)
unary(int op, DM x) -> DM
which_function(...)

Get function - only valid when is_call() is true.

which_function(self) -> Function

Extra doc | Doc source | Implementation

which_output(...)

Get the index of evaluation output - only valid when is_output() is true.

which_output(self) -> int

Extra doc | Doc source | Implementation

static zeros(...)
zeros(int nrow, int ncol) -> DM
zeros((int,int) rc) -> DM
zeros(Sparsity sp) -> DM

Create a dense matrix or a matrix with specified sparsity with all entries zero.

zeros(nrow, ncol) stores nrow*ncol numerical zeros; zeros(sp) stores a zero at every structural nonzero of sp. To get structural zeros instead, construct from a shape, e.g. DM(2, 2).

>>> DM.zeros(2, 2).nnz(), DM.zeros(Sparsity.diag(2)).nnz(), DM(2, 2).nnz()
(4, 2, 0)
>>> MX.zeros(2, 3)
MX(zeros(2x3))
>> Z = DM.zeros(Sparsity.diag(2));
>> fprintf('%d %d %d\n', DM.zeros(2, 2).nnz(), Z.nnz(), DM(2, 2).nnz())
4 2 0
>> MX.zeros(2, 3)
zeros(2x3)
julia> Z = ca.DM.zeros(ca.Sparsity.diag(2));
julia> ca.nnz(ca.DM.zeros(2, 2)), ca.nnz(Z), ca.nnz(ca.DM(2, 2))
(4, 2, 0)
julia> ca.MX.zeros(2, 3)
MX(zeros(2x3))

See also: ones, Sparsity

Extra doc | Doc source | Implementation

SX

class SX(...)
static binary(...)
binary(int op, SX x, SX y) -> SX
static call(...)
call(Function f, [SX] x) -> [SX]
call(Function f, [SXElem] x) -> [SXElem]
clear(...)

Reset to an empty 0-by-0 matrix, in place.

clear(self)

Doc source

colind(...)
colind(self) -> [int]
colind(self, int col) -> int

Get the sparsity pattern. See the Sparsity class for details.

The pattern is stored in compressed column format: colind has size2()+1 entries, the nonzeros of column j are the entries colind(j) up to colind(j+1) (exclusive), and row(el) is the row index of nonzero el. Without argument, the full vectors are returned. Out-of-range indices raise an error.

>>> x = DM(Sparsity.diag(2), [5, 6])
>>> x.row(), x.colind()
([0, 1], [0, 1, 2])
>>> x.row(1), x.colind(2)
(1, 2)
>> x = DM(Sparsity.diag(2), [5; 6]);
>> x.row(), x.colind()
0 1
0 1 2
>> fprintf('%d %d\n', x.row(1), x.colind(2))
1 2
julia> x = ca.DM(ca.Sparsity.diag(2), [5, 6]);
julia> ca.row(x), ca.colind(x)
([0, 1], [0, 1, 2])
julia> ca.row(x, 1), ca.colind(x, 2)
(1, 2)

Extra doc | Doc source | Implementation

columns(...)

Get the number of columns, Octave-style syntax (same as size2())

columns(self) -> int

Extra doc | Doc source | Implementation

dep(...)

Get operand ch of a 1-by-1 SX expression.

dep(self, int ch) -> SX

Only defined for a scalar SX that is the result of an operation; a symbol, a constant or a DM raises an error.

Parameters:

ch -- Operand index, 0 or 1

>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = x * y
>>> e.dep(0), e.dep(1), e.n_dep()
(SX(x), SX(y), 2)
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x * y;
>> e.dep(0), e.dep(1), e.n_dep()
x
y
2
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = x * y;
julia> ca.dep(e, 0), ca.dep(e, 1), ca.n_dep(e)
(x, y, 2)

See also: n_dep, op

Extra doc | Doc source | Implementation

static deserialize(...)
deserialize(std::istream & stream) -> SX
deserialize(casadi::DeserializingStream & s) -> SX
deserialize(str s) -> SX

Overload: deserialize(std::istream & stream)

Build a matrix from a serialization stream.

Overload: deserialize(str s)

Build a matrix from a string produced by serialize.

A string that is not a CasADi serialization raises an error.

See also: serialize

Extra doc | Doc source

dim(...)

Get string representation of dimensions.

dim(self, bool with_nz) -> str

The representation is e.g. "4x5" or, with with_nz true, "4x5,10nz".

>>> DM.eye(3).dim(), DM.eye(3).dim(True), DM.ones(3, 3).dim(True)
('3x3', '3x3,3nz', '3x3,9nz')
>> fprintf('%s %s %s\n', DM.eye(3).dim(), DM.eye(3).dim(true), DM.ones(3, 3).dim(true))
3x3 3x3,3nz 3x3,9nz
julia> ca.dim(ca.DM.eye(3)), ca.dim(ca.DM.eye(3), true), ca.dim(ca.DM.ones(3, 3), true)
("3x3", "3x3,3nz", "3x3,9nz")

See also: size, nnz

Extra doc | Doc source | Implementation

disp(...)

Print a representation of the object to a stream.

disp(self, bool more)

Picks the layout automatically: scalar, vector, dense matrix (small or at least half full) or sparse coordinate list. This is what str() and print() use. more has no effect for matrices.

Extra doc | Doc source

element_hash(...)

Hash of the node of a 1-by-1 SX expression.

element_hash(self) -> int

Equal expressions (same node) have the same hash. Only defined for a scalar SX; a vector or a DM raises an error.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> x.element_hash() == x.element_hash(), x.element_hash() == y.element_hash()
(True, False)
>> x = SX.sym('x'); y = SX.sym('y');
>> h = x.element_hash();
>> fprintf('%d %d\n', h == x.element_hash(), h == y.element_hash())
1 0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.element_hash(x) == ca.element_hash(x), ca.element_hash(x) == ca.element_hash(y)
(true, false)

Extra doc | Doc source | Implementation

elements(...)

Get all elements as a flat list in column-major order (Python: elements())

elements(self) -> [SXElem]

Like nonzeros, but structural zeros are included as 0, so the list has numel() entries.

>>> DM(Sparsity.diag(2)).elements()
[1.0, 0.0, 0.0, 1.0]
>> DM(Sparsity.diag(2)).elements()
1 0 0 1
julia> ca.elements(ca.DM(ca.Sparsity.diag(2)))
4-element Vector{Float64}:
 1.0
 0.0
 0.0
 1.0

See also: nonzeros, densify

Extra doc | Doc source

enlarge(...)

Enlarge the matrix in place, moving the existing rows and columns to new

enlarge(self, int nrow, int ncol, [int] rr, [int] cc, bool ind1)

positions.

The new shape is nrow-by-ncol. rr lists, for every existing row, its index in the enlarged matrix; cc does the same for the columns. Both must have exactly size1() and size2() entries. All other rows and columns are structurally zero.

Parameters:
  • nrow -- New number of rows

  • ncol -- New number of columns

  • rr -- New position of each existing row, length size1()

  • cc -- New position of each existing column, length size2()

  • ind1 -- True for one-based indices

>>> A = DM([[1, 2], [3, 4]])
>>> A.enlarge(3, 4, [0, 2], [0, 1])
>>> A
DM(
[[1, 2, 00, 00],
 [00, 00, 00, 00],
 [3, 4, 00, 00]])
>>> try: A.enlarge(4, 4, [0, 1], [0, 1])
... except Exception as e: print("error")
error
>> A = DM([1 2; 3 4]);
>> A.enlarge(3, 4, [1 3], [1 2], true);
>> A
[[1, 2, 00, 00],
[00, 00, 00, 00],
[3, 4, 00, 00]]
>> try, A.enlarge(4, 4, [1 2], [1 2], true); catch e, disp('error'); end
error
julia> A = ca.DM([1 2; 3 4]);
julia> ca.enlarge(A, 3, 4, [0, 2], [0, 1])
julia> A
DM(
[[1, 2, 00, 00],
 [00, 00, 00, 00],
 [3, 4, 00, 00]])
julia> try ca.enlarge(A, 4, 4, [0, 1], [0, 1]); catch; println("error") end
error

See also: resize, Sparsity.enlarge

Extra doc | Doc source

erase(...)

Erase the elements at the given linear indices, leaving structural zeros.

erase(self, [int] rr, bool ind1)
erase(self, [int] rr, [int] cc, bool ind1)

Column-major linear indices, as in get. The shape is unchanged.

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A.erase([0, -1])
>>> A
DM(
[[00, 2, 3],
 [4, 5, 00]])
>> A = DM([1 2 3; 4 5 6]);
>> A.erase([1 6], true);
>> A
[[00, 2, 3],
[4, 5, 00]]
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> ca.erase(A, [0, 5])
julia> A
DM(
[[00, 2, 3],
 [4, 5, 00]])

Erase the block at the given rows and columns, leaving structural zeros.

The shape is unchanged; the entries of the submatrix rr x cc are removed from the sparsity pattern. Negative indices count from the end; out-of-range indices raise an error.

Parameters:
  • rr -- Row indices

  • cc -- Column indices

  • ind1 -- True for one-based indices

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A.erase([0], [1])
>>> A
DM(
[[1, 00, 3],
 [4, 5, 6]])
>>> A.dim(), A.nnz()
('2x3', 5)
>> A = DM([1 2 3; 4 5 6]);
>> A.erase(1, 2, true);
>> A
[[1, 00, 3],
[4, 5, 6]]
>> fprintf('%s %d\n', A.dim(), A.nnz())
2x3 5
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> ca.erase(A, [0], [1])
julia> A
DM(
[[1, 00, 3],
 [4, 5, 6]])
julia> ca.dim(A), ca.nnz(A)
("2x3", 5)

See also: remove, sparsify

Extra doc | Doc source

export_code(...)

Export matrix in specific language.

export_code(self, str lang, dict options)

lang: only 'matlab' supported for now

options:
  inline: Indicates if you want everything on a single line (default: False)
  name: Name of exported variable (default: 'm')
  indent_level: Level of indentation (default: 0)
  spoof_zero: Replace numerical zero by a 1e-200 (default: false)
              might be needed for matlab sparse construct,
              which doesn't allow numerical zero

Extra doc | Doc source

static eye(...)

Create an n-by-n identity matrix.

eye(int n) -> SX

The result is sparse: only the n diagonal entries are structural nonzeros.

>>> DM.eye(2)
DM(
[[1, 00],
 [00, 1]])
>>> DM.eye(3).nnz(), DM.eye(0).dim()
(3, '0x0')
>> DM.eye(2)
[[1, 00],
[00, 1]]
>> fprintf('%d %s\n', DM.eye(3).nnz(), DM.eye(0).dim())
3 0x0
julia> ca.DM.eye(2)
DM(
[[1, 00],
 [00, 1]])
julia> ca.nnz(ca.DM.eye(3)), ca.dim(ca.DM.eye(0))
(3, "0x0")

See also: is_eye, Sparsity.diag

Extra doc | Doc source

static from_file(...)

Read a numerical matrix from a text file written by to_file (DM only)

from_file(str filename, str format_hint) -> DM

Same formats as to_file. In txt format, lines starting with #, % or / and empty lines are skipped, 00 marks a structural zero and a plain 0 a stored zero; every row must have the same number of columns, otherwise an error is raised. An empty file gives a 0-by-0 matrix. A missing file raises an error.

Parameters:
  • filename -- Input path

  • format_hint -- "mtx" or "txt"; empty means deduce from the extension

>>> import os, tempfile
>>> fn = os.path.join(tempfile.mkdtemp(), "a.txt")
>>> with open(fn, "w") as f: n = f.write("# comment\n1 00\n0 2\n")
>>> A = DM.from_file(fn)
>>> A
DM(
[[1, 00],
 [0, 2]])
>>> A.nnz()
3
>>> os.remove(fn); os.rmdir(os.path.dirname(fn))
>> fn = [tempname '.txt'];
>> fid = fopen(fn, 'w'); fprintf(fid, '# comment\n1 00\n0 2\n'); fclose(fid);
>> A = DM.from_file(fn);
>> A
[[1, 00],
[0, 2]]
>> A.nnz()
3
>> delete(fn);
julia> fn = joinpath(mktempdir(), "a.txt");
julia> write(fn, "# comment\n1 00\n0 2\n");
julia> A = ca.DM.from_file(fn)
DM(
[[1, 00],
 [0, 2]])
julia> ca.nnz(A)
3
julia> rm(dirname(fn), recursive=true)

See also: to_file

Extra doc | Doc source

get(...)
get(self, bool ind1, Sparsity sp) -> SX
get(self, bool ind1, Slice rr) -> SX
get(self, bool ind1, IM rr) -> SX
get(self, bool ind1, Slice rr, Slice cc) -> SX
get(self, bool ind1, Slice rr, IM cc) -> SX
get(self, bool ind1, IM rr, Slice cc) -> SX
get(self, bool ind1, IM rr, IM cc) -> SX

Overload: get(self, bool ind1, Slice rr)

Get elements by a single (linear) index.

Backs the Python expressions x[k] and x[sp]. The index addresses elements, not nonzeros, in column-major order: element (i, j) has linear index i + j*size1(). Negative indices count from the end; out- of-range indices raise an error.

  • A scalar index returns a 1-by-1 matrix. If that element is a structural zero, the result is structurally empty (prints 00).

  • A Slice (Python slice) or a list of indices returns a column vector, except that indexing a row vector gives a row vector.

  • A matrix of indices (IM) returns a matrix of the same shape.

  • A Sparsity pattern must have the same shape as the matrix; the result is the projection of the matrix onto that pattern (entries outside it are dropped).

Note that the result of a comparison such as A > 2 is a DM of zeros and ones, not a boolean mask: indexing with it uses those values as linear indices. Use a Sparsity pattern or the nz accessor for masking.

Parameters:
  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Linear index, Slice or list/matrix of indices

  • sp -- Sparsity pattern of the same shape as the matrix

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A[1], A[2], A[-1]
(DM(4), DM(2), DM(6))
>>> A[[0, 5]]
DM([1, 6])
>>> A[Sparsity.diag(2, 3)]
DM(
[[1, 00, 00],
 [00, 5, 00]])
>>> S = DM(Sparsity.diag(2))
>>> S[1]
DM(00)
>>> A.get(False, Slice(0, 2))
DM([1, 4])
>>> try: A[6]
... except Exception as e: print("error")
error
>> A = DM([1 2 3; 4 5 6]);
>> A(2), A(3), A(end)
4
2
6
>> A([1 6])
[[1, 6]]
>> A(Sparsity.diag(2, 3))
[[1, 00, 00],
[00, 5, 00]]
>> S = DM(Sparsity.diag(2));
>> S(2)
00
>> A.get(true, [1; 2])
[1, 4]
>> try, A(7); catch e, disp('error'); end
error
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> A[2], A[3], A[end]
(4, 2, 6)
julia> A[[1, 6]]
DM([1, 6])
julia> S = ca.DM(ca.Sparsity.diag(2));
julia> S[2]
DM(00)
julia> try A[7]; catch; println("error") end
error

See also: set, get_nz, Sparsity.sub

Overload: get(self, bool ind1, Slice rr, Slice cc)

Get a submatrix by row and column indices.

Backs the Python expression x[i, j]. Each of rr and cc is a scalar, a Slice or a list/vector of indices (any order, repetitions allowed, negative counts from the end). The result has len(rr) rows and len(cc) columns and keeps the sparsity of the selected entries. Two scalar indices give a 1-by-1 matrix (structurally empty when the entry is a structural zero). Out-of-range indices raise an error.

Parameters:
  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Row index, Slice or list/matrix of row indices

  • cc -- Column index, Slice or list/matrix of column indices

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A[0, 1], A[1, -1]
(DM(2), DM(6))
>>> A[:, 1]
DM([2, 5])
>>> A[[1, 0], [0, 2]]
DM(
[[4, 6],
 [1, 3]])
>>> A[1:1, :].dim()
'0x3'
>>> x = SX.sym("x", 2, 2)
>>> x[0, :]
SX([[x_0, x_2]])
>>> DM(Sparsity.diag(2))[1, 0]
DM(00)
>>> try: A[2, 0]
... except Exception as e: print("error")
error
>> A = DM([1 2 3; 4 5 6]);
>> A(1, 2), A(2, end)
2
6
>> A(:, 2)
[2, 5]
>> A([2 1], [1 3])
[[4, 6],
[1, 3]]
>> B = A(2:1, :); disp(B.dim())
0x3
>> x = SX.sym('x', 2, 2);
>> x(1, :)
[[x_0, x_2]]
>> S = DM(Sparsity.diag(2));
>> S(2, 1)
00
>> try, A(3, 1); catch e, disp('error'); end
error
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> A[1, 2], A[2, end]
(2, 6)
julia> A[:, 2]
DM([2, 5])
julia> A[[2, 1], [1, 3]]
DM(
[[4, 6],
 [1, 3]])
julia> ca.dim(A[2:1, :])
"0x3"
julia> x = ca.SX.sym("x", 2, 2);
julia> x[1, :]
SX([[x_0, x_2]])
julia> ca.DM(ca.Sparsity.diag(2))[2, 1]
DM(00)
julia> try A[3, 1]; catch; println("error") end
error

See also: set

Extra doc | Doc source | Implementation

static get_free(...)

Get the free symbols of an SX Function.

get_free(Function f) -> [SX]

Same as Function::free_sx. Only defined for SX.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> SX.get_free(Function("f", [x], [x + y], {"allow_free": True}))
[SX(y)]
>> x = SX.sym('x'); y = SX.sym('y');
>> v = SX.get_free(Function('f', {x}, {x + y}, struct('allow_free', true)));
>> v{1}
y
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.SX.get_free(ca.Function("f", [x], [x + y], Dict("allow_free" => true)))
1-element Vector{SX}:
 SX(y)

See also: Function.free_sx, get_input

Extra doc | Doc source | Implementation

static get_input(...)

Get the symbolic input expressions of an SX Function.

get_input(Function f) -> [SX]

Same as Function::sx_in. Only defined for SX.

>>> x = SX.sym("x")
>>> SX.get_input(Function("f", [x], [x + 1]))
[SX(x)]
>> x = SX.sym('x');
>> v = SX.get_input(Function('f', {x}, {x + 1}));
>> numel(v), v{1}
1
x
julia> x = ca.SX.sym("x");
julia> ca.SX.get_input(ca.Function("f", [x], [x + 1]))
1-element Vector{SX}:
 SX(x)

See also: Function.sx_in, get_free

Extra doc | Doc source | Implementation

static get_max_depth(...)

Get the depth to which SX subexpressions are compared during simplification.

get_max_depth() -> int

See also: set_max_depth

Extra doc | Doc source | Implementation

get_nz(...)
get_nz(self, bool ind1, Slice k) -> SX
get_nz(self, bool ind1, IM k) -> SX

Get structural nonzeros by their position in the nonzero storage.

Backs the Python expression x.nz[k]. Index k runs over the nonzeros in column-major order, 0 <= k < nnz(); negative values count from the end and out-of-range values raise an error. Structural zeros are skipped, so for a dense matrix this coincides with linear indexing. The result is a column vector shaped like the index (a row vector when indexing a row vector; a matrix for a matrix index). Iterating over x.nz in Python yields the nonzeros one by one.

Parameters:
  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • k -- Nonzero index, Slice or list/matrix of indices

>>> S = DM(Sparsity.diag(3)); S[0, 2] = 7
>>> S.nz[:]
DM([1, 1, 7, 1])
>>> S.nz[2], S.nz[-1], len(S.nz)
(DM(7), DM(1), 4)
>>> x = SX.sym("x", Sparsity.lower(2))
>>> x.nz[[0, 2]]
SX([x_0, x_2])
>>> SX.sym("e", 2, 0).nz[:].dim()
'0x1'
>>> try: S.nz[4]
... except Exception as e: print("error")
error
>> S = DM(Sparsity.diag(3)); S(1, 3) = 7;
>> S.get_nz(true, Slice())
[1, 1, 7, 1]
>> S.get_nz(true, 3), S.get_nz(true, [1; 3])
7
[1, 7]
>> x = SX.sym('x', Sparsity.lower(2));
>> x.get_nz(true, [1; 3])
[x_0, x_2]
>> SX.sym('e', 2, 0).get_nz(true, Slice()).dim()
0x1
>> try, S.get_nz(true, 5); catch e, disp('error'); end
error
julia> S = ca.DM(ca.Sparsity.diag(3)); S[1, 3] = 7;
julia> S.nz[:]
DM([1, 1, 7, 1])
julia> S.nz[3], S.nz[end], length(S.nz)
(7, 1, 4)
julia> x = ca.SX.sym("x", ca.Sparsity.lower(2));
julia> x.nz[[1, 3]]
SX([x_0, x_2])
julia> ca.dim(ca.SX.sym("e", 2, 0).nz[:])
"0x1"
julia> try S.nz[5]; catch e; println(typeof(e)) end
BoundsError

See also: set_nz, get, nonzeros

Extra doc | Doc source | Implementation

get_output(...)

Get an output.

get_output(self, int oind) -> SX

Extra doc | Doc source | Implementation

static get_precision(...)

Get the precision, field width and scientific flag used when printing

get_precision() -> int

nonzeros.

Doc source | Implementation

static get_scientific(...)
get_scientific() -> bool
static get_width(...)
get_width() -> int
has_duplicates(...)
has_duplicates(self) -> bool
has_nz(...)

Check whether element (rr, cc) is a structural nonzero.

has_nz(self, int rr, int cc) -> bool

Looks only at the sparsity pattern; a stored numerical zero still counts as a nonzero. Negative indices count from the end. An index past the end raises an error.

>>> S = DM(Sparsity.diag(2))
>>> S.has_nz(0, 0), S.has_nz(0, 1), DM([0, 1]).has_nz(0, 0)
(True, False, True)
>> S = DM(Sparsity.diag(2));
>> fprintf('%d %d %d\n', S.has_nz(0, 0), S.has_nz(0, 1), DM([0; 1]).has_nz(0, 0))
1 0 1
julia> S = ca.DM(ca.Sparsity.diag(2));
julia> ca.has_nz(S, 0, 0), ca.has_nz(S, 0, 1), ca.has_nz(ca.DM([0, 1]), 0, 0)
(true, false, true)

See also: has_zeros, Sparsity.has_nz

Extra doc | Doc source | Implementation

has_output(...)

Check if a multiple output node.

has_output(self) -> bool

Extra doc | Doc source | Implementation

has_zeros(...)

Check if any structural nonzero is known to be numerically zero.

has_zeros(self) -> bool

For SX only entries that are the constant 0 count. Use sparsify to remove them.

>>> DM([1, 0]).has_zeros(), DM([1, 2]).has_zeros(), DM(2, 2).has_zeros()
(True, False, False)
>>> x = SX.sym("x")
>>> vertcat(x, 0).has_zeros(), vertcat(x, x * 0).has_zeros()
(True, True)
>> fprintf('%d %d\n', DM([1; 0]).has_zeros(), DM([1; 2]).has_zeros())
1 0
>> DM(2, 2).has_zeros()
0
>> x = SX.sym('x');
>> fprintf('%d %d\n', vertcat(x, 0).has_zeros(), vertcat(x, x * 0).has_zeros())
1 1
julia> ca.has_zeros(ca.DM([1, 0])), ca.has_zeros(ca.DM([1, 2])), ca.has_zeros(ca.DM(2, 2))
(true, false, false)
julia> x = ca.SX.sym("x");
julia> ca.has_zeros([x; 0]), ca.has_zeros([x; x * 0])
(true, true)

See also: sparsify, has_nz

Extra doc | Doc source

static inf(...)
inf(int nrow, int ncol) -> SX
inf((int,int) rc) -> SX
inf(Sparsity sp) -> SX

Create a matrix with every nonzero equal to +inf.

Takes a shape (dense result, default 1-by-1) or a sparsity pattern.

>>> DM.inf(), DM.inf(2, 1).is_inf()
(DM(inf), True)
>>> DM.inf(Sparsity.diag(2))
DM(
[[inf, 00],
 [00, inf]])
>> DM.inf(), DM.inf(2, 1).is_inf()
inf
1
>> DM.inf(Sparsity.diag(2))
[[inf, 00],
[00, inf]]
julia> ca.DM.inf(), ca.is_inf(ca.DM.inf(2, 1))
(inf, true)
julia> ca.DM.inf(ca.Sparsity.diag(2))
DM(
[[inf, 00],
 [00, inf]])

See also: nan, is_inf

Extra doc | Doc source

info(...)

Dictionary with the sparsity pattern and the nonzeros (DM only)

info(self) -> dict
>>> sorted(DM([1, 2]).info().keys())
['data', 'sparsity']
>> s = DM([1; 2]).info();
>> strjoin(sort(fieldnames(s))', ' ')
data sparsity
julia> sort(collect(keys(ca.info(ca.DM([1, 2])))))
2-element Vector{String}:
 "data"
 "sparsity"

Extra doc | Doc source | Implementation

is_call(...)

Check if function call.

is_call(self) -> bool

Extra doc | Doc source | Implementation

is_column(...)

Check if the matrix is a column vector (i.e. size2()==1)

is_column(self) -> bool

Extra doc | Doc source | Implementation

is_commutative(...)

Check whether a binary SX is commutative.

is_commutative(self) -> bool

Only defined if symbolic scalar.

Extra doc | Doc source | Implementation

is_constant(...)

Check if every entry is a numerical constant (no symbols)

is_constant(self) -> bool

Always true for DM. For SX, true when no entry depends on a symbol; the simplifications make x*0 and x-x constant. A false negative is possible for expressions that are constant only in value, e.g. x - x after other operations.

>>> x = SX.sym("x")
>>> SX([1, 2]).is_constant(), x.is_constant(), (x * 0).is_constant()
(True, False, True)
>>> vertcat(x, 1).is_constant(), SX.sym("e", 2, 0).is_constant()
(False, True)
>> x = SX.sym('x'); z = x * 0;
>> fprintf('%d %d %d\n', SX([1; 2]).is_constant(), x.is_constant(), z.is_constant())
1 0 1
>> fprintf('%d %d\n', vertcat(x, 1).is_constant(), SX.sym('e', 2, 0).is_constant())
0 1
julia> x = ca.SX.sym("x");
julia> ca.is_constant(ca.SX([1, 2])), ca.is_constant(x), ca.is_constant(x * 0)
(true, false, true)
julia> ca.is_constant([x; 1]), ca.is_constant(ca.SX.sym("e", 2, 0))
(false, true)

See also: is_symbolic, evalf

Extra doc | Doc source

is_dense(...)

Check if the matrix is dense, i.e. nnz() equals numel()

is_dense(self) -> bool

Based on the sparsity pattern only: stored numerical zeros still count as nonzeros. Empty matrices are dense.

>>> DM.zeros(2, 2).is_dense(), DM(2, 2).is_dense(), DM(0, 3).is_dense()
(True, False, True)
>> Z = DM.zeros(2, 2);
>> fprintf('%d %d %d\n', Z.is_dense(), DM(2, 2).is_dense(), DM(0, 3).is_dense())
1 0 1
julia> ca.is_dense(ca.DM.zeros(2, 2)), ca.is_dense(ca.DM(2, 2)), ca.is_dense(ca.DM(0, 3))
(true, false, true)

See also: nnz, numel, densify

Extra doc | Doc source | Implementation

is_empty(...)

Check if the matrix is empty, i.e. if one of the dimensions is zero.

is_empty(self, bool both) -> bool

With both true, only a 0-by-0 matrix counts as empty.

>>> DM(0, 3).is_empty(), DM(0, 3).is_empty(True), DM(0, 0).is_empty(True)
(True, False, True)
>>> DM(1, 1).is_empty()
False
>> E = DM(0, 3);
>> fprintf('%d %d %d\n', E.is_empty(), E.is_empty(true), DM(0, 0).is_empty(true))
1 0 1
>> DM(1, 1).is_empty()
0
julia> E = ca.DM(0, 3);
julia> ca.is_empty(E), ca.is_empty(E, true), ca.is_empty(ca.DM(0, 0), true)
(true, false, true)
julia> ca.is_empty(ca.DM(1, 1))
false

Extra doc | Doc source | Implementation

is_eye(...)

check if the matrix is an identity matrix (note that false negative answers

is_eye(self) -> bool

are possible)

Extra doc | Doc source

is_half(...)

check if the matrix is 0.5 (note that false negative answers are possible)

is_half(self) -> bool

Extra doc | Doc source

is_inf(...)

check if the matrix is inf (note that false negative answers are possible)

is_inf(self) -> bool

Extra doc | Doc source

is_integer(...)

Check if the matrix is integer-valued.

is_integer(self) -> bool

(note that false negative answers are possible)

Extra doc | Doc source

is_leaf(...)

Check if SX is a leaf of the SX graph.

is_leaf(self) -> bool

Only defined if symbolic scalar.

Extra doc | Doc source | Implementation

is_minus_inf(...)

check if the matrix is -inf (note that false negative answers are possible)

is_minus_inf(self) -> bool

Extra doc | Doc source

is_minus_one(...)

check if the matrix is -1 (note that false negative answers are possible)

is_minus_one(self) -> bool

Extra doc | Doc source

is_nonnegative(...)

check if the matrix is not negative

is_nonnegative(self) -> bool

(note that false negative answers are possible)

Extra doc | Doc source

is_one(...)

check if the matrix is 1 (note that false negative answers are possible)

is_one(self) -> bool

Extra doc | Doc source

is_op(...)

Is it a certain operation.

is_op(self, int op) -> bool

Doc source | Implementation

is_output(...)

Check if evaluation output.

is_output(self) -> bool

Extra doc | Doc source | Implementation

is_regular(...)

Check that no entry is nan, inf or -inf.

is_regular(self) -> bool

Structural zeros are ignored. For SX, every entry must be a constant: the check raises an error when it reaches a symbolic entry (an infinite constant found before it still gives false).

>>> DM([1, 2]).is_regular(), DM([1, inf]).is_regular(), DM.nan(2, 2).is_regular()
(True, False, False)
>>> DM(2, 2).is_regular(), SX([1, 2]).is_regular()
(True, True)
>>> try: SX.sym("x").is_regular()
... except Exception as e: print("error")
error
>> fprintf('%d %d\n', DM([1; 2]).is_regular(), DM([1; inf]).is_regular())
1 0
>> fprintf('%d %d\n', DM.nan(2, 2).is_regular(), DM(2, 2).is_regular())
0 1
>> SX([1; 2]).is_regular()
1
>> try, SX.sym('x').is_regular(); catch e, disp('error'); end
error
julia> ca.is_regular(ca.DM([1, 2])), ca.is_regular(ca.DM([1, Inf]))
(true, false)
julia> ca.is_regular(ca.DM.nan(2, 2))
false
julia> ca.is_regular(ca.DM(2, 2)), ca.is_regular(ca.SX([1, 2]))
(true, true)
julia> try ca.is_regular(ca.SX.sym("x")); catch; println("error") end
error

See also: nan, inf

Extra doc | Doc source | Implementation

is_row(...)

Check if the matrix is a row vector (i.e. size1()==1)

is_row(self) -> bool

Extra doc | Doc source | Implementation

is_scalar(...)

Check if the matrix is scalar, i.e. 1-by-1.

is_scalar(self, bool scalar_and_dense) -> bool
Parameters:

scalar_and_dense -- When true, a 1-by-1 matrix with a structural zero does not count

>>> x = SX.sym("x", Sparsity(1, 1))
>>> x.is_scalar(), x.is_scalar(True), SX.sym("y").is_scalar(True)
(True, False, True)
>> x = SX.sym('x', Sparsity(1, 1));
>> fprintf('%d %d %d\n', x.is_scalar(), x.is_scalar(true), SX.sym('y').is_scalar(true))
1 0 1
julia> x = ca.SX.sym("x", ca.Sparsity(1, 1));
julia> ca.is_scalar(x), ca.is_scalar(x, true), ca.is_scalar(ca.SX.sym("y"), true)
(true, false, true)

Extra doc | Doc source | Implementation

is_smooth(...)

Check whether an SX expression contains only smooth operations.

is_smooth(self) -> bool

False when any node is a non-smooth operation such as floor, ceil, sign, a comparison or if_else. Operations such as fabs, fmin and fmax count as smooth. Always true for DM.

>>> x = SX.sym("x")
>>> sin(x).is_smooth(), fabs(x).is_smooth(), floor(x).is_smooth()
(True, True, False)
>>> if_else(x > 0, x, 0).is_smooth(), (x > 0).is_smooth(), DM(1).is_smooth()
(False, False, True)
>> x = SX.sym('x');
>> fprintf('%d %d %d\n', sin(x).is_smooth(), abs(x).is_smooth(), floor(x).is_smooth())
1 1 0
>> c = x > 0; b = if_else(c, x, 0);
>> fprintf('%d %d %d\n', b.is_smooth(), c.is_smooth(), DM(1).is_smooth())
0 0 1
julia> x = ca.SX.sym("x");
julia> ca.is_smooth(sin(x)), ca.is_smooth(abs(x)), ca.is_smooth(floor(x))
(true, true, false)
julia> ca.is_smooth(ifelse(x > 0, x, 0)), ca.is_smooth(x > 0), ca.is_smooth(ca.DM(1))
(false, false, true)

Extra doc | Doc source | Implementation

is_square(...)

Check if the matrix is square, i.e. size1() equals size2()

is_square(self) -> bool

Extra doc | Doc source | Implementation

is_symbolic(...)

Check if symbolic (Dense)

is_symbolic(self) -> bool

Check if an expression is a pure symbol. Pure means that no operations should happen on the symbol (not even vec, transpose, index, concatenation, ...) By consequence, a slice of a vector-shaped MX symbol is not a symbol. However, the SX type is really a container format with scalar entries. Therefore, a slice of a vector-shaped SX symbol is still a symbol.

Sparse matrices invariable return false

seealso is_valid_input

Extra doc | Doc source | Implementation

is_tril(...)

Check if the matrix is lower triangular.

is_tril(self) -> bool

Decided on the sparsity pattern alone, see is_triu.

See also: is_triu, tril, tril2symm

Extra doc | Doc source | Implementation

is_triu(...)

Check if the matrix is upper triangular.

is_triu(self) -> bool

Decided on the sparsity pattern alone: all structural nonzeros must lie on or above the diagonal. A dense matrix with numerical zeros below the diagonal is not upper triangular. Also defined for non- square matrices.

>>> DM(Sparsity.upper(3), 1).is_triu(), DM.zeros(2, 2).is_triu(), DM(2, 2).is_triu()
(True, False, True)
>> U = DM(Sparsity.upper(3), 1);
>> fprintf('%d %d %d\n', U.is_triu(), DM.zeros(2, 2).is_triu(), DM(2, 2).is_triu())
1 0 1
julia> U = ca.DM(ca.Sparsity.upper(3), 1);
julia> ca.is_triu(U), ca.is_triu(ca.DM.zeros(2, 2)), ca.is_triu(ca.DM(2, 2))
(true, false, true)

See also: is_tril, triu, triu2symm

Extra doc | Doc source | Implementation

is_valid_input(...)

Check if matrix can be used to define function inputs.

is_valid_input(self) -> bool

is_valid_input is more forgiving than is_symbolic. Some compositions are allowed: vec, vertcat.

Sparse matrices can return true if all non-zero elements are symbolic

seealso is_symbolic

Extra doc | Doc source | Implementation

is_value(...)

check if the matrix is value

is_value(self, float val) -> bool

Extra doc | Doc source

is_vector(...)

Check if the matrix is a row or column vector.

is_vector(self) -> bool

True when size1() or size2() is one, so scalars and n-by-1 or 1-by-n empties count. A 0-by-0 matrix does not.

>>> DM(3, 1).is_vector(), DM(1, 3).is_vector(), DM(1, 1).is_vector()
(True, True, True)
>>> DM(3, 3).is_vector(), DM(0, 1).is_vector(), DM(0, 0).is_vector()
(False, True, False)
>> fprintf('%d %d %d\n', DM(3, 1).is_vector(), DM(1, 3).is_vector(), DM(1, 1).is_vector())
1 1 1
>> fprintf('%d %d %d\n', DM(3, 3).is_vector(), DM(0, 1).is_vector(), DM(0, 0).is_vector())
0 1 0
julia> ca.is_vector(ca.DM(3, 1)), ca.is_vector(ca.DM(1, 3)), ca.is_vector(ca.DM(1, 1))
(true, true, true)
julia> ca.is_vector(ca.DM(3, 3)), ca.is_vector(ca.DM(0, 1)), ca.is_vector(ca.DM(0, 0))
(false, true, false)

See also: is_row, is_column

Extra doc | Doc source | Implementation

is_zero(...)

check if the matrix is 0 (note that false negative answers are possible)

is_zero(self) -> bool

Extra doc | Doc source

static matrix_matrix(...)
matrix_matrix(int op, SX x, SX y) -> SX
static matrix_scalar(...)
matrix_scalar(int op, SX x, SX y) -> SX
n_dep(...)

Number of operands of a 1-by-1 SX expression (0 for symbols and constants)

n_dep(self) -> int

See also: dep

Extra doc | Doc source | Implementation

name(...)

Name of a 1-by-1 symbolic SX primitive.

name(self) -> str

Raises an error for a non-scalar, for an expression that is not a pure symbol, and for DM.

>>> SX.sym("x").name(), SX.sym("v", 2)[1].name()
('x', 'v_1')
>> v = SX.sym('v', 2); v2 = v(2);
>> fprintf('%s %s\n', SX.sym('x').name(), v2.name())
x v_1
julia> ca.name(ca.SX.sym("x")), ca.name(ca.SX.sym("v", 2)[2])
("x", "v_1")

See also: is_symbolic

Extra doc | Doc source | Implementation

static nan(...)
nan(int nrow, int ncol) -> SX
nan((int,int) rc) -> SX
nan(Sparsity sp) -> SX

Create a matrix with every nonzero equal to nan.

Takes a shape (dense result, default 1-by-1) or a sparsity pattern. Useful as a placeholder that is easy to detect with is_regular.

>>> DM.nan(), DM.nan((2, 1)).dim()
(DM(nan), '2x1')
>>> DM.nan(2, 2).is_regular()
False
>> DM.nan(), DM.nan([2 1]).dim()
nan
2x1
>> DM.nan(2, 2).is_regular()
0
julia> ca.DM.nan(), ca.dim(ca.DM.nan(2, 1))
(nan, "2x1")
julia> ca.is_regular(ca.DM.nan(2, 2))
false

See also: inf, is_regular

Extra doc | Doc source

nnz(...)

Get the number of structural nonzeros.

nnz(self) -> int

Counts the entries present in the sparsity pattern. Entries that are stored but numerically zero still count; structural zeros (not stored) do not. For a dense matrix this equals numel().

>>> DM.eye(3).nnz(), DM.ones(3, 3).nnz(), DM(3, 3).nnz()
(3, 9, 0)
>>> DM([[1, 0], [0, 2]]).nnz()
4
>>> MX.sym("x", 2, 0).nnz()
0
>> fprintf('%d %d %d\n', DM.eye(3).nnz(), DM.ones(3, 3).nnz(), DM(3, 3).nnz())
3 9 0
>> DM([1 0; 0 2]).nnz()
4
>> MX.sym('x', 2, 0).nnz()
0
julia> ca.nnz(ca.DM.eye(3)), ca.nnz(ca.DM.ones(3, 3)), ca.nnz(ca.DM(3, 3))
(3, 9, 0)
julia> ca.nnz(ca.DM([1 0; 0 2]))
4
julia> ca.nnz(ca.MX.sym("x", 2, 0))
0

See also: numel, nnz_lower, nnz_upper, nnz_diag, sparsity

Extra doc | Doc source | Implementation

nnz_diag(...)

Get the number of structural nonzeros on the diagonal.

nnz_diag(self) -> int

Also defined for non-square matrices.

>>> DM.ones(3, 3).nnz_diag(), DM.eye(3).nnz_diag(), DM.ones(2, 3).nnz_diag()
(3, 3, 2)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_diag(), I.nnz_diag(), B.nnz_diag())
3 3 2
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_diag(A), ca.nnz_diag(I), ca.nnz_diag(B)
(3, 3, 2)

See also: nnz, nnz_lower, nnz_upper

Extra doc | Doc source | Implementation

nnz_lower(...)

Get the number of structural nonzeros on or below the diagonal.

nnz_lower(self) -> int
>>> DM.ones(3, 3).nnz_lower(), DM.eye(3).nnz_lower(), DM.ones(2, 3).nnz_lower()
(6, 3, 3)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_lower(), I.nnz_lower(), B.nnz_lower())
6 3 3
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_lower(A), ca.nnz_lower(I), ca.nnz_lower(B)
(6, 3, 3)

See also: nnz, nnz_upper, nnz_diag

Extra doc | Doc source | Implementation

nnz_upper(...)

Get the number of structural nonzeros on or above the diagonal.

nnz_upper(self) -> int
>>> DM.ones(3, 3).nnz_upper(), DM.eye(3).nnz_upper(), DM.ones(2, 3).nnz_upper()
(6, 3, 5)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_upper(), I.nnz_upper(), B.nnz_upper())
6 3 5
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_upper(A), ca.nnz_upper(I), ca.nnz_upper(B)
(6, 3, 5)

See also: nnz, nnz_lower, nnz_diag

Extra doc | Doc source | Implementation

nonzeros(...)

Get all nonzeros.

nonzeros(self) -> [SXElem]

Extra doc | Doc source

numel(...)

Get the number of elements, size1()*size2()

numel(self) -> int

Counts all entries, structural zeros included.

>>> DM.eye(3).numel(), MX.sym("x", 2, 0).numel(), SX.sym("x").numel()
(9, 0, 1)
>> fprintf('%d %d %d\n', DM.eye(3).numel(), MX.sym('x', 2, 0).numel(), SX.sym('x').numel())
9 0 1
julia> ca.numel(ca.DM.eye(3)), ca.numel(ca.MX.sym("x", 2, 0)), ca.numel(ca.SX.sym("x"))
(9, 0, 1)
julia> length(ca.DM.eye(3))
9

See also: nnz, size

Extra doc | Doc source | Implementation

static ones(...)
ones(int nrow, int ncol) -> SX
ones((int,int) rc) -> SX
ones(Sparsity sp) -> SX

Create a dense matrix or a matrix with specified sparsity with all entries one.

ones(sp) sets every structural nonzero of sp to one; other entries stay structurally zero.

>>> DM.ones(2, 3)
DM(
[[1, 1, 1],
 [1, 1, 1]])
>>> DM.ones(Sparsity.diag(2))
DM(
[[1, 00],
 [00, 1]])
>> DM.ones(2, 3)
[[1, 1, 1],
[1, 1, 1]]
>> DM.ones(Sparsity.diag(2))
[[1, 00],
[00, 1]]
julia> ca.DM.ones(2, 3)
DM(
[[1, 1, 1],
 [1, 1, 1]])
julia> ca.DM.ones(ca.Sparsity.diag(2))
DM(
[[1, 00],
 [00, 1]])

See also: zeros, Sparsity

Extra doc | Doc source | Implementation

op(...)

Get operation type.

op(self) -> int

Doc source | Implementation

print_dense(...)

Print as a dense matrix, one row per line, structural zeros as 00.

print_dense(self, bool truncate)

Shared SX subexpressions are printed first as @1=..., @2=....

Parameters:

truncate -- Print only 3 leading and trailing rows and columns when the matrix has more than 1000 elements and at least 7 rows or columns

>>> DM(Sparsity.diag(2)).print_dense()
[[1, 00],
 [00, 1]]
julia> ca.print_dense(ca.DM(ca.Sparsity.diag(2)))
[[1, 00],
 [00, 1]]

See also: print_sparse

Extra doc | Doc source | Implementation

print_scalar(...)

Print a 1-by-1 matrix as a bare number or expression.

print_scalar(self)

A structurally empty 1-by-1 matrix prints as 00; other shapes raise an error.

>>> DM(3).print_scalar()
3
>>> DM(1, 1).print_scalar()
00
julia> ca.print_scalar(ca.DM(3))
3
julia> ca.print_scalar(ca.DM(1, 1))
00

Extra doc | Doc source | Implementation

print_sparse(...)

Print as a list of (row, col) -> value triplets, column-major order.

print_sparse(self, bool truncate)
Parameters:

truncate -- Print only the first and last 3 nonzeros when there are more than 1000

>>> DM(Sparsity.diag(2)).print_sparse()
sparse: 2-by-2, 2 nnz
 (0, 0) -> 1
 (1, 1) -> 1
>>> DM(2, 2).print_sparse()
all zero sparse: 2-by-2
julia> ca.print_sparse(ca.DM(ca.Sparsity.diag(2)))
sparse: 2-by-2, 2 nnz
 (0, 0) -> 1
 (1, 1) -> 1
julia> ca.print_sparse(ca.DM(2, 2))
all zero sparse: 2-by-2

See also: print_dense

Extra doc | Doc source | Implementation

print_split(...)

String representation of each nonzero and of the shared subexpressions.

print_split(self) -> ([str], [str])

Returns two lists: one string per nonzero (in storage order) and the definitions of the intermediate expressions "@1", "@2", ... that the nonzero strings refer to (always empty for DM).

>>> DM([[1, 2], [3, 4]]).print_split()
(['1', '3', '2', '4'], [])
>>> x = SX.sym("x"); y = SX.sym("y")
>>> e = x * y
>>> vertcat(e + 1, e - 1).print_split()
(['(@1+@2)', '(@1-@2)'], ['(x*y)', '1'])
>> [nz, inter] = DM([1 2; 3 4]).print_split();
>> disp(strjoin(cellstr(nz)', ' ')), disp(isempty(inter))
1 3 2 4
1
>> x = SX.sym('x'); y = SX.sym('y');
>> e = x * y;
>> [nz, inter] = vertcat(e + 1, e - 1).print_split();
>> disp(strjoin(cellstr(nz)', ' ')), disp(strjoin(cellstr(inter)', ' '))
(@1+@2) (@1-@2)
(x*y) 1
julia> ca.print_split(ca.DM([1 2; 3 4]))
(["1", "3", "2", "4"], String[])
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> e = x * y;
julia> ca.print_split([e + 1; e - 1])
(["(@1+@2)", "(@1-@2)"], ["(x*y)", "1"])

Extra doc | Doc source | Implementation

print_vector(...)

Print a column vector as [a, b, ...], structural zeros as 00.

print_vector(self, bool truncate)

Only column vectors are accepted; a row vector raises an error.

Parameters:

truncate -- Print only the first and last 3 entries of vectors longer than 1000

>>> DM(Sparsity.unit(3, 1)).print_vector()
[00, 1, 00]
julia> ca.print_vector(ca.DM(ca.Sparsity.unit(3, 1)))
[00, 1, 00]

Extra doc | Doc source | Implementation

printme(...)
printme(self, SX y) -> SX
static rand(...)
rand(int nrow, int ncol) -> SX
rand((int,int) rc) -> SX
rand(Sparsity sp) -> SX

Create a matrix with uniformly distributed random numbers in [0, 1)

Takes a shape (dense result, default 1-by-1) or a sparsity pattern, in which case only the structural nonzeros get a random value. Only available for DM.

>>> DM.rand(2, 3).dim(), DM.rand().dim(), DM.rand(Sparsity.diag(3)).nnz()
('2x3', '1x1', 3)
>>> try: SX.rand(2)
... except Exception as e: print("error")
error
>> fprintf('%s %s\n', DM.rand(2, 3).dim(), DM.rand().dim())
2x3 1x1
>> DM.rand(Sparsity.diag(3)).nnz()
3
>> try, SX.rand(2); catch e, disp('error'); end
error
julia> ca.dim(ca.DM.rand(2, 3)), ca.dim(ca.DM.rand())
("2x3", "1x1")
julia> ca.nnz(ca.DM.rand(ca.Sparsity.diag(3)))
3
julia> try ca.SX.rand(2); catch; println("error") end
error

See also: rng

Extra doc | Doc source

remove(...)

Delete rows and columns, shrinking the matrix in place.

remove(self, [int] rr, [int] cc)

Both lists may be empty; duplicates are ignored, out-of-range indices raise an error.

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A.remove([0], [1])
>>> A
DM([[4, 6]])
>> A = DM([1 2 3; 4 5 6]);
>> A.remove(0, 1);
>> A
[[4, 6]]
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> ca.remove(A, [0], [1])
julia> A
DM([[4, 6]])

See also: erase

Extra doc | Doc source

reserve(...)
reserve(self, int nnz)
reserve(self, int nnz, int ncol)

Reserve storage for the given number of nonzeros (performance hint, no visible effect)

Doc source

reset_input(...)
reset_input(self)
resize(...)

Change the shape in place, keeping nonzeros that remain inside the new

resize(self, int nrow, int ncol)

bounds.

Growing appends structural zeros; shrinking drops the entries outside the new shape.

>>> A = DM([[1, 2], [3, 4]])
>>> A.resize(3, 3)
>>> A
DM(
[[1, 2, 00],
 [3, 4, 00],
 [00, 00, 00]])
>>> A.resize(1, 1)
>>> A
DM(1)
>> A = DM([1 2; 3 4]);
>> A.resize(3, 3);
>> A
[[1, 2, 00],
[3, 4, 00],
[00, 00, 00]]
>> A.resize(1, 1);
>> A
1
julia> A = ca.DM([1 2; 3 4]);
julia> ca.resize(A, 3, 3)
julia> A
DM(
[[1, 2, 00],
 [3, 4, 00],
 [00, 00, 00]])
julia> ca.resize(A, 1, 1)
julia> A
DM(1)

See also: enlarge, reshape

Extra doc | Doc source

static rng(...)

Seed the random number generator used by rand.

rng(int seed)

The generator is global to the class and is seeded from the clock at startup; seeding it makes subsequent rand calls reproducible.

>>> DM.rng(1); a = DM.rand(2, 2)
>>> DM.rng(1); b = DM.rand(2, 2)
>>> norm_inf(a - b)
DM(0)
>> DM.rng(1); a = DM.rand(2, 2);
>> DM.rng(1); b = DM.rand(2, 2);
>> norm_inf(a - b)
0
julia> ca.DM.rng(1); a = ca.DM.rand(2, 2);
julia> ca.DM.rng(1); b = ca.DM.rand(2, 2);
julia> ca.norm_inf(a - b)
DM(0)

See also: rand

Extra doc | Doc source | Implementation

row(...)
row(self) -> [int]
row(self, int el) -> int

Get the sparsity pattern. See the Sparsity class for details.

The pattern is stored in compressed column format: colind has size2()+1 entries, the nonzeros of column j are the entries colind(j) up to colind(j+1) (exclusive), and row(el) is the row index of nonzero el. Without argument, the full vectors are returned. Out-of-range indices raise an error.

>>> x = DM(Sparsity.diag(2), [5, 6])
>>> x.row(), x.colind()
([0, 1], [0, 1, 2])
>>> x.row(1), x.colind(2)
(1, 2)
>> x = DM(Sparsity.diag(2), [5; 6]);
>> x.row(), x.colind()
0 1
0 1 2
>> fprintf('%d %d\n', x.row(1), x.colind(2))
1 2
julia> x = ca.DM(ca.Sparsity.diag(2), [5, 6]);
julia> ca.row(x), ca.colind(x)
([0, 1], [0, 1, 2])
julia> ca.row(x, 1), ca.colind(x, 2)
(1, 2)

Extra doc | Doc source | Implementation

rows(...)

Get the number of rows, Octave-style syntax (same as size1())

rows(self) -> int

Extra doc | Doc source | Implementation

static scalar_matrix(...)
scalar_matrix(int op, SX x, SX y) -> SX
serialize(...)

Serialize an object.

serialize(self) -> str
serialize(self, casadi::SerializingStream & s)

Serialize to a string.

The string can be restored with deserialize of the same class (DM or SX). For SX the whole expression graph is stored, symbols included.

>>> s = DM([[1, 2], [3, 4]]).serialize()
>>> DM.deserialize(s)
DM(
[[1, 2],
 [3, 4]])
>>> x = SX.sym("x")
>>> SX.deserialize((sin(x) + x).serialize())
SX((sin(x)+x))
>> s = DM([1 2; 3 4]).serialize();
>> DM.deserialize(s)
[[1, 2],
[3, 4]]
>> x = SX.sym('x'); e = sin(x) + x;
>> SX.deserialize(e.serialize())
(sin(x)+x)
julia> s = ca.serialize(ca.DM([1 2; 3 4]));
julia> ca.DM.deserialize(s)
DM(
[[1, 2],
 [3, 4]])
julia> x = ca.SX.sym("x");
julia> ca.SX.deserialize(ca.serialize(sin(x) + x))
SX((sin(x)+x))

See also: deserialize, StringSerializer

Extra doc | Doc source

set(...)
set(self, SX m, bool ind1, Sparsity sp)
set(self, SX m, bool ind1, Slice rr)
set(self, SX m, bool ind1, IM rr)
set(self, SX m, bool ind1, Slice rr, Slice cc)
set(self, SX m, bool ind1, Slice rr, IM cc)
set(self, SX m, bool ind1, IM rr, Slice cc)
set(self, SX m, bool ind1, IM rr, IM cc)

Overload: set(self, SX m, bool ind1, Slice rr)

Assign elements by a single (linear) index.

Backs the Python statements x[k] = v and x[sp] = v. Indices are linear, column-major and zero-based (see get). The matrix is modified in place.

  • m must be a scalar (assigned to every selected element) or have as many entries as there are indices (a vector of the other orientation is transposed). Any other shape raises an error.

  • Assigning to a structural zero inserts a new nonzero; the sparsity pattern grows. Assigning a structurally empty value (e.g. DM(1, 1)) removes the entry instead.

  • With a Sparsity index of the same shape, the entries at the pattern's positions receive m (a scalar) or the corresponding entries of m (a matrix).

Parameters:
  • m -- Value(s) to assign

  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Linear index, Slice or list/matrix of indices

  • sp -- Sparsity pattern of the same shape as the matrix

>>> A = DM([[1, 2], [3, 4]])
>>> A[1] = 10; A[[0, 3]] = [7, 8]
>>> A
DM(
[[7, 2],
 [10, 8]])
>>> A[Sparsity.diag(2)] = 0
>>> A
DM(
[[0, 2],
 [10, 0]])
>>> S = DM(Sparsity.diag(2))
>>> S[1] = 5
>>> S.nnz(), S[0, 1]
(3, DM(00))
>>> try: A[[0, 1]] = [1, 2, 3]
... except Exception as e: print("error")
error
>> A = DM([1 2; 3 4]);
>> A(2) = 10; A([1 4]) = [7 8];
>> A
[[7, 2],
[10, 8]]
>> A(Sparsity.diag(2)) = 0;
>> A
[[0, 2],
[10, 0]]
>> S = DM(Sparsity.diag(2));
>> S(2) = 5;
>> S.nnz(), S(1, 2)
3
00
>> try, A([1 2]) = [1 2 3]; catch e, disp('error'); end
error
julia> A = ca.DM([1 2; 3 4]);
julia> A[2] = 10; A[[1, 4]] = [7, 8];
julia> A
DM(
[[7, 2],
 [10, 8]])
julia> S = ca.DM(ca.Sparsity.diag(2));
julia> S[2] = 5;
julia> ca.nnz(S), S[1, 2]
(3, 00)
julia> try A[[1, 2]] = [1, 2, 3]; catch; println("error") end
error

See also: get, set_nz, erase

Overload: set(self, SX m, bool ind1, Slice rr, Slice cc)

Assign a submatrix by row and column indices.

Backs the Python statement x[i, j] = v. The matrix is modified in place. m must be len(rr)-by-len(cc), a scalar (broadcast to all selected entries) or a vector of the transposed orientation (transposed automatically); other shapes raise an error. Assigning into structural zeros inserts nonzeros; assigning a sparse m first erases the selected block, so its structural zeros become structural zeros.

Parameters:
  • m -- Value(s) to assign

  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • rr -- Row index, Slice or list/matrix of row indices

  • cc -- Column index, Slice or list/matrix of column indices

>>> A = DM([[1, 2, 3], [4, 5, 6]])
>>> A[0, 1] = 9; A[1, :] = 0
>>> A
DM(
[[1, 9, 3],
 [0, 0, 0]])
>>> A[0, :] = DM([7, 8, 9])
>>> A[0, :]
DM([[7, 8, 9]])
>>> A[:, 0] = DM(2, 1)
>>> A.nnz()
4
>>> x = SX.sym("x", 2, 2)
>>> x[0, 0] = 0
>>> x
SX(
[[0, x_2],
 [x_1, x_3]])
>>> try: A[0, :] = [1, 2]
... except Exception as e: print("error")
error
>> A = DM([1 2 3; 4 5 6]);
>> A(1, 2) = 9; A(2, :) = 0;
>> A
[[1, 9, 3],
[0, 0, 0]]
>> A(1, :) = DM([7; 8; 9]);
>> A(1, :)
[[7, 8, 9]]
>> A(:, 1) = DM(2, 1);
>> A.nnz()
4
>> x = SX.sym('x', 2, 2);
>> x(1, 1) = 0;
>> x
[[0, x_2],
[x_1, x_3]]
>> try, A(1, :) = [1 2]; catch e, disp('error'); end
error
julia> A = ca.DM([1 2 3; 4 5 6]);
julia> A[1, 2] = 9; A[2, :] = 0;
julia> A
DM(
[[1, 9, 3],
 [0, 0, 0]])
julia> A[1, :] = ca.DM([7, 8, 9]);
julia> A[1, :]
DM([[7, 8, 9]])
julia> A[:, 1] = ca.DM(2, 1);
julia> ca.nnz(A)
4
julia> x = ca.SX.sym("x", 2, 2);
julia> x[1, 1] = 0;
julia> x
SX(
[[0, x_2],
 [x_1, x_3]])
julia> try A[1, :] = [1, 2]; catch; println("error") end
error

See also: get

Extra doc | Doc source | Implementation

static set_max_depth(...)

Set the depth to which SX subexpressions are compared during simplification.

set_max_depth(int eq_depth)

The on-the-fly simplifications (x - x -> 0, x/x -> 1, x == x -> 1, ...) recognise two operands as equal when they are the same node, or, up to this depth, when they are the same operation applied to equal operands. Depth 1 (the default) recognises (x+y) - (x+y); depth 2 also sin(x+y) - sin(x+y). Depth 0 compares nodes only. Global setting, SX only; calling without an argument restores the default.

Parameters:

eq_depth -- Comparison depth, default 1

>>> x = SX.sym("x"); y = SX.sym("y")
>>> sin(x + y) - sin(x + y)
SX((sin((x+y))-sin((x+y))))
>>> SX.set_max_depth(2)
>>> sin(x + y) - sin(x + y)
SX(0)
>>> SX.set_max_depth()
>>> SX.get_max_depth()
1
>> x = SX.sym('x'); y = SX.sym('y');
>> sin(x + y) - sin(x + y)
(sin((x+y))-sin((x+y)))
>> SX.set_max_depth(2);
>> sin(x + y) - sin(x + y)
0
>> SX.set_max_depth();
>> SX.get_max_depth()
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> sin(x + y) - sin(x + y)
SX((sin((x+y))-sin((x+y))))
julia> ca.SX.set_max_depth(2)
julia> sin(x + y) - sin(x + y)
SX(0)
julia> ca.SX.set_max_depth()
julia> ca.SX.get_max_depth()
1

See also: get_max_depth, is_equal

Extra doc | Doc source | Implementation

set_nz(...)
set_nz(self, SX m, bool ind1, Slice k)
set_nz(self, SX m, bool ind1, IM k)

Assign structural nonzeros by their position in the nonzero storage.

Backs the Python statement x.nz[k] = v. The sparsity pattern never changes: only stored values are overwritten (writing 0 keeps the entry as a structural nonzero). m must be a scalar (assigned to every selected nonzero) or have as many entries as there are indices; a mismatch raises an error.

Parameters:
  • m -- Value(s) to assign

  • ind1 -- True for one-based indices (MATLAB); Python always passes false

  • k -- Nonzero index, Slice or list/matrix of indices

>>> S = DM(Sparsity.diag(3))
>>> S.nz[:] = [4, 5, 6]; S.nz[0] = 0
>>> S
DM(
[[0, 00, 00],
 [00, 5, 00],
 [00, 00, 6]])
>>> S.nnz()
3
>>> try: S.nz[[0, 1]] = [1, 2, 3]
... except Exception as e: print("error")
error
>> S = DM(Sparsity.diag(3));
>> S.set_nz([4 5 6], true, 1:3); S.set_nz(0, true, 1);
>> S
[[0, 00, 00],
[00, 5, 00],
[00, 00, 6]]
>> S.nnz()
3
>> try, S.set_nz([1 2 3], true, [1 2]); catch e, disp('error'); end
error
julia> S = ca.DM(ca.Sparsity.diag(3));
julia> S.nz[:] = [4, 5, 6]; S.nz[1] = 0;
julia> S
DM(
[[0, 00, 00],
 [00, 5, 00],
 [00, 00, 6]])
julia> ca.nnz(S)
3
julia> try S.nz[[1, 2]] = [1, 2, 3]; catch; println("error") end
error

See also: get_nz, set

Extra doc | Doc source | Implementation

static set_precision(...)

Set the precision, field width and scientific flag used when printing

set_precision(int precision)

nonzeros.

Global settings per class (DM and SX each keep their own), applied by str(), print() and the print_* methods. Defaults: precision 6, width 0, scientific false.

>>> DM.set_precision(3)
>>> DM(1/3)
DM(0.333)
>>> DM.set_precision(6)
>>> DM(1/3)
DM(0.333333)
>> DM.set_precision(3);
>> DM(1/3)
0.333
>> DM.set_precision(6);
>> DM(1/3)
0.333333
julia> ca.DM.set_precision(3)
julia> ca.DM(1/3)
DM(0.333)
julia> ca.DM.set_precision(6)
julia> ca.DM(1/3)
DM(0.333333)

See also: get_precision

Extra doc | Doc source | Implementation

static set_scientific(...)
set_scientific(bool scientific)
static set_width(...)
set_width(int width)
size(...)

Get the size along a particular dimension.

size(self) -> (int,int)
size(self, int axis) -> int
Parameters:

axis -- 1 for the number of rows, 2 for the number of columns; any other value raises an error

Get the shape as a pair (number of rows, number of columns)

>>> x = MX.sym("x", 2, 3)
>>> x.size(), x.size(1), x.size(2)
((2, 3), 2, 3)
>> x = MX.sym('x', 2, 3);
>> size(x)
2 3
>> fprintf('%d %d\n', size(x, 1), size(x, 2))
2 3
julia> x = ca.MX.sym("x", 2, 3);
julia> size(x), size(x, 1), size(x, 2)
((2, 3), 2, 3)

See also: size1, size2, numel, dim

Extra doc | Doc source | Implementation

size1(...)

Get the first dimension (i.e. number of rows)

size1(self) -> int
>>> x = MX.sym("x", 2, 3)
>>> x.size1(), x.size2()
(2, 3)
>> x = MX.sym('x', 2, 3);
>> fprintf('%d %d\n', x.size1(), x.size2())
2 3
julia> x = ca.MX.sym("x", 2, 3);
julia> ca.size1(x), ca.size2(x)
(2, 3)

See also: size2, size, rows

Extra doc | Doc source | Implementation

size2(...)

Get the second dimension (i.e. number of columns)

size2(self) -> int

See also: size1, size, columns

Extra doc | Doc source | Implementation

sparsity(...)

Get the sparsity pattern (Python: sparsity())

sparsity(self) -> Sparsity

Returns a copy of the Sparsity object; patterns are reference counted, so this is cheap.

>>> DM(Sparsity.diag(2)).sparsity()
Sparsity(2x2,2nz)
>> DM(Sparsity.diag(2)).sparsity()
2x2,2nz
julia> ca.sparsity(ca.DM(ca.Sparsity.diag(2)))
Sparsity(2x2,2nz)

See also: nonzeros

Extra doc | Doc source

str(...)

Get the string representation that disp prints.

str(self, bool more) -> str

Doc source

static sym(...)

Create a list of length r of lists of length p of nrow-by-ncol symbolic

sym(str name, int nrow, int ncol) -> SX
sym(str name, (int,int) rc) -> SX
sym(str name, Sparsity sp) -> SX
sym(str name, Sparsity sp, int p) -> [SX]
sym(str name, int nrow, int ncol, int p) -> [SX]
sym(str name, Sparsity sp, int p, int r) -> [[SX]]
sym(str name, int nrow, int ncol, int p, int r) -> [[SX]]

primitives.

>>> MX.sym("x", 1, 1, 2, 2)
[[MX(x_00), MX(x_01)], [MX(x_10), MX(x_11)]]
>> v = MX.sym('x', 1, 1, 2, 2);
>> numel(v), v{1}{2}, v{2}{1}
2
x_01
x_10
julia> ca.MX.sym("x", 1, 1, 2, 2)
2-element Vector{Vector{MX}}:
 MX[x_00, x_01]
 MX[x_10, x_11]

Overload: sym(str name, int nrow, int ncol)

Create an nrow-by-ncol symbolic primitive.

Creates a new, dense symbol; two symbols with the same name are still different symbols. For SX each entry is a separate scalar symbol named name_k (k the column-major index), while an MX symbol is a single node with the given name. Only SX and MX have symbols; DM.sym raises an error.

Parameters:
  • name -- Name used for printing. For SX, a name of the form "[a,b,c]" assigns individual names to the numel() entries.

  • nrow -- Number of rows, default 1

  • ncol -- Number of columns, default 1

>>> SX.sym("x"), MX.sym("x", 2, 3).dim()
(SX(x), '2x3')
>>> SX.sym("x", 2, 2)
SX(
[[x_0, x_2],
 [x_1, x_3]])
>>> SX.sym("[a,b,c]", 3)
SX([a, b, c])
>>> is_equal(SX.sym("x"), SX.sym("x"))
False
>> SX.sym('x'), MX.sym('x', 2, 3).dim()
x
2x3
>> SX.sym('x', 2, 2)
[[x_0, x_2],
[x_1, x_3]]
>> SX.sym('[a,b,c]', 3)
[a, b, c]
>> is_equal(SX.sym('x'), SX.sym('x'))
0
julia> ca.SX.sym("x"), ca.dim(ca.MX.sym("x", 2, 3))
(x, "2x3")
julia> ca.SX.sym("x", 2, 2)
SX(
[[x_0, x_2],
 [x_1, x_3]])
julia> ca.SX.sym("[a,b,c]", 3)
SX([a, b, c])
julia> isequal(ca.SX.sym("x"), ca.SX.sym("x"))
false

See also: symvar, zeros, ones

Overload: sym(str name, (int,int) rc)

Construct a symbolic primitive with given dimensions, as a pair (nrow, ncol)

Overload: sym(str name, Sparsity sp)

Create symbolic primitive with a given sparsity pattern.

Only the structural nonzeros of sp become symbolic entries; for SX they are numbered by nonzero index.

>>> SX.sym("p", Sparsity.diag(2))
SX(
[[p_0, 00],
 [00, p_1]])
>>> MX.sym("p", Sparsity.diag(2)).dim(True)
'2x2,2nz'
>> SX.sym('p', Sparsity.diag(2))
[[p_0, 00],
[00, p_1]]
>> MX.sym('p', Sparsity.diag(2)).dim(true)
2x2,2nz
julia> ca.SX.sym("p", ca.Sparsity.diag(2))
SX(
[[p_0, 00],
 [00, p_1]])
julia> ca.dim(ca.MX.sym("p", ca.Sparsity.diag(2)), true)
"2x2,2nz"

Overload: sym(str name, Sparsity sp, int p)

Create a list of length p of symbolic primitives with a given sparsity.

The k-th symbol is named name followed by k (no separator).

>>> MX.sym("x", Sparsity.dense(2, 1), 3)
[MX(x0), MX(x1), MX(x2)]
>> v = MX.sym('x', Sparsity.dense(2, 1), 3);
>> numel(v), v{1}, v{3}
3
x0
x2
julia> ca.MX.sym("x", ca.Sparsity.dense(2, 1), 3)
3-element Vector{MX}:
 MX(x0)
 MX(x1)
 MX(x2)

Overload: sym(str name, int nrow, int ncol, int p)

Create a list of length p of nrow-by-ncol symbolic primitives.

>>> SX.sym("x", 1, 1, 2)
[SX(x0), SX(x1)]
>> v = SX.sym('x', 1, 1, 2);
>> v{1}, v{2}
x0
x1
julia> ca.SX.sym("x", 1, 1, 2)
2-element Vector{SX}:
 SX(x0)
 SX(x1)

Overload: sym(str name, Sparsity sp, int p, int r)

Create a list of length r of lists of length p of symbolic primitives.

with given sparsity. The symbol at outer index i and inner index k is named name_ik.

Extra doc | Doc source | Implementation

to_file(...)

Write a numerical matrix to a text file (DM only)

to_file(self, str filename, str format)

Supported formats, selected by the file extension unless format is given:

  • mtx: Matrix Market coordinate format (sparse, one-based row/col/value triplets)

  • txt: one line per row, whitespace separated, aligned columns, full precision, structural zeros written as 00. Does not scale to large sparse matrices. Values are written with the C locale; nan and inf round-trip. An unknown extension or format raises an error. SX is not supported.

Parameters:
  • filename -- Output path

  • format -- "mtx" or "txt"; empty means deduce from the extension

>>> import os, tempfile
>>> fn = os.path.join(tempfile.mkdtemp(), "a.txt")
>>> A = DM(Sparsity.diag(2)) * 2.5
>>> A.to_file(fn)
>>> DM.from_file(fn)
DM(
[[2.5, 00],
 [00, 2.5]])
>>> os.remove(fn); os.rmdir(os.path.dirname(fn))
>> fn = [tempname '.txt'];
>> A = DM(Sparsity.diag(2)) * 2.5;
>> A.to_file(fn);
>> DM.from_file(fn)
[[2.5, 00],
[00, 2.5]]
>> delete(fn);
julia> fn = joinpath(mktempdir(), "a.txt");
julia> A = ca.DM(ca.Sparsity.diag(2)) * 2.5;
julia> ca.to_file(A, fn)
julia> ca.DM.from_file(fn)
DM(
[[2.5, 00],
 [00, 2.5]])
julia> rm(dirname(fn), recursive=true)

See also: from_file, Sparsity.to_file

Extra doc | Doc source

static triplet(...)
triplet([int] row, [int] col, SX d) -> SX
triplet([int] row, [int] col, SX d, (int,int) rc) -> SX
triplet([int] row, [int] col, SX d, int nrow, int ncol) -> SX

Construct a sparse matrix from triplet form (row indices, column indices, values)

Entry k of the result is at (row[k], col[k]) with value d[k]. The three lists must have the same length; indices are zero-based and must be within the matrix bounds. The nonzeros are reordered into column- major order. When the same (row, col) pair appears more than once, only the first value is kept; duplicates are not summed.

Parameters:
  • row -- Row index of each entry

  • col -- Column index of each entry

  • d -- Dense vector of values, one per entry

  • nrow -- Number of rows of the result [default: largest row index plus one]

  • ncol -- Number of columns of the result [default: largest column index plus one]

>>> DM.triplet([0, 1], [1, 0], [5, 6], 3, 3)
DM(
[[00, 5, 00],
 [6, 00, 00],
 [00, 00, 00]])
>>> DM.triplet([0, 1], [1, 0], [5, 6], (3, 3)).nonzeros()
[6.0, 5.0]
>>> SX.triplet([0, 1], [0, 1], SX.sym("v", 2), 2, 2)
SX(
[[v_0, 00],
 [00, v_1]])
>>> DM.triplet([], [], [], 2, 2).nnz()
0
>>> try: DM.triplet([0, 1], [1, 0], [5], 3, 3)
... except Exception as e: print("error")
error
>> DM.triplet([0 1], [1 0], [5 6], 3, 3)
[[00, 5, 00],
[6, 00, 00],
[00, 00, 00]]
>> DM.triplet([0 1], [1 0], [5 6], [3 3]).nonzeros()
6 5
>> SX.triplet([0 1], [0 1], SX.sym('v', 2), 2, 2)
[[v_0, 00],
[00, v_1]]
>> DM.triplet([], [], [], 2, 2).nnz()
0
>> try, DM.triplet([0 1], [1 0], 5, 3, 3); catch e, disp('error'); end
error
julia> ca.DM.triplet([0, 1], [1, 0], [5, 6], 3, 3)
DM(
[[00, 5, 00],
 [6, 00, 00],
 [00, 00, 00]])
julia> ca.SX.triplet([0, 1], [0, 1], ca.SX.sym("v", 2), 2, 2)
SX(
[[v_0, 00],
 [00, v_1]])
julia> ca.nnz(ca.DM.triplet([], [], [], 2, 2))
0
julia> try ca.DM.triplet([0, 1], [1, 0], [5], 3, 3); catch; println("error") end
error

See also: Sparsity.triplet

Extra doc | Doc source

static type_name(...)

Name of the class: "DM" or "SX".

type_name() -> str
>>> DM.type_name(), SX.type_name()
('DM', 'SX')
>> fprintf('%s %s\n', DM.type_name(), SX.type_name())
DM SX
julia> ca.DM.type_name(), ca.SX.type_name()
("DM", "SX")

Extra doc | Doc source | Implementation

static unary(...)
unary(int op, SX x) -> SX
which_function(...)

Get function - only valid when is_call() is true.

which_function(self) -> Function

Extra doc | Doc source | Implementation

which_output(...)

Get the index of evaluation output - only valid when is_output() is true.

which_output(self) -> int

Extra doc | Doc source | Implementation

static zeros(...)
zeros(int nrow, int ncol) -> SX
zeros((int,int) rc) -> SX
zeros(Sparsity sp) -> SX

Create a dense matrix or a matrix with specified sparsity with all entries zero.

zeros(nrow, ncol) stores nrow*ncol numerical zeros; zeros(sp) stores a zero at every structural nonzero of sp. To get structural zeros instead, construct from a shape, e.g. DM(2, 2).

>>> DM.zeros(2, 2).nnz(), DM.zeros(Sparsity.diag(2)).nnz(), DM(2, 2).nnz()
(4, 2, 0)
>>> MX.zeros(2, 3)
MX(zeros(2x3))
>> Z = DM.zeros(Sparsity.diag(2));
>> fprintf('%d %d %d\n', DM.zeros(2, 2).nnz(), Z.nnz(), DM(2, 2).nnz())
4 2 0
>> MX.zeros(2, 3)
zeros(2x3)
julia> Z = ca.DM.zeros(ca.Sparsity.diag(2));
julia> ca.nnz(ca.DM.zeros(2, 2)), ca.nnz(Z), ca.nnz(ca.DM(2, 2))
(4, 2, 0)
julia> ca.MX.zeros(2, 3)
MX(zeros(2x3))

See also: ones, Sparsity

Extra doc | Doc source | Implementation

MX

class MX(...)

MX - Matrix expression.

The MX class is used to build up trees made up from MXNodes. It is a more general graph representation than the scalar expression, SX, and much less efficient for small objects. On the other hand, the class allows much more general operations than does SX, in particular matrix valued operations and calls to arbitrary differentiable functions.

The MX class is designed to have identical syntax with the Matrix<> template class, and uses DM (i.e. Matrix<double>) as its internal representation of the values at a node. By keeping the syntaxes identical, it is possible to switch from one class to the other, as well as inlining MX functions to SXElem functions.

Note that an operation is always "lazy", making a matrix multiplication will create a matrix multiplication node, not perform the actual multiplication.

Each node is a matrix-valued operation (symbolic primitive, constant, binary operation, concatenation, matrix product, call to a Function, ...), so an expression such as A +1 is a small number of nodes regardless of the matrix sizes. The graph is immutable: every operation creates new nodes. Symbolic primitives are created with MX.sym; MX(...) creates constants.

>>> x = MX.sym("x", 2)
>>> A = MX.sym("A", 2, 2)
>>> e = A @ x + 1
>>> e
MX((ones(2x1)+mac(A,x,zeros(2x1))))
>>> e.shape, e.n_dep(), e.is_symbolic()
((2, 1), 2, False)
>>> f = Function("f", [A, x], [e])
>>> f(DM([[1, 2], [3, 4]]), DM([1, 1]))
DM([4, 8])
>> x = MX.sym('x', 2); A = MX.sym('A', 2, 2);
>> e = A*x + 1;
>> e
(ones(2x1)+mac(A,x,zeros(2x1)))
>> size(e), e.n_dep(), e.is_symbolic()
2 1
2
0
>> f = Function('f', {A, x}, {e});
>> f(DM([1 2; 3 4]), DM([1; 1]))
[4, 8]
julia> x = ca.MX.sym("x", 2); A = ca.MX.sym("A", 2, 2);
julia> e = A * x + 1;
julia> e
MX((ones(2x1)+mac(A,x,zeros(2x1))))
julia> size(e), ca.n_dep(e), ca.is_symbolic(e)
((2, 1), 2, false)
julia> f = ca.Function("f", [A, x], [e]);
julia> f([1 2; 3 4], [1, 1])
DM([4, 8])

See also: SX, DM, Function

Authors: Joel Andersson

Extra doc

attachAssert(...)

Return the expression with a run-time assertion attached.

attachAssert(self, MX y, str fail_message) -> MX

The result is equal to this expression, but when it is evaluated the scalar expression y is evaluated too and a runtime error with fail_message is raised unless y equals 1. Useful to check preconditions inside a Function. A non-scalar y raises an error at construction.

>>> x = MX.sym("x")
>>> e = x.attachAssert(x > 0, "x must be positive")
>>> e
MX(assertion(x, (0<x)))
>>> f = Function("f", [x], [e])
>>> f(1)
DM(1)
>>> try:
...   f(-1)
... except Exception as e:
...   print("Assertion error: x must be positive" in str(e))
True
>> x = MX.sym('x');
>> e = x.attachAssert(x > 0, 'x must be positive');
>> e
assertion(x, (0<x))
>> f = Function('f', {x}, {e});
>> f(1)
1
>> try, f(-1); catch err, disp('assertion error'); end
assertion error
julia> x = ca.MX.sym("x");
julia> e = ca.attachAssert(x, x > 0, "x must be positive");
julia> e
MX(assertion(x, (0<x)))
julia> f = ca.Function("f", [x], [e]);
julia> f(1)
DM(1)
julia> try
           f(-1)
       catch err
           println(occursin("Assertion error: x must be positive", sprint(showerror, err)))
       end
true

See also: monitor, printme

Extra doc | Doc source | Implementation

static binary(...)

Create an elementwise binary or unary node from an operation code.

binary(int op, MX x, MX y, bool unique_x, bool unique_y) -> MX

Low-level constructors behind the operators: MX.binary(OP_ADD, x, y) is x + y. Operands must have the same shape, or one of them is a scalar, or one is a horizontal repetition of the other (which is repmat-ed). The usual simplifications are applied. An invalid operation code is not checked.

Parameters:
  • op -- One of the OP_* constants

  • unique_x -- Internal hints for in-place simplification; leave false

  • unique_y -- Internal hints for in-place simplification; leave false

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> MX.binary(OP_ADD, x, y), MX.unary(OP_SIN, x)
(MX((x+y)), MX(sin(x)))
>>> MX.binary(OP_ADD, MX.sym("V", 2, 4), MX.sym("W", 2, 2))
MX((V+repmat(W, 2)))
>>> try:
...   MX.binary(OP_ADD, MX.sym("v", 2), MX.sym("w", 3))
... except Exception as e:
...   print("Dimension mismatch" in str(e))
True
>> x = MX.sym('x'); y = MX.sym('y');
>> MX.binary(OP_ADD, x, y), MX.unary(OP_SIN, x)
(x+y)
sin(x)
>> MX.binary(OP_ADD, MX.sym('V', 2, 4), MX.sym('W', 2, 2))
(V+repmat(W, 2))
>> v = MX.sym('v', 2); w = MX.sym('w', 3);
>> try, MX.binary(OP_ADD, v, w); catch e, disp('dimension mismatch'); end
dimension mismatch
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.MX.binary(ca.OP_ADD, x, y), ca.MX.unary(ca.OP_SIN, x)
((x+y), sin(x))
julia> ca.MX.binary(ca.OP_ADD, ca.MX.sym("V", 2, 4), ca.MX.sym("W", 2, 2))
MX((V+repmat(W, 2)))
julia> try
           ca.MX.binary(ca.OP_ADD, ca.MX.sym("v", 2), ca.MX.sym("w", 3))
       catch e
           println(occursin("Dimension mismatch", sprint(showerror, e)))
       end
true

See also: op

Extra doc | Doc source | Implementation

static bspline_dual(...)

Evaluate the B-spline basis functions at given points, see MX::bspline_dual.

bspline_dual([float] x, [[float]] knots, [int] degree, dict opts) -> DM

Doc source | Implementation

class_name(...)

Get class name.

class_name(self) -> str

Extra doc | Doc source | Implementation

colind(...)
colind(self) -> [int]
colind(self, int col) -> int

Get the sparsity pattern. See the Sparsity class for details.

The pattern is stored in compressed column format: colind has size2()+1 entries, the nonzeros of column j are the entries colind(j) up to colind(j+1) (exclusive), and row(el) is the row index of nonzero el. Without argument, the full vectors are returned. Out-of-range indices raise an error.

>>> x = DM(Sparsity.diag(2), [5, 6])
>>> x.row(), x.colind()
([0, 1], [0, 1, 2])
>>> x.row(1), x.colind(2)
(1, 2)
>> x = DM(Sparsity.diag(2), [5; 6]);
>> x.row(), x.colind()
0 1
0 1 2
>> fprintf('%d %d\n', x.row(1), x.colind(2))
1 2
julia> x = ca.DM(ca.Sparsity.diag(2), [5, 6]);
julia> ca.row(x), ca.colind(x)
([0, 1], [0, 1, 2])
julia> ca.row(x, 1), ca.colind(x, 2)
(1, 2)

Extra doc | Doc source | Implementation

columns(...)

Get the number of columns, Octave-style syntax (same as size2())

columns(self) -> int

Extra doc | Doc source | Implementation

debug_repr(...)
debug_repr(self) -> str
dep(...)

Get the ch-th dependency (child node) of this node.

dep(self, int ch) -> MX

Together with n_dep, op and is_op this allows walking the expression graph. Symbolic primitives and constants have no dependencies.

Parameters:

ch -- Index in [0, n_dep()); out of range raises an error

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> e = x*y + 1
>>> e.n_dep(), e.dep(0), e.dep(1)
(2, MX(1), MX((x*y)))
>>> e.dep(1).dep(0), x.n_dep()
(MX(x), 0)
>> x = MX.sym('x'); y = MX.sym('y');
>> e = x*y + 1;
>> e.n_dep(), e.dep(0), e.dep(1)
2
1
(x*y)
>> e.dep(1).dep(0), x.n_dep()
x
0
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> e = x * y + 1;
julia> ca.n_dep(e), ca.dep(e, 0), ca.dep(e, 1)
(2, 1, (x*y))
julia> ca.dep(ca.dep(e, 1), 0), ca.n_dep(x)
(x, 0)

See also: n_dep, op, is_op

Extra doc | Doc source | Implementation

static deserialize(...)

Deserialize an expression from a stream, with type disambiguation.

deserialize(casadi::DeserializingStream & s) -> MX

Counterpart of serialize; use StringDeserializer.unpack from Python.

Extra doc | Doc source | Implementation

dim(...)

Get string representation of dimensions.

dim(self, bool with_nz) -> str

The representation is e.g. "4x5" or, with with_nz true, "4x5,10nz".

>>> DM.eye(3).dim(), DM.eye(3).dim(True), DM.ones(3, 3).dim(True)
('3x3', '3x3,3nz', '3x3,9nz')
>> fprintf('%s %s %s\n', DM.eye(3).dim(), DM.eye(3).dim(true), DM.ones(3, 3).dim(true))
3x3 3x3,3nz 3x3,9nz
julia> ca.dim(ca.DM.eye(3)), ca.dim(ca.DM.eye(3), true), ca.dim(ca.DM.ones(3, 3), true)
("3x3", "3x3,3nz", "3x3,9nz")

See also: size, nnz

Extra doc | Doc source | Implementation

disp(...)

Print a description of the object.

disp(self, bool more)

Doc source | Implementation

dump(...)

Return the expression with the side effect of writing its value to a file.

dump(self, str base_filename, dict opts) -> MX

Each evaluation writes the value to a new file named after base_filename and a running counter. The value is unchanged. A matrix without nonzeros is returned as is.

Parameters:
  • base_filename -- Prefix of the file names

  • opts -- "dir" (directory, default "."), "format" (file format, default "mtx", Matrix Market), "verbose" (print the file name on each dump, default false). Unknown keys raise an error.

See also: monitor, reset_dump_count

Extra doc | Doc source | Implementation

static einstein(...)
einstein(MX A, MX B, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> MX
einstein(MX A, MX B, MX C, [int] dim_a, [int] dim_b, [int] dim_c, [int] a, [int] b, [int] c) -> MX

Compute a dense tensor contraction in Einstein notation.

Computes C_c += A_a * B_b, where a, b and c are index labels in Einstein notation: a label appearing in both a and b is summed over, the remaining labels index the result. Tensors are passed as flat column vectors in column-major (Fortran) order together with their dimensions. Labels are encoded as strictly negative integers. For the matrix product C_ij = A_ik B_kj one writes a = [-1, -3], b = [-3, -2], c = [-1, -2].

Parameters:
  • A -- Dense column vectors with product(dim_a), product(dim_b) entries

  • B -- Dense column vectors with product(dim_a), product(dim_b) entries

  • C -- Optional accumulator with product(dim_c) entries, added to the result; when omitted the result starts from zero

  • dim_a -- Tensor dimensions

  • dim_b -- Tensor dimensions

  • dim_c -- Tensor dimensions

  • a -- Negative labels, one per dimension

  • b -- Negative labels, one per dimension

  • c -- Negative labels, one per dimension

Returns:

Column vector with product(dim_c) entries

Inconsistent dimensions or labels are not validated with a user- facing message. Also available for SX and DM.

>>> A = MX.sym("A", 6)
>>> B = MX.sym("B", 6)
>>> C = einstein(A, B, [2, 3], [3, 2], [2, 2], [-1, -3], [-3, -2], [-1, -2])
>>> C.shape
(4, 1)
>>> f = Function("f", [A, B], [C])
>>> f(DM(range(1, 7)), DM(range(1, 7)))
DM([22, 28, 49, 64])
>>> reshape(DM(range(1, 7)), 2, 3) @ reshape(DM(range(1, 7)), 3, 2)
DM(
[[22, 49],
 [28, 64]])
>> A = MX.sym('A', 6); B = MX.sym('B', 6);
>> C = einstein(A, B, [2 3], [3 2], [2 2], [-1 -3], [-3 -2], [-1 -2]);
>> size(C)
4 1
>> f = Function('f', {A, B}, {C});
>> f(DM((1:6)'), DM((1:6)'))
[22, 28, 49, 64]
>> reshape(DM((1:6)'), 2, 3) * reshape(DM((1:6)'), 3, 2)
[[22, 49],
[28, 64]]
julia> A = ca.MX.sym("A", 6); B = ca.MX.sym("B", 6);
julia> C = ca.einstein(A, B, [2, 3], [3, 2], [2, 2], [-1, -3], [-3, -2], [-1, -2]);
julia> size(C)
(4, 1)
julia> f = ca.Function("f", [A, B], [C]);
julia> f(1:6, 1:6)
DM([22, 28, 49, 64])
julia> reshape(ca.DM(1:6), 2, 3) * reshape(ca.DM(1:6), 3, 2)
DM(
[[22, 49],
 [28, 64]])

Extra doc | Doc source | Implementation

enlarge(...)

Enlarge matrix.

enlarge(self, int nrow, int ncol, [int] rr, [int] cc, bool ind1)

Makes the matrix nrow-by-ncolby inserting empty rows and columns, keeping the existing nonzeros. Modifies the expression in place.

Parameters:
  • nrow -- New number of rows

  • ncol -- New number of columns

  • rr -- Rows of the new matrix that receive the existing rows; one entry per existing row

  • cc -- Columns of the new matrix that receive the existing columns; one entry per existing column

  • ind1 -- True for 1-based indices (MATLAB), default 0-based

>>> B = MX.sym("B", 2, 2)
>>> B.enlarge(3, 3, [0, 2], [0, 2])
>>> B.shape, B.nnz(), B.sparsity().row()
((3, 3), 4, [0, 2, 0, 2])
>> B = MX.sym('B', 2, 2);
>> B.enlarge(3, 3, [1, 3], [1, 3], true);
>> size(B), B.nnz(), B.sparsity().row()
3 3
4
0 2 0 2
julia> B = ca.MX.sym("B", 2, 2);
julia> ca.enlarge(B, 3, 3, [0, 2], [0, 2]);
julia> size(B), ca.nnz(B), ca.row(ca.sparsity(B))
((3, 3), 4, [0, 2, 0, 2])

See also: erase, Sparsity.enlarge

Extra doc | Doc source | Implementation

erase(...)

Erase elements (leaving structural zeros in their place)

erase(self, [int] rr, bool ind1)
erase(self, [int] rr, [int] cc, bool ind1)

Same as the two-index overload, but rr holds linear (column-major) element indices.

>>> B = MX.sym("B", 3, 3)
>>> B.erase([0, 4])
>>> B.sparsity()
Sparsity(3x3,7nz)
>> B = MX.sym('B', 3, 3);
>> B.erase([1, 5], true);
>> B.sparsity()
3x3,7nz
julia> B = ca.MX.sym("B", 3, 3);
julia> ca.erase(B, [0, 4]);
julia> ca.sparsity(B)
Sparsity(3x3,7nz)

Erase a submatrix (leaving structural zeros in its place)

Removes the nonzeros at the intersection of rows rr and columns cc from the sparsity pattern. The shape is unchanged. Modifies the expression in place by replacing it with a new node that references the remaining nonzeros.

Parameters:
  • rr -- Row indices to erase; out-of-range values raise an error

  • cc -- Column indices to erase

  • ind1 -- True for 1-based indices (MATLAB), default 0-based

>>> B = MX.sym("B", 3, 3)
>>> B.erase([0], [1])
>>> B.sparsity(), B.shape
(Sparsity(3x3,8nz), (3, 3))
>> B = MX.sym('B', 3, 3);
>> B.erase(1, 2, true);
>> B.sparsity(), size(B)
3x3,8nz
3 3
julia> B = ca.MX.sym("B", 3, 3);
julia> ca.erase(B, [0], [1]);
julia> ca.sparsity(B), size(B)
(3x3,8nz, (3, 3))

See also: enlarge, Sparsity.erase

Extra doc | Doc source | Implementation

eval_mx(...)

Re-apply the operation of this node to new dependencies.

eval_mx(self, [MX] arg, [bool] unique) -> [MX]

Creates the same operation as this node, applied to arg instead of the node's own dependencies, with the usual simplifications. arg must have exactly n_dep() entries of matching shapes; a mismatch is a developer error. Symbolic primitives and constants return the node itself. Call nodes are re- called with the new arguments; OutputNodes cannot be evaluated this way. Mainly useful for writing graph transformations.

Parameters:
  • arg -- New dependencies

  • unique -- Internal hints that the arguments are not referenced elsewhere; leave empty

Returns:

List with n_out() results

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> (x * y).eval_mx([MX(2), MX(3)]), (x + y).eval_mx([y, x])
([MX(6)], [MX((y+x))])
>>> MX.sym("v", 3)[1].eval_mx([MX([4, 5, 6])])
[MX([4, 5, 6][1])]
>> x = MX.sym('x'); y = MX.sym('y');
>> e = x * y; r = e.eval_mx({MX(2), MX(3)});
>> numel(r), r{1}
1
6
>> e = x + y; r = e.eval_mx({y, x});
>> r{1}
(y+x)
>> v = MX.sym('v', 3); e = v(2); r = e.eval_mx({MX([4; 5; 6])});
>> r{1}
[4, 5, 6][1]
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.eval_mx(x * y, [ca.MX(2), ca.MX(3)]), ca.eval_mx(x + y, [y, x])
(MX[6], MX[(y+x)])
julia> ca.eval_mx(ca.MX.sym("v", 3)[2], [ca.MX([4, 5, 6])])
1-element Vector{MX}:
 MX([4, 5, 6][1])

See also: dep, n_dep, graph_substitute

Extra doc | Doc source | Implementation

static eye(...)

Identity matrix constant of size n-by-n, with a diagonal sparsity

eye(int n) -> MX

pattern.

>>> MX.eye(2), MX.eye(2).is_eye()
(MX(ones(2x2,2nz)), True)
>> MX.eye(2), MX.eye(2).is_eye()
ones(2x2,2nz)
1
julia> ca.MX.eye(2), ca.is_eye(ca.MX.eye(2))
(ones(2x2,2nz), true)

Extra doc | Doc source | Implementation

get(...)
get(self, bool ind1, int rr) -> MX
get(self, bool ind1, Sparsity sp) -> MX
get(self, bool ind1, Slice rr) -> MX
get(self, bool ind1, IM rr) -> MX
get(self, bool ind1, MX rr) -> MX
get(self, bool ind1, int rr, int cc) -> MX
get(self, bool ind1, int rr, Slice cc) -> MX
get(self, bool ind1, Slice rr, int cc) -> MX
get(self, bool ind1, Slice rr, Slice cc) -> MX
get(self, bool ind1, Slice rr, IM cc) -> MX
get(self, bool ind1, Slice rr, MX cc) -> MX
get(self, bool ind1, IM rr, Slice cc) -> MX
get(self, bool ind1, IM rr, IM cc) -> MX
get(self, bool ind1, MX rr, Slice cc) -> MX
get(self, bool ind1, MX rr, MX cc) -> MX

Overload: get(self, bool ind1, Slice rr)

Get a submatrix by linear index (what x[k] does)

Backs single-index subscripting. Elements are addressed in column- major order over all numel() entries, including structural zeros. Indices may be negative (counted from the end); out-of-range indices raise an error. The result is a new GetNonzeros node referencing the selected nonzeros of this expression; a structural zero is returned as an empty-sparsity constant. Accepted index types: integer, slice, list of integers, list of booleans (mask), integer DM, Sparsity pattern of the same shape (returns the projection on that pattern) and MX (a symbolic index into the nonzeros of a dense expression, evaluated at run time with truncation and NaN for out-of- range values).

Parameters:
  • ind1 -- True for 1-based indices (MATLAB), false for 0-based

  • rr -- Element indices

>>> X = MX.sym("X", 3, 3)
>>> X[4], X[-1], X[[0, 4]], X[1:3].shape
(MX(X[4]), MX(X[8]), MX(X[:8:4]), (2, 1))
>>> try:
...   X[9]
... except Exception as e:
...   print("Out of bounds" in str(e))
True
>>> S = MX.sym("S", Sparsity.lower(2))
>>> S[2], S[2].nnz()
(MX(00), 0)
>>> X[Sparsity.lower(3)]
MX(project(X))
>>> k = MX.sym("k")
>>> v = MX.sym("v", 4)
>>> v[k], Function("f", [v, k], [v[k]])(DM([10, 20, 30, 40]), 1.7)
(MX(v[k]), DM(20))
>> X = MX.sym('X', 3, 3);
>> a = X(5); b = X(end); c = X([1, 5]); d = X([2; 3]);
>> a, b, c, size(d)
X[4]
X[8]
X[:8:4]
2 1
>> try, X(10); catch e, disp('out of bounds'); end
out of bounds
>> S = MX.sym('S', Sparsity.lower(2));
>> e = S(3);
>> e, e.nnz()
00
0
>> X(Sparsity.lower(3))
project(X)
>> k = MX.sym('k'); v = MX.sym('v', 4);
>> f = Function('f', {v, k}, {v(k)});
>> v(k), f(DM([10; 20; 30; 40]), 2.7)
v[(k-1)]
20
julia> X = ca.MX.sym("X", 3, 3);
julia> X[5], X[end], X[[1, 5]], size(X[2:3])
(X[4], X[8], X[[0, 4]], (2, 1))
julia> try
           X[10]
       catch e
           println(e isa BoundsError)
       end
true
julia> S = ca.MX.sym("S", ca.Sparsity.lower(2));
julia> S[3], ca.nnz(S[3])
(00, 0)
julia> X[ca.Sparsity.lower(3)]
MX(project(X))
julia> k = ca.MX.sym("k"); v = ca.MX.sym("v", 4);
julia> v[k]
MX(v[(k-1)])
julia> ca.Function("f", [v, k], [v[k]])([10, 20, 30, 40], 2.7)
DM(20)

See also: set, get_nz, nz

Overload: get(self, bool ind1, Slice rr, Slice cc)

Get a submatrix by row and column index (what x[i, j] does)

Backs two-index subscripting. rr and cc select rows and columns (integer, slice, list, integer DM); the result has shape len(rr)-by-len(cc) and the corresponding part of the sparsity pattern. Out-of-range indices raise an error. An MX index is only allowed for dense expressions and selects at run time.

>>> X = MX.sym("X", 3, 3)
>>> X[0, 1], X[1, :].shape, X[[0, 2], [0, 2]].shape
(MX(X[3]), (1, 3), (2, 2))
>>> S = MX.sym("S", Sparsity.lower(3))
>>> S[:, 0].sparsity(), S[0, 2].nnz()
(Sparsity(3x1), 0)
>>> k = MX.sym("k")
>>> X[k, 1]
MX(X[(k;3:6:3)])
>> X = MX.sym('X', 3, 3);
>> a = X(1, 2); b = X(2, :); c = X([1 3], [1 3]);
>> a, size(b), size(c)
X[3]
1 3
2 2
>> S = MX.sym('S', Sparsity.lower(3));
>> a = S(:, 1); b = S(1, 3);
>> a.sparsity(), b.nnz()
3x1
0
>> k = MX.sym('k');
>> X(k, 2)
X[((k-1);3)]
julia> X = ca.MX.sym("X", 3, 3);
julia> X[1, 2], size(X[2, :]), size(X[[1, 3], [1, 3]])
(X[3], (1, 3), (2, 2))
julia> S = ca.MX.sym("S", ca.Sparsity.lower(3));
julia> ca.sparsity(S[:, 1]), ca.nnz(S[1, 3])
(3x1, 0)

See also: set

Extra doc | Doc source | Implementation

static get_free(...)

Get the free variables of a Function.

get_free(Function f) -> [MX]

Same as f.free_mx(): the symbolic primitives that occur in the outputs of an MXFunction without being an input. Such a Function can only be created with the option "allow_free" and cannot be evaluated until the free variables are bound.

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> f = Function("f", [x], [x + y], {"allow_free": True})
>>> MX.get_free(f), MX.get_free(Function("g", [x], [x]))
([MX(y)], [])
>>> try:
...   Function("f", [x], [x + y])
... except Exception as e:
...   print("variables [y] are free" in str(e))
True
>> x = MX.sym('x'); y = MX.sym('y');
>> f = Function('f', {x}, {x + y}, struct('allow_free', true));
>> v = MX.get_free(f);
>> numel(v), v{1}
1
y
>> numel(MX.get_free(Function('g', {x}, {x})))
0
>> try, Function('f', {x}, {x + y}); catch e, disp('free variables'); end
free variables
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> f = ca.Function("f", [x], [x + y], Dict("allow_free" => true));
julia> ca.MX.get_free(f), ca.MX.get_free(ca.Function("g", [x], [x]))
(MX[y], MX[])
julia> try
           ca.Function("f", [x], [x + y])
       catch e
           println(occursin("variables [y] are free", sprint(showerror, e)))
       end
true

See also: Function.free_mx, symvar

Extra doc | Doc source | Implementation

static get_input(...)

Get the symbolic inputs of a Function, as MX.

get_input(Function f) -> [MX]

Same as f.mx_in(). For an MXFunction these are the original input expressions; for other Functions fresh symbols with the input names and sparsities.

>>> x = MX.sym("x")
>>> f = Function("f", [x], [2*x])
>>> MX.get_input(f), is_equal(MX.get_input(f)[0], x)
([MX(x)], True)
>> x = MX.sym('x');
>> f = Function('f', {x}, {2*x});
>> v = MX.get_input(f);
>> numel(v), v{1}, is_equal(v{1}, x)
1
x
1
julia> x = ca.MX.sym("x");
julia> f = ca.Function("f", [x], [2 * x]);
julia> ca.MX.get_input(f), ca.is_equal(ca.MX.get_input(f)[1], x)
(MX[x], true)

See also: Function.mx_in, get_free

Extra doc | Doc source | Implementation

static get_max_depth(...)

Get the depth to which equalities are checked for simplifications.

get_max_depth() -> int

See also: set_max_depth

Extra doc | Doc source | Implementation

get_nz(...)
get_nz(self, bool ind1, int kk) -> MX
get_nz(self, bool ind1, Slice kk) -> MX
get_nz(self, bool ind1, IM kk) -> MX
get_nz(self, bool ind1, MX kk) -> MX
get_nz(self, bool ind1, Slice inner, MX outer) -> MX
get_nz(self, bool ind1, MX inner, Slice outer) -> MX
get_nz(self, bool ind1, MX inner, MX outer) -> MX

Get a set of nonzeros (what x.nz[k] does)

Indexes the nnz() nonzeros directly, skipping structural zeros, in column- major order. Negative indices count from the end; out-of-range indices raise an error. An MX index (or an inner/outer pair of indices) creates a parametric lookup that is resolved at evaluation time; such a node has no derivative with respect to the index. For dense expressions x[k] and x.nz[k] coincide.

>>> S = MX.sym("S", Sparsity.lower(3))
>>> S.nz[1], S.nz[:].shape, len(S.nz)
(MX(S[1]), (6, 1), 6)
>>> k = MX.sym("k")
>>> S.nz[k]
MX(S[k])
>>> MX.sym("x", 2, 2).nz[[]].shape
(0, 1)
>> S = MX.sym('S', Sparsity.lower(3));
>> a = S.get_nz(true, 2); b = S.get_nz(true, Slice());
>> a, size(b), S.nnz()
S[1]
6 1
6
>> k = MX.sym('k');
>> S.get_nz(true, k)
S[(k-1)]
>> size(MX.sym('x', 2, 2).get_nz(true, []))
0 0
julia> S = ca.MX.sym("S", ca.Sparsity.lower(3));
julia> S.nz[2], size(S.nz[:]), length(S.nz)
(S[1], (6, 1), 6)
julia> k = ca.MX.sym("k");
julia> S.nz[k]
MX(S[(k-1)])
julia> size(ca.MX.sym("x", 2, 2).nz[Int[]])
(0, 1)

See also: set_nz, get

Extra doc | Doc source | Implementation

get_output(...)

Get an output of a multiple-output node.

get_output(self, int oind) -> MX

For a multiple-output node (a Function call), returns the OutputNode selecting output oind. For any other node only oind == 0 is valid and the node itself is returned.

>>> a = SX.sym("a")
>>> f = Function("f", [a], [a + 1, 2*a])
>>> x = MX.sym("x")
>>> r0, r1 = f(x, )
>>> call = r0.dep(0)
>>> call.get_output(1), is_equal(call.get_output(0), r0)
(MX(f(x){1}), True)
>>> x.get_output(0)
MX(x)
>> a = SX.sym('a');
>> f = Function('f', {a}, {a + 1, 2*a});
>> x = MX.sym('x');
>> [r0, r1] = f(x);
>> call = r0.dep(0);
>> call.get_output(1), is_equal(call.get_output(0), r0)
f(x){1}
1
>> x.get_output(0)
x
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [a + 1, 2 * a]);
julia> x = ca.MX.sym("x");
julia> r0, r1 = f(x);
julia> call = ca.dep(r0, 0);
julia> ca.get_output(call, 1), ca.is_equal(ca.get_output(call, 0), r0)
(f(x){1}, true)
julia> ca.get_output(x, 0)
MX(x)

See also: n_out, which_output

Extra doc | Doc source | Implementation

get_temp(...)
get_temp(self) -> int
has_duplicates(...)
has_duplicates(self) -> bool
has_output(...)

Check if this is a multiple-output node.

has_output(self) -> bool

True for the call node of a Function with several outputs. Such a node cannot be used directly in expressions; select an output with get_output.

>>> a = SX.sym("a")
>>> f = Function("f", [a], [a + 1, 2*a])
>>> x = MX.sym("x")
>>> r0, r1 = f(x, )
>>> r0.dep(0).has_output(), r0.has_output(), x.has_output()
(True, False, False)
>> a = SX.sym('a');
>> f = Function('f', {a}, {a + 1, 2*a});
>> x = MX.sym('x');
>> [r0, r1] = f(x);
>> call = r0.dep(0);
>> call.has_output(), r0.has_output(), x.has_output()
1
0
0
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [a + 1, 2 * a]);
julia> x = ca.MX.sym("x");
julia> r0, r1 = f(x);
julia> ca.has_output(ca.dep(r0, 0)), ca.has_output(r0), ca.has_output(x)
(true, false, false)

See also: n_out, get_output, is_output

Extra doc | Doc source | Implementation

static inf(...)
inf(int nrow, int ncol) -> MX
inf((int,int) rc) -> MX
inf(Sparsity sp) -> MX

Create a constant with all nonzeros +inf.

Dense nrow-by-ncol (default 1-by-1), or with the given sparsity pattern.

>>> MX.inf(), MX.inf(2, 1), MX.inf(Sparsity.lower(2))
(MX(inf), MX(inf(2x1)), MX(inf(2x2,3nz)))
>> MX.inf(), MX.inf(2, 1), MX.inf(Sparsity.lower(2))
inf
inf(2x1)
inf(2x2,3nz)
julia> ca.MX.inf(), ca.MX.inf(2, 1), ca.MX.inf(ca.Sparsity.lower(2))
(inf, inf(2x1), inf(2x2,3nz))

See also: is_inf, nan

Extra doc | Doc source | Implementation

info(...)

Obtain information about the node as a dictionary.

info(self) -> dict

The contents depend on the node type; most nodes return an empty dictionary. For example, a slicing node reports the slice it takes.

>>> X = MX.sym("X", 2, 2)
>>> X[0, 1].info()
{'slice': {'start': 2, 'step': 1, 'stop': 3}}
>>> X.info()
{}
>> X = MX.sym('X', 2, 2);
>> e = X(1, 2); s = e.info();
>> s.slice
start: 2
step: 1
stop: 3
>> isempty(fieldnames(X.info()))
1
julia> X = ca.MX.sym("X", 3, 3);
julia> ca.info(X[1, 2])
Dict{String, Any} with 1 entry:
  "slice" => Dict{String, Any}("step"=>1, "stop"=>4, "start"=>3)
julia> ca.info(X)
Dict{String, Any}()

Extra doc | Doc source | Implementation

static interpn_linear(...)

Low-level inlined multilinear interpolation.

interpn_linear([MX] x, MX v, [MX] xq, dict opts) -> MX

Builds the interpolation as explicit MX operations (low, nonzero lookups and arithmetic) instead of an interpolant Function, so that the grid and values can be symbolic. Usually you want interpolant('name', 'linear', ...) instead. Extrapolates linearly outside the grid.

Parameters:
  • x -- Grid points, one vector per dimension

  • v -- Values on the grid, flattened in column-major order over the grid; its length must be an integer multiple m of the number of grid points, giving m outputs per query point

  • xq -- Query coordinates, one vector per dimension, all of the same length nq

  • opts -- "lookup_mode": list with one of "linear", "exact", "binary", "auto" (default) per dimension, see low

Returns:

nq-by-m matrix

>>> g = MX.sym("g", 3)
>>> v = MX.sym("v", 3)
>>> xq = MX.sym("xq", 2)
>>> e = MX.interpn_linear([g], v, [xq])
>>> f = Function("f", [g, v, xq], [e])
>>> f(DM([0, 1, 2]), DM([0, 10, 40]), DM([0.5, 3]))
DM([5, 70])
>>> try:
...   MX.interpn_linear([g], MX.sym("w", 4), [xq])
... except Exception as e:
...   print("Dimension mismatch" in str(e))
True
>> g = MX.sym('g', 3); v = MX.sym('v', 3); xq = MX.sym('xq', 2);
>> e = MX.interpn_linear({g}, v, {xq});
>> f = Function('f', {g, v, xq}, {e});
>> f(DM([0; 1; 2]), DM([0; 10; 40]), DM([0.5; 3]))
[5, 70]
>> w = MX.sym('w', 4);
>> try, MX.interpn_linear({g}, w, {xq}); catch e, disp('dimension mismatch'); end
dimension mismatch
julia> g = ca.MX.sym("g", 3); v = ca.MX.sym("v", 3); xq = ca.MX.sym("xq", 2);
julia> ex = ca.MX.interpn_linear([g], v, [xq]);
julia> f = ca.Function("f", [g, v, xq], [ex]);
julia> f([0, 1, 2], [0, 10, 40], [0.5, 3])
DM([5, 70])
julia> try
           ca.MX.interpn_linear([g], ca.MX.sym("w", 4), [xq])
       catch e
           println(occursin("Dimension mismatch", sprint(showerror, e)))
       end
true

See also: interpolant, low

Extra doc | Doc source | Implementation

inv(...)

Element-wise inverse, 1/x.

inv(self) -> MX

Not the matrix inverse: use inv or inv_node for that. Applied twice it returns the original node. Not available in MATLAB and Julia, where inv is the matrix inverse; use 1./x there.

>>> A = MX.sym("A", 2, 2)
>>> A.inv(), A.inv().inv()
(MX((1./A)), MX(A))
>>> evalf(MX(4).inv())
DM(0.25)

See also: inv, inv_node

Extra doc | Doc source | Implementation

is_binary(...)

Check if the node is an elementwise binary operation.

is_binary(self) -> bool

Elementwise operations with two operands (OP_ADD, OP_MUL, OP_POW, comparisons, ...). Matrix products, concatenations and calls are not binary nodes. Note that x + x and x*x are stored as unary nodes (doubling, square).

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> A = MX.sym("A", 2, 2)
>>> (x + y).is_binary(), (x**y).is_binary(), (A @ A).is_binary(), (x + x).is_binary()
(True, True, False, False)
>> x = MX.sym('x'); y = MX.sym('y'); A = MX.sym('A', 2, 2);
>> a = x + y; b = x^y; c = A*A; d = x + x;
>> a.is_binary(), b.is_binary(), c.is_binary(), d.is_binary()
1
1
0
0
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y"); A = ca.MX.sym("A", 2, 2);
julia> ca.is_binary(x + y), ca.is_binary(x^y), ca.is_binary(A * A), ca.is_binary(x + x)
(true, true, false, false)

See also: is_unary, op

Extra doc | Doc source | Implementation

is_call(...)

Check if the node is a call to a Function.

is_call(self) -> bool

A call to a Function with several outputs is a single call node; the values you get back from calling the Function are OutputNodes that reference it (see is_output). MX Functions are inlined when called with MX arguments unless never_inline is set, so no call node appears in that case.

>>> a = SX.sym("a")
>>> f = Function("f", [a], [a + 1, 2*a])
>>> x = MX.sym("x")
>>> r0, r1 = f(x, )
>>> r0.is_call(), r0.is_output(), r0.dep(0).is_call()
(False, True, True)
>>> r0.dep(0).which_function().name()
'f'
>> a = SX.sym('a');
>> f = Function('f', {a}, {a + 1, 2*a});
>> x = MX.sym('x');
>> [r0, r1] = f(x);
>> call = r0.dep(0);
>> r0.is_call(), r0.is_output(), call.is_call()
0
1
1
>> call.which_function().name()
f
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [a + 1, 2 * a]);
julia> x = ca.MX.sym("x");
julia> r0, r1 = f(x);
julia> ca.is_call(r0), ca.is_output(r0), ca.is_call(ca.dep(r0, 0))
(false, true, true)
julia> ca.name(ca.which_function(ca.dep(r0, 0)))
"f"

See also: which_function, is_output, which_output, n_out

Extra doc | Doc source | Implementation

is_column(...)

Check if the matrix is a column vector (i.e. size2()==1)

is_column(self) -> bool

Extra doc | Doc source | Implementation

is_commutative(...)

Check if a binary operation is commutative.

is_commutative(self) -> bool

Unary operations count as commutative. Any other node raises an error.

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> (x + y).is_commutative(), (x - y).is_commutative()
(True, False)
>> x = MX.sym('x'); y = MX.sym('y');
>> a = x + y; b = x - y;
>> a.is_commutative(), b.is_commutative()
1
0
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.is_commutative(x + y), ca.is_commutative(x - y)
(true, false)

See also: is_binary, is_unary

Extra doc | Doc source | Implementation

is_constant(...)

Check if the node is a constant.

is_constant(self) -> bool

True only for constant nodes. Operations between constants are folded into a new constant where possible, but an expression without symbols is not constant in general (e.g. a Function call with constant arguments); use evalf to evaluate it.

>>> MX(1).is_constant(), MX(2, 2).is_constant(), MX.sym("x").is_constant()
(True, True, False)
>>> (MX(1) + MX(2)).is_constant()
True
>> MX(1).is_constant(), MX(2, 2).is_constant(), MX.sym('x').is_constant()
1
1
0
>> e = MX(1) + MX(2);
>> e.is_constant()
1
julia> ca.is_constant(ca.MX(1)), ca.is_constant(ca.MX(2, 2)), ca.is_constant(ca.MX.sym("x"))
(true, true, false)
julia> ca.is_constant(ca.MX(1) + ca.MX(2))
true

See also: is_symbolic, to_DM, evalf

Extra doc | Doc source | Implementation

is_dense(...)

Check if the matrix is dense, i.e. nnz() equals numel()

is_dense(self) -> bool

Based on the sparsity pattern only: stored numerical zeros still count as nonzeros. Empty matrices are dense.

>>> DM.zeros(2, 2).is_dense(), DM(2, 2).is_dense(), DM(0, 3).is_dense()
(True, False, True)
>> Z = DM.zeros(2, 2);
>> fprintf('%d %d %d\n', Z.is_dense(), DM(2, 2).is_dense(), DM(0, 3).is_dense())
1 0 1
julia> ca.is_dense(ca.DM.zeros(2, 2)), ca.is_dense(ca.DM(2, 2)), ca.is_dense(ca.DM(0, 3))
(true, false, true)

See also: nnz, numel, densify

Extra doc | Doc source | Implementation

is_doubled(...)

Check if the node is the sum of two equal expressions, or 2*x.

is_doubled(self) -> bool

True for x + x (which is stored as a doubling node) and for 2*x, and for a sum whose two operands compare equal up to get_max_depth.

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> (x + x).is_doubled(), (2*x).is_doubled(), (x + y).is_doubled()
(True, True, False)
>> x = MX.sym('x'); y = MX.sym('y');
>> a = x + x; b = 2*x; c = x + y;
>> a.is_doubled(), b.is_doubled(), c.is_doubled()
1
1
0
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.is_doubled(x + x), ca.is_doubled(2 * x), ca.is_doubled(x + y)
(true, true, false)

Extra doc | Doc source | Implementation

is_empty(...)

Check if the matrix is empty, i.e. if one of the dimensions is zero.

is_empty(self, bool both) -> bool

With both true, only a 0-by-0 matrix counts as empty.

>>> DM(0, 3).is_empty(), DM(0, 3).is_empty(True), DM(0, 0).is_empty(True)
(True, False, True)
>>> DM(1, 1).is_empty()
False
>> E = DM(0, 3);
>> fprintf('%d %d %d\n', E.is_empty(), E.is_empty(true), DM(0, 0).is_empty(true))
1 0 1
>> DM(1, 1).is_empty()
0
julia> E = ca.DM(0, 3);
julia> ca.is_empty(E), ca.is_empty(E, true), ca.is_empty(ca.DM(0, 0), true)
(true, false, true)
julia> ca.is_empty(ca.DM(1, 1))
false

Extra doc | Doc source | Implementation

is_eye(...)

Check if the node is a constant identity matrix.

is_eye(self) -> bool

Only recognizes constants created as an identity (MX.eye, DM.eye); a dense constant that happens to equal the identity is not detected. A 1-by-1 constant one counts.

>>> MX.eye(2).is_eye(), MX(DM([[1, 0], [0, 1]])).is_eye(), MX(1).is_eye()
(True, False, True)
>> MX.eye(2).is_eye(), MX(DM([1 0; 0 1])).is_eye(), MX(1).is_eye()
1
0
1
julia> ca.is_eye(ca.MX.eye(2)), ca.is_eye(ca.MX([1 0; 0 1])), ca.is_eye(ca.MX(1))
(true, false, true)

Extra doc | Doc source | Implementation

is_half(...)

Check if the node is a constant with all nonzeros 0.5 (false negatives

is_half(self) -> bool

possible)

Extra doc | Doc source | Implementation

is_inf(...)

Check if the node is a constant with all nonzeros +inf (false negatives

is_inf(self) -> bool

possible)

>>> MX.inf().is_inf(), MX.inf(2, 2).is_inf(), MX(1).is_inf()
(True, True, False)
>> MX.inf().is_inf(), MX.inf(2, 2).is_inf(), MX(1).is_inf()
1
1
0
julia> ca.is_inf(ca.MX.inf()), ca.is_inf(ca.MX.inf(2, 2)), ca.is_inf(ca.MX(1))
(true, true, false)

See also: is_minus_inf, MX.inf

Extra doc | Doc source | Implementation

is_integer(...)

Check if the node is a constant with integer-valued nonzeros.

is_integer(self) -> bool

False for non-constant nodes.

>>> MX(3).is_integer(), MX(3.5).is_integer(), MX.sym("x").is_integer()
(True, False, False)
>> MX(3).is_integer(), MX(3.5).is_integer(), MX.sym('x').is_integer()
1
0
0
julia> ca.is_integer(ca.MX(3)), ca.is_integer(ca.MX(3.5)), ca.is_integer(ca.MX.sym("x"))
(true, false, false)

Extra doc | Doc source | Implementation

is_minus_inf(...)

Check if the node is a constant with all nonzeros -inf (false negatives

is_minus_inf(self) -> bool

possible)

>>> (-MX.inf()).is_minus_inf(), MX.inf().is_minus_inf()
(True, False)
>> m = -MX.inf();
>> m.is_minus_inf(), MX.inf().is_minus_inf()
1
0
julia> ca.is_minus_inf(-ca.MX.inf()), ca.is_minus_inf(ca.MX.inf())
(true, false)

Extra doc | Doc source | Implementation

is_minus_one(...)

Check if the node is a constant with all nonzeros -1 (false negatives

is_minus_one(self) -> bool

possible)

>>> MX(-1).is_minus_one(), (-MX(1)).is_minus_one(), MX(1).is_minus_one()
(True, True, False)
>> m = -MX(1);
>> MX(-1).is_minus_one(), m.is_minus_one(), MX(1).is_minus_one()
1
1
0
julia> ca.is_minus_one(ca.MX(-1)), ca.is_minus_one(-ca.MX(1)), ca.is_minus_one(ca.MX(1))
(true, true, false)

Extra doc | Doc source | Implementation

is_multiplication(...)

Check if the node is a matrix product (mtimes)

is_multiplication(self) -> bool

Elementwise multiplication does not count.

>>> A = MX.sym("A", 2, 2)
>>> (A @ A).is_multiplication(), (A * A).is_multiplication()
(True, False)
>> A = MX.sym('A', 2, 2);
>> a = A*A; b = A.*A;
>> a.is_multiplication(), b.is_multiplication()
1
0
julia> A = ca.MX.sym("A", 2, 2);
julia> ca.is_multiplication(A * A), ca.is_multiplication(A .* A)
(true, false)

Extra doc | Doc source | Implementation

is_nonnegative(...)

Check if a value is always nonnegative (false negatives are allowed)

is_nonnegative(self) -> bool

Recognizes nonnegative constants and operations with a nonnegative range such as squares, absolute values, exponentials and square roots.

>>> x = MX.sym("x")
>>> (x**2).is_nonnegative(), fabs(x).is_nonnegative(), exp(x).is_nonnegative()
(True, True, True)
>>> x.is_nonnegative(), MX(-3).is_nonnegative(), MX(0).is_nonnegative()
(False, False, True)
>> x = MX.sym('x');
>> a = x^2; b = abs(x); c = exp(x);
>> a.is_nonnegative(), b.is_nonnegative(), c.is_nonnegative()
1
1
1
>> x.is_nonnegative(), MX(-3).is_nonnegative(), MX(0).is_nonnegative()
0
0
1
julia> x = ca.MX.sym("x");
julia> ca.is_nonnegative(x^2), ca.is_nonnegative(abs(x)), ca.is_nonnegative(exp(x))
(true, true, true)
julia> ca.is_nonnegative(x), ca.is_nonnegative(ca.MX(-3)), ca.is_nonnegative(ca.MX(0))
(false, false, true)

Extra doc | Doc source | Implementation

is_norm(...)

Check if the node is a norm (norm_1, norm_2, norm_inf or norm_fro)

is_norm(self) -> bool
>>> A = MX.sym("A", 2, 2)
>>> norm_2(A).is_norm(), norm_fro(A).is_norm(), sqrt(dot(A, A)).is_norm()
(True, True, False)
>> A = MX.sym('A', 2, 2);
>> a = norm_2(A); b = norm_fro(A); c = sqrt(dot(A, A));
>> a.is_norm(), b.is_norm(), c.is_norm()
1
1
0
julia> A = ca.MX.sym("A", 2, 2);
julia> ca.is_norm(ca.norm_2(A)), ca.is_norm(ca.norm_fro(A)), ca.is_norm(sqrt(ca.dot(A, A)))
(true, true, false)

Extra doc | Doc source | Implementation

is_null(...)
is_null(self) -> bool
is_one(...)

Check if the node is a constant with all nonzeros one (false negatives

is_one(self) -> bool

possible)

Structural zeros are ignored: MX(Sparsity.lower(2)) is not "one" because it has structural zeros that would be zero when densified.

>>> MX(1).is_one(), MX.ones(2, 2).is_one(), MX(Sparsity.lower(2)).is_one()
(True, True, False)
>> MX(1).is_one(), MX.ones(2, 2).is_one(), MX(Sparsity.lower(2)).is_one()
1
1
0
julia> ca.is_one(ca.MX(1)), ca.is_one(ca.MX.ones(2, 2)),
       ca.is_one(ca.MX(ca.Sparsity.lower(2)))
(true, true, false)

Extra doc | Doc source | Implementation

is_op(...)

Check if the node is a certain operation.

is_op(self, int op) -> bool
Parameters:

op -- One of the OP_* constants (OP_ADD, OP_SIN, OP_CALL, OP_GETNONZEROS,...)

>>> x = MX.sym("x", 2)
>>> (x + 1).is_op(OP_ADD), sin(x).is_op(OP_SIN), x.is_op(OP_PARAMETER)
(True, True, True)
>>> x[0].is_op(OP_GETNONZEROS), MX(1).is_op(OP_CONST)
(True, True)
>> x = MX.sym('x', 2);
>> a = x + 1; b = sin(x);
>> a.is_op(OP_ADD), b.is_op(OP_SIN), x.is_op(OP_PARAMETER)
1
1
1
>> c = x(1);
>> c.is_op(OP_GETNONZEROS), MX(1).is_op(OP_CONST)
1
1
julia> x = ca.MX.sym("x", 2);
julia> ca.is_op(x + 1, ca.OP_ADD), ca.is_op(sin.(x), ca.OP_SIN),
       ca.is_op(x, ca.OP_PARAMETER)
(true, true, true)
julia> ca.is_op(x[1], ca.OP_GETNONZEROS), ca.is_op(ca.MX(1), ca.OP_CONST)
(true, true)

See also: op

Extra doc | Doc source | Implementation

is_output(...)

Check if the node selects one output of a multiple-output node.

is_output(self) -> bool

The expressions obtained by calling a Function with several outputs are OutputNodes: they have one dependency, the call node, and which_output gives the index.

>>> a = SX.sym("a")
>>> f = Function("f", [a], [a + 1, 2*a])
>>> x = MX.sym("x")
>>> r0, r1 = f(x, )
>>> r1, r1.is_output(), r1.which_output(), r1.dep(0)
(MX(f(x){1}), True, 1, MX(f(x)))
>>> x.is_output(), (x + 1).is_output()
(False, False)
>> a = SX.sym('a');
>> f = Function('f', {a}, {a + 1, 2*a});
>> x = MX.sym('x');
>> [r0, r1] = f(x);
>> r1, r1.is_output(), r1.which_output(), r1.dep(0)
f(x){1}
1
1
f(x)
>> e = x + 1;
>> x.is_output(), e.is_output()
0
0
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [a + 1, 2 * a]);
julia> x = ca.MX.sym("x");
julia> r0, r1 = f(x);
julia> r1, ca.is_output(r1), ca.which_output(r1), ca.dep(r1, 0)
(f(x){1}, true, 1, f(x))
julia> ca.is_output(x), ca.is_output(x + 1)
(false, false)

See also: which_output, is_call, has_output

Extra doc | Doc source | Implementation

is_regular(...)

Check that a constant node contains neither NaN nor Inf.

is_regular(self) -> bool

Only defined for constant nodes; a symbolic expression raises an error.

>>> MX(1).is_regular(), MX.inf().is_regular(), MX(DM([1, float("nan")])).is_regular()
(True, False, False)
>>> try:
...   MX.sym("x").is_regular()
... except Exception as e:
...   print("Cannot check regularity for symbolic MX" in str(e))
True
>> MX(1).is_regular(), MX.inf().is_regular()
1
0
>> MX(DM([1; nan])).is_regular()
0
>> try, MX.sym('x').is_regular(); catch e, disp('error'); end
error
julia> ca.is_regular(ca.MX(1)), ca.is_regular(ca.MX.inf()), ca.is_regular(ca.MX([1, NaN]))
(true, false, false)
julia> try
           ca.is_regular(ca.MX.sym("x"))
       catch e
           println(occursin("Cannot check regularity", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

is_row(...)

Check if the matrix is a row vector (i.e. size1()==1)

is_row(self) -> bool

Extra doc | Doc source | Implementation

is_scalar(...)

Check if the matrix is scalar, i.e. 1-by-1.

is_scalar(self, bool scalar_and_dense) -> bool
Parameters:

scalar_and_dense -- When true, a 1-by-1 matrix with a structural zero does not count

>>> x = SX.sym("x", Sparsity(1, 1))
>>> x.is_scalar(), x.is_scalar(True), SX.sym("y").is_scalar(True)
(True, False, True)
>> x = SX.sym('x', Sparsity(1, 1));
>> fprintf('%d %d %d\n', x.is_scalar(), x.is_scalar(true), SX.sym('y').is_scalar(true))
1 0 1
julia> x = ca.SX.sym("x", ca.Sparsity(1, 1));
julia> ca.is_scalar(x), ca.is_scalar(x, true), ca.is_scalar(ca.SX.sym("y"), true)
(true, false, true)

Extra doc | Doc source | Implementation

is_square(...)

Check if the matrix is square, i.e. size1() equals size2()

is_square(self) -> bool

Extra doc | Doc source | Implementation

is_symbolic(...)

Check if the node is a symbolic primitive (created by MX.sym)

is_symbolic(self) -> bool

False for any expression built from primitives, including concatenations of primitives (use is_valid_input for those). A symbol without nonzeros, e.g. MX.sym("x", 2, 0), is stored as an empty constant and is not symbolic.

>>> x = MX.sym("x")
>>> x.is_symbolic(), (x + 1).is_symbolic(), vertcat(x, x).is_symbolic()
(True, False, False)
>>> MX.sym("e", 2, 0).is_symbolic()
False
>> x = MX.sym('x'); e = x + 1; v = vertcat(x, x);
>> x.is_symbolic(), e.is_symbolic(), v.is_symbolic()
1
0
0
>> MX.sym('e', 2, 0).is_symbolic()
0
julia> x = ca.MX.sym("x");
julia> ca.is_symbolic(x), ca.is_symbolic(x + 1), ca.is_symbolic([x; x])
(true, false, false)
julia> ca.is_symbolic(ca.MX.sym("e", 2, 0))
false

See also: is_constant, is_valid_input, name

Extra doc | Doc source | Implementation

is_transpose(...)

Check if the node is a transpose operation.

is_transpose(self) -> bool

The transpose of a scalar is the scalar itself and that of a vector is a reshape, so only transposes of genuine matrices create a transpose node.

>>> A = MX.sym("A", 2, 2)
>>> A.T.is_transpose(), A.is_transpose(), MX.sym("v", 2).T.is_transpose()
(True, False, False)
>> A = MX.sym('A', 2, 2); At = A'; vt = MX.sym('v', 2)';
>> At.is_transpose(), A.is_transpose(), vt.is_transpose()
1
0
0
julia> A = ca.MX.sym("A", 2, 2);
julia> ca.is_transpose(A'), ca.is_transpose(A), ca.is_transpose(ca.MX.sym("v", 2)')
(true, false, false)

See also: T

Extra doc | Doc source | Implementation

is_tril(...)

Check if the matrix is lower triangular.

is_tril(self) -> bool

Decided on the sparsity pattern alone, see is_triu.

See also: is_triu, tril, tril2symm

Extra doc | Doc source | Implementation

is_triu(...)

Check if the matrix is upper triangular.

is_triu(self) -> bool

Decided on the sparsity pattern alone: all structural nonzeros must lie on or above the diagonal. A dense matrix with numerical zeros below the diagonal is not upper triangular. Also defined for non- square matrices.

>>> DM(Sparsity.upper(3), 1).is_triu(), DM.zeros(2, 2).is_triu(), DM(2, 2).is_triu()
(True, False, True)
>> U = DM(Sparsity.upper(3), 1);
>> fprintf('%d %d %d\n', U.is_triu(), DM.zeros(2, 2).is_triu(), DM(2, 2).is_triu())
1 0 1
julia> U = ca.DM(ca.Sparsity.upper(3), 1);
julia> ca.is_triu(U), ca.is_triu(ca.DM.zeros(2, 2)), ca.is_triu(ca.DM(2, 2))
(true, false, true)

See also: is_tril, triu, triu2symm

Extra doc | Doc source | Implementation

is_unary(...)

Check if the node is an elementwise unary operation.

is_unary(self) -> bool

OP_SIN, OP_NEG, OP_SQ, ... Transposes, reshapes and projections are not unary nodes even though they have one dependency.

>>> x = MX.sym("x")
>>> A = MX.sym("A", 2, 2)
>>> sin(x).is_unary(), (-x).is_unary(), x.is_unary(), A.T.is_unary()
(True, True, False, False)
>> x = MX.sym('x'); A = MX.sym('A', 2, 2);
>> a = sin(x); b = -x; c = A';
>> a.is_unary(), b.is_unary(), x.is_unary(), c.is_unary()
1
1
0
0
julia> x = ca.MX.sym("x"); A = ca.MX.sym("A", 2, 2);
julia> ca.is_unary(sin(x)), ca.is_unary(-x), ca.is_unary(x), ca.is_unary(A')
(true, true, false, false)

See also: is_binary, op

Extra doc | Doc source | Implementation

is_valid_input(...)

Check if the expression can be used as a Function input.

is_valid_input(self) -> bool

Valid inputs are symbolic primitives, reshapes and transposes of them, and (nested) concatenations of valid inputs. Constants without nonzeros are also accepted. An expression that is not a valid input raises an error when passed as a Function input.

>>> x = MX.sym("x", 2)
>>> y = MX.sym("y", 3)
>>> vertcat(x, y).is_valid_input(), vertcat(x, y).T.is_valid_input()
(True, True)
>>> (x + 1).is_valid_input(), MX(1).is_valid_input(), MX(2, 2).is_valid_input()
(False, False, True)
>> x = MX.sym('x', 2); y = MX.sym('y', 3);
>> v = [x; y]; vt = v';
>> v.is_valid_input(), vt.is_valid_input()
1
1
>> e = x + 1;
>> e.is_valid_input(), MX(1).is_valid_input(), MX(2, 2).is_valid_input()
0
0
1
julia> x = ca.MX.sym("x", 2); y = ca.MX.sym("y", 3);
julia> ca.is_valid_input([x; y]), ca.is_valid_input([x; y]')
(true, true)
julia> ca.is_valid_input(x + 1), ca.is_valid_input(ca.MX(1)), ca.is_valid_input(ca.MX(2, 2))
(false, false, true)

See also: primitives, n_primitives, is_symbolic

Extra doc | Doc source | Implementation

is_value(...)

Check if the node is a constant with all nonzeros equal to val.

is_value(self, float val) -> bool

False negatives are possible: only constant nodes are inspected; symbolic expressions always give false.

>>> MX(3).is_value(3), MX(DM([3, 3])).is_value(3), MX(DM([3, 4])).is_value(3)
(True, True, False)
>>> MX.sym("x").is_value(3)
False
>> MX(3).is_value(3), MX(DM([3; 3])).is_value(3)
1
1
>> MX(DM([3; 4])).is_value(3)
0
>> MX.sym('x').is_value(3)
0
julia> ca.is_value(ca.MX(3), 3), ca.is_value(ca.MX([3, 3]), 3),
       ca.is_value(ca.MX([3, 4]), 3)
(true, true, false)
julia> ca.is_value(ca.MX.sym("x"), 3)
false

Extra doc | Doc source | Implementation

is_vector(...)

Check if the matrix is a row or column vector.

is_vector(self) -> bool

True when size1() or size2() is one, so scalars and n-by-1 or 1-by-n empties count. A 0-by-0 matrix does not.

>>> DM(3, 1).is_vector(), DM(1, 3).is_vector(), DM(1, 1).is_vector()
(True, True, True)
>>> DM(3, 3).is_vector(), DM(0, 1).is_vector(), DM(0, 0).is_vector()
(False, True, False)
>> fprintf('%d %d %d\n', DM(3, 1).is_vector(), DM(1, 3).is_vector(), DM(1, 1).is_vector())
1 1 1
>> fprintf('%d %d %d\n', DM(3, 3).is_vector(), DM(0, 1).is_vector(), DM(0, 0).is_vector())
0 1 0
julia> ca.is_vector(ca.DM(3, 1)), ca.is_vector(ca.DM(1, 3)), ca.is_vector(ca.DM(1, 1))
(true, true, true)
julia> ca.is_vector(ca.DM(3, 3)), ca.is_vector(ca.DM(0, 1)), ca.is_vector(ca.DM(0, 0))
(false, true, false)

See also: is_row, is_column

Extra doc | Doc source | Implementation

is_zero(...)

Check if the node is a constant zero (false negatives are possible)

is_zero(self) -> bool

True for constants with all nonzeros zero and for any matrix without nonzeros, whether symbolic or not. Expressions that simplify to zero (x - x, 0*x) are folded to a constant at construction and therefore report true.

>>> x = MX.sym("x")
>>> MX(0).is_zero(), MX(2, 2).is_zero(), (x - x).is_zero(), x.is_zero()
(True, True, True, False)
>>> MX.sym("e", 2, 0).is_zero()
True
>> x = MX.sym('x'); e = x - x;
>> MX(0).is_zero(), MX(2, 2).is_zero(), e.is_zero(), x.is_zero()
1
1
1
0
>> MX.sym('e', 2, 0).is_zero()
1
julia> x = ca.MX.sym("x");
julia> ca.is_zero(ca.MX(0)), ca.is_zero(ca.MX(2, 2)), ca.is_zero(x - x), ca.is_zero(x)
(true, true, true, false)
julia> ca.is_zero(ca.MX.sym("e", 2, 0))
true

Extra doc | Doc source | Implementation

join_primitives(...)
join_primitives(self, [DM] v) -> DM
join_primitives(self, [SX] v) -> SX
join_primitives(self, [MX] v) -> MX

Join values along the symbolic primitives of this expression.

Inverse of split_primitives: v holds one value per primitive, with the shape of that primitive, and the result has the shape of this expression. A wrong number of pieces raises an error.

>>> x = MX.sym("x", 2)
>>> y = MX.sym("y", 3)
>>> X = vertcat(x, y)
>>> X.join_primitives([DM([1, 2]), DM([3, 4, 5])])
DM([1, 2, 3, 4, 5])
>>> try:
...   X.join_primitives([DM([1, 2])])
... except Exception as e:
...   print("Wrong number of primitives" in str(e))
True
>> x = MX.sym('x', 2); y = MX.sym('y', 3);
>> X = [x; y];
>> X.join_primitives({DM([1; 2]), DM([3; 4; 5])})
[1, 2, 3, 4, 5]
>> try, X.join_primitives({DM([1; 2])}); catch e, disp('wrong number of primitives'); end
wrong number of primitives
julia> x = ca.MX.sym("x", 2); y = ca.MX.sym("y", 3);
julia> X = [x; y];
julia> ca.join_primitives(X, [ca.DM([1, 2]), ca.DM([3, 4, 5])])
DM([1, 2, 3, 4, 5])
julia> try
           ca.join_primitives(X, [ca.DM([1, 2])])
       catch e
           println(occursin("Wrong number of primitives", sprint(showerror, e)))
       end
true

See also: split_primitives, primitives

Extra doc | Doc source | Implementation

mapping(...)

Get the nonzero mapping of a GetNonzeros or SetNonzeros node.

mapping(self) -> IM

For a slicing node (x[...], x.nz[...]) returns the indices of the nonzeros of the dependency that make up the result; for an assignment node, the target indices. Any other node raises an error.

>>> X = MX.sym("X", 3, 3)
>>> X[0, 1].mapping(), X[:, 1].mapping()
(DM(3), DM([3, 4, 5]))
>>> try:
...   X.mapping()
... except Exception as e:
...   print("'mapping' not defined" in str(e))
True
>> X = MX.sym('X', 3, 3);
>> a = X(1, 2); b = X(:, 2);
>> a.mapping(), b.mapping()
3
[3, 4, 5]
>> try, X.mapping(); catch e, disp('error'); end
error
julia> X = ca.MX.sym("X", 3, 3);
julia> ca.mapping(X[1, 2]), ca.mapping(X[:, 2])
([3;;], [3; 4; 5;;])
julia> try
           ca.mapping(X)
       catch e
           println(occursin("'mapping' not defined", sprint(showerror, e)))
       end
true

See also: info

Extra doc | Doc source | Implementation

monitor(...)

Return the expression with the side effect of printing its value.

monitor(self, str comment) -> MX

When the returned expression is evaluated, comment followed by the nonzeros is printed to standard output. The value is unchanged. A matrix without nonzeros is returned as is.

>>> x = MX.sym("x")
>>> e = x.monitor("value of x")
>>> e, e.is_op(OP_MONITOR)
(MX(monitor(x, value of x)), True)
>> x = MX.sym('x');
>> e = x.monitor('value of x');
>> e, e.is_op(OP_MONITOR)
monitor(x, value of x)
1
julia> x = ca.MX.sym("x");
julia> e = ca.monitor(x, "value of x");
julia> e, ca.is_op(e, ca.OP_MONITOR)
(monitor(x, value of x), true)

See also: printme, dump, attachAssert

Extra doc | Doc source | Implementation

n_dep(...)

Get the number of dependencies (child nodes) of this node.

n_dep(self) -> int

Zero for symbolic primitives and constants, one for unary operations and projections, two for binary operations, the number of arguments for concatenations and Function calls.

>>> x = MX.sym("x")
>>> A = MX.sym("A", 2, 2)
>>> x.n_dep(), sin(x).n_dep(), (x + 1).n_dep(), vertcat(x, x, x).n_dep()
(0, 1, 2, 3)
>>> (A @ A).n_dep(), A[0, 0].n_dep(), MX(1).n_dep()
(3, 1, 0)
>> x = MX.sym('x'); A = MX.sym('A', 2, 2);
>> e = x + 1; v = vertcat(x, x, x);
>> x.n_dep(), sin(x).n_dep(), e.n_dep(), v.n_dep()
0
1
2
3
>> P = A*A; a = A(1, 1);
>> P.n_dep(), a.n_dep(), MX(1).n_dep()
3
1
0
julia> x = ca.MX.sym("x"); A = ca.MX.sym("A", 2, 2);
julia> ca.n_dep(x), ca.n_dep(sin(x)), ca.n_dep(x + 1), ca.n_dep([x; x; x])
(0, 1, 2, 3)
julia> ca.n_dep(A * A), ca.n_dep(A[1, 1]), ca.n_dep(ca.MX(1))
(3, 1, 0)

See also: dep

Extra doc | Doc source | Implementation

n_out(...)

Number of outputs of this node.

n_out(self) -> int

Greater than one only for multiple-output nodes, i.e. a call to a Function with several outputs. Every other node, including the OutputNode that selects one output of such a call, reports 1.

>>> a = SX.sym("a")
>>> f = Function("f", [a], [a + 1, 2*a])
>>> x = MX.sym("x")
>>> r0, r1 = f(x, )
>>> call = r0.dep(0)
>>> call, call.n_out(), r0.n_out()
(MX(f(x)), 2, 1)
>> a = SX.sym('a');
>> f = Function('f', {a}, {a + 1, 2*a});
>> x = MX.sym('x');
>> [r0, r1] = f(x);
>> call = r0.dep(0);
>> call, call.n_out(), r0.n_out()
f(x)
2
1
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [a + 1, 2 * a]);
julia> x = ca.MX.sym("x");
julia> r0, r1 = f(x);
julia> call = ca.dep(r0, 0);
julia> call, ca.n_out(call), ca.n_out(r0)
(f(x), 2, 1)

See also: get_output, has_output, is_output

Extra doc | Doc source | Implementation

n_primitives(...)

Get the number of symbolic primitives in a valid Function input.

n_primitives(self) -> int

For an expression that is not a valid input the count is 1 (the expression itself); check is_valid_input first.

>>> x = MX.sym("x", 2)
>>> y = MX.sym("y", 3)
>>> vertcat(x, y).n_primitives(), x.n_primitives()
(2, 1)
>> x = MX.sym('x', 2); y = MX.sym('y', 3);
>> v = [x; y];
>> v.n_primitives(), x.n_primitives()
2
1
julia> x = ca.MX.sym("x", 2); y = ca.MX.sym("y", 3);
julia> ca.n_primitives([x; y]), ca.n_primitives(x)
(2, 1)

See also: primitives, is_valid_input

Extra doc | Doc source | Implementation

name(...)

Get the name of a symbolic primitive.

name(self) -> str

Only defined for nodes created by MX.sym; any other node raises an error. Check with is_symbolic first.

>>> x = MX.sym("x", 2)
>>> x.name()
'x'
>>> try:
...   (x + 1).name()
... except Exception as e:
...   print("'name' not defined" in str(e))
True
>> x = MX.sym('x', 2);
>> x.name()
x
>> e = x + 1;
>> try, e.name(); catch err, disp('error'); end
error
julia> x = ca.MX.sym("x", 2);
julia> ca.name(x)
"x"
julia> try
           ca.name(x + 1)
       catch e
           println(occursin("'name' not defined", sprint(showerror, e)))
       end
true

See also: is_symbolic, symvar

Extra doc | Doc source | Implementation

static nan(...)
nan(int nrow, int ncol) -> MX
nan((int,int) rc) -> MX
nan(Sparsity sp) -> MX

Create a constant with all nonzeros NaN.

Dense nrow-by-ncol (default 1-by-1), or with the given sparsity pattern.

>>> MX.nan(), MX.nan(Sparsity.lower(2))
(MX(nan), MX(nan(2x2,3nz)))
>> MX.nan(), MX.nan(Sparsity.lower(2))
nan
nan(2x2,3nz)
julia> ca.MX.nan(), ca.MX.nan(ca.Sparsity.lower(2))
(nan, nan(2x2,3nz))

See also: inf

Extra doc | Doc source | Implementation

nnz(...)

Get the number of structural nonzeros.

nnz(self) -> int

Counts the entries present in the sparsity pattern. Entries that are stored but numerically zero still count; structural zeros (not stored) do not. For a dense matrix this equals numel().

>>> DM.eye(3).nnz(), DM.ones(3, 3).nnz(), DM(3, 3).nnz()
(3, 9, 0)
>>> DM([[1, 0], [0, 2]]).nnz()
4
>>> MX.sym("x", 2, 0).nnz()
0
>> fprintf('%d %d %d\n', DM.eye(3).nnz(), DM.ones(3, 3).nnz(), DM(3, 3).nnz())
3 9 0
>> DM([1 0; 0 2]).nnz()
4
>> MX.sym('x', 2, 0).nnz()
0
julia> ca.nnz(ca.DM.eye(3)), ca.nnz(ca.DM.ones(3, 3)), ca.nnz(ca.DM(3, 3))
(3, 9, 0)
julia> ca.nnz(ca.DM([1 0; 0 2]))
4
julia> ca.nnz(ca.MX.sym("x", 2, 0))
0

See also: numel, nnz_lower, nnz_upper, nnz_diag, sparsity

Extra doc | Doc source | Implementation

nnz_diag(...)

Get the number of structural nonzeros on the diagonal.

nnz_diag(self) -> int

Also defined for non-square matrices.

>>> DM.ones(3, 3).nnz_diag(), DM.eye(3).nnz_diag(), DM.ones(2, 3).nnz_diag()
(3, 3, 2)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_diag(), I.nnz_diag(), B.nnz_diag())
3 3 2
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_diag(A), ca.nnz_diag(I), ca.nnz_diag(B)
(3, 3, 2)

See also: nnz, nnz_lower, nnz_upper

Extra doc | Doc source | Implementation

nnz_lower(...)

Get the number of structural nonzeros on or below the diagonal.

nnz_lower(self) -> int
>>> DM.ones(3, 3).nnz_lower(), DM.eye(3).nnz_lower(), DM.ones(2, 3).nnz_lower()
(6, 3, 3)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_lower(), I.nnz_lower(), B.nnz_lower())
6 3 3
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_lower(A), ca.nnz_lower(I), ca.nnz_lower(B)
(6, 3, 3)

See also: nnz, nnz_upper, nnz_diag

Extra doc | Doc source | Implementation

nnz_upper(...)

Get the number of structural nonzeros on or above the diagonal.

nnz_upper(self) -> int
>>> DM.ones(3, 3).nnz_upper(), DM.eye(3).nnz_upper(), DM.ones(2, 3).nnz_upper()
(6, 3, 5)
>> A = DM.ones(3, 3); I = DM.eye(3); B = DM.ones(2, 3);
>> fprintf('%d %d %d\n', A.nnz_upper(), I.nnz_upper(), B.nnz_upper())
6 3 5
julia> A = ca.DM.ones(3, 3); I = ca.DM.eye(3); B = ca.DM.ones(2, 3);
julia> ca.nnz_upper(A), ca.nnz_upper(I), ca.nnz_upper(B)
(6, 3, 5)

See also: nnz, nnz_lower, nnz_diag

Extra doc | Doc source | Implementation

nonzeros(...)

Get the nonzeros as a list of 1-by-1 expressions.

nonzeros(self) -> [MX]

Since an MX is not a container, each entry is an expression that selects one nonzero of this expression. When the expression satisfies is_valid_input, the entries are the scalar primitives themselves: for vertcat(x, y) with scalar symbols x and y the result is [x, y]. The list has nnz() entries, in column-major order.

See also: x.nz[:], primitives

Extra doc | Doc source | Implementation

numel(...)

Get the number of elements, size1()*size2()

numel(self) -> int

Counts all entries, structural zeros included.

>>> DM.eye(3).numel(), MX.sym("x", 2, 0).numel(), SX.sym("x").numel()
(9, 0, 1)
>> fprintf('%d %d %d\n', DM.eye(3).numel(), MX.sym('x', 2, 0).numel(), SX.sym('x').numel())
9 0 1
julia> ca.numel(ca.DM.eye(3)), ca.numel(ca.MX.sym("x", 2, 0)), ca.numel(ca.SX.sym("x"))
(9, 0, 1)
julia> length(ca.DM.eye(3))
9

See also: nnz, size

Extra doc | Doc source | Implementation

nzref(...)
nzref(self, Sparsity sp, [int] nz) -> MX
static ones(...)
ones(int nrow, int ncol) -> MX
ones((int,int) rc) -> MX
ones(Sparsity sp) -> MX

Create a dense matrix or a matrix with specified sparsity with all entries one.

ones(sp) sets every structural nonzero of sp to one; other entries stay structurally zero.

>>> DM.ones(2, 3)
DM(
[[1, 1, 1],
 [1, 1, 1]])
>>> DM.ones(Sparsity.diag(2))
DM(
[[1, 00],
 [00, 1]])
>> DM.ones(2, 3)
[[1, 1, 1],
[1, 1, 1]]
>> DM.ones(Sparsity.diag(2))
[[1, 00],
[00, 1]]
julia> ca.DM.ones(2, 3)
DM(
[[1, 1, 1],
 [1, 1, 1]])
julia> ca.DM.ones(ca.Sparsity.diag(2))
DM(
[[1, 00],
 [00, 1]])

See also: zeros, Sparsity

Extra doc | Doc source | Implementation

op(...)

Get the operation type of the node.

op(self) -> int

Returns one of the OP_* constants. Every node, not only elementwise operations, has an operation code (OP_PARAMETER, OP_CONST, OP_CALL, OP_MTIMES, OP_GETNONZEROS, ...). Function print_operator shows the symbol of an operation.

>>> x = MX.sym("x")
>>> x.op() == OP_PARAMETER, (x + 1).op() == OP_ADD, MX(1).op() == OP_CONST
(True, True, True)
>>> print_operator(x + 1, ["a", "b"])
'(a+b)'
>> x = MX.sym('x'); e = x + 1;
>> x.op() == OP_PARAMETER, e.op() == OP_ADD, MX(1).op() == OP_CONST
1
1
1
>> print_operator(x + 1, {'a', 'b'})
(a+b)
julia> x = ca.MX.sym("x");
julia> ca.op(x) == ca.OP_PARAMETER, ca.op(x + 1) == ca.OP_ADD,
       ca.op(ca.MX(1)) == ca.OP_CONST
(true, true, true)
julia> ca.print_operator(x + 1, ["a", "b"])
"(a+b)"

See also: is_op, print_operator

Extra doc | Doc source | Implementation

primitives(...)

Get the symbolic primitives of a valid Function input.

primitives(self) -> [MX]

Returns the symbolic primitives in the order in which they appear in the concatenation. For an expression that is not a valid input, the expression itself is returned.

>>> x = MX.sym("x", 2)
>>> y = MX.sym("y", 3)
>>> vertcat(x, y).primitives()
[MX(x), MX(y)]
>>> reshape(x, 1, 2).primitives()
[MX(x)]
>> x = MX.sym('x', 2); y = MX.sym('y', 3);
>> v = [x; y];
>> p = v.primitives();
>> numel(p), p{1}, p{2}
2
x
y
>> p = reshape(x, 1, 2).primitives();
>> numel(p), p{1}
1
x
julia> x = ca.MX.sym("x", 2); y = ca.MX.sym("y", 3);
julia> ca.primitives([x; y])
2-element Vector{MX}:
 MX(x)
 MX(y)
julia> ca.primitives(reshape(x, 1, 2))
1-element Vector{MX}:
 MX(x)

See also: n_primitives, split_primitives, join_primitives, is_valid_input

Extra doc | Doc source | Implementation

print_ptr(...)
print_ptr(self)
printme(...)

Return the expression with the side effect of printing its value with a tag.

printme(self, MX b) -> MX

Returns an expression equal to this one; when it is evaluated, every nonzero is printed to standard output as "|> b : value", where b is a scalar expression evaluated alongside it (an identifier for the print). Useful to trace values inside a Function. The printing is not part of the returned value and not seen by the doctest runner's output capture.

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> e = x.printme(y)
>>> e, e.is_op(OP_PRINTME)
(MX(printme(x,y)), True)
>> x = MX.sym('x'); y = MX.sym('y');
>> e = x.printme(y);
>> e, e.is_op(OP_PRINTME)
printme(x,y)
1
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> e = ca.printme(x, y);
julia> e, ca.is_op(e, ca.OP_PRINTME)
(printme(x,y), true)

See also: monitor, attachAssert

Extra doc | Doc source | Implementation

reset_dump_count(...)

Reset the file counter of a dump node; raises an error on any other node.

reset_dump_count(self)

Doc source | Implementation

reset_input(...)
reset_input(self)
row(...)
row(self) -> [int]
row(self, int el) -> int

Get the sparsity pattern. See the Sparsity class for details.

The pattern is stored in compressed column format: colind has size2()+1 entries, the nonzeros of column j are the entries colind(j) up to colind(j+1) (exclusive), and row(el) is the row index of nonzero el. Without argument, the full vectors are returned. Out-of-range indices raise an error.

>>> x = DM(Sparsity.diag(2), [5, 6])
>>> x.row(), x.colind()
([0, 1], [0, 1, 2])
>>> x.row(1), x.colind(2)
(1, 2)
>> x = DM(Sparsity.diag(2), [5; 6]);
>> x.row(), x.colind()
0 1
0 1 2
>> fprintf('%d %d\n', x.row(1), x.colind(2))
1 2
julia> x = ca.DM(ca.Sparsity.diag(2), [5, 6]);
julia> ca.row(x), ca.colind(x)
([0, 1], [0, 1, 2])
julia> ca.row(x, 1), ca.colind(x, 2)
(1, 2)

Extra doc | Doc source | Implementation

rows(...)

Get the number of rows, Octave-style syntax (same as size1())

rows(self) -> int

Extra doc | Doc source | Implementation

serialize(...)

Serialize the expression to a stream.

serialize(self, casadi::SerializingStream & s)

From Python, serialize through StringSerializer, FileSerializer or pickle within a pickle context; the stream object is not constructed directly.

>>> x = MX.sym("x")
>>> s = StringSerializer()
>>> s.pack(x + 1)
>>> d = StringDeserializer(s.encode())
>>> d.unpack()
MX((1+x))
>> x = MX.sym('x');
>> s = StringSerializer();
>> s.pack(x + 1);
>> d = StringDeserializer(s.encode());
>> d.unpack()
(1+x)
julia> x = ca.MX.sym("x");
julia> s = ca.StringSerializer();
julia> ca.pack(s, x + 1)
julia> d = ca.StringDeserializer(ca.encode(s));
julia> ca.unpack(d)
MX((1+x))

See also: deserialize, StringSerializer

Extra doc | Doc source | Implementation

set(...)
set(self, MX m, bool ind1, Sparsity sp)
set(self, MX m, bool ind1, Slice rr)
set(self, MX m, bool ind1, IM rr)
set(self, MX m, bool ind1, Slice rr, Slice cc)
set(self, MX m, bool ind1, Slice rr, IM cc)
set(self, MX m, bool ind1, IM rr, Slice cc)
set(self, MX m, bool ind1, IM rr, IM cc)

Overload: set(self, MX m, bool ind1, Slice rr)

Assign to a submatrix by linear index (what x[k] = m does)

Expressions are immutable: assignment rebinds this object to a new SetNonzeros node whose dependencies are the old expression and m. Expressions built earlier from the old value are unaffected, but a second name bound to the same object (Y0 = Y) sees the new node; copy the handle with MX(Y) to keep the old value. The sparsity pattern grows to include the assigned elements; assigning a sparse m first erases the targeted elements. m must have the shape of the index set, be a scalar (broadcast), or be its transpose when the index set is a vector; anything else raises a dimension mismatch error. A Sparsity index assigns to the nonzero positions of that pattern. An MX index is only supported for the nonzero (x.nz[k]) form.

>>> Y = MX.sym("Y", 3, 3)
>>> alias, copy, twice = Y, MX(Y), 2*Y
>>> Y[[4]] = 5
>>> Y, Y.n_dep(), Y.dep(0), Y.dep(1)
(MX((Y[4] = 5)), 2, MX(Y), MX(5))
>>> alias, copy, twice
(MX((Y[4] = 5)), MX(Y), MX((2.*Y)))
>>> Z = MX(3, 3)
>>> Z[[0, 8]] = MX.sym("a", 2)
>>> Z.sparsity()
Sparsity(3x3,2nz)
>>> Y = MX.sym("Y", 3, 3)
>>> Y[Sparsity.lower(3)] = 1
>>> Y
MX((Y[0, 1, 2, 4, 5, 8] = ones(6x1)))
>> Y = MX.sym('Y', 3, 3);
>> alias = Y; copy = MX(Y); twice = 2*Y;
>> Y(5) = 5;
>> Y, Y.n_dep(), Y.dep(0), Y.dep(1)
(Y[4] = 5)
2
Y
5
>> alias, copy, twice
(Y[4] = 5)
Y
(2.*Y)
>> Z = MX(3, 3);
>> Z([1, 9]) = MX.sym('a', 2);
>> Z.sparsity()
3x3,2nz
>> Y = MX.sym('Y', 3, 3);
>> Y(Sparsity.lower(3)) = 1;
>> Y
(Y[0, 1, 2, 4, 5, 8] = ones(6x1))
julia> Y = ca.MX.sym("Y", 3, 3);
julia> alias, copy, twice = Y, ca.MX(Y), 2 * Y;
julia> Y[[5]] = 5;
julia> Y, ca.n_dep(Y), ca.dep(Y, 0), ca.dep(Y, 1)
((Y[4] = 5), 2, Y, 5)
julia> alias, copy, twice
((Y[4] = 5), Y, (2.*Y))
julia> Z = ca.MX(3, 3);
julia> Z[[1, 9]] = ca.MX.sym("a", 2);
julia> ca.sparsity(Z)
Sparsity(3x3,2nz)

See also: get, set_nz

Overload: set(self, MX m, bool ind1, Slice rr, Slice cc)

Assign to a submatrix by row and column index (what x[i, j] = m does)

Same semantics as the single-index form. m must be len(rr)-by-len(cc), a scalar, or the transpose of a vector block.

>>> Y = MX.sym("Y", 3, 3)
>>> Y[:, 0] = MX.sym("c", 1, 3)
>>> Y
MX((Y[:3] = c'))
>>> Y[0:2, 0:2] = 0
>>> Y.sparsity()
Sparsity(3x3)
>>> try:
...   Y[:, 0] = MX.sym("d", 2)
... except Exception as e:
...   print("Dimension mismatch" in str(e))
True
>> Y = MX.sym('Y', 3, 3);
>> Y(:, 1) = MX.sym('c', 1, 3);
>> Y
(Y[:3] = c')
>> Y(1:2, 1:2) = 0;
>> Y.sparsity()
3x3
>> try, Y(:, 1) = MX.sym('d', 2); catch e, disp('dimension mismatch'); end
dimension mismatch
julia> Y = ca.MX.sym("Y", 3, 3);
julia> Y[:, 1] = ca.MX.sym("c", 1, 3);
julia> Y
MX((Y[:3] = c'))
julia> Y[1:2, 1:2] = 0;
julia> ca.sparsity(Y)
Sparsity(3x3)
julia> try
           Y[:, 1] = ca.MX.sym("d", 2)
       catch e
           println(occursin("Dimension mismatch", sprint(showerror, e)))
       end
true

See also: get

Extra doc | Doc source | Implementation

static set_max_depth(...)

Set the depth to which equalities are checked for simplifications.

set_max_depth(int eq_depth)

Global setting (default 1) used when building expressions: operations such as x - y or x/y test whether their operands are equal up to this depth with is_equal and simplify to 0 or 1 when they are. Depth 0 compares node identity only; each extra level compares the operation and recurses into the dependencies. Larger depths find more simplifications at a cost per created node. Calling without an argument restores the default.

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> MX.get_max_depth(), (x + y) - (x + y)
(1, MX(0))
>>> MX.set_max_depth(0)
>>> (x + y) - (x + y)
MX(((x+y)-(x+y)))
>>> MX.set_max_depth()
>>> MX.get_max_depth()
1
>> x = MX.sym('x'); y = MX.sym('y');
>> MX.get_max_depth(), (x + y) - (x + y)
1
0
>> MX.set_max_depth(0);
>> (x + y) - (x + y)
((x+y)-(x+y))
>> MX.set_max_depth();
>> MX.get_max_depth()
1
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.MX.get_max_depth(), (x + y) - (x + y)
(1, 0)
julia> ca.MX.set_max_depth(0)
julia> (x + y) - (x + y)
MX(((x+y)-(x+y)))
julia> ca.MX.set_max_depth()
julia> ca.MX.get_max_depth()
1

See also: get_max_depth, is_equal

Extra doc | Doc source | Implementation

set_nz(...)
set_nz(self, MX m, bool ind1, int kk)
set_nz(self, MX m, bool ind1, Slice kk)
set_nz(self, MX m, bool ind1, IM kk)
set_nz(self, MX m, bool ind1, MX kk)

Assign to a set of nonzeros (what x.nz[k] = m does)

Rebinds this object to a SetNonzeros node; the sparsity pattern is unchanged. m must have as many nonzeros as the index set or be a scalar. With an MX index the assignment is parametric and resolved at evaluation time.

>>> Y = MX.sym("Y", 3, 3)
>>> Y.nz[0] = 7
>>> Y
MX((Y[0] = 7))
>>> k = MX.sym("k")
>>> Y.nz[k] = 8
>>> Y, Y.is_op(OP_SETNONZEROS_PARAM)
(MX(((Y[0] = 7)[k] = 8)), True)
>> Y = MX.sym('Y', 3, 3);
>> Y.set_nz(7, true, 1);
>> Y
(Y[0] = 7)
>> k = MX.sym('k');
>> Y.set_nz(8, true, k);
>> Y, Y.is_op(OP_SETNONZEROS_PARAM)
((Y[0] = 7)[(k-1)] = 8)
1
julia> Y = ca.MX.sym("Y", 3, 3);
julia> Y.nz[1] = 7;
julia> Y
MX((Y[0] = 7))
julia> k = ca.MX.sym("k");
julia> Y.nz[k] = 8;
julia> Y
MX(((Y[0] = 7)[(k-1)] = 8))
julia> ca.is_op(Y, ca.OP_SETNONZEROS_PARAM)
true

See also: get_nz, set

Extra doc | Doc source | Implementation

set_temp(...)
set_temp(self, int t)
static simplify_combine_terms(...)
simplify_combine_terms(std::vector< casadi::MX,std::allocator< casadi::MX > > & arg, std::vector< casadi::MX,std::allocator< casadi::MX > > & res, dict opts) -> bool
static simplify_const_folding(...)
simplify_const_folding(std::vector< casadi::MX,std::allocator< casadi::MX > > & arg, std::vector< casadi::MX,std::allocator< casadi::MX > > & res, dict opts) -> bool
static simplify_ref_count(...)
simplify_ref_count(std::vector< casadi::MX,std::allocator< casadi::MX > > & arg, std::vector< casadi::MX,std::allocator< casadi::MX > > & res, dict opts) -> bool
size(...)

Get the size along a particular dimension.

size(self) -> (int,int)
size(self, int axis) -> int
Parameters:

axis -- 1 for the number of rows, 2 for the number of columns; any other value raises an error

Get the shape as a pair (number of rows, number of columns)

>>> x = MX.sym("x", 2, 3)
>>> x.size(), x.size(1), x.size(2)
((2, 3), 2, 3)
>> x = MX.sym('x', 2, 3);
>> size(x)
2 3
>> fprintf('%d %d\n', size(x, 1), size(x, 2))
2 3
julia> x = ca.MX.sym("x", 2, 3);
julia> size(x), size(x, 1), size(x, 2)
((2, 3), 2, 3)

See also: size1, size2, numel, dim

Extra doc | Doc source | Implementation

size1(...)

Get the first dimension (i.e. number of rows)

size1(self) -> int
>>> x = MX.sym("x", 2, 3)
>>> x.size1(), x.size2()
(2, 3)
>> x = MX.sym('x', 2, 3);
>> fprintf('%d %d\n', x.size1(), x.size2())
2 3
julia> x = ca.MX.sym("x", 2, 3);
julia> ca.size1(x), ca.size2(x)
(2, 3)

See also: size2, size, rows

Extra doc | Doc source | Implementation

size2(...)

Get the second dimension (i.e. number of columns)

size2(self) -> int

See also: size1, size, columns

Extra doc | Doc source | Implementation

sparsity(...)

Get an owning reference to the sparsity pattern.

sparsity(self) -> Sparsity

Extra doc | Doc source | Implementation

split_primitives(...)
split_primitives(self, DM x) -> [DM]
split_primitives(self, SX x) -> [SX]
split_primitives(self, MX x) -> [MX]

Split a value along the symbolic primitives of this expression.

Uses this expression (a valid Function input, see is_valid_input) as a template: x must have the same shape and is cut into one piece per primitive, each with the shape of that primitive. The typical use is to split a solver result back into the variables it was concatenated from. Works with numeric (DM), SX and MX values. A shape mismatch raises an error.

>>> x = MX.sym("x", 2)
>>> y = MX.sym("y", 3)
>>> X = vertcat(x, y)
>>> X.split_primitives(DM([1, 2, 3, 4, 5]))
[DM([1, 2]), DM([3, 4, 5])]
>>> X.split_primitives(SX.sym("z", 5))
[SX([z_0, z_1]), SX([z_2, z_3, z_4])]
>> x = MX.sym('x', 2); y = MX.sym('y', 3);
>> X = [x; y];
>> parts = X.split_primitives(DM([1; 2; 3; 4; 5]));
>> parts{1}, parts{2}
[1, 2]
[3, 4, 5]
>> parts = X.split_primitives(SX.sym('z', 5));
>> parts{1}, parts{2}
[z_0, z_1]
[z_2, z_3, z_4]
julia> x = ca.MX.sym("x", 2); y = ca.MX.sym("y", 3);
julia> X = [x; y];
julia> ca.split_primitives(X, ca.DM([1, 2, 3, 4, 5]))
2-element Vector{DM}:
 DM([1, 2])
 DM([3, 4, 5])
julia> ca.split_primitives(X, ca.SX.sym("z", 5))
2-element Vector{SX}:
 SX([z_0, z_1])
 SX([z_2, z_3, z_4])

See also: join_primitives, primitives

Extra doc | Doc source | Implementation

str(...)

Get string representation.

str(self, bool more) -> str

Doc source | Implementation

static sym(...)

Create a list of length r of lists of length p of nrow-by-ncol symbolic

sym(str name, int nrow, int ncol) -> MX
sym(str name, (int,int) rc) -> MX
sym(str name, Sparsity sp) -> MX
sym(str name, Sparsity sp, int p) -> [MX]
sym(str name, int nrow, int ncol, int p) -> [MX]
sym(str name, Sparsity sp, int p, int r) -> [[MX]]
sym(str name, int nrow, int ncol, int p, int r) -> [[MX]]

primitives.

>>> MX.sym("x", 1, 1, 2, 2)
[[MX(x_00), MX(x_01)], [MX(x_10), MX(x_11)]]
>> v = MX.sym('x', 1, 1, 2, 2);
>> numel(v), v{1}{2}, v{2}{1}
2
x_01
x_10
julia> ca.MX.sym("x", 1, 1, 2, 2)
2-element Vector{Vector{MX}}:
 MX[x_00, x_01]
 MX[x_10, x_11]

Overload: sym(str name, int nrow, int ncol)

Create an nrow-by-ncol symbolic primitive.

Creates a new, dense symbol; two symbols with the same name are still different symbols. For SX each entry is a separate scalar symbol named name_k (k the column-major index), while an MX symbol is a single node with the given name. Only SX and MX have symbols; DM.sym raises an error.

Parameters:
  • name -- Name used for printing. For SX, a name of the form "[a,b,c]" assigns individual names to the numel() entries.

  • nrow -- Number of rows, default 1

  • ncol -- Number of columns, default 1

>>> SX.sym("x"), MX.sym("x", 2, 3).dim()
(SX(x), '2x3')
>>> SX.sym("x", 2, 2)
SX(
[[x_0, x_2],
 [x_1, x_3]])
>>> SX.sym("[a,b,c]", 3)
SX([a, b, c])
>>> is_equal(SX.sym("x"), SX.sym("x"))
False
>> SX.sym('x'), MX.sym('x', 2, 3).dim()
x
2x3
>> SX.sym('x', 2, 2)
[[x_0, x_2],
[x_1, x_3]]
>> SX.sym('[a,b,c]', 3)
[a, b, c]
>> is_equal(SX.sym('x'), SX.sym('x'))
0
julia> ca.SX.sym("x"), ca.dim(ca.MX.sym("x", 2, 3))
(x, "2x3")
julia> ca.SX.sym("x", 2, 2)
SX(
[[x_0, x_2],
 [x_1, x_3]])
julia> ca.SX.sym("[a,b,c]", 3)
SX([a, b, c])
julia> isequal(ca.SX.sym("x"), ca.SX.sym("x"))
false

See also: symvar, zeros, ones

Overload: sym(str name, (int,int) rc)

Construct a symbolic primitive with given dimensions, as a pair (nrow, ncol)

Overload: sym(str name, Sparsity sp)

Create symbolic primitive with a given sparsity pattern.

Only the structural nonzeros of sp become symbolic entries; for SX they are numbered by nonzero index.

>>> SX.sym("p", Sparsity.diag(2))
SX(
[[p_0, 00],
 [00, p_1]])
>>> MX.sym("p", Sparsity.diag(2)).dim(True)
'2x2,2nz'
>> SX.sym('p', Sparsity.diag(2))
[[p_0, 00],
[00, p_1]]
>> MX.sym('p', Sparsity.diag(2)).dim(true)
2x2,2nz
julia> ca.SX.sym("p", ca.Sparsity.diag(2))
SX(
[[p_0, 00],
 [00, p_1]])
julia> ca.dim(ca.MX.sym("p", ca.Sparsity.diag(2)), true)
"2x2,2nz"

Overload: sym(str name, Sparsity sp, int p)

Create a list of length p of symbolic primitives with a given sparsity.

The k-th symbol is named name followed by k (no separator).

>>> MX.sym("x", Sparsity.dense(2, 1), 3)
[MX(x0), MX(x1), MX(x2)]
>> v = MX.sym('x', Sparsity.dense(2, 1), 3);
>> numel(v), v{1}, v{3}
3
x0
x2
julia> ca.MX.sym("x", ca.Sparsity.dense(2, 1), 3)
3-element Vector{MX}:
 MX(x0)
 MX(x1)
 MX(x2)

Overload: sym(str name, int nrow, int ncol, int p)

Create a list of length p of nrow-by-ncol symbolic primitives.

>>> SX.sym("x", 1, 1, 2)
[SX(x0), SX(x1)]
>> v = SX.sym('x', 1, 1, 2);
>> v{1}, v{2}
x0
x1
julia> ca.SX.sym("x", 1, 1, 2)
2-element Vector{SX}:
 SX(x0)
 SX(x1)

Overload: sym(str name, Sparsity sp, int p, int r)

Create a list of length r of lists of length p of symbolic primitives.

with given sparsity. The symbol at outer index i and inner index k is named name_ik.

Extra doc | Doc source | Implementation

static test_cast(...)

Check if a SharedObjectInternal pointer refers to an MX node (C++ only)

test_cast(casadi::SharedObjectInternal const * ptr) -> bool

Doc source | Implementation

to_DM(...)
to_DM(self) -> DM
static type_name(...)

Get type name.

type_name() -> str

Extra doc | Doc source | Implementation

static unary(...)

Create an elementwise binary or unary node from an operation code.

unary(int op, MX x, bool unique) -> MX

Low-level constructors behind the operators: MX.binary(OP_ADD, x, y) is x + y. Operands must have the same shape, or one of them is a scalar, or one is a horizontal repetition of the other (which is repmat-ed). The usual simplifications are applied. An invalid operation code is not checked.

Parameters:
  • op -- One of the OP_* constants

  • unique_x -- Internal hints for in-place simplification; leave false

  • unique_y -- Internal hints for in-place simplification; leave false

>>> x = MX.sym("x")
>>> y = MX.sym("y")
>>> MX.binary(OP_ADD, x, y), MX.unary(OP_SIN, x)
(MX((x+y)), MX(sin(x)))
>>> MX.binary(OP_ADD, MX.sym("V", 2, 4), MX.sym("W", 2, 2))
MX((V+repmat(W, 2)))
>>> try:
...   MX.binary(OP_ADD, MX.sym("v", 2), MX.sym("w", 3))
... except Exception as e:
...   print("Dimension mismatch" in str(e))
True
>> x = MX.sym('x'); y = MX.sym('y');
>> MX.binary(OP_ADD, x, y), MX.unary(OP_SIN, x)
(x+y)
sin(x)
>> MX.binary(OP_ADD, MX.sym('V', 2, 4), MX.sym('W', 2, 2))
(V+repmat(W, 2))
>> v = MX.sym('v', 2); w = MX.sym('w', 3);
>> try, MX.binary(OP_ADD, v, w); catch e, disp('dimension mismatch'); end
dimension mismatch
julia> x = ca.MX.sym("x"); y = ca.MX.sym("y");
julia> ca.MX.binary(ca.OP_ADD, x, y), ca.MX.unary(ca.OP_SIN, x)
((x+y), sin(x))
julia> ca.MX.binary(ca.OP_ADD, ca.MX.sym("V", 2, 4), ca.MX.sym("W", 2, 2))
MX((V+repmat(W, 2)))
julia> try
           ca.MX.binary(ca.OP_ADD, ca.MX.sym("v", 2), ca.MX.sym("w", 3))
       catch e
           println(occursin("Dimension mismatch", sprint(showerror, e)))
       end
true

See also: op

Extra doc | Doc source | Implementation

which_function(...)

Get the Function of a call node.

which_function(self) -> Function

Only valid when is_call() is true; raises an error otherwise, also for the OutputNode of a call (use dep(0) to reach the call node).

>>> a = SX.sym("a")
>>> f = Function("f", [a], [2*a])
>>> x = MX.sym("x")
>>> r = f(x)
>>> r.dep(0).which_function().name()
'f'
>>> try:
...   r.which_function()
... except Exception as e:
...   print("'which_function' not defined" in str(e))
True
>> a = SX.sym('a');
>> f = Function('f', {a}, {2*a});
>> x = MX.sym('x');
>> r = f(x);
>> call = r.dep(0);
>> call.which_function().name()
f
>> try, r.which_function(); catch e, disp('error'); end
error
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [2 * a]);
julia> x = ca.MX.sym("x");
julia> r = f(x);
julia> ca.name(ca.which_function(ca.dep(r, 0)))
"f"
julia> try
           ca.which_function(r)
       catch e
           println(occursin("'which_function' not defined", sprint(showerror, e)))
       end
true

See also: is_call

Extra doc | Doc source | Implementation

which_output(...)

Get the output index of an OutputNode.

which_output(self) -> int

Only valid when is_output() is true; raises an error otherwise.

>>> a = SX.sym("a")
>>> f = Function("f", [a], [a + 1, 2*a])
>>> x = MX.sym("x")
>>> r0, r1 = f(x, )
>>> r0.which_output(), r1.which_output()
(0, 1)
>> a = SX.sym('a');
>> f = Function('f', {a}, {a + 1, 2*a});
>> x = MX.sym('x');
>> [r0, r1] = f(x);
>> r0.which_output(), r1.which_output()
0
1
julia> a = ca.SX.sym("a");
julia> f = ca.Function("f", [a], [a + 1, 2 * a]);
julia> x = ca.MX.sym("x");
julia> r0, r1 = f(x);
julia> ca.which_output(r0), ca.which_output(r1)
(0, 1)

See also: is_output

Extra doc | Doc source | Implementation

static zeros(...)
zeros(int nrow, int ncol) -> MX
zeros((int,int) rc) -> MX
zeros(Sparsity sp) -> MX

Create a dense matrix or a matrix with specified sparsity with all entries zero.

zeros(nrow, ncol) stores nrow*ncol numerical zeros; zeros(sp) stores a zero at every structural nonzero of sp. To get structural zeros instead, construct from a shape, e.g. DM(2, 2).

>>> DM.zeros(2, 2).nnz(), DM.zeros(Sparsity.diag(2)).nnz(), DM(2, 2).nnz()
(4, 2, 0)
>>> MX.zeros(2, 3)
MX(zeros(2x3))
>> Z = DM.zeros(Sparsity.diag(2));
>> fprintf('%d %d %d\n', DM.zeros(2, 2).nnz(), Z.nnz(), DM(2, 2).nnz())
4 2 0
>> MX.zeros(2, 3)
zeros(2x3)
julia> Z = ca.DM.zeros(ca.Sparsity.diag(2));
julia> ca.nnz(ca.DM.zeros(2, 2)), ca.nnz(Z), ca.nnz(ca.DM(2, 2))
(4, 2, 0)
julia> ca.MX.zeros(2, 3)
MX(zeros(2x3))

See also: ones, Sparsity

Extra doc | Doc source | Implementation

Sparsity

class Sparsity(...)

General sparsity class.

The storage format is a compressed column storage (CCS) format. In this format, the structural non-zero elements are stored in column-major order, starting from the upper left corner of the matrix and ending in the lower right corner.

In addition to the dimension (size1(), size2()), (i.e. the number of rows and the number of columns respectively), there are also two vectors of integers:

  1. "colind" [length size2() +1], which contains the index to the first non-zero element on or after the corresponding column. All the non-zero elements of a particular column i are thus the elements with index el that fulfills: colind[i] <= el < colind[i+1].

  2. "row" [same length as the number of non-zero elements, nnz()] The rows for each of the structural non-zeros.

Note that with this format, it is cheap to loop over all the non-zero elements of a particular column, at constant time per element, but expensive to jump to access a location (i, j).

If the matrix is dense, i.e. length(row) == size1()*size2(), the format reduces to standard dense column major format, which allows access to an arbitrary element in constant time.

Since the object is reference counted (it inherits from SharedObject), several matrices are allowed to share the same sparsity pattern.

The implementations of methods marked as such in this class has been taken from the CSparse package and modified to fit CasADi data structures and separation of sparsity pattern calculation and numerical evaluation. These functions are Copyright(c) Timothy A. Davis, 2006-2009 and licensed as a derivative work under the GNU LGPL

Every DM, SX and MX carries a pattern, obtained with sparsity(), and a symbolic or numeric matrix can be created from one, e.g. SX.sym("x", sp) or DM(sp, 1). Entries outside the pattern are structural zeros: they are never stored and never computed with. The row indices within a column are strictly increasing.

Patterns are immutable and cached: constructing a pattern that already exists returns a reference to the cached object, so equal patterns are cheap to compare. The in-place methods (resize, enlarge, erase, append, add_nz, ...) rebind the object to a new pattern rather than modify the shared one. Use is_equal or the == operator to compare patterns; object identity is not meaningful in the target languages.

A default-constructed Sparsity is a null object (is_null() is true): it carries no pattern and most methods raise an error on it. It is used as "no pattern" sentinel, e.g. as the result of a coloring that exceeds its cutoff. Empty patterns are allowed: a 0-by-n or n-by-0 pattern has no nonzeros, is dense, and is_empty() is true for it.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> DM(sp, 1)
DM(
[[1, 00, 00, 1],
 [00, 00, 1, 00],
 [1, 00, 00, 00]])
>>> sp
Sparsity(3x4,4nz)
>>> sp.size1(), sp.size2(), sp.nnz(), sp.numel()
(3, 4, 4, 12)
>>> sp.colind(), sp.row()
([0, 2, 2, 3, 4], [0, 2, 1, 0])
>>> sp == Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
True
>>> SX.sym("x", sp)
SX(
[[x_0, 00, 00, x_3],
 [00, 00, x_2, 00],
 [x_1, 00, 00, 00]])
>>> Sparsity.dense(0, 3), Sparsity().is_null()
(Sparsity(0x3), True)
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> DM(sp, 1)
[[1, 00, 00, 1],
[00, 00, 1, 00],
[1, 00, 00, 00]]
>> sp
3x4,4nz
>> fprintf('%d %d %d %d\n', sp.size1(), sp.size2(), sp.nnz(), sp.numel())
3 4 4 12
>> sp.colind(), sp.row()
0 2 2 3 4
0 2 1 0
>> sp == Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
1
>> SX.sym('x', sp)
[[x_0, 00, 00, x_3],
[00, 00, x_2, 00],
[x_1, 00, 00, 00]]
>> Sparsity.dense(0, 3), Sparsity().is_null()
0x3
1
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.DM(sp, 1)
DM(
[[1, 00, 00, 1],
 [00, 00, 1, 00],
 [1, 00, 00, 00]])
julia> sp
Sparsity(3x4,4nz)
julia> ca.size1(sp), ca.size2(sp), ca.nnz(sp), ca.numel(sp)
(3, 4, 4, 12)
julia> ca.colind(sp), ca.row(sp)
([0, 2, 2, 3, 4], [0, 2, 1, 0])
julia> ca.is_equal(sp, ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]))
true
julia> ca.SX.sym("x", sp)
SX(
[[x_0, 00, 00, x_3],
 [00, 00, x_2, 00],
 [x_1, 00, 00, 00]])
julia> ca.Sparsity.dense(0, 3), ca.is_null(ca.Sparsity())
(0x3, true)

See also: Matrix

Authors: Joel Andersson

Extra doc

add_nz(...)

Nonzero index of entry (rr, cc), inserting the entry into the pattern if

add_nz(self, int rr, int cc) -> int

needed.

Returns the position of the entry among the nonzeros. If the entry is a structural zero, the object is rebound to a pattern that includes it (nonzero indices after it shift by one). Negative indices count from the end. An index out of bounds raises an error.

>>> sp = Sparsity(3, 3)
>>> sp.add_nz(1, 1), sp.add_nz(0, 0), sp.add_nz(1, 1), sp
(0, 0, 1, Sparsity(3x3,2nz))
>>> DM(sp, 1)
DM(
[[1, 00, 00],
 [00, 1, 00],
 [00, 00, 00]])
>>> try: sp.add_nz(3, 0)
... except Exception as e: print("out of bounds")
out of bounds
>> sp = Sparsity(3, 3);
>> [sp.add_nz(1, 1), sp.add_nz(0, 0), sp.add_nz(1, 1)], sp
0 0 1
3x3,2nz
>> DM(sp, 1)
[[1, 00, 00],
[00, 1, 00],
[00, 00, 00]]
>> try, sp.add_nz(3, 0); catch e, disp('out of bounds'); end
out of bounds
julia> sp = ca.Sparsity(3, 3);
julia> ca.add_nz(sp, 1, 1), ca.add_nz(sp, 0, 0), ca.add_nz(sp, 1, 1)
(0, 0, 1)
julia> ca.DM(sp, 1)
DM(
[[1, 00, 00],
 [00, 1, 00],
 [00, 00, 00]])
julia> try
           ca.add_nz(sp, 3, 0)
       catch e
           println("out of bounds")
       end
out of bounds

See also: get_nz, has_nz

Extra doc | Doc source | Implementation

amd(...)

Approximate minimum degree (AMD) ordering of a symmetric pattern.

amd(self) -> [int]

Fill-reducing ordering p to apply to a symmetric linear system before factorization: factorize A[p, p] instead of A. The pattern must be symmetric, otherwise an error is raised; for an unsymmetric A, order the pattern of A^T*A (as qr_sparse does). Used by ldl and qr_sparse when their amd argument is true.

The implementation is a modified version of cs_amd in CSparse Copyright(c) Timothy A. Davis, 2006-2009 Licensed as a derivative work under the GNU LGPL

>>> Sparsity.banded(4, 1).amd(), Sparsity.dense(3, 3).amd(), Sparsity(0, 0).amd()
([3, 2, 0, 1], [0, 1, 2], [])
>>> try: Sparsity.upper(3).amd()
... except Exception as e: print("not symmetric")
not symmetric
>> Sparsity.banded(4, 1).amd(), Sparsity.dense(3, 3).amd()
3 2 0 1
0 1 2
>> isempty(Sparsity(0, 0).amd())
1
>> try, Sparsity.upper(3).amd(); catch e, disp('not symmetric'); end
not symmetric
julia> ca.amd(ca.Sparsity.banded(4, 1)), ca.amd(ca.Sparsity.dense(3, 3))
([3, 2, 0, 1], [0, 1, 2])
julia> ca.amd(ca.Sparsity(0, 0))
Int64[]
julia> try
           ca.amd(ca.Sparsity.upper(3))
       catch e
           println("not symmetric")
       end
not symmetric

See also: ldl, qr_sparse, etree, is_symmetric

Extra doc | Doc source | Implementation

append(...)

Append a pattern below this one, in place (vertical concatenation)

append(self, Sparsity sp)

The number of columns must match, otherwise an error is raised; a 0-by-0 pattern on either side is ignored. Equivalent to rebinding to vertcat(self, sp); only cheap when both are column vectors.

>>> sp = Sparsity.dense(2, 2); sp.append(Sparsity.diag(2)); print(DM(sp, 1))
[[1, 1],
 [1, 1],
 [1, 00],
 [00, 1]]
>>> sp = Sparsity(0, 0); sp.append(Sparsity.diag(2)); print(sp)
2x2,2nz
>>> try: Sparsity.dense(2, 2).append(Sparsity.dense(2, 3))
... except Exception as e: print("column mismatch")
column mismatch
>> sp = Sparsity.dense(2, 2); sp.append(Sparsity.diag(2)); disp(DM(sp, 1))
[[1, 1],
[1, 1],
[1, 00],
[00, 1]]
>> sp = Sparsity(0, 0); sp.append(Sparsity.diag(2)); disp(sp)
2x2,2nz
>> try, sp.append(Sparsity.dense(2, 3)); catch e, disp('column mismatch'); end
column mismatch
julia> sp = ca.Sparsity.dense(2, 2); ca.append(sp, ca.Sparsity.diag(2)); ca.DM(sp, 1)
DM(
[[1, 1],
 [1, 1],
 [1, 00],
 [00, 1]])
julia> sp = ca.Sparsity(0, 0); ca.append(sp, ca.Sparsity.diag(2)); print(sp)
2x2,2nz
julia> try
           ca.append(ca.Sparsity.dense(2, 2), ca.Sparsity.dense(2, 3))
       catch e
           println("column mismatch")
       end
column mismatch

See also: appendColumns, vertcat

Extra doc | Doc source | Implementation

appendColumns(...)

Append a pattern to the right of this one, in place (horizontal

appendColumns(self, Sparsity sp)

concatenation)

The number of rows must match, otherwise an error is raised; a 0-by-0 pattern on either side is ignored. Equivalent to rebinding to horzcat(self, sp).

>>> sp = Sparsity.dense(2, 2); sp.appendColumns(Sparsity.diag(2)); print(DM(sp, 1))
[[1, 1, 1, 00],
 [1, 1, 00, 1]]
>>> try: Sparsity.dense(2, 2).appendColumns(Sparsity.dense(3, 2))
... except Exception as e: print("row mismatch")
row mismatch
>> sp = Sparsity.dense(2, 2); sp.appendColumns(Sparsity.diag(2)); disp(DM(sp, 1))
[[1, 1, 1, 00],
[1, 1, 00, 1]]
>> try, sp.appendColumns(Sparsity.dense(3, 2)); catch e, disp('row mismatch'); end
row mismatch
julia> sp = ca.Sparsity.dense(2, 2); ca.appendColumns(sp, ca.Sparsity.diag(2)); ca.DM(sp, 1)
DM(
[[1, 1, 1, 00],
 [1, 1, 00, 1]])
julia> try
           ca.appendColumns(ca.Sparsity.dense(2, 2), ca.Sparsity.dense(3, 2))
       catch e
           println("row mismatch")
       end
row mismatch

See also: append, horzcat

Extra doc | Doc source | Implementation

static band(...)

Create a single band in a square sparsity pattern.

band(int n, int p) -> Sparsity

The nonzeros are the entries (i+p, i): band(n, 0) equals diag(n), band(n, 1) is the first subdiagonal and band(n, -1) the first superdiagonal.

Parameters:
  • n -- Size of the square pattern

  • p -- Offset of the band from the diagonal, positive below the diagonal and negative above it; |p| must be smaller than n, otherwise an error is raised

>>> DM(Sparsity.band(4, 1), 1)
DM(
[[00, 00, 00, 00],
 [1, 00, 00, 00],
 [00, 1, 00, 00],
 [00, 00, 1, 00]])
>>> DM(Sparsity.band(4, -2), 1)
DM(
[[00, 00, 1, 00],
 [00, 00, 00, 1],
 [00, 00, 00, 00],
 [00, 00, 00, 00]])
>>> Sparsity.band(4, 0) == Sparsity.diag(4)
True
>> DM(Sparsity.band(4, 1), 1)
[[00, 00, 00, 00],
[1, 00, 00, 00],
[00, 1, 00, 00],
[00, 00, 1, 00]]
>> DM(Sparsity.band(4, -2), 1)
[[00, 00, 1, 00],
[00, 00, 00, 1],
[00, 00, 00, 00],
[00, 00, 00, 00]]
>> Sparsity.band(4, 0) == Sparsity.diag(4)
1
julia> ca.DM(ca.Sparsity.band(4, 1), 1)
DM(
[[00, 00, 00, 00],
 [1, 00, 00, 00],
 [00, 1, 00, 00],
 [00, 00, 1, 00]])
julia> ca.DM(ca.Sparsity.band(4, -2), 1)
DM(
[[00, 00, 1, 00],
 [00, 00, 00, 1],
 [00, 00, 00, 00],
 [00, 00, 00, 00]])
julia> ca.is_equal(ca.Sparsity.band(4, 0), ca.Sparsity.diag(4))
true

See also: banded, diag

Extra doc | Doc source | Implementation

static banded(...)

Create a banded square sparsity pattern.

banded(int n, int p) -> Sparsity

Union of band(n, k) for all k in [-p, p]: banded(n, 0) equals diag(n) and banded(n, 1) is tridiagonal.

Parameters:
  • n -- Size of the square pattern

  • p -- Half-bandwidth; p >= n gives a dense pattern and a negative p an all-zero pattern

>>> DM(Sparsity.banded(4, 1), 1)
DM(
[[1, 1, 00, 00],
 [1, 1, 1, 00],
 [00, 1, 1, 1],
 [00, 00, 1, 1]])
>>> Sparsity.banded(4, 1).bw_upper(), Sparsity.banded(4, 1).bw_lower()
(1, 1)
>> DM(Sparsity.banded(4, 1), 1)
[[1, 1, 00, 00],
[1, 1, 1, 00],
[00, 1, 1, 1],
[00, 00, 1, 1]]
>> [Sparsity.banded(4, 1).bw_upper(), Sparsity.banded(4, 1).bw_lower()]
1 1
julia> ca.DM(ca.Sparsity.banded(4, 1), 1)
DM(
[[1, 1, 00, 00],
 [1, 1, 1, 00],
 [00, 1, 1, 1],
 [00, 00, 1, 1]])
julia> ca.bw_upper(ca.Sparsity.banded(4, 1)), ca.bw_lower(ca.Sparsity.banded(4, 1))
(1, 1)

See also: band, bw_upper, bw_lower

Extra doc | Doc source | Implementation

btf(...)

Block triangular form (BTF) through the Dulmage-Mendelsohn decomposition.

btf(self) -> (int, [int], [int], [int], [int], [int], [int])

Computes a row permutation and a column permutation that bring the pattern into block upper triangular form, see Direct Methods for Sparse Linear Systems by Davis (2006). The pattern may be rectangular.

Returns:

row and column permutation vectors, so that A[rowperm, colperm] is in block upper triangular form rowblock, colblock (length nb+1): block k spans rows rowblock[k] to rowblock[k+1]-1 and columns colblock[k] to colblock[k+1]-1 of the permuted matrix coarse_rowblock, coarse_colblock (length 5): boundaries of the coarse decomposition into the underdetermined, square (well-determined) and overdetermined parts; coarse_colblock[3] is the structural rank (sprank) the number of fine blocks nb rowperm, colperm: row and column permutation vectors, so that A[rowperm, colperm] is in block upper triangular form rowblock, colblock (length nb+1): block k spans rows rowblock[k] to rowblock[k+1]-1 and columns colblock[k] to colblock[k+1]-1 of the permuted matrix coarse_rowblock, coarse_colblock (length 5): boundaries of the coarse decomposition into the underdetermined, square (well-determined) and overdetermined parts; coarse_colblock[3] is the structural rank (sprank)

Return type:

the number of fine blocks nb rowperm, colperm

Only structure is used: the distance of entries to the diagonal plays no role, so a randomly permuted block-diagonal matrix is not necessarily brought back to block diagonal form, and the row and column permutations differ in general, which destroys symmetry. The result is cached in the pattern.

The implementation is a modified version of cs_dmperm in CSparse Copyright(c) Timothy A. Davis, 2006-2009 Licensed as a derivative work under the GNU LGPL

>>> B = Sparsity.triplet(3, 3, [0, 0, 1, 2], [0, 2, 1, 2])
>>> DM(B, 1)
DM(
[[1, 00, 1],
 [00, 1, 00],
 [00, 00, 1]])
>>> nb, rowperm, colperm, rowblock, colblock, crb, ccb = B.btf()
>>> nb, rowperm, colperm, rowblock, colblock
(3, [2, 0, 1], [2, 0, 1], [0, 1, 2, 3], [0, 1, 2, 3])
>>> crb, ccb
([0, 0, 0, 3, 3], [0, 0, 3, 3, 3])
>>> DM(B, 1)[rowperm, colperm]
DM(
[[1, 00, 00],
 [1, 1, 00],
 [00, 00, 1]])
>>> sprank(Sparsity.nonzeros(3, 3, [0, 1, 2])), sprank(Sparsity.diag(3))
(1, 3)
>> B = Sparsity.triplet(3, 3, [0, 0, 1, 2], [0, 2, 1, 2]);
>> DM(B, 1)
[[1, 00, 1],
[00, 1, 00],
[00, 00, 1]]
>> [nb, rowperm, colperm, rowblock, colblock, crb, ccb] = B.btf();
>> nb, rowperm, colperm, rowblock, colblock
3
2 0 1
2 0 1
0 1 2 3
0 1 2 3
>> crb, ccb
0 0 0 3 3
0 0 3 3 3
>> Bf = DM(B, 1); disp(Bf(rowperm + 1, colperm + 1))
[[1, 00, 00],
[1, 1, 00],
[00, 00, 1]]
>> [sprank(Sparsity.nonzeros(3, 3, [1, 2, 3])), sprank(Sparsity.diag(3))]
1 3
julia> B = ca.Sparsity.triplet(3, 3, [0, 0, 1, 2], [0, 2, 1, 2]);
julia> ca.DM(B, 1)
DM(
[[1, 00, 1],
 [00, 1, 00],
 [00, 00, 1]])
julia> ca.btf(B)
(3, [2, 0, 1], [2, 0, 1], [0, 1, 2, 3], [0, 1, 2, 3], [0, 0, 0, 3, 3], [0, 0, 3, 3, 3])
julia> ca.sprank(ca.Sparsity.nonzeros(3, 3, [0, 1, 2])), ca.sprank(ca.Sparsity.diag(3))
(1, 3)

See also: scc, sprank, is_singular

Extra doc | Doc source | Implementation

bw_lower(...)

Lower half-bandwidth: the largest i - j over all nonzeros (i, j) with i > j.

bw_lower(self) -> int

Zero for a diagonal, upper triangular or all-zero pattern.

>>> Sparsity.banded(5, 2).bw_lower(), Sparsity.band(5, 2).bw_lower()
(2, 2)
>>> Sparsity.band(5, -2).bw_lower()
0
>>> Sparsity.dense(5, 2).bw_lower()
4
>> [Sparsity.banded(5, 2).bw_lower(), Sparsity.band(5, 2).bw_lower()]
2 2
>> Sparsity.band(5, -2).bw_lower()
0
>> Sparsity.dense(5, 2).bw_lower()
4
julia> ca.bw_lower(ca.Sparsity.banded(5, 2)), ca.bw_lower(ca.Sparsity.band(5, 2))
(2, 2)
julia> ca.bw_lower(ca.Sparsity.band(5, -2))
0
julia> ca.bw_lower(ca.Sparsity.dense(5, 2))
4

See also: bw_upper, banded

Extra doc | Doc source | Implementation

bw_upper(...)

Upper half-bandwidth: the largest j - i over all nonzeros (i, j) with j > i.

bw_upper(self) -> int

Zero for a diagonal, lower triangular or all-zero pattern.

>>> Sparsity.banded(5, 2).bw_upper(), Sparsity.band(5, -2).bw_upper()
(2, 2)
>>> Sparsity.band(5, 2).bw_upper(), Sparsity.diag(3).bw_upper()
(0, 0)
>>> Sparsity(3, 3).bw_upper(), Sparsity.dense(2, 5).bw_upper()
(0, 4)
>> [Sparsity.banded(5, 2).bw_upper(), Sparsity.band(5, -2).bw_upper()]
2 2
>> [Sparsity.band(5, 2).bw_upper(), Sparsity.diag(3).bw_upper()]
0 0
>> [Sparsity(3, 3).bw_upper(), Sparsity.dense(2, 5).bw_upper()]
0 4
julia> ca.bw_upper(ca.Sparsity.banded(5, 2)), ca.bw_upper(ca.Sparsity.band(5, -2))
(2, 2)
julia> ca.bw_upper(ca.Sparsity.band(5, 2)), ca.bw_upper(ca.Sparsity.diag(3))
(0, 0)
julia> ca.bw_upper(ca.Sparsity(3, 3)), ca.bw_upper(ca.Sparsity.dense(2, 5))
(0, 4)

See also: bw_lower, banded

Extra doc | Doc source | Implementation

class_name(...)

Get class name.

class_name(self) -> str

Extra doc | Doc source | Implementation

colind(...)

Index of the first nonzero of column cc.

colind(self) -> [int]
colind(self, int cc) -> int
Parameters:

cc -- Column, in [0, size2()]; colind(size2()) equals nnz(). An index out of range raises an error.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.row(1), sp.colind(1), sp.colind(4)
(2, 2, 4)
>>> try: sp.row(4)
... except Exception as e: print("out of range")
out of range
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [sp.row(1), sp.colind(1), sp.colind(4)]
2 2 4
>> try, sp.row(4); catch e, disp('out of range'); end
out of range
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.row(sp, 1), ca.colind(sp, 1), ca.colind(sp, 4)
(2, 2, 4)
julia> try
           ca.row(sp, 4)
       catch e
           println("out of range")
       end
out of range

See also: row, get_colind

Column offsets of the compressed column storage.

Length size2()+1: entry j is the index of the first nonzero of column j and the last entry equals nnz(). In the target languages this method is called colind(), the same name as the single-column accessor.

See also: get_row, get_ccs

Extra doc | Doc source | Implementation

columns(...)

Number of columns, Octave-style alias of size2.

columns(self) -> int

Doc source | Implementation

combine(...)
combine(self, Sparsity y, bool f0x_is_zero, bool function0_is_zero) -> Sparsity
compress(...)

Compact single-vector representation of the pattern.

compress(self, bool canonical) -> [int]

Returns [nrow, ncol, colind..., row...], the layout accepted by compressed() and used for sparsity patterns in generated C code. With canonical false, a dense pattern is abbreviated to [nrow, ncol, 1] (an abbreviation that compressed() given a vector does not accept).

>>> Sparsity.diag(2).compress()
[2, 2, 0, 1, 2, 0, 1]
>>> Sparsity.dense(2, 2).compress()
[2, 2, 0, 2, 4, 0, 1, 0, 1]
>>> Sparsity.dense(2, 2).compress(False)
[2, 2, 1]
>>> Sparsity(0, 2).compress()
[0, 2, 0, 0, 0]
>> Sparsity.diag(2).compress()
2 2 0 1 2 0 1
>> Sparsity.dense(2, 2).compress()
2 2 0 2 4 0 1 0 1
>> Sparsity.dense(2, 2).compress(false)
2 2 1
>> Sparsity(0, 2).compress()
0 2 0 0 0
julia> println(ca.compress(ca.Sparsity.diag(2)))
[2, 2, 0, 1, 2, 0, 1]
julia> println(ca.compress(ca.Sparsity.dense(2, 2)))
[2, 2, 0, 2, 4, 0, 1, 0, 1]
julia> println(ca.compress(ca.Sparsity.dense(2, 2), false))
[2, 2, 1]
julia> println(ca.compress(ca.Sparsity(0, 2)))
[0, 2, 0, 0, 0]

See also: compressed, get_ccs

Extra doc | Doc source | Implementation

static compressed(...)

Create from the compact single-vector representation of a pattern.

compressed([int] v, bool order_rows) -> Sparsity

The vector is laid out as [nrow, ncol, colind (ncol+1 entries), row (colind[ncol] entries)]. This is the format returned by compress() and used by generated C code (casadi_int arrays). When colind[ncol] equals nrow*ncol the row entries may be omitted (a dense pattern). An inconsistent vector raises an error.

Parameters:
  • v -- Compact representation

  • order_rows -- If true, unsorted row indices within a column are sorted instead of raising an error

>>> sp = Sparsity.compressed([3, 2, 0, 1, 2, 0, 2])
>>> DM(sp, 1)
DM(
[[1, 00],
 [00, 00],
 [00, 1]])
>>> Sparsity.compressed(sp.compress()) == sp
True
>>> Sparsity.compressed([2, 2, 0, 2, 4])
Sparsity(2x2)
>> sp = Sparsity.compressed([3, 2, 0, 1, 2, 0, 2]);
>> DM(sp, 1)
[[1, 00],
[00, 00],
[00, 1]]
>> Sparsity.compressed(sp.compress()) == sp
1
>> Sparsity.compressed([2, 2, 0, 2, 4])
2x2
julia> sp = ca.Sparsity.compressed([3, 2, 0, 1, 2, 0, 2]);
julia> ca.DM(sp, 1)
DM(
[[1, 00],
 [00, 00],
 [00, 1]])
julia> ca.is_equal(ca.Sparsity.compressed(ca.compress(sp)), sp)
true
julia> ca.Sparsity.compressed([2, 2, 0, 2, 4])
Sparsity(2x2)

See also: compress, Sparsity(nrow, ncol, colind, row)

Extra doc | Doc source | Implementation

debug_repr(...)
debug_repr(self) -> str
static dense(...)
dense(int nrow, int ncol) -> Sparsity
dense((int,int) rc) -> Sparsity

Create a dense rectangular sparsity pattern.

All nrow*ncol entries are nonzeros, stored column by column. This is the pattern of every matrix created without an explicit sparsity, e.g. SX.sym("x", 2, 3).

Parameters:
  • nrow -- Number of rows, nonnegative

  • ncol -- Number of columns, nonnegative; default 1 (a dense column vector)

The shape can also be given as a single pair (nrow, ncol).

>>> sp = Sparsity.dense(2, 3)
>>> sp, sp.nnz(), sp.is_dense()
(Sparsity(2x3), 6, True)
>>> sp.colind(), sp.row()
([0, 2, 4, 6], [0, 1, 0, 1, 0, 1])
>>> Sparsity.dense(3), Sparsity.dense((2, 3))
(Sparsity(3x1), Sparsity(2x3))
>>> Sparsity.dense(0, 3).nnz(), Sparsity.dense(0, 3).is_dense()
(0, True)
>> sp = Sparsity.dense(2, 3);
>> sp, sp.nnz(), sp.is_dense()
2x3
6
1
>> sp.colind(), sp.row()
0 2 4 6
0 1 0 1 0 1
>> Sparsity.dense(3), Sparsity.dense([2, 3])
3x1
2x3
>> Sparsity.dense(0, 3).nnz(), Sparsity.dense(0, 3).is_dense()
0
1
julia> sp = ca.Sparsity.dense(2, 3)
Sparsity(2x3)
julia> ca.nnz(sp), ca.is_dense(sp)
(6, true)
julia> ca.colind(sp), ca.row(sp)
([0, 2, 4, 6], [0, 1, 0, 1, 0, 1])
julia> ca.Sparsity.dense(3), ca.Sparsity.dense(2, 3)
(3x1, 2x3)
julia> ca.nnz(ca.Sparsity.dense(0, 3)), ca.is_dense(ca.Sparsity.dense(0, 3))
(0, true)

See also: Sparsity(nrow, ncol), scalar, is_dense

Extra doc | Doc source | Implementation

density(...)

Percentage of nonzeros: 100*nnz()/numel()

density(self) -> float

Computed in floating point, so it does not overflow for large shapes. An empty pattern (numel() == 0) is dense and gives 100.

>>> Sparsity.diag(4).density(), Sparsity.dense(2, 2).density()
(25.0, 100.0)
>>> Sparsity(0, 3).density()
100.0
>> fprintf('%g %g\n', Sparsity.diag(4).density(), Sparsity.dense(2, 2).density())
25 100
>> Sparsity(0, 3).density()
100
julia> ca.density(ca.Sparsity.diag(4)), ca.density(ca.Sparsity.dense(2, 2))
(25.0, 100.0)
julia> ca.density(ca.Sparsity(0, 3))
100.0

See also: nnz, numel, is_dense

Extra doc | Doc source | Implementation

static deserialize(...)

Deserialize.

deserialize(std::istream & stream) -> Sparsity
deserialize(casadi::DeserializingStream & s) -> Sparsity
deserialize(str s) -> Sparsity

Overload: deserialize(std::istream & stream)

Build a Sparsity from a serialized stream.

Overload: deserialize(str s)

Build a Sparsity from a string produced by serialize()

See also: serialize

Extra doc | Doc source | Implementation

dfs(...)
dfs(self, int j, int top, [int] pinv) -> (int, [int] INOUT1, [int] INOUT2, [bool] INOUT3)
static diag(...)
diag(int nrow) -> Sparsity
diag((int,int) rc) -> Sparsity
diag(int nrow, int ncol) -> Sparsity

Create a diagonal sparsity pattern.

The nonzeros are the entries (i, i) for i < min(nrow, ncol); a rectangular diagonal pattern is allowed. The shape can be given as one integer (square), as two integers or as a pair.

>>> DM(Sparsity.diag(3), 1)
DM(
[[1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])
>>> DM(Sparsity.diag(2, 4), 1)
DM(
[[1, 00, 00, 00],
 [00, 1, 00, 00]])
>>> Sparsity.diag((4, 2)).nnz(), Sparsity.diag(0).nnz()
(2, 0)
>> DM(Sparsity.diag(3), 1)
[[1, 00, 00],
[00, 1, 00],
[00, 00, 1]]
>> DM(Sparsity.diag(2, 4), 1)
[[1, 00, 00, 00],
[00, 1, 00, 00]]
>> Sparsity.diag([4, 2]).nnz(), Sparsity.diag(0).nnz()
2
0
julia> ca.DM(ca.Sparsity.diag(3), 1)
DM(
[[1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])
julia> ca.DM(ca.Sparsity.diag(2, 4), 1)
DM(
[[1, 00, 00, 00],
 [00, 1, 00, 00]])
julia> ca.nnz(ca.Sparsity.diag(4, 2)), ca.nnz(ca.Sparsity.diag(0))
(2, 0)

See also: band, is_diag, get_diag

Extra doc | Doc source | Implementation

dim(...)

Dimensions as a string "nrow x ncol", optionally with the number of

dim(self, bool with_nz) -> str

nonzeros.

Parameters:

with_nz -- If true, append ",<nnz>nz"

This is the string printed for a Sparsity: with the nonzero count when the pattern is not dense.

>>> sp = Sparsity.diag(2, 3)
>>> sp.dim(), sp.dim(True)
('2x3', '2x3,2nz')
>>> Sparsity.dense(2, 2).dim(), Sparsity.dense(2, 2).dim(True)
('2x2', '2x2,4nz')
>>> sp
Sparsity(2x3,2nz)
>> sp = Sparsity.diag(2, 3);
>> sp.dim(), sp.dim(true)
2x3
2x3,2nz
>> Sparsity.dense(2, 2).dim(), Sparsity.dense(2, 2).dim(true)
2x2
2x2,4nz
>> sp
2x3,2nz
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.dim(sp), ca.dim(sp, true)
("2x3", "2x3,2nz")
julia> ca.dim(ca.Sparsity.dense(2, 2)), ca.dim(ca.Sparsity.dense(2, 2), true)
("2x2", "2x2,4nz")
julia> sp
Sparsity(2x3,2nz)

See also: postfix_dim, repr_el

Extra doc | Doc source | Implementation

disp(...)

Print a description of the object.

disp(self, bool more)

Doc source | Implementation

enlarge(...)

Enlarge the pattern in place by inserting empty rows and columns.

enlarge(self, int nrow, int ncol, [int] rr, [int] cc, bool ind1)

The existing nonzeros are kept and scattered: row i of the old pattern becomes row rr[i] and column j becomes column cc[j] of the new nrow- by-ncol pattern, so that B[rr, cc] has the old pattern. The new rows and columns are structural zeros. Nonzero indices are unchanged. The object is rebound to the new pattern.

Parameters:
  • nrow -- New number of rows

  • ncol -- New number of columns

  • rr -- New row of every old row: length size1(), strictly increasing, entries in [0, nrow); negative entries count from the end

  • cc -- New column of every old column: length size2(), strictly increasing, entries in [0, ncol)

  • ind1 -- If true, indices are one-based

A wrong length or an index out of range raises an error.

>>> sp = Sparsity.dense(2, 2)
>>> sp.enlarge(4, 3, [0, 3], [1, 2])
>>> DM(sp, 1)
DM(
[[00, 1, 1],
 [00, 00, 00],
 [00, 00, 00],
 [00, 1, 1]])
>>> try: Sparsity.dense(2, 2).enlarge(4, 3, [0], [1, 2])
... except Exception as e: print("wrong length")
wrong length
>> sp = Sparsity.dense(2, 2);
>> sp.enlarge(4, 3, [0, 3], [1, 2]);
>> DM(sp, 1)
[[00, 1, 1],
[00, 00, 00],
[00, 00, 00],
[00, 1, 1]]
>> try, Sparsity.dense(2, 2).enlarge(4, 3, 0, [1, 2]); catch e, disp('wrong length'); end
wrong length
julia> sp = ca.Sparsity.dense(2, 2);
julia> ca.enlarge(sp, 4, 3, [0, 3], [1, 2])
julia> ca.DM(sp, 1)
DM(
[[00, 1, 1],
 [00, 00, 00],
 [00, 00, 00],
 [00, 1, 1]])
julia> try
           ca.enlarge(ca.Sparsity.dense(2, 2), 4, 3, [0], [1, 2])
       catch e
           println("wrong length")
       end
wrong length

See also: enlargeRows, enlargeColumns, resize, erase

Extra doc | Doc source | Implementation

enlargeColumns(...)

Enlarge the pattern in place by inserting empty columns.

enlargeColumns(self, int ncol, [int] cc, bool ind1)

Same as enlarge with the rows left unchanged.

Parameters:
  • ncol -- New number of columns

  • cc -- New column of every old column, length size2(), strictly increasing

  • ind1 -- If true, indices are one-based

>>> sp = Sparsity.dense(2, 2); sp.enlargeColumns(3, [0, 2]); print(DM(sp, 1))
[[1, 00, 1],
 [1, 00, 1]]
>> sp = Sparsity.dense(2, 2); sp.enlargeColumns(3, [0, 2]); disp(DM(sp, 1))
[[1, 00, 1],
[1, 00, 1]]
julia> sp = ca.Sparsity.dense(2, 2); ca.enlargeColumns(sp, 3, [0, 2]); ca.DM(sp, 1)
DM(
[[1, 00, 1],
 [1, 00, 1]])

See also: enlarge, enlargeRows

Extra doc | Doc source | Implementation

enlargeRows(...)

Enlarge the pattern in place by inserting empty rows.

enlargeRows(self, int nrow, [int] rr, bool ind1)

Same as enlarge with the columns left unchanged.

Parameters:
  • nrow -- New number of rows

  • rr -- New row of every old row, length size1(), strictly increasing

  • ind1 -- If true, indices are one-based

>>> sp = Sparsity.dense(2, 2); sp.enlargeRows(3, [0, 2]); print(DM(sp, 1))
[[1, 1],
 [00, 00],
 [1, 1]]
>> sp = Sparsity.dense(2, 2); sp.enlargeRows(3, [0, 2]); disp(DM(sp, 1))
[[1, 1],
[00, 00],
[1, 1]]
julia> sp = ca.Sparsity.dense(2, 2); ca.enlargeRows(sp, 3, [0, 2]); ca.DM(sp, 1)
DM(
[[1, 1],
 [00, 00],
 [1, 1]])

See also: enlarge, enlargeColumns

Extra doc | Doc source | Implementation

erase(...)

Turn the entries with flat (column-major) indices rr into structural

erase(self, [int] rr, bool ind1) -> [int]
erase(self, [int] rr, [int] cc, bool ind1) -> [int]

zeros.

The shape is unchanged. Indices may be unsorted and negative; out of range raises an error. The object is rebound to the new pattern.

Parameters:
  • rr -- Flat element indices, in [0, numel())

  • ind1 -- If true, indices are one-based

Returns:

nonzero k of the result was nonzero mapping[k] of the original pattern

Return type:

Mapping of length nnz() of the result

>>> sp = Sparsity.dense(3, 3)
>>> sp.erase([0, 4, 8]), sp
([1, 2, 3, 5, 6, 7], Sparsity(3x3,6nz))
>>> DM(sp, 1)
DM(
[[00, 1, 1],
 [1, 00, 1],
 [1, 1, 00]])
>>> try: Sparsity.dense(3, 3).erase([9])
... except Exception as e: print("out of range")
out of range
>> sp = Sparsity.dense(3, 3);
>> sp.erase([0, 4, 8]), sp
1 2 3 5 6 7
3x3,6nz
>> DM(sp, 1)
[[00, 1, 1],
[1, 00, 1],
[1, 1, 00]]
>> try, Sparsity.dense(3, 3).erase(9); catch e, disp('out of range'); end
out of range
julia> sp = ca.Sparsity.dense(3, 3);
julia> println(ca.erase(sp, [0, 4, 8]))
[1, 2, 3, 5, 6, 7]
julia> ca.DM(sp, 1)
DM(
[[00, 1, 1],
 [1, 00, 1],
 [1, 1, 00]])
julia> try
           ca.erase(ca.Sparsity.dense(3, 3), [9])
       catch e
           println("out of range")
       end
out of range

See also: erase(rr, cc), find

Turn the entries with rows rr and columns cc into structural zeros, in place.

The shape is unchanged: only the nonzeros in the block rr x cc are removed. An entry is removed when its row is in rr and its column is in cc, so an empty rr or cc removes nothing. Indices may be unsorted and negative (counting from the end); out of range raises an error. The object is rebound to the new pattern.

Parameters:
  • rr -- Rows of the block to clear

  • cc -- Columns of the block to clear

  • ind1 -- If true, indices are one-based

Returns:

nonzero k of the result was nonzero mapping[k] of the original pattern

Return type:

Mapping of length nnz() of the result

>>> sp = Sparsity.dense(3, 3)
>>> mapping = sp.erase([0, 2], [1])
>>> DM(sp, 1), mapping
(DM(
[[1, 00, 1],
 [1, 1, 1],
 [1, 00, 1]]), [0, 1, 2, 4, 6, 7, 8])
>> sp = Sparsity.dense(3, 3);
>> mapping = sp.erase([0, 2], 1);
>> DM(sp, 1), mapping
[[1, 00, 1],
[1, 1, 1],
[1, 00, 1]]
0 1 2 4 6 7 8
julia> sp = ca.Sparsity.dense(3, 3);
julia> mapping = ca.erase(sp, [0, 2], [1]);
julia> println(mapping)
[0, 1, 2, 4, 6, 7, 8]
julia> ca.DM(sp, 1)
DM(
[[1, 00, 1],
 [1, 1, 1],
 [1, 00, 1]])

See also: erase(rr), sub, enlarge

Extra doc | Doc source | Implementation

etree(...)

Elimination tree of the pattern.

etree(self, bool ata) -> [int]

Returns, for every column, the index of its parent in the elimination tree, or -1 for a root. See Direct Methods for Sparse Linear Systems by Davis (2006). With ata false the result matches MATLAB's etree(A) with zero- based indices (the pattern is treated as symmetric, only the upper triangular part is used); with ata true it matches etree(A, 'col'), the tree of A'*A.

The implementation is a modified version of cs_etree in CSparse Copyright(c) Timothy A. Davis, 2006-2009 Licensed as a derivative work under the GNU LGPL

>>> Sparsity.banded(4, 1).etree(), Sparsity.diag(4).etree()
([1, 2, 3, -1], [-1, -1, -1, -1])
>>> Sparsity.dense(2, 3).etree(True)
[1, 2, -1]
>> Sparsity.banded(4, 1).etree(), Sparsity.diag(4).etree()
1 2 3 -1
-1 -1 -1 -1
>> Sparsity.dense(2, 3).etree(true)
1 2 -1
julia> ca.etree(ca.Sparsity.banded(4, 1)), ca.etree(ca.Sparsity.diag(4))
([1, 2, 3, -1], [-1, -1, -1, -1])
julia> println(ca.etree(ca.Sparsity.dense(2, 3), true))
[1, 2, -1]

See also: ldl, qr_sparse, amd

Extra doc | Doc source | Implementation

export_code(...)

Write code that reconstructs the pattern in another language.

export_code(self, str lang, dict options)

Only "matlab" is supported: the code defines the dimensions, one- based column and row indices and the nonzero values of a sparse matrix. The code is written to the standard output or to the given stream.

Parameters:
  • lang -- Target language, must be "matlab"

  • options -- Dictionary with "name": name of the generated variable (default "sp") "as_matrix": also emit "<name> = sparse(...)" (default true) "nonzeros": list of strings used as the nonzero values (default: ones) "indent_level": number of two-space indents (default 0) "inline": not supported, true raises an error "name": name of the generated variable (default "sp") "as_matrix": also emit "<name> = sparse(...)" (default true) "nonzeros": list of strings used as the nonzero values (default: ones) "indent_level": number of two-space indents (default 0) "inline": not supported, true raises an error

An unknown option raises an error.

>>> Sparsity.diag(2, 3).export_code("matlab")
sp_m = 2;
sp_n = 3;
sp_j = [1, 2];
sp_i = [1, 2];
sp_v = ones(size(sp_i));
sp = sparse(sp_i, sp_j, sp_v, sp_m, sp_n);
>>> opts = {"name": "A", "as_matrix": False, "nonzeros": ["1.5", "2"]}
>>> Sparsity.diag(2).export_code("matlab", opts)
A_m = 2;
A_n = 2;
A_j = [1, 2];
A_i = [1, 2];
A_v = [1.5, 2];
>>> try: Sparsity.diag(2).export_code("python")
... except Exception as e: print("unsupported language")
unsupported language
>> Sparsity.diag(2, 3).export_code('matlab');
sp_m = 2;
sp_n = 3;
sp_j = [1, 2];
sp_i = [1, 2];
sp_v = ones(size(sp_i));
sp = sparse(sp_i, sp_j, sp_v, sp_m, sp_n);
>> opts = struct('name', 'A', 'as_matrix', false, 'nonzeros', {{'1.5', '2'}});
>> Sparsity.diag(2).export_code('matlab', opts);
A_m = 2;
A_n = 2;
A_j = [1, 2];
A_i = [1, 2];
A_v = [1.5, 2];
>> try, Sparsity.diag(2).export_code('python'); catch e, disp('unsupported language'); end
unsupported language
julia> ca.export_code(ca.Sparsity.diag(2, 3), "matlab")
sp_m = 2;
sp_n = 3;
sp_j = [1, 2];
sp_i = [1, 2];
sp_v = ones(size(sp_i));
sp = sparse(sp_i, sp_j, sp_v, sp_m, sp_n);
julia> opts = Dict("name" => "A", "as_matrix" => false, "nonzeros" => ["1.5", "2"]);
julia> ca.export_code(ca.Sparsity.diag(2), "matlab", opts)
A_m = 2;
A_n = 2;
A_j = [1, 2];
A_i = [1, 2];
A_v = [1.5, 2];
julia> try
           ca.export_code(ca.Sparsity.diag(2), "python")
       catch e
           println("unsupported language")
       end
unsupported language

See also: spy_matlab, compress

Extra doc | Doc source | Implementation

find(...)

Flat (column-major) element index of every nonzero.

find(self, bool ind1) -> [int]

Returns, in nonzero order, the position each nonzero would have in a dense column-major matrix of the same shape: row + col*size1(). Indexing a dense matrix A of this shape with the result picks the entries that are nonzeros of the pattern. Inverse of nonzeros(). For a dense pattern this is 0, ..., numel()-1.

Parameters:

ind1 -- If true, the indices are one-based

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.find(), sp.find(True)
([0, 2, 7, 9], [1, 3, 8, 10])
>>> Sparsity.dense(2, 2).find(), Sparsity(2, 2).find(), Sparsity(0, 3).find()
([0, 1, 2, 3], [], [])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> sp.find(), sp.find(false)
1 3 8 10
0 2 7 9
>> Sparsity.dense(2, 2).find()
1 2 3 4
>> [isempty(Sparsity(2, 2).find()), isempty(Sparsity(0, 3).find())]
1 1
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.find(sp), ca.find(sp, true)
([0, 2, 7, 9], [1, 3, 8, 10])
julia> println(ca.find(ca.Sparsity.dense(2, 2)))
[0, 1, 2, 3]
julia> ca.find(ca.Sparsity(2, 2)), ca.find(ca.Sparsity(0, 3))
(Int64[], Int64[])

See also: nonzeros, get_nz, makeDense

Extra doc | Doc source | Implementation

static from_file(...)

Read a pattern from a file written by to_file (Matrix Market pattern format)

from_file(str filename, str format_hint) -> Sparsity
Parameters:
  • filename -- Path of the file to read; a missing file raises an error

  • format_hint -- Format name, e.g. "mtx", when the extension does not tell

See also: to_file

Extra doc | Doc source | Implementation

get_ccs(...)

The pattern in compressed column storage: the colind and row vectors.

get_ccs(self) -> ([int], [int])
>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> colind, row = sp.get_ccs()
>>> colind, row
([0, 2, 2, 3, 4], [0, 2, 1, 0])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [colind, row] = sp.get_ccs(); disp(colind), disp(row)
0 2 2 3 4
0 2 1 0
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> colind, row = ca.get_ccs(sp);
julia> colind, row
([0, 2, 2, 3, 4], [0, 2, 1, 0])

See also: get_crs, get_triplet, get_colind, get_row

Extra doc | Doc source | Implementation

get_col(...)

Column index of every nonzero, in nonzero (column-major) order.

get_col(self) -> [int]

Length nnz(). Together with get_row() this gives the pattern in sparse triplet format.

See also: get_row, get_triplet

Extra doc | Doc source | Implementation

get_crs(...)

The pattern in compressed row storage: the rowind and col vectors.

get_crs(self) -> ([int], [int])

Equivalent to the compressed column storage of the transpose. Note that the resulting order of the nonzeros (row-major) differs from the storage order of the pattern.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> rowind, col = sp.get_crs()
>>> rowind, col
([0, 2, 3, 4], [0, 3, 2, 0])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [rowind, col] = sp.get_crs(); disp(rowind), disp(col)
0 2 3 4
0 3 2 0
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> rowind, col = ca.get_crs(sp);
julia> rowind, col
([0, 2, 3, 4], [0, 3, 2, 0])

See also: get_ccs, T

Extra doc | Doc source | Implementation

get_diag(...)

Pattern of the diagonal of a matrix, or of the diagonal matrix built from a

get_diag(self) -> (Sparsity, [int])

vector.

If the pattern is not a vector, the result is the min(nrow, ncol)-by-1 pattern of the main diagonal: it has a nonzero for every diagonal entry (i, i) present in the pattern. If the pattern is a row or column vector of length n, the result is the n-by-n pattern with the vector entries on the diagonal.

Returns:

mapping[k] is the nonzero index in the original pattern of nonzero k of the result

Return type:

The pattern and a mapping

>>> sp, mapping = Sparsity.banded(3, 1).get_diag()
>>> sp, mapping
(Sparsity(3x1), [0, 3, 6])
>>> sp, mapping = Sparsity.unit(3, 1).get_diag()
>>> DM(sp, 1), mapping
(DM(
[[00, 00, 00],
 [00, 1, 00],
 [00, 00, 00]]), [0])
>>> sp, mapping = Sparsity(2, 3).get_diag()
>>> sp, mapping
(Sparsity(2x1,0nz), [])
>> [sp, mapping] = Sparsity.banded(3, 1).get_diag(); disp(sp), disp(mapping)
3x1
0 3 6
>> [sp, mapping] = Sparsity.unit(3, 1).get_diag(); disp(DM(sp, 1)), disp(mapping)
[[00, 00, 00],
[00, 1, 00],
[00, 00, 00]]
0
>> [sp, mapping] = Sparsity(2, 3).get_diag(); disp(sp), disp(isempty(mapping))
2x1,0nz
1
julia> ca.get_diag(ca.Sparsity.banded(3, 1))
(3x1, [0, 3, 6])
julia> ca.get_diag(ca.Sparsity.unit(3, 1))
(3x3,1nz, [0])
julia> ca.get_diag(ca.Sparsity(2, 3))
(2x1,0nz, Int64[])

See also: diag, nnz_diag

Extra doc | Doc source | Implementation

get_lower(...)

Nonzero indices of the entries in the lower triangular part (row >= col)

get_lower(self) -> [int]
>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.get_lower(), sp.get_upper()
([0, 1], [0, 2, 3])
>>> Sparsity.dense(2, 2).get_lower(), Sparsity.dense(2, 2).get_upper()
([0, 1, 3], [0, 2, 3])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> sp.get_lower(), sp.get_upper()
0 1
0 2 3
>> Sparsity.dense(2, 2).get_lower(), Sparsity.dense(2, 2).get_upper()
0 1 3
0 2 3
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.get_lower(sp), ca.get_upper(sp)
([0, 1], [0, 2, 3])
julia> ca.get_lower(ca.Sparsity.dense(2, 2)), ca.get_upper(ca.Sparsity.dense(2, 2))
([0, 1, 3], [0, 2, 3])

See also: get_upper, nnz_lower, tril

Extra doc | Doc source | Implementation

get_nz(...)

Map flat (column-major) element indices to nonzero indices.

get_nz(self) -> [int]
get_nz(self, int rr, int cc) -> int
get_nz(self, [int] rr, [int] cc) -> [int]

Each entry of indices is replaced by the nonzero index of that element, or by -1 if the element is a structural zero. Entries that are already negative are left alone. The indices need not be sorted. An index of numel() or more raises an error.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.get_nz([0, 2, 4, 9, 1])
[0, 1, -1, 3, -1]
>>> Sparsity.dense(2, 2).get_nz([3, 0])
[3, 0]
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> sp.get_nz([0, 2, 4, 9, 1])
0 1 -1 3 -1
>> Sparsity.dense(2, 2).get_nz([3, 0])
3 0
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.get_nz(sp, [0, 2, 4, 9, 1])
5-element Vector{Int64}:
  0
  1
 -1
  3
 -1
julia> ca.get_nz(ca.Sparsity.dense(2, 2), [3, 0])
2-element Vector{Int64}:
 3
 0

See also: find, nonzeros

Overload: get_nz(self, int rr, int cc)

Nonzero index of entry (rr, cc), or -1 if it is a structural zero.

Negative indices count from the end. An index out of bounds raises an error. For a dense pattern the result is rr + cc*size1(). The returned index addresses the nonzeros() vector of a matrix with this pattern.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.get_nz(0, 0), sp.get_nz(2, 0), sp.get_nz(1, 0), sp.get_nz(-1, 0)
(0, 1, -1, 1)
>>> try: sp.get_nz(3, 0)
... except Exception as e: print("out of bounds")
out of bounds
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [sp.get_nz(0, 0), sp.get_nz(2, 0), sp.get_nz(1, 0), sp.get_nz(-1, 0)]
0 1 -1 1
>> try, sp.get_nz(3, 0); catch e, disp('out of bounds'); end
out of bounds
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.get_nz(sp, 0, 0), ca.get_nz(sp, 2, 0), ca.get_nz(sp, 1, 0), ca.get_nz(sp, -1, 0)
(0, 1, -1, 1)
julia> try
           ca.get_nz(sp, 3, 0)
       catch e
           println("out of bounds")
       end
out of bounds

See also: has_nz, add_nz, find

Overload: get_nz(self, [int] rr, [int] cc)

Nonzero indices of the block of entries with rows rr and columns cc.

Returns one index per (row, column) combination, in column-major order over the block (all rows of the first column first); -1 marks a structural zero. Indices must be in range (no negative indices); otherwise an error is raised.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.get_nz([0, 2], [0, 3])
[0, 1, 3, -1]
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> sp.get_nz([0, 2], [0, 3])
0 1 3 -1
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> println(ca.get_nz(sp, [0, 2], [0, 3]))
[0, 1, 3, -1]

See also: get_nz(rr, cc), sub

Extra doc | Doc source | Implementation

get_triplet(...)

The pattern in sparse triplet format: the row and column of every nonzero.

get_triplet(self) -> ([int], [int])

Inverse of triplet(): Sparsity.triplet(nrow, ncol, row, col) rebuilds the pattern.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> row, col = sp.get_triplet()
>>> row, col
([0, 2, 1, 0], [0, 0, 2, 3])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [row, col] = sp.get_triplet(); disp(row), disp(col)
0 2 1 0
0 0 2 3
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> row, col = ca.get_triplet(sp);
julia> row, col
([0, 2, 1, 0], [0, 0, 2, 3])

See also: triplet, get_row, get_col

Extra doc | Doc source | Implementation

get_upper(...)

Nonzero indices of the entries in the upper triangular part (row <= col)

get_upper(self) -> [int]

See also: get_lower, nnz_upper, triu

Extra doc | Doc source | Implementation

has_nz(...)

Check whether entry (rr, cc) is a structural nonzero.

has_nz(self, int rr, int cc) -> bool

Same index rules as get_nz.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.has_nz(2, 0), sp.has_nz(1, 0)
(True, False)
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [sp.has_nz(2, 0), sp.has_nz(1, 0)]
1 0
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.has_nz(sp, 2, 0), ca.has_nz(sp, 1, 0)
(true, false)

See also: get_nz

Extra doc | Doc source | Implementation

hash(...)

Hash of the pattern (dimensions, colind and row)

hash(self) -> std::size_t

Equal patterns have equal hashes; the hash is used for the pattern cache. In Python, Sparsity objects are not hashable with the built-in hash(); use this method.

>>> sp = Sparsity.diag(2, 3)
>>> sp.hash() == Sparsity.diag(2, 3).hash(), sp.hash() == Sparsity.dense(2, 3).hash()
(True, False)
>> sp = Sparsity.diag(2, 3);
>> class(sp.hash())
uint64
>> [sp.hash() == Sparsity.diag(2, 3).hash(), sp.hash() == Sparsity.dense(2, 3).hash()]
1 0
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.hash(sp) == ca.hash(ca.Sparsity.diag(2, 3)), ca.hash(sp) == ca.hash(ca.Sparsity.dense(2, 3))
(true, false)
julia> sp == ca.Sparsity.diag(2, 3), hash(sp) == hash(ca.Sparsity.diag(2, 3))
(true, true)

See also: is_equal

Extra doc | Doc source | Implementation

info(...)

The pattern as a dictionary with entries nrow, ncol, colind and row.

info(self) -> dict

An empty dictionary for a null object.

>>> Sparsity.diag(2, 3).info()
{'colind': [0, 1, 2, 2], 'ncol': 3, 'nrow': 2, 'row': [0, 1]}
>>> Sparsity().info()
{}
>> s = Sparsity.diag(2, 3).info(); disp(s)
colind: [0 1 2 2]
ncol: 3
nrow: 2
row: [0 1]
>> isempty(fieldnames(Sparsity().info()))
1
julia> ca.info(ca.Sparsity.diag(2, 3))
Dict{String, Any} with 4 entries:
  "nrow" => 2
  "colind" => [0, 1, 2, 2]
  "ncol" => 3
  "row" => [0, 1]
julia> ca.info(ca.Sparsity())
Dict{String, Any}()

See also: get_ccs, compress

Extra doc | Doc source | Implementation

intersect(...)
intersect(self, Sparsity y) -> Sparsity
is_column(...)

Check whether the pattern is a column vector, i.e. size2() == 1.

is_column(self) -> bool
>>> Sparsity.dense(3, 1).is_column(), Sparsity.dense(1, 3).is_column()
(True, False)
>>> Sparsity(1, 1).is_column()
True
>> [Sparsity.dense(3, 1).is_column(), Sparsity.dense(1, 3).is_column()]
1 0
>> Sparsity(1, 1).is_column()
1
julia> ca.is_column(ca.Sparsity.dense(3, 1)), ca.is_column(ca.Sparsity.dense(1, 3))
(true, false)
julia> ca.is_column(ca.Sparsity(1, 1))
true

See also: is_row, is_vector

Extra doc | Doc source | Implementation

is_compactible(...)

Check if the nonzero pattern is the Cartesian product of a row and a column

is_compactible(self) -> (bool, [int], [int])

subset.

If true, returns the (sorted) row and column index sets such that nz(i, j) <-> i in row and j in col. The nonzero buffer of a compactible matrix in CCS is laid out exactly as a column-major dense row.size() x col.size() matrix, so it can be consumed by dense kernels without gather/scatter. The index sets are returned in either case (the nonempty rows and columns); a pattern without nonzeros is compactible.

>>> ok, row, col = Sparsity.rowcol([0, 2], [0, 2], 3, 3).is_compactible()
>>> ok, row, col
(True, [0, 2], [0, 2])
>>> ok, row, col = Sparsity.diag(3).is_compactible()
>>> ok, row, col
(False, [0, 1, 2], [0, 1, 2])
>> [ok, row, col] = Sparsity.rowcol([0, 2], [0, 2], 3, 3).is_compactible();
>> ok, row, col
1
0 2
0 2
>> [ok, row, col] = Sparsity.diag(3).is_compactible(); disp(ok), disp(row), disp(col)
0
0 1 2
0 1 2
julia> ca.is_compactible(ca.Sparsity.rowcol([0, 2], [0, 2], 3, 3))
(true, [0, 2], [0, 2])
julia> ca.is_compactible(ca.Sparsity.diag(3))
(false, [0, 1, 2], [0, 1, 2])

See also: rowcol

Extra doc | Doc source | Implementation

is_dense(...)

Check whether every entry is a structural nonzero, i.e. nnz() == numel()

is_dense(self) -> bool

An empty pattern (a zero dimension) is dense. Note that a DM built from a nested list is dense even if it holds numerical zeros.

>>> Sparsity.dense(2, 3).is_dense(), Sparsity.diag(3).is_dense()
(True, False)
>>> Sparsity(0, 3).is_dense(), Sparsity(1, 1).is_dense()
(True, False)
>>> DM([[1, 0], [0, 1]]).sparsity().is_dense()
True
>> [Sparsity.dense(2, 3).is_dense(), Sparsity.diag(3).is_dense()]
1 0
>> [Sparsity(0, 3).is_dense(), Sparsity(1, 1).is_dense()]
1 0
>> sparsity(DM([1, 0; 0, 1])).is_dense()
1
julia> ca.is_dense(ca.Sparsity.dense(2, 3)), ca.is_dense(ca.Sparsity.diag(3))
(true, false)
julia> ca.is_dense(ca.Sparsity(0, 3)), ca.is_dense(ca.Sparsity(1, 1))
(true, false)
julia> ca.is_dense(ca.sparsity(ca.DM([1 0; 0 1])))
true

See also: dense, density, makeDense

Extra doc | Doc source | Implementation

is_diag(...)

Check whether the pattern is square with exactly the full diagonal as

is_diag(self) -> bool

nonzeros.

True only for Sparsity.diag(n) (including n == 0); a rectangular diagonal pattern, an all-zero square pattern or a pattern with off- diagonal entries is not diagonal.

>>> Sparsity.diag(3).is_diag(), Sparsity.diag(2, 3).is_diag()
(True, False)
>>> Sparsity.dense(1, 1).is_diag(), Sparsity(2, 2).is_diag()
(True, False)
>>> Sparsity(0, 0).is_diag(), Sparsity.dense(2, 2).is_diag()
(True, False)
>> [Sparsity.diag(3).is_diag(), Sparsity.diag(2, 3).is_diag()]
1 0
>> [Sparsity.dense(1, 1).is_diag(), Sparsity(2, 2).is_diag()]
1 0
>> [Sparsity(0, 0).is_diag(), Sparsity.dense(2, 2).is_diag()]
1 0
julia> ca.is_diag(ca.Sparsity.diag(3)), ca.is_diag(ca.Sparsity.diag(2, 3))
(true, false)
julia> ca.is_diag(ca.Sparsity.dense(1, 1)), ca.is_diag(ca.Sparsity(2, 2))
(true, false)
julia> ca.is_diag(ca.Sparsity(0, 0)), ca.is_diag(ca.Sparsity.dense(2, 2))
(true, false)

See also: diag, nnz_diag

Extra doc | Doc source | Implementation

is_empty(...)

Check whether the pattern has a zero dimension.

is_empty(self, bool both) -> bool
Parameters:

both -- If false (default), true when the number of rows or the number of columns is zero; if true, only when both are zero

A pattern without nonzeros but with positive dimensions is not empty.

>>> Sparsity(0, 3).is_empty(), Sparsity(0, 3).is_empty(True)
(True, False)
>>> Sparsity(0, 0).is_empty(True)
True
>>> Sparsity(3, 3).is_empty(), Sparsity(3, 3).nnz()
(False, 0)
>> Sparsity(0, 3).is_empty(), Sparsity(0, 3).is_empty(true)
1
0
>> Sparsity(0, 0).is_empty(true)
1
>> Sparsity(3, 3).is_empty(), Sparsity(3, 3).nnz()
0
0
julia> ca.is_empty(ca.Sparsity(0, 3)), ca.is_empty(ca.Sparsity(0, 3), true)
(true, false)
julia> ca.is_empty(ca.Sparsity(0, 0), true)
true
julia> ca.is_empty(ca.Sparsity(3, 3)), ca.nnz(ca.Sparsity(3, 3))
(false, 0)

See also: numel, nnz

Extra doc | Doc source | Implementation

is_equal(...)
is_equal(self, Sparsity y) -> bool
is_equal(self, int nrow, int ncol, [int] colind, [int] row) -> bool

Check whether two sparsity patterns are identical.

True when the dimensions and the nonzero positions coincide. This is the comparison behind the == operator. Shared (cached) patterns are detected in constant time; otherwise colind and row are compared. The second overload compares against a pattern given in compressed column storage vectors.

>>> a = Sparsity.diag(2)
>>> a.is_equal(Sparsity.diag(2)), a == Sparsity.diag(2), a != Sparsity.dense(2, 2)
(True, True, True)
>>> a.is_equal(2, 2, [0, 1, 2], [0, 1])
True
>>> Sparsity.dense(2, 2) == Sparsity.dense(2, 3)
False
>>> Sparsity(2, 2) == Sparsity.dense(2, 2)
False
>> a = Sparsity.diag(2);
>> a.is_equal(Sparsity.diag(2)), a == Sparsity.diag(2)
1
1
>> a ~= Sparsity.dense(2, 2)
1
>> a.is_equal(2, 2, [0, 1, 2], [0, 1])
1
>> Sparsity.dense(2, 2) == Sparsity.dense(2, 3)
0
>> Sparsity(2, 2) == Sparsity.dense(2, 2)
0
julia> a = ca.Sparsity.diag(2);
julia> ca.is_equal(a, ca.Sparsity.diag(2)), !ca.is_equal(a, ca.Sparsity.dense(2, 2))
(true, true)
julia> ca.is_equal(a, 2, 2, [0, 1, 2], [0, 1])
true
julia> ca.is_equal(ca.Sparsity.dense(2, 2), ca.Sparsity.dense(2, 3))
false
julia> ca.is_equal(ca.Sparsity(2, 2), ca.Sparsity.dense(2, 2))
false

See also: is_subset, is_transpose, is_reshape, hash

Extra doc | Doc source | Implementation

is_null(...)
is_null(self) -> bool
is_orthonormal(...)

Check whether every row and every column has at most one nonzero.

is_orthonormal(self, bool allow_empty) -> bool

Without allow_empty the pattern must also be square with exactly one nonzero per row and column (a permutation pattern). With allow_empty, rows and columns without nonzeros are disregarded and the shape may be rectangular.

Parameters:

allow_empty -- Disregard empty rows and columns in the analysis

>>> Sparsity.diag(3).is_orthonormal()
True
>>> Sparsity.triplet(3, 3, [0, 1], [0, 1]).is_orthonormal()
False
>>> Sparsity.triplet(3, 3, [0, 1], [0, 1]).is_orthonormal(True)
True
>>> Sparsity.triplet(3, 3, [0, 0], [0, 1]).is_orthonormal(True)
False
>>> Sparsity.diag(2, 3).is_orthonormal(), Sparsity.diag(2, 3).is_orthonormal(True)
(False, True)
>> Sparsity.diag(3).is_orthonormal()
1
>> Sparsity.triplet(3, 3, [0, 1], [0, 1]).is_orthonormal()
0
>> Sparsity.triplet(3, 3, [0, 1], [0, 1]).is_orthonormal(true)
1
>> Sparsity.triplet(3, 3, [0, 0], [0, 1]).is_orthonormal(true)
0
>> [Sparsity.diag(2, 3).is_orthonormal(), Sparsity.diag(2, 3).is_orthonormal(true)]
0 1
julia> ca.is_orthonormal(ca.Sparsity.diag(3))
true
julia> ca.is_orthonormal(ca.Sparsity.triplet(3, 3, [0, 1], [0, 1]))
false
julia> ca.is_orthonormal(ca.Sparsity.triplet(3, 3, [0, 1], [0, 1]), true)
true
julia> ca.is_orthonormal(ca.Sparsity.triplet(3, 3, [0, 0], [0, 1]), true)
false
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.is_orthonormal(sp), ca.is_orthonormal(sp, true)
(false, true)

See also: is_orthonormal_rows, is_orthonormal_columns, is_permutation

Extra doc | Doc source | Implementation

is_orthonormal_columns(...)

Check whether the columns are orthonormal (see is_orthonormal_rows)

is_orthonormal_columns(self, bool allow_empty) -> bool

Without allow_empty the pattern must have at most as many columns as rows and exactly one nonzero per column. With allow_empty, columns without nonzeros are disregarded.

Parameters:

allow_empty -- Disregard empty columns in the analysis

See also: is_orthonormal_rows, is_orthonormal

Extra doc | Doc source | Implementation

is_orthonormal_rows(...)

Check whether the rows are orthonormal: one nonzero per row, at most one per

is_orthonormal_rows(self, bool allow_empty) -> bool

column.

Without allow_empty the pattern must have at most as many rows as columns and exactly one nonzero per row. With allow_empty, rows without nonzeros are disregarded.

Parameters:

allow_empty -- Disregard empty rows in the analysis

>>> sp = Sparsity.diag(2, 3)
>>> sp.is_orthonormal_rows(), sp.is_orthonormal_columns()
(True, False)
>>> sp.T.is_orthonormal_rows(), sp.T.is_orthonormal_columns()
(False, True)
>> sp = Sparsity.diag(2, 3);
>> [sp.is_orthonormal_rows(), sp.is_orthonormal_columns()]
1 0
>> [sp.T.is_orthonormal_rows(), sp.T.is_orthonormal_columns()]
0 1
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.is_orthonormal_rows(sp), ca.is_orthonormal_columns(sp)
(true, false)
julia> ca.is_orthonormal_rows(ca.T(sp)), ca.is_orthonormal_columns(ca.T(sp))
(false, true)

See also: is_orthonormal_columns, is_selection

Extra doc | Doc source | Implementation

is_permutation(...)

Check whether the pattern is that of a permutation matrix.

is_permutation(self) -> bool

A square pattern with exactly one nonzero in every row and every column, so that multiplying a dense vector permutes its entries. Equivalent to is_orthonormal().

>>> Sparsity.permutation([1, 2, 0]).is_permutation()
True
>>> Sparsity.diag(3).is_permutation()
True
>>> Sparsity.dense(2, 2).is_permutation(), Sparsity.diag(2, 3).is_permutation()
(False, False)
>> Sparsity.permutation([1, 2, 0]).is_permutation()
1
>> Sparsity.diag(3).is_permutation()
1
>> [Sparsity.dense(2, 2).is_permutation(), Sparsity.diag(2, 3).is_permutation()]
0 0
julia> ca.is_permutation(ca.Sparsity.permutation([1, 2, 0]))
true
julia> ca.is_permutation(ca.Sparsity.diag(3))
true
julia> ca.is_permutation(ca.Sparsity.dense(2, 2)), ca.is_permutation(ca.Sparsity.diag(2, 3))
(false, false)

See also: permutation, permutation_vector, is_selection, is_orthonormal

Extra doc | Doc source | Implementation

is_reshape(...)

Check whether y is a reshape of this pattern.

is_reshape(self, Sparsity y) -> bool

True when both have the same number of elements and the same flat (column- major) nonzero positions, i.e. reshape(A, y.size()) has pattern y.

>>> Sparsity.dense(2, 3).is_reshape(Sparsity.dense(6, 1))
True
>>> Sparsity.diag(2).is_reshape(Sparsity.nonzeros(4, 1, [0, 3]))
True
>>> Sparsity.diag(2).is_reshape(Sparsity.nonzeros(4, 1, [0, 2]))
False
>> Sparsity.dense(2, 3).is_reshape(Sparsity.dense(6, 1))
1
>> Sparsity.diag(2).is_reshape(Sparsity.nonzeros(4, 1, [1, 4]))
1
>> Sparsity.diag(2).is_reshape(Sparsity.nonzeros(4, 1, [1, 3]))
0
julia> ca.is_reshape(ca.Sparsity.dense(2, 3), ca.Sparsity.dense(6, 1))
true
julia> ca.is_reshape(ca.Sparsity.diag(2), ca.Sparsity.nonzeros(4, 1, [0, 3]))
true
julia> ca.is_reshape(ca.Sparsity.diag(2), ca.Sparsity.nonzeros(4, 1, [0, 2]))
false

See also: reshape, find

Extra doc | Doc source | Implementation

is_row(...)

Check whether the pattern is a row vector, i.e. size1() == 1.

is_row(self) -> bool

The number of columns (including zero) and the nonzeros play no role.

>>> Sparsity.dense(1, 3).is_row(), Sparsity.dense(3, 1).is_row()
(True, False)
>>> Sparsity(1, 0).is_row()
True
>> [Sparsity.dense(1, 3).is_row(), Sparsity.dense(3, 1).is_row()]
1 0
>> Sparsity(1, 0).is_row()
1
julia> ca.is_row(ca.Sparsity.dense(1, 3)), ca.is_row(ca.Sparsity.dense(3, 1))
(true, false)
julia> ca.is_row(ca.Sparsity(1, 0))
true

See also: is_column, is_vector

Extra doc | Doc source | Implementation

is_scalar(...)

Check whether the pattern is 1-by-1.

is_scalar(self, bool scalar_and_dense) -> bool
Parameters:

scalar_and_dense -- If true, additionally require the single entry to be a nonzero (a 1-by-1 pattern with zero nonzeros is a structural zero)

>>> Sparsity.dense(1, 1).is_scalar(), Sparsity(1, 1).is_scalar()
(True, True)
>>> Sparsity(1, 1).is_scalar(True), Sparsity.dense(2, 1).is_scalar()
(False, False)
>> [Sparsity.dense(1, 1).is_scalar(), Sparsity(1, 1).is_scalar()]
1 1
>> [Sparsity(1, 1).is_scalar(true), Sparsity.dense(2, 1).is_scalar()]
0 0
julia> ca.is_scalar(ca.Sparsity.dense(1, 1)), ca.is_scalar(ca.Sparsity(1, 1))
(true, true)
julia> ca.is_scalar(ca.Sparsity(1, 1), true), ca.is_scalar(ca.Sparsity.dense(2, 1))
(false, false)

See also: scalar, is_dense

Extra doc | Doc source | Implementation

is_selection(...)

Check whether the pattern is that of a selection matrix.

is_selection(self, bool allow_empty) -> bool

A selection matrix S picks a subset of the entries of a dense vector: S @ v is a vector of distinct entries of v. The pattern has at most one nonzero per column and exactly one per row. Equivalent to is_orthonormal_rows(allow_empty).

Parameters:

allow_empty -- If true, rows without nonzeros are allowed (the result may contain structural zeros)

>>> S = Sparsity.triplet(2, 3, [0, 1], [2, 0])
>>> DM(S, 1) @ DM([10, 20, 30])
DM([30, 10])
>>> S.is_selection(), Sparsity.triplet(2, 3, [0], [2]).is_selection()
(True, False)
>>> Sparsity.triplet(2, 3, [0], [2]).is_selection(True)
True
>>> Sparsity.diag(3, 2).is_selection()
False
>> S = Sparsity.triplet(2, 3, [0, 1], [2, 0]);
>> DM(S, 1) * DM([10; 20; 30])
[30, 10]
>> [S.is_selection(), Sparsity.triplet(2, 3, 0, 2).is_selection()]
1 0
>> Sparsity.triplet(2, 3, 0, 2).is_selection(true)
1
>> Sparsity.diag(3, 2).is_selection()
0
julia> S = ca.Sparsity.triplet(2, 3, [0, 1], [2, 0]);
julia> ca.DM(S, 1) * ca.DM([10, 20, 30])
DM([30, 10])
julia> ca.is_selection(S), ca.is_selection(ca.Sparsity.triplet(2, 3, [0], [2]))
(true, false)
julia> ca.is_selection(ca.Sparsity.triplet(2, 3, [0], [2]), true)
true
julia> ca.is_selection(ca.Sparsity.diag(3, 2))
false

See also: is_permutation, is_orthonormal_rows

Extra doc | Doc source | Implementation

is_singular(...)

Check whether a square pattern is structurally singular.

is_singular(self) -> bool

True when the structural rank (sprank) is smaller than the size, i.e. no choice of nonzero values can make a matrix with this pattern invertible. A non-square pattern raises an error.

>>> Sparsity.diag(3).is_singular(), Sparsity(3, 3).is_singular()
(False, True)
>>> Sparsity.nonzeros(3, 3, [0, 1, 2]).is_singular(), Sparsity(0, 0).is_singular()
(True, False)
>>> try: Sparsity.dense(2, 3).is_singular()
... except Exception as e: print("not square")
not square
>> [Sparsity.diag(3).is_singular(), Sparsity(3, 3).is_singular()]
0 1
>> [Sparsity.nonzeros(3, 3, [1, 2, 3]).is_singular(), Sparsity(0, 0).is_singular()]
1 0
>> try, Sparsity.dense(2, 3).is_singular(); catch e, disp('not square'); end
not square
julia> ca.is_singular(ca.Sparsity.diag(3)), ca.is_singular(ca.Sparsity(3, 3))
(false, true)
julia> ca.is_singular(ca.Sparsity.nonzeros(3, 3, [0, 1, 2]))
true
julia> ca.is_singular(ca.Sparsity(0, 0))
false
julia> try
           ca.is_singular(ca.Sparsity.dense(2, 3))
       catch e
           println("not square")
       end
not square

See also: sprank, btf

Extra doc | Doc source | Implementation

is_square(...)

Check whether the number of rows equals the number of columns.

is_square(self) -> bool
>>> Sparsity.dense(2, 2).is_square(), Sparsity.dense(2, 3).is_square()
(True, False)
>>> Sparsity(0, 0).is_square()
True
>> [Sparsity.dense(2, 2).is_square(), Sparsity.dense(2, 3).is_square()]
1 0
>> Sparsity(0, 0).is_square()
1
julia> ca.is_square(ca.Sparsity.dense(2, 2)), ca.is_square(ca.Sparsity.dense(2, 3))
(true, false)
julia> ca.is_square(ca.Sparsity(0, 0))
true

Extra doc | Doc source | Implementation

is_stacked(...)

Check whether the pattern is n copies of y placed side by side.

is_stacked(self, Sparsity y, int n) -> bool

True when this pattern equals horzcat(y, ..., y) with n repetitions, i.e. the pattern of repmat(y, 1, n). The patterns are compared structurally, so a dense pattern of the right shape does not count as a stack of a sparse one.

>>> sp = horzcat(Sparsity.diag(2), Sparsity.diag(2), Sparsity.diag(2))
>>> sp.is_stacked(Sparsity.diag(2), 3), sp.is_stacked(Sparsity.diag(2), 2)
(True, False)
>>> Sparsity.dense(2, 6).is_stacked(Sparsity.diag(2), 3)
False
>> sp = [Sparsity.diag(2), Sparsity.diag(2), Sparsity.diag(2)];
>> sp.is_stacked(Sparsity.diag(2), 3), sp.is_stacked(Sparsity.diag(2), 2)
1
0
>> Sparsity.dense(2, 6).is_stacked(Sparsity.diag(2), 3)
0
julia> sp = ca.repmat(ca.Sparsity.diag(2), 1, 3)
Sparsity(2x6,6nz)
julia> ca.is_stacked(sp, ca.Sparsity.diag(2), 3), ca.is_stacked(sp, ca.Sparsity.diag(2), 2)
(true, false)
julia> ca.is_stacked(ca.Sparsity.dense(2, 6), ca.Sparsity.diag(2), 3)
false

See also: is_equal, horzcat

Extra doc | Doc source | Implementation

is_subset(...)

Check whether every nonzero of this pattern is also a nonzero of rhs.

is_subset(self, Sparsity rhs) -> bool

Both patterns must have the same shape, otherwise an error is raised. A pattern is a subset of itself and an all-zero pattern is a subset of any pattern of its shape.

>>> Sparsity.diag(3).is_subset(Sparsity.dense(3, 3))
True
>>> Sparsity.dense(3, 3).is_subset(Sparsity.diag(3))
False
>>> Sparsity(3, 3).is_subset(Sparsity.diag(3))
True
>>> Sparsity.diag(3).is_subset(Sparsity.diag(3))
True
>> Sparsity.diag(3).is_subset(Sparsity.dense(3, 3))
1
>> Sparsity.dense(3, 3).is_subset(Sparsity.diag(3))
0
>> Sparsity(3, 3).is_subset(Sparsity.diag(3))
1
>> Sparsity.diag(3).is_subset(Sparsity.diag(3))
1
julia> ca.is_subset(ca.Sparsity.diag(3), ca.Sparsity.dense(3, 3))
true
julia> ca.is_subset(ca.Sparsity.dense(3, 3), ca.Sparsity.diag(3))
false
julia> ca.is_subset(ca.Sparsity(3, 3), ca.Sparsity.diag(3))
true
julia> ca.is_subset(ca.Sparsity.diag(3), ca.Sparsity.diag(3))
true

See also: unite, intersect, is_equal

Extra doc | Doc source | Implementation

is_symmetric(...)

Check whether the pattern equals its transpose.

is_symmetric(self) -> bool

Structural symmetry only: (i, j) is a nonzero if and only if (j, i) is. Required by amd, ldl and the star colorings. A rectangular pattern is never symmetric.

>>> Sparsity.banded(3, 1).is_symmetric(), Sparsity.upper(3).is_symmetric()
(True, False)
>>> Sparsity(3, 3).is_symmetric(), Sparsity.dense(2, 3).is_symmetric()
(True, False)
>> [Sparsity.banded(3, 1).is_symmetric(), Sparsity.upper(3).is_symmetric()]
1 0
>> [Sparsity(3, 3).is_symmetric(), Sparsity.dense(2, 3).is_symmetric()]
1 0
julia> ca.is_symmetric(ca.Sparsity.banded(3, 1)), ca.is_symmetric(ca.Sparsity.upper(3))
(true, false)
julia> ca.is_symmetric(ca.Sparsity(3, 3)), ca.is_symmetric(ca.Sparsity.dense(2, 3))
(true, false)

See also: is_transpose, T

Extra doc | Doc source | Implementation

is_transpose(...)

Check whether y is the transpose of this pattern.

is_transpose(self, Sparsity y) -> bool
>>> Sparsity.band(3, 1).is_transpose(Sparsity.band(3, -1))
True
>>> Sparsity.band(3, 1).is_transpose(Sparsity.band(3, 1))
False
>>> Sparsity.dense(2, 3).is_transpose(Sparsity.dense(3, 2))
True
>> Sparsity.band(3, 1).is_transpose(Sparsity.band(3, -1))
1
>> Sparsity.band(3, 1).is_transpose(Sparsity.band(3, 1))
0
>> Sparsity.dense(2, 3).is_transpose(Sparsity.dense(3, 2))
1
julia> ca.is_transpose(ca.Sparsity.band(3, 1), ca.Sparsity.band(3, -1))
true
julia> ca.is_transpose(ca.Sparsity.band(3, 1), ca.Sparsity.band(3, 1))
false
julia> ca.is_transpose(ca.Sparsity.dense(2, 3), ca.Sparsity.dense(3, 2))
true

See also: T, is_symmetric

Extra doc | Doc source | Implementation

is_tril(...)

Check whether all nonzeros are on or below the diagonal (row >= col)

is_tril(self, bool strictly) -> bool
Parameters:

strictly -- If true, require row > col (no diagonal entries)

>>> Sparsity.lower(3).is_tril(), Sparsity.lower(3).is_tril(True)
(True, False)
>>> Sparsity.band(3, 1).is_tril(True), Sparsity.diag(3).is_tril()
(True, True)
>>> Sparsity.dense(3, 1).is_tril(), Sparsity.dense(1, 3).is_tril()
(True, False)
>> [Sparsity.lower(3).is_tril(), Sparsity.lower(3).is_tril(true)]
1 0
>> [Sparsity.band(3, 1).is_tril(true), Sparsity.diag(3).is_tril()]
1 1
>> [Sparsity.dense(3, 1).is_tril(), Sparsity.dense(1, 3).is_tril()]
1 0
julia> ca.is_tril(ca.Sparsity.lower(3)), ca.is_tril(ca.Sparsity.lower(3), true)
(true, false)
julia> ca.is_tril(ca.Sparsity.band(3, 1), true), ca.is_tril(ca.Sparsity.diag(3))
(true, true)
julia> ca.is_tril(ca.Sparsity.dense(3, 1)), ca.is_tril(ca.Sparsity.dense(1, 3))
(true, false)

See also: is_triu, lower, tril, nnz_lower

Extra doc | Doc source | Implementation

is_triu(...)

Check whether all nonzeros are on or above the diagonal (row <= col)

is_triu(self, bool strictly) -> bool
Parameters:

strictly -- If true, require row < col (no diagonal entries)

Defined for any shape; a pattern without nonzeros is upper triangular.

>>> Sparsity.upper(3).is_triu(), Sparsity.upper(3).is_triu(True)
(True, False)
>>> Sparsity.band(3, -1).is_triu(True), Sparsity(3, 3).is_triu()
(True, True)
>>> Sparsity.dense(1, 3).is_triu(), Sparsity.dense(3, 1).is_triu()
(True, False)
>> [Sparsity.upper(3).is_triu(), Sparsity.upper(3).is_triu(true)]
1 0
>> [Sparsity.band(3, -1).is_triu(true), Sparsity(3, 3).is_triu()]
1 1
>> [Sparsity.dense(1, 3).is_triu(), Sparsity.dense(3, 1).is_triu()]
1 0
julia> ca.is_triu(ca.Sparsity.upper(3)), ca.is_triu(ca.Sparsity.upper(3), true)
(true, false)
julia> ca.is_triu(ca.Sparsity.band(3, -1), true), ca.is_triu(ca.Sparsity(3, 3))
(true, true)
julia> ca.is_triu(ca.Sparsity.dense(1, 3)), ca.is_triu(ca.Sparsity.dense(3, 1))
(true, false)

See also: is_tril, upper, triu, nnz_upper

Extra doc | Doc source | Implementation

is_vector(...)

Check whether the pattern is a row or a column vector.

is_vector(self) -> bool

A 1-by-1 pattern is a vector; a 0-by-3 pattern is not.

>>> Sparsity.dense(3, 1).is_vector(), Sparsity.dense(1, 3).is_vector()
(True, True)
>>> Sparsity.dense(1, 1).is_vector(), Sparsity.dense(2, 2).is_vector()
(True, False)
>>> Sparsity(0, 3).is_vector()
False
>> [Sparsity.dense(3, 1).is_vector(), Sparsity.dense(1, 3).is_vector()]
1 1
>> [Sparsity.dense(1, 1).is_vector(), Sparsity.dense(2, 2).is_vector()]
1 0
>> Sparsity(0, 3).is_vector()
0
julia> ca.is_vector(ca.Sparsity.dense(3, 1)), ca.is_vector(ca.Sparsity.dense(1, 3))
(true, true)
julia> ca.is_vector(ca.Sparsity.dense(1, 1)), ca.is_vector(ca.Sparsity.dense(2, 2))
(true, false)
julia> ca.is_vector(ca.Sparsity(0, 3))
false

See also: is_row, is_column

Extra doc | Doc source | Implementation

static kkt(...)

Pattern of a KKT system [H + I1, J'; J, I2].

kkt(Sparsity H, Sparsity J, bool with_x_diag, bool with_lam_g_diag) -> Sparsity

Block pattern of the KKT matrix of an NLP with Hessian H (square, n-by-n) and constraint Jacobian J (m-by-n), where I1 and I2 are the n-by-n and m-by-m diagonal patterns that are included on request. Shape (n+m)-by-(n+m).

Parameters:
  • H -- Hessian pattern, must be square

  • J -- Jacobian pattern, its number of columns must equal the size of H

  • with_x_diag -- Add the diagonal to the H block

  • with_lam_g_diag -- Make the lower right block diagonal instead of all-zero

>>> DM(Sparsity.kkt(Sparsity.diag(2), Sparsity.dense(1, 2)), 1)
DM(
[[1, 00, 1],
 [00, 1, 1],
 [1, 1, 1]])
>>> DM(Sparsity.kkt(Sparsity(2, 2), Sparsity.dense(1, 2), False, False), 1)
DM(
[[00, 00, 1],
 [00, 00, 1],
 [1, 1, 00]])
>>> try: Sparsity.kkt(Sparsity.diag(2), Sparsity.dense(1, 3))
... except Exception as e: print("dimension mismatch")
dimension mismatch
>> DM(Sparsity.kkt(Sparsity.diag(2), Sparsity.dense(1, 2)), 1)
[[1, 00, 1],
[00, 1, 1],
[1, 1, 1]]
>> DM(Sparsity.kkt(Sparsity(2, 2), Sparsity.dense(1, 2), false, false), 1)
[[00, 00, 1],
[00, 00, 1],
[1, 1, 00]]
>> J = Sparsity.dense(1, 3);
>> try, Sparsity.kkt(Sparsity.diag(2), J); catch e, disp('dimension mismatch'); end
dimension mismatch
julia> ca.DM(ca.Sparsity.kkt(ca.Sparsity.diag(2), ca.Sparsity.dense(1, 2)), 1)
DM(
[[1, 00, 1],
 [00, 1, 1],
 [1, 1, 1]])
julia> ca.DM(ca.Sparsity.kkt(ca.Sparsity(2, 2), ca.Sparsity.dense(1, 2), false, false), 1)
DM(
[[00, 00, 1],
 [00, 00, 1],
 [1, 1, 00]])
julia> try
           ca.Sparsity.kkt(ca.Sparsity.diag(2), ca.Sparsity.dense(1, 3))
       catch e
           println("dimension mismatch")
       end
dimension mismatch

See also: blockcat

Extra doc | Doc source | Implementation

largest_first(...)

Column indices ordered by decreasing number of nonzeros.

largest_first(self) -> [int]

Columns with the same number of nonzeros keep their relative order. Used as the ordering of the star colorings.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.largest_first(), Sparsity.diag(3).largest_first()
([0, 2, 3, 1], [0, 1, 2])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> sp.largest_first(), Sparsity.diag(3).largest_first()
0 2 3 1
0 1 2
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.largest_first(sp), ca.largest_first(ca.Sparsity.diag(3))
([0, 2, 3, 1], [0, 1, 2])

See also: star_coloring

Extra doc | Doc source | Implementation

ldl(...)

Symbolic LDL factorization of a symmetric pattern.

ldl(self, bool amd) -> (Sparsity, [int])

Computes the pattern of the factor in A[p, p] = L*D*L^T, where L is unit lower triangular. Returns the pattern of the strictly upper triangular L^T (the unit diagonal is not stored) and the ordering p. A non-symmetric pattern raises an error. The numerical counterpart is ldl() applied to a matrix.

Parameters:

amd -- If true (default), a fill-reducing AMD ordering is computed and returned in p; if false, p is the identity

Returns:

Pattern of L^T and the permutation vector p

>>> Lt, p = Sparsity.banded(4, 1).ldl(False)
>>> DM(Lt, 1), p
(DM(
[[00, 1, 00, 00],
 [00, 00, 1, 00],
 [00, 00, 00, 1],
 [00, 00, 00, 00]]), [0, 1, 2, 3])
>>> A = Sparsity.nonzeros(4, 4, [0, 3, 5, 10, 12, 15])
>>> Lt, p = A.ldl()
>>> Lt.nnz(), p
(1, [1, 2, 0, 3])
>>> try: Sparsity.upper(3).ldl()
... except Exception as e: print("not symmetric")
not symmetric
>> [Lt, p] = Sparsity.banded(4, 1).ldl(false);
>> DM(Lt, 1), p
[[00, 1, 00, 00],
[00, 00, 1, 00],
[00, 00, 00, 1],
[00, 00, 00, 00]]
0 1 2 3
>> A = Sparsity.nonzeros(4, 4, [1, 4, 6, 11, 13, 16]);
>> [Lt, p] = A.ldl(); disp(Lt.nnz()), disp(p)
1
1 2 0 3
>> try, Sparsity.upper(3).ldl(); catch e, disp('not symmetric'); end
not symmetric
julia> ca.ldl(ca.Sparsity.banded(4, 1), false)
(4x4,3nz, [0, 1, 2, 3])
julia> A = ca.Sparsity.nonzeros(4, 4, [0, 3, 5, 10, 12, 15]);
julia> ca.nnz(first(ca.ldl(A)))
1
julia> try
           ca.ldl(ca.Sparsity.upper(3))
       catch e
           println("not symmetric")
       end
not symmetric

The implementation is a modified version of LDL Copyright(c) Timothy A. Davis, 2005-2013 Licensed as a derivative work under the GNU LGPL

See also: amd, etree, qr_sparse

Extra doc | Doc source | Implementation

static lower(...)

Create a lower triangular square sparsity pattern.

lower(int n) -> Sparsity

Column j contains the rows j, ..., n-1, so the diagonal is included and the pattern has n*(n+1)/2 nonzeros.

Parameters:

n -- Size of the square pattern, nonnegative

>>> DM(Sparsity.lower(3), 1)
DM(
[[1, 00, 00],
 [1, 1, 00],
 [1, 1, 1]])
>>> SX.sym("x", Sparsity.lower(2))
SX(
[[x_0, 00],
 [x_1, x_2]])
>> DM(Sparsity.lower(3), 1)
[[1, 00, 00],
[1, 1, 00],
[1, 1, 1]]
>> SX.sym('x', Sparsity.lower(2))
[[x_0, 00],
[x_1, x_2]]
julia> ca.DM(ca.Sparsity.lower(3), 1)
DM(
[[1, 00, 00],
 [1, 1, 00],
 [1, 1, 1]])
julia> ca.SX.sym("x", ca.Sparsity.lower(2))
SX(
[[x_0, 00],
 [x_1, x_2]])

See also: upper, tril, is_tril

Extra doc | Doc source | Implementation

makeDense(...)

Dense pattern of the same shape, with the flat index of every nonzero.

makeDense(self) -> (Sparsity, [int])
Returns:

mapping[k] is the flat (column-major) element index of nonzero k, as returned by find()

Return type:

The dense pattern and a mapping of length nnz()

>>> sp = Sparsity.triplet(3, 2, [0, 2], [0, 1])
>>> dense, mapping = sp.makeDense()
>>> dense, mapping
(Sparsity(3x2), [0, 5])
>> sp = Sparsity.triplet(3, 2, [0, 2], [0, 1]);
>> [dense, mapping] = sp.makeDense(); disp(dense), disp(mapping)
3x2
0 5
julia> sp = ca.Sparsity.triplet(3, 2, [0, 2], [0, 1]);
julia> ca.makeDense(sp)
(3x2, [0, 5])

See also: find, dense

Extra doc | Doc source | Implementation

nnz(...)

Number of structural nonzeros.

nnz(self) -> int

Equals colind[size2()] and the length of the row vector. Zero for an empty pattern and for a pattern created with Sparsity(nrow, ncol).

See also: numel, density, nnz_upper, nnz_lower, nnz_diag

Extra doc | Doc source | Implementation

nnz_diag(...)

Number of nonzeros on the main diagonal, i.e. entries (i, i)

nnz_diag(self) -> int

See also: nnz_upper, nnz_lower, get_diag

Extra doc | Doc source | Implementation

nnz_lower(...)

Number of nonzeros in the lower triangular part, i.e. entries (i, j) with i

nnz_lower(self, bool strictly) -> int

>= j.

Parameters:

strictly -- If true, exclude the diagonal (count i > j only)

See also: nnz_upper, nnz_diag, get_lower, is_tril

Extra doc | Doc source | Implementation

nnz_upper(...)

Number of nonzeros in the upper triangular part, i.e. entries (i, j) with i

nnz_upper(self, bool strictly) -> int

<= j.

Parameters:

strictly -- If true, exclude the diagonal (count i < j only)

Defined for any shape, not only square patterns.

>>> sp = Sparsity.dense(3, 3)
>>> sp.nnz_upper(), sp.nnz_upper(True), sp.nnz_lower(), sp.nnz_lower(True)
(6, 3, 6, 3)
>>> sp.nnz_diag()
3
>>> sp = Sparsity.dense(2, 4)
>>> sp.nnz_upper(), sp.nnz_lower(), sp.nnz_diag()
(7, 3, 2)
>>> Sparsity.lower(3).nnz_upper(), Sparsity.lower(3).nnz_upper(True)
(3, 0)
>> sp = Sparsity.dense(3, 3);
>> [sp.nnz_upper(), sp.nnz_upper(true), sp.nnz_lower(), sp.nnz_lower(true)]
6 3 6 3
>> sp.nnz_diag()
3
>> sp = Sparsity.dense(2, 4);
>> [sp.nnz_upper(), sp.nnz_lower(), sp.nnz_diag()]
7 3 2
>> [Sparsity.lower(3).nnz_upper(), Sparsity.lower(3).nnz_upper(true)]
3 0
julia> sp = ca.Sparsity.dense(3, 3);
julia> ca.nnz_upper(sp), ca.nnz_upper(sp, true), ca.nnz_lower(sp), ca.nnz_lower(sp, true)
(6, 3, 6, 3)
julia> ca.nnz_diag(sp)
3
julia> sp = ca.Sparsity.dense(2, 4);
julia> ca.nnz_upper(sp), ca.nnz_lower(sp), ca.nnz_diag(sp)
(7, 3, 2)
julia> ca.nnz_upper(ca.Sparsity.lower(3)), ca.nnz_upper(ca.Sparsity.lower(3), true)
(3, 0)

See also: nnz_lower, nnz_diag, get_upper, is_triu

Extra doc | Doc source | Implementation

static nonzeros(...)

Create a sparsity pattern from the flat (column-major) index of every

nonzeros(int nrow, int ncol, [int] nz, bool ind1) -> Sparsity

nonzero.

Inverse of find(): Sparsity.nonzeros(sp.size1(), sp.size2(), sp.find()) equals sp. Duplicates are merged.

Parameters:
  • nrow -- Number of rows, must be positive

  • ncol -- Number of columns

  • nz -- Flat indices, each in [0, nrow*ncol); an index out of range raises an error

  • ind1 -- If true, the indices are one-based

>>> DM(Sparsity.nonzeros(3, 2, [0, 4]), 1)
DM(
[[1, 00],
 [00, 1],
 [00, 00]])
>>> sp = Sparsity.banded(3, 1)
>>> Sparsity.nonzeros(3, 3, sp.find()) == sp
True
>>> Sparsity.nonzeros(3, 2, [1, 5], True) == Sparsity.nonzeros(3, 2, [0, 4])
True
>> DM(Sparsity.nonzeros(3, 2, [1, 5]), 1)
[[1, 00],
[00, 1],
[00, 00]]
>> sp = Sparsity.banded(3, 1);
>> Sparsity.nonzeros(3, 3, sp.find()) == sp
1
>> Sparsity.nonzeros(3, 2, [0, 4], false) == Sparsity.nonzeros(3, 2, [1, 5])
1
julia> ca.DM(ca.Sparsity.nonzeros(3, 2, [0, 4]), 1)
DM(
[[1, 00],
 [00, 1],
 [00, 00]])
julia> sp = ca.Sparsity.banded(3, 1);
julia> ca.is_equal(ca.Sparsity.nonzeros(3, 3, ca.find(sp)), sp)
true
julia> sp1 = ca.Sparsity.nonzeros(3, 2, [1, 5], true);
julia> ca.is_equal(sp1, ca.Sparsity.nonzeros(3, 2, [0, 4]))
true

See also: find, triplet

Extra doc | Doc source | Implementation

numel(...)

Total number of entries, structural zeros included, i.e. size1()*size2()

numel(self) -> int

The product may overflow for very large shapes; nnz() never exceeds it.

>>> sp = Sparsity.diag(2, 3)
>>> sp.numel(), sp.nnz(), Sparsity(0, 3).numel()
(6, 2, 0)
>> sp = Sparsity.diag(2, 3);
>> fprintf('%d %d %d\n', sp.numel(), sp.nnz(), Sparsity(0, 3).numel())
6 2 0
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.numel(sp), ca.nnz(sp), ca.numel(ca.Sparsity(0, 3))
(6, 2, 0)

See also: nnz, size

Extra doc | Doc source | Implementation

pattern_inverse(...)

Complement of the pattern: structural zeros become nonzeros and vice versa.

pattern_inverse(self) -> Sparsity

The result has the same shape; a dense pattern becomes all-zero and an all- zero pattern becomes dense.

>>> DM(Sparsity.diag(2).pattern_inverse(), 1)
DM(
[[00, 1],
 [1, 00]])
>>> Sparsity.dense(2, 2).pattern_inverse(), Sparsity(2, 2).pattern_inverse()
(Sparsity(2x2,0nz), Sparsity(2x2))
>> DM(Sparsity.diag(2).pattern_inverse(), 1)
[[00, 1],
[1, 00]]
>> Sparsity.dense(2, 2).pattern_inverse(), Sparsity(2, 2).pattern_inverse()
2x2,0nz
2x2
julia> ca.DM(ca.pattern_inverse(ca.Sparsity.diag(2)), 1)
DM(
[[00, 1],
 [1, 00]])
julia> ca.pattern_inverse(ca.Sparsity.dense(2, 2)), ca.pattern_inverse(ca.Sparsity(2, 2))
(2x2,0nz, 2x2)

See also: unite, intersect

Extra doc | Doc source | Implementation

static permutation(...)

Construct the pattern of a permutation matrix P from a permutation vector p.

permutation([int] p, bool invert) -> Sparsity

P is square with one nonzero per row and column, placed such that multiplying a column vector v from the left gives the same result as indexing it: P @ v == v[p]. The inverse of a permutation matrix is its transpose, so invert true returns the transpose pattern, for which P @ v puts v[i] at position p[i].

Parameters:
  • p -- Permutation vector: every integer in [0, len(p)) exactly once; anything else raises an error

  • invert -- If true, build the inverse (transposed) permutation

>>> P = Sparsity.permutation([2, 0, 1])
>>> DM(P, 1)
DM(
[[00, 00, 1],
 [1, 00, 00],
 [00, 1, 00]])
>>> DM(P, 1) @ DM([10, 20, 30])
DM([30, 10, 20])
>>> DM(Sparsity.permutation([2, 0, 1], True), 1) @ DM([10, 20, 30])
DM([20, 30, 10])
>>> Sparsity.permutation([2, 0, 1], True) == P.T
True
>>> try: Sparsity.permutation([0, 0, 1])
... except Exception as e: print("not a permutation")
not a permutation
>> P = Sparsity.permutation([2, 0, 1]);
>> DM(P, 1)
[[00, 00, 1],
[1, 00, 00],
[00, 1, 00]]
>> DM(P, 1) * DM([10; 20; 30])
[30, 10, 20]
>> DM(Sparsity.permutation([2, 0, 1], true), 1) * DM([10; 20; 30])
[20, 30, 10]
>> Sparsity.permutation([2, 0, 1], true) == P.T
1
>> try, Sparsity.permutation([0, 0, 1]); catch e, disp('not a permutation'); end
not a permutation
julia> P = ca.Sparsity.permutation([2, 0, 1]);
julia> ca.DM(P, 1)
DM(
[[00, 00, 1],
 [1, 00, 00],
 [00, 1, 00]])
julia> ca.DM(P, 1) * ca.DM([10, 20, 30])
DM([30, 10, 20])
julia> ca.DM(ca.Sparsity.permutation([2, 0, 1], true), 1) * ca.DM([10, 20, 30])
DM([20, 30, 10])
julia> ca.is_equal(ca.Sparsity.permutation([2, 0, 1], true), ca.T(P))
true
julia> try
           ca.Sparsity.permutation([0, 0, 1])
       catch e
           println("not a permutation")
       end
not a permutation

See also: permutation_vector, is_permutation, pmult

Extra doc | Doc source | Implementation

permutation_vector(...)

Recover the permutation vector p from the pattern of a permutation matrix.

permutation_vector(self, bool invert) -> [int]

Inverse of permutation(): Sparsity.permutation(p).permutation_vector() returns p. Raises an error if is_permutation() is false.

Parameters:

invert -- If true, return the inverse permutation instead

>>> Sparsity.permutation([2, 0, 1]).permutation_vector()
[2, 0, 1]
>>> Sparsity.permutation([2, 0, 1]).permutation_vector(True)
[1, 2, 0]
>>> try: Sparsity.dense(2, 2).permutation_vector()
... except Exception as e: print("not a permutation matrix")
not a permutation matrix
>> Sparsity.permutation([2, 0, 1]).permutation_vector()
2 0 1
>> Sparsity.permutation([2, 0, 1]).permutation_vector(true)
1 2 0
>> try, Sparsity.dense(2, 2).permutation_vector(); catch e, disp('not a permutation'); end
not a permutation
julia> ca.permutation_vector(ca.Sparsity.permutation([2, 0, 1]))
3-element Vector{Int64}:
 2
 0
 1
julia> ca.permutation_vector(ca.Sparsity.permutation([2, 0, 1]), true)
3-element Vector{Int64}:
 1
 2
 0
julia> try
           ca.permutation_vector(ca.Sparsity.dense(2, 2))
       catch e
           println("not a permutation matrix")
       end
not a permutation matrix

See also: permutation, is_permutation

Extra doc | Doc source | Implementation

pmult(...)

Permute the rows and/or columns of the pattern.

pmult(self, [int] p, bool permute_rows, bool permute_columns, bool invert_permutation) -> Sparsity

Nonzero (i, j) moves to (p[i], p[j]) when both rows and columns are permuted, to (p[i], j) for rows only and to (i, p[j]) for columns only. In matrix terms this is P^T*A*P, P^T*A or A*P with P the matrix of Sparsity.permutation(p). With invert_permutation the inverse of p is used instead, so that pmult(p, True, True, True) is the pattern of A[p, p].

Parameters:
  • p -- Permutation vector; its length must equal the number of rows (if permute_rows) and the number of columns (if permute_columns)

  • permute_rows -- Permute the rows

  • permute_columns -- Permute the columns

  • invert_permutation -- Use the inverse permutation

>>> A = Sparsity.triplet(3, 3, [0, 1, 2, 0], [1, 2, 0, 0])
>>> DM(A, 1)
DM(
[[1, 1, 00],
 [00, 00, 1],
 [1, 00, 00]])
>>> p = [2, 0, 1]
>>> DM(A.pmult(p), 1)
DM(
[[00, 1, 00],
 [00, 00, 1],
 [1, 00, 1]])
>>> P = DM(Sparsity.permutation(p), 1)
>>> A.pmult(p) == (P.T @ DM(A, 1) @ P).sparsity()
True
>>> A.pmult(p, True, True, True) == A.sub(p, p)[0]
True
>>> DM(A.pmult(p, True, False), 1)
DM(
[[00, 00, 1],
 [1, 00, 00],
 [1, 1, 00]])
>> A = Sparsity.triplet(3, 3, [0, 1, 2, 0], [1, 2, 0, 0]);
>> DM(A, 1)
[[1, 1, 00],
[00, 00, 1],
[1, 00, 00]]
>> p = [2, 0, 1];
>> DM(A.pmult(p), 1)
[[00, 1, 00],
[00, 00, 1],
[1, 00, 1]]
>> P = DM(Sparsity.permutation(p), 1);
>> A.pmult(p) == sparsity(P' * DM(A, 1) * P)
1
>> [sub, mapping] = A.sub(p, p); disp(A.pmult(p, true, true, true) == sub)
1
>> DM(A.pmult(p, true, false), 1)
[[00, 00, 1],
[1, 00, 00],
[1, 1, 00]]
julia> A = ca.Sparsity.triplet(3, 3, [0, 1, 2, 0], [1, 2, 0, 0]);
julia> ca.DM(A, 1)
DM(
[[1, 1, 00],
 [00, 00, 1],
 [1, 00, 00]])
julia> p = [2, 0, 1];
julia> ca.DM(ca.pmult(A, p), 1)
DM(
[[00, 1, 00],
 [00, 00, 1],
 [1, 00, 1]])
julia> P = ca.DM(ca.Sparsity.permutation(p), 1);
julia> ca.is_equal(ca.pmult(A, p), ca.sparsity(P' * ca.DM(A, 1) * P))
true
julia> ca.is_equal(ca.pmult(A, p, true, true, true), first(ca.sub(A, p, p)))
true
julia> ca.DM(ca.pmult(A, p, true, false), 1)
DM(
[[00, 00, 1],
 [1, 00, 00],
 [1, 1, 00]])

See also: permutation, sub

Extra doc | Doc source | Implementation

postfix_dim(...)

Dimension string to append to a name, as used when printing symbolic

postfix_dim(self) -> str

primitives.

Rules:

  1. Dense scalar: ""

  2. 0-by-0: "[]"

  3. Dense column vector: "[5]"

  4. Other dense pattern: "[5x10]"

  5. Otherwise: "[5x10,3nz]"

>>> repr(Sparsity.dense(1, 1).postfix_dim()), repr(Sparsity(0, 0).postfix_dim())
("''", "'[]'")
>>> Sparsity.dense(5).postfix_dim(), Sparsity.dense(5, 10).postfix_dim()
('[5]', '[5x10]')
>>> Sparsity.diag(5, 10).postfix_dim(), Sparsity(1, 1).postfix_dim()
('[5x10,5nz]', '[1x1,0nz]')
>>> Sparsity.dense(1, 5).postfix_dim(), Sparsity(0, 3).postfix_dim()
('[1x5]', '[0x3]')
>> fprintf('"%s" "%s"\n', Sparsity.dense(1, 1).postfix_dim(), Sparsity(0, 0).postfix_dim())
"" "[]"
>> Sparsity.dense(5).postfix_dim(), Sparsity.dense(5, 10).postfix_dim()
[5]
[5x10]
>> Sparsity.diag(5, 10).postfix_dim(), Sparsity(1, 1).postfix_dim()
[5x10,5nz]
[1x1,0nz]
>> Sparsity.dense(1, 5).postfix_dim(), Sparsity(0, 3).postfix_dim()
[1x5]
[0x3]
julia> ca.postfix_dim(ca.Sparsity.dense(1, 1)), ca.postfix_dim(ca.Sparsity(0, 0))
("", "[]")
julia> ca.postfix_dim(ca.Sparsity.dense(5)), ca.postfix_dim(ca.Sparsity.dense(5, 10))
("[5]", "[5x10]")
julia> ca.postfix_dim(ca.Sparsity.diag(5, 10)), ca.postfix_dim(ca.Sparsity(1, 1))
("[5x10,5nz]", "[1x1,0nz]")
julia> ca.postfix_dim(ca.Sparsity.dense(1, 5)), ca.postfix_dim(ca.Sparsity(0, 3))
("[1x5]", "[0x3]")

See also: dim

Extra doc | Doc source | Implementation

print_ptr(...)
print_ptr(self)
qr_sparse(...)

Symbolic QR factorization.

qr_sparse(self, bool amd) -> (Sparsity, Sparsity, [int], [int])

Computes the patterns of V (the Householder vectors, a compact representation of Q) and R for the factorization of this pattern with its columns permuted by pc, plus the row permutation prinv used by the numerical factorization (qr_sparse on a matrix) and solution. V and R may have more rows than the pattern (the matrix is extended with zero rows when it has fewer rows than columns in the structural sense).

Parameters:

amd -- If true (default), the columns are reordered with the AMD ordering of A^T*A, returned in pc; if false, pc is the identity

Returns:

V, R, prinv, pc

>>> V, R, prinv, pc = Sparsity.dense(3, 2).qr_sparse()
>>> V, R, prinv, pc
(Sparsity(3x2,5nz), Sparsity(3x2,3nz), [0, 1, 2], [0, 1])
>>> V, R, prinv, pc = Sparsity.banded(4, 1).qr_sparse(False)
>>> V, R, prinv, pc
(Sparsity(4x4,7nz), Sparsity(4x4,9nz), [0, 1, 2, 3], [0, 1, 2, 3])
>> [V, R, prinv, pc] = Sparsity.dense(3, 2).qr_sparse();
>> V, R, prinv, pc
3x2,5nz
3x2,3nz
0 1 2
0 1
>> [V, R, prinv, pc] = Sparsity.banded(4, 1).qr_sparse(false);
>> V, R, prinv, pc
4x4,7nz
4x4,9nz
0 1 2 3
0 1 2 3
julia> V, R, prinv, pc = ca.qr_sparse(ca.Sparsity.dense(3, 2));
julia> V, R, prinv, pc
(3x2,5nz, 3x2,3nz, [0, 1, 2], [0, 1])
julia> V, R, prinv, pc = ca.qr_sparse(ca.Sparsity.banded(4, 1), false);
julia> V, R, prinv, pc
(4x4,7nz, 4x4,9nz, [0, 1, 2, 3], [0, 1, 2, 3])

The implementation is a modified version of CSparse Copyright(c) Timothy A. Davis, 2006-2009 Licensed as a derivative work under the GNU LGPL

See also: ldl, amd, etree

Extra doc | Doc source | Implementation

removeDuplicates(...)

Remove duplicate entries, in place.

removeDuplicates(self) -> [int]

Patterns created through the public interface have no duplicates, so this is a no-op for them. The entries of mapping (one per nonzero) corresponding to the removed duplicates are removed as well.

Parameters:

mapping -- Vector of length nnz(), filtered in the same way as the nonzeros

>>> sp = Sparsity.banded(3, 1)
>>> m = sp.removeDuplicates([0, 1, 2, 3, 4, 5, 6])
>>> m, sp
([0, 1, 2, 3, 4, 5, 6], Sparsity(3x3,7nz))
>> sp = Sparsity.banded(3, 1);
>> m = sp.removeDuplicates([0, 1, 2, 3, 4, 5, 6]);
>> m, sp
0 1 2 3 4 5 6
3x3,7nz
julia> sp = ca.Sparsity.banded(3, 1);
julia> m = ca.removeDuplicates(sp, [0, 1, 2, 3, 4, 5, 6]);
julia> m, sp
([0, 1, 2, 3, 4, 5, 6], 3x3,7nz)

See also: rowsSequential, triplet

Extra doc | Doc source | Implementation

repr_el(...)

Describe the position of nonzero k as a string.

repr_el(self, int k) -> str

Gives "(row i, col j)", prefixed with "nonzero index k " when the pattern is not dense. Indices follow the global start_index option (zero- based by default). k must be in [0, nnz()); it is not checked.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sp.repr_el(1)
'nonzero index 1 (row 2, col 0)'
>>> Sparsity.dense(2, 2).repr_el(3)
'(row 1, col 1)'
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> sp.repr_el(1)
nonzero index 2 (row 3, col 1)
>> Sparsity.dense(2, 2).repr_el(3)
(row 2, col 2)
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.repr_el(sp, 1)
"nonzero index 1 (row 2, col 0)"
julia> ca.repr_el(ca.Sparsity.dense(2, 2), 3)
"(row 1, col 1)"

See also: dim, get_nz

Extra doc | Doc source | Implementation

resize(...)

Change the shape in place, keeping the nonzeros that still fit.

resize(self, int nrow, int ncol)

Nonzeros with row >= nrow or column >= ncol are dropped; growing adds structural zeros. Unlike reshape, the (row, col) position of the kept nonzeros is unchanged. The object is rebound to the new pattern; other references to the old pattern are unaffected.

Parameters:
  • nrow -- New number of rows, nonnegative

  • ncol -- New number of columns, nonnegative

>>> sp = Sparsity.dense(3, 3); sp.resize(2, 2); print(sp)
2x2
>>> sp.resize(4, 4); print(DM(sp, 1))
[[1, 1, 00, 00],
 [1, 1, 00, 00],
 [00, 00, 00, 00],
 [00, 00, 00, 00]]
>>> sp.resize(0, 2); print(sp)
0x2
>> sp = Sparsity.dense(3, 3); sp.resize(2, 2); disp(sp)
2x2
>> sp.resize(4, 4); disp(DM(sp, 1))
[[1, 1, 00, 00],
[1, 1, 00, 00],
[00, 00, 00, 00],
[00, 00, 00, 00]]
>> sp.resize(0, 2); disp(sp)
0x2
julia> sp = ca.Sparsity.dense(3, 3); ca.resize(sp, 2, 2); sp
Sparsity(2x2)
julia> ca.resize(sp, 4, 4); ca.DM(sp, 1)
DM(
[[1, 1, 00, 00],
 [1, 1, 00, 00],
 [00, 00, 00, 00],
 [00, 00, 00, 00]])
julia> ca.resize(sp, 0, 2); sp
Sparsity(0x2)

See also: enlarge, reshape

Extra doc | Doc source | Implementation

row(...)

Row index of nonzero el.

row(self) -> [int]
row(self, int el) -> int
Parameters:

el -- Nonzero index, in [0, nnz()); out of range raises an error

See also: colind, get_row

Row index of every nonzero, in nonzero (column-major) order.

Length nnz(). Together with get_colind() this is the compressed column storage of the pattern; together with get_col() it is the triplet form. In the target languages this method is called row(), the same name as the single-element accessor.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> DM(sp, 1)
DM(
[[1, 00, 00, 1],
 [00, 00, 1, 00],
 [1, 00, 00, 00]])
>>> sp.row(), sp.colind(), sp.get_col()
([0, 2, 1, 0], [0, 2, 2, 3, 4], [0, 0, 2, 3])
>>> Sparsity.dense(2, 2).row(), Sparsity(2, 2).colind()
([0, 1, 0, 1], [0, 0, 0])
>>> Sparsity(0, 2).colind(), Sparsity(2, 0).colind()
([0, 0, 0], [0])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> DM(sp, 1)
[[1, 00, 00, 1],
[00, 00, 1, 00],
[1, 00, 00, 00]]
>> sp.row(), sp.colind(), sp.get_col()
0 2 1 0
0 2 2 3 4
0 0 2 3
>> Sparsity.dense(2, 2).row(), Sparsity(2, 2).colind()
0 1 0 1
0 0 0
>> Sparsity(0, 2).colind(), Sparsity(2, 0).colind()
0 0 0
0
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.row(sp), ca.colind(sp), ca.get_col(sp)
([0, 2, 1, 0], [0, 2, 2, 3, 4], [0, 0, 2, 3])
julia> ca.row(ca.Sparsity.dense(2, 2)), ca.colind(ca.Sparsity(2, 2))
([0, 1, 0, 1], [0, 0, 0])
julia> ca.colind(ca.Sparsity(0, 2)), ca.colind(ca.Sparsity(2, 0))
([0, 0, 0], [0])

See also: get_colind, get_col, get_ccs, get_triplet

Extra doc | Doc source | Implementation

static rowcol(...)

Create the pattern of a block: all entries (i, j) with i in row and j in

rowcol([int] row, [int] col, int nrow, int ncol) -> Sparsity

col.

Every combination of a row index and a column index becomes a nonzero; the block need not be contiguous. Duplicate indices are merged.

Parameters:
  • row -- Row indices, each in [0, nrow)

  • col -- Column indices, each in [0, ncol)

  • nrow -- Number of rows of the pattern

  • ncol -- Number of columns of the pattern

>>> DM(Sparsity.rowcol([0, 2], [1, 2], 3, 4), 1)
DM(
[[00, 1, 1, 00],
 [00, 00, 00, 00],
 [00, 1, 1, 00]])
>>> Sparsity.rowcol([], [1], 3, 4).nnz()
0
>> DM(Sparsity.rowcol([0, 2], [1, 2], 3, 4), 1)
[[00, 1, 1, 00],
[00, 00, 00, 00],
[00, 1, 1, 00]]
>> Sparsity.rowcol([], [1], 3, 4).nnz()
0
julia> ca.DM(ca.Sparsity.rowcol([0, 2], [1, 2], 3, 4), 1)
DM(
[[00, 1, 1, 00],
 [00, 00, 00, 00],
 [00, 1, 1, 00]])
julia> ca.nnz(ca.Sparsity.rowcol([], [1], 3, 4))
0

See also: triplet

Extra doc | Doc source | Implementation

rows(...)

Number of rows, Octave-style alias of size1.

rows(self) -> int

Doc source | Implementation

rowsSequential(...)

Check whether the row indices are increasing within every column.

rowsSequential(self, bool strictly) -> bool

A pattern constructed through the public interface always satisfies this: row indices are sorted and unique within a column.

Parameters:

strictly -- If true (default), duplicate rows within a column are not allowed

>>> Sparsity.banded(3, 1).rowsSequential()
True
>>> Sparsity.dense(2, 2).rowsSequential(False)
True
>> Sparsity.banded(3, 1).rowsSequential()
1
>> Sparsity.dense(2, 2).rowsSequential(false)
1
julia> ca.rowsSequential(ca.Sparsity.banded(3, 1))
true
julia> ca.rowsSequential(ca.Sparsity.dense(2, 2), false)
true

See also: removeDuplicates

Extra doc | Doc source | Implementation

static scalar(...)

Create a 1-by-1 sparsity pattern.

scalar(bool dense_scalar) -> Sparsity
Parameters:

dense_scalar -- If true (default), the single entry is a nonzero; if false, the pattern is 1-by-1 with zero nonzeros (a structurally zero scalar)

>>> Sparsity.scalar(), Sparsity.scalar().nnz()
(Sparsity(1x1), 1)
>>> Sparsity.scalar(False), Sparsity.scalar(False).nnz()
(Sparsity(1x1,0nz), 0)
>>> Sparsity.scalar() == Sparsity.dense(1, 1)
True
>> Sparsity.scalar(), Sparsity.scalar().nnz()
1x1
1
>> Sparsity.scalar(false), Sparsity.scalar(false).nnz()
1x1,0nz
0
>> Sparsity.scalar() == Sparsity.dense(1, 1)
1
julia> ca.Sparsity.scalar(), ca.nnz(ca.Sparsity.scalar())
(1x1, 1)
julia> ca.Sparsity.scalar(false), ca.nnz(ca.Sparsity.scalar(false))
(1x1,0nz, 0)
julia> ca.is_equal(ca.Sparsity.scalar(), ca.Sparsity.dense(1, 1))
true

See also: dense, is_scalar

Extra doc | Doc source | Implementation

scc(...)

Strongly connected components of the directed graph of a square pattern.

scc(self) -> (int, [int], [int])

Node j is the j-th row/column and nonzero (i, j) is an edge from j to i. See Direct Methods for Sparse Linear Systems by Davis (2006).

Returns:

component i consists of the nodes index[offset[i]],..., index[offset[i+1]-1], in increasing order.

Return type:

The number of components n, the node indices grouped by component, and the offsets (length n+1)

The components are ordered so that the symmetric permutation A[index, index] is block upper triangular with n diagonal blocks; for a symmetric pattern it is block diagonal, with the block boundaries given by offset.

The implementation is a modified version of cs_scc in CSparse Copyright(c) Timothy A. Davis, 2006-2009 Licensed as a derivative work under the GNU LGPL

>>> A = Sparsity.nonzeros(4, 4, [0, 2, 5, 7, 10, 13, 15])
>>> DM(A, 1)
DM(
[[1, 00, 00, 00],
 [00, 1, 00, 1],
 [1, 00, 1, 00],
 [00, 1, 00, 1]])
>>> n, index, offset = A.scc()
>>> n, index, offset
(3, [2, 0, 1, 3], [0, 1, 2, 4])
>>> DM(A, 1)[index, index]
DM(
[[1, 1, 00, 00],
 [00, 1, 00, 00],
 [00, 00, 1, 1],
 [00, 00, 1, 1]])
>>> Sparsity.diag(3).scc(), Sparsity.dense(3, 3).scc(), Sparsity(0, 0).scc()
((3, [0, 1, 2], [0, 1, 2, 3]), (1, [0, 1, 2], [0, 3]), (0, [], [0]))
>> A = Sparsity.nonzeros(4, 4, [1, 3, 6, 8, 11, 14, 16]);
>> DM(A, 1)
[[1, 00, 00, 00],
[00, 1, 00, 1],
[1, 00, 1, 00],
[00, 1, 00, 1]]
>> [n, index, offset] = A.scc(); disp(n), disp(index), disp(offset)
3
2 0 1 3
0 1 2 4
>> Af = DM(A, 1); disp(Af(index + 1, index + 1))
[[1, 1, 00, 00],
[00, 1, 00, 00],
[00, 00, 1, 1],
[00, 00, 1, 1]]
>> [n, index, offset] = Sparsity.diag(3).scc(); disp(n), disp(index), disp(offset)
3
0 1 2
0 1 2 3
>> [n, index, offset] = Sparsity.dense(3, 3).scc(); disp(n), disp(index), disp(offset)
1
0 1 2
0 3
>> [n, index, offset] = Sparsity(0, 0).scc(); disp(n), disp(isempty(index)), disp(offset)
0
1
0
julia> A = ca.Sparsity.nonzeros(4, 4, [0, 2, 5, 7, 10, 13, 15]);
julia> ca.DM(A, 1)
DM(
[[1, 00, 00, 00],
 [00, 1, 00, 1],
 [1, 00, 1, 00],
 [00, 1, 00, 1]])
julia> ca.scc(A)
(3, [2, 0, 1, 3], [0, 1, 2, 4])
julia> ca.scc(ca.Sparsity.diag(3)), ca.scc(ca.Sparsity.dense(3, 3))
((3, [0, 1, 2], [0, 1, 2, 3]), (1, [0, 1, 2], [0, 3]))
julia> ca.scc(ca.Sparsity(0, 0))
(0, Int64[], [0])

See also: btf, dfs

Extra doc | Doc source | Implementation

serialize(...)

Serialize an object.

serialize(self) -> str
serialize(self, casadi::SerializingStream & s)

Serialize the pattern to a string.

The string can be stored and turned back into an equal pattern with deserialize(). A null object serializes and deserializes as a null object. Pickling in Python uses this mechanism.

>>> s = Sparsity.diag(2, 3).serialize()
>>> type(s).__name__, Sparsity.deserialize(s) == Sparsity.diag(2, 3)
('str', True)
>>> Sparsity.deserialize(Sparsity().serialize()).is_null()
True
>>> import pickle
>>> pickle.loads(pickle.dumps(Sparsity.diag(2, 3)))
Sparsity(2x3,2nz)
>> s = Sparsity.diag(2, 3).serialize();
>> class(s), Sparsity.deserialize(s) == Sparsity.diag(2, 3)
char
1
>> Sparsity.deserialize(Sparsity().serialize()).is_null()
1
julia> s = ca.serialize(ca.Sparsity.diag(2, 3));
julia> typeof(s), ca.is_equal(ca.Sparsity.deserialize(s), ca.Sparsity.diag(2, 3))
(String, true)
julia> ca.is_null(ca.Sparsity.deserialize(ca.serialize(ca.Sparsity())))
true

See also: deserialize, compress

Extra doc | Doc source | Implementation

size(...)

Size along one dimension.

size(self) -> (int,int)
size(self, int axis) -> int
Parameters:

axis -- 1 for the number of rows, 2 for the number of columns; any other value raises an error

Shape as a pair (number of rows, number of columns)

>>> sp = Sparsity.diag(2, 3)
>>> sp.size(), sp.size(1), sp.size(2), sp.shape
((2, 3), 2, 3, (2, 3))
>> sp = Sparsity.diag(2, 3);
>> size(sp), sp.size(1), sp.size(2)
2 3
2
3
>> [m, n] = size(sp); fprintf('%d %d\n', m, n)
2 3
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.size(sp), ca.size(sp, 1), ca.size(sp, 2)
((2, 3), 2, 3)

See also: size1, size2, numel

Extra doc | Doc source | Implementation

size1(...)

Number of rows.

size1(self) -> int
>>> sp = Sparsity.diag(2, 3)
>>> sp.size1(), sp.rows(), sp.size2(), sp.columns()
(2, 2, 3, 3)
>> sp = Sparsity.diag(2, 3);
>> fprintf('%d %d %d %d\n', sp.size1(), sp.rows(), sp.size2(), sp.columns())
2 2 3 3
julia> sp = ca.Sparsity.diag(2, 3);
julia> ca.size1(sp), ca.rows(sp), ca.size2(sp), ca.columns(sp)
(2, 2, 3, 3)

See also: size2, size, numel

Extra doc | Doc source | Implementation

size2(...)

Number of columns.

size2(self) -> int

Doc source | Implementation

sparsity_cast_mod(...)

Propagate a subset of a pattern through a sparsity cast.

sparsity_cast_mod(self, Sparsity X, Sparsity Y) -> Sparsity

X and Y have the same number of nonzeros and sparsity_cast(X, Y) maps nonzero k of X to nonzero k of Y. Given that this pattern is a subset of X, the result is the subset of Y made of the nonzeros of Y whose counterpart in X is in this pattern.

>>> X = Sparsity.diag(4)
>>> Y = Sparsity.dense(2, 2)
>>> x = Sparsity.nonzeros(4, 4, [0, 10, 15])
>>> DM(x.sparsity_cast_mod(X, Y), 1)
DM(
[[1, 1],
 [00, 1]])
>> X = Sparsity.diag(4);
>> Y = Sparsity.dense(2, 2);
>> x = Sparsity.nonzeros(4, 4, [1, 11, 16]);
>> DM(x.sparsity_cast_mod(X, Y), 1)
[[1, 1],
[00, 1]]
julia> X = ca.Sparsity.diag(4);
julia> Y = ca.Sparsity.dense(2, 2);
julia> x = ca.Sparsity.nonzeros(4, 4, [0, 10, 15]);
julia> ca.DM(ca.sparsity_cast_mod(x, X, Y), 1)
DM(
[[1, 1],
 [00, 1]])

See also: sparsity_cast, is_subset

Extra doc | Doc source | Implementation

spy(...)

Print a textual picture of the pattern.

spy(self)

Writes one line per row, with "*" for a structural nonzero and "." for a structural zero, to the standard output (or the given stream). Large patterns produce nrow lines of ncol characters.

See also: spy_matlab, export_code

Extra doc | Doc source | Implementation

spy_matlab(...)

Write a MATLAB/Octave script that builds the pattern as a sparse matrix and

spy_matlab(self, str mfile)

calls spy.

The file is overwritten. The script defines a sparse matrix A of ones with this pattern (see export_code) and ends with spy(A).

Parameters:

mfile -- Path of the.m file to write

>>> import os, tempfile
>>> d = tempfile.mkdtemp()
>>> f = os.path.join(d, "show_pattern.m")
>>> Sparsity.diag(2, 3).spy_matlab(f)
>>> print(open(f).read())
% This function was automatically generated by CasADi
A_m = 2;
A_n = 3;
A_j = [1, 2];
A_i = [1, 2];
A_v = ones(size(A_i));
A = sparse(A_i, A_j, A_v, A_m, A_n);
spy(A);
>>> os.remove(f); os.rmdir(d)
>> f = [tempname '.m'];
>> Sparsity.diag(2, 3).spy_matlab(f);
>> fileread(f)
% This function was automatically generated by CasADi
A_m = 2;
A_n = 3;
A_j = [1, 2];
A_i = [1, 2];
A_v = ones(size(A_i));
A = sparse(A_i, A_j, A_v, A_m, A_n);
spy(A);
>> delete(f);
julia> d = mktempdir();
julia> f = joinpath(d, "show_pattern.m");
julia> ca.spy_matlab(ca.Sparsity.diag(2, 3), f)
julia> print(read(f, String))
% This function was automatically generated by CasADi
A_m = 2;
A_n = 3;
A_j = [1, 2];
A_i = [1, 2];
A_v = ones(size(A_i));
A = sparse(A_i, A_j, A_v, A_m, A_n);
spy(A);
julia> rm(d, recursive=true)

See also: spy, export_code

Extra doc | Doc source | Implementation

star_coloring(...)

Star coloring of a symmetric pattern (greedy distance-2 coloring)

star_coloring(self, int ordering, int cutoff) -> Sparsity

Algorithm 4.1 in Gebremedhin, Manne and Pothen, What Color Is Your Jacobian?, SIAM Rev. 47(4), 2006. Exploits symmetry so that fewer colors than uni_coloring are needed to recover all nonzeros of a Hessian. A non- symmetric pattern raises an error.

Parameters:
  • ordering -- 0 for the natural column order, 1 (default) to color in largest_first() order

  • cutoff -- If more than this many colors are needed, a null Sparsity is returned

Returns:

column c lists the columns with color c

Return type:

A size2() -by-ncolors pattern

>>> H = Sparsity.banded(4, 1)
>>> DM(H.star_coloring(), 1)
DM(
[[00, 1, 00],
 [1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])
>>> Sparsity.diag(5).star_coloring()
Sparsity(5x1)
>>> Sparsity.dense(4, 4).star_coloring(1, 2).is_null()
True
>> H = Sparsity.banded(4, 1);
>> DM(H.star_coloring(), 1)
[[00, 1, 00],
[1, 00, 00],
[00, 1, 00],
[00, 00, 1]]
>> Sparsity.diag(5).star_coloring()
5x1
>> Sparsity.dense(4, 4).star_coloring(1, 2).is_null()
1
julia> H = ca.Sparsity.banded(4, 1);
julia> ca.DM(ca.star_coloring(H, 1, 1000), 1)
DM(
[[00, 1, 00],
 [1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])
julia> ca.star_coloring(ca.Sparsity.diag(5), 1, 1000)
Sparsity(5x1)
julia> ca.is_null(ca.star_coloring(ca.Sparsity.dense(4, 4), 0, 2))
true

See also: star_coloring_new, star_coloring2, uni_coloring, largest_first

Extra doc | Doc source | Implementation

star_coloring2(...)

Star coloring of a symmetric pattern with the newer algorithm.

star_coloring2(self, int ordering, int cutoff) -> Sparsity

Algorithm 4.1 in Gebremedhin, Tarafdar, Manne and Pothen, New Acyclic and Star Coloring Algorithms with Application to Computing Hessians, SIAM J. Sci. Comput. 29(3), 2007. Same arguments and return value as star_coloring.

>>> H = Sparsity.banded(4, 1)
>>> DM(H.star_coloring2(), 1)
DM(
[[00, 1, 00],
 [1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])
>> H = Sparsity.banded(4, 1);
>> DM(H.star_coloring2(), 1)
[[00, 1, 00],
[1, 00, 00],
[00, 1, 00],
[00, 00, 1]]
julia> H = ca.Sparsity.banded(4, 1);
julia> ca.DM(ca.star_coloring2(H, 1, 1000), 1)
DM(
[[00, 1, 00],
 [1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])

See also: star_coloring, star_coloring_new

Extra doc | Doc source | Implementation

star_coloring_new(...)

Star coloring of a symmetric pattern, with the color that recovers each

star_coloring_new(self, dict opts) -> (Sparsity, [int])

nonzero.

Front end to star_coloring and star_coloring2 for compressed Hessian evaluation. A non-symmetric pattern raises an error.

Parameters:

opts -- Options: "new_algo" (bool, default false) selects star_coloring2 instead of star_coloring; "largest_first" (bool, default true) selects the largest-first ordering; "cutoff" (int) returns a null pattern when more colors are needed

Returns:

the color whose directional derivative yields that nonzero, or -1 when the nonzero is obtained from its symmetric counterpart instead (the lowest color index is preferred)

Return type:

The coloring (a size2() -by-ncolors pattern as in uni_coloring) and which_color, one entry per nonzero

>>> H = Sparsity.banded(4, 1)
>>> coloring, which_color = H.star_coloring_new()
>>> DM(coloring, 1)
DM(
[[00, 1, 00],
 [1, 00, 00],
 [00, 1, 00],
 [00, 00, 1]])
>>> for k in range(H.nnz()): print(H.row()[k], H.get_col()[k], which_color[k])
0 0 1
1 0 -1
0 1 0
1 1 0
2 1 0
1 2 -1
2 2 1
3 2 1
2 3 -1
3 3 2
>>> try: Sparsity.upper(3).star_coloring_new()
... except Exception as e: print("not symmetric")
not symmetric
>> H = Sparsity.banded(4, 1);
>> [coloring, which_color] = H.star_coloring_new();
>> DM(coloring, 1)
[[00, 1, 00],
[1, 00, 00],
[00, 1, 00],
[00, 00, 1]]
>> [H.row(); H.get_col(); which_color]'
0 0 1
1 0 -1
0 1 0
1 1 0
2 1 0
1 2 -1
2 2 1
3 2 1
2 3 -1
3 3 2
>> try, Sparsity.upper(3).star_coloring_new(); catch e, disp('not symmetric'); end
not symmetric
julia> H = ca.Sparsity.banded(4, 1);
julia> ca.star_coloring_new(H)
(4x3,4nz, [1, -1, 0, 0, 0, -1, 1, 1, -1, 2])
julia> try
           ca.star_coloring_new(ca.Sparsity.upper(3))
       catch e
           println("not symmetric")
       end
not symmetric

See also: star_coloring, star_coloring2, uni_coloring

Extra doc | Doc source | Implementation

str(...)

Get string representation.

str(self, bool more) -> str

Doc source | Implementation

sub(...)

Pattern of a set of elements, arranged according to a given pattern.

sub(self, [int] rr, Sparsity sp, bool ind1) -> (Sparsity, [int])
sub(self, [int] rr, [int] cc, bool ind1) -> (Sparsity, [int])

rr lists one flat (column-major) element index per nonzero of sp. The result has the shape of sp and keeps the nonzeros of sp whose element in this pattern is a structural nonzero. This is the sparsity counterpart of indexing a matrix with a Sparsity or with a list of element indices.

Parameters:
  • rr -- Flat element indices, length sp.nnz(); negative indices count from the end, out of range raises an error

  • sp -- Pattern that lays out the result

  • ind1 -- If true, indices are one-based

Returns:

nonzero k of the result is nonzero mapping[k] of this pattern

Return type:

The pattern and a mapping

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sub, mapping = sp.sub([0, 2, 9], Sparsity.dense(3, 1))
>>> sub, mapping
(Sparsity(3x1), [0, 1, 3])
>>> sub, mapping = sp.sub([0, 1, 2, 3], Sparsity.dense(2, 2))
>>> DM(sub, 1), mapping
(DM(
[[1, 1],
 [00, 00]]), [0, 1])
>>> try: sp.sub([0, 2], Sparsity.dense(3, 1))
... except Exception as e: print("length mismatch")
length mismatch
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [sub, mapping] = sp.sub([0, 2, 9], Sparsity.dense(3, 1)); disp(sub), disp(mapping)
3x1
0 1 3
>> [sub, mapping] = sp.sub([0, 1, 2, 3], Sparsity.dense(2, 2));
>> DM(sub, 1), mapping
[[1, 1],
[00, 00]]
0 1
>> try, sp.sub([0, 2], Sparsity.dense(3, 1)); catch e, disp('length mismatch'); end
length mismatch
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.sub(sp, [0, 2, 9], ca.Sparsity.dense(3, 1))
(3x1, [0, 1, 3])
julia> ca.sub(sp, [0, 1, 2, 3], ca.Sparsity.dense(2, 2))
(2x2,2nz, [0, 1])
julia> try
           ca.sub(sp, [0, 2], ca.Sparsity.dense(3, 1))
       catch e
           println("length mismatch")
       end
length mismatch

See also: get_nz, find

Pattern of the submatrix with rows rr and columns cc.

This is the sparsity counterpart of slicing a matrix as A[rr, cc]. Indices may repeat and may be negative (counting from the end); an index out of range raises an error.

Parameters:
  • rr -- Row indices of the submatrix

  • cc -- Column indices of the submatrix

  • ind1 -- If true, indices are one-based

Returns:

nonzero k of the submatrix is nonzero mapping[k] of this pattern

Return type:

The len(rr)-by-len(cc) pattern and a mapping with one entry per nonzero of the result

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> sub, mapping = sp.sub([0, 2], [0, 3])
>>> DM(sub, 1), mapping
(DM(
[[1, 1],
 [1, 00]]), [0, 1, 3])
>>> sub, mapping = sp.sub([-1], [0])
>>> sub, mapping
(Sparsity(1x1), [1])
>>> sub, mapping = sp.sub([0, 0], [0])
>>> sub, mapping
(Sparsity(2x1), [0, 0])
>>> try: sp.sub([3], [0])
... except Exception as e: print("out of range")
out of range
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [sub, mapping] = sp.sub([0, 2], [0, 3]); disp(DM(sub, 1)), disp(mapping)
[[1, 1],
[1, 00]]
0 1 3
>> [sub, mapping] = sp.sub(-1, 0); disp(sub), disp(mapping)
1x1
1
>> [sub, mapping] = sp.sub([0, 0], 0); disp(sub), disp(mapping)
2x1
0 0
>> try, sp.sub(3, 0); catch e, disp('out of range'); end
out of range
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.sub(sp, [0, 2], [0, 3])
(2x2,3nz, [0, 1, 3])
julia> ca.sub(sp, [-1], [0])
(1x1, [1])
julia> ca.sub(sp, [0, 0], [0])
(2x1, [0, 0])
julia> try
           ca.sub(sp, [3], [0])
       catch e
           println("out of range")
       end
out of range

See also: get_nz, erase, pmult

Extra doc | Doc source | Implementation

static test_cast(...)

Check if a particular cast is allowed.

test_cast(casadi::SharedObjectInternal const * ptr) -> bool

Doc source | Implementation

to_file(...)

Write the pattern to a file.

to_file(self, str filename, str format_hint)

The only supported format is Matrix Market ("mtx", coordinate pattern general), with one-based (row, col) pairs. The format is taken from the file extension unless format_hint is given; an unknown format raises an error. The file is overwritten.

Parameters:
  • filename -- Path of the file to write

  • format_hint -- Format name, e.g. "mtx", when the extension does not tell

>>> import os, tempfile
>>> d = tempfile.mkdtemp()
>>> f = os.path.join(d, "pattern.mtx")
>>> sp = Sparsity.triplet(3, 2, [0, 2, 1], [0, 0, 1])
>>> sp.to_file(f)
>>> print(open(f).read())
%%MatrixMarket matrix coordinate pattern general
3 2 3
1 1
3 1
2 2
>>> print(Sparsity.from_file(f) == sp)
True
>>> os.remove(f); os.rmdir(d)
>>> try: sp.to_file("pattern.txt")
... except Exception as e: print("unknown extension")
unknown extension
>> f = [tempname '.mtx'];
>> sp = Sparsity.triplet(3, 2, [0, 2, 1], [0, 0, 1]);
>> sp.to_file(f);
>> fileread(f)
%%MatrixMarket matrix coordinate pattern general
3 2 3
1 1
3 1
2 2
>> Sparsity.from_file(f) == sp
1
>> delete(f);
>> try, sp.to_file('pattern.txt'); catch e, disp('unknown extension'); end
unknown extension
julia> d = mktempdir();
julia> f = joinpath(d, "pattern.mtx");
julia> sp = ca.Sparsity.triplet(3, 2, [0, 2, 1], [0, 0, 1]);
julia> ca.to_file(sp, f)
julia> print(read(f, String))
%%MatrixMarket matrix coordinate pattern general
3 2 3
1 1
3 1
2 2
julia> ca.is_equal(ca.Sparsity.from_file(f), sp)
true
julia> rm(d, recursive=true)
julia> try
           ca.to_file(sp, "pattern.txt")
       catch e
           println("unknown extension")
       end
unknown extension

See also: from_file, DM.to_file

Extra doc | Doc source | Implementation

transpose(...)

Transposed pattern together with the reordering of the nonzeros.

transpose(self, bool invert_mapping) -> (Sparsity, [int])
Parameters:

invert_mapping -- Direction of the mapping

Returns:

The transposed pattern and a mapping of length nnz(). By default mapping[k] is the nonzero of the original pattern that becomes nonzero k of the transpose; with invert_mapping true, mapping[k] is the nonzero of the transpose that original nonzero k becomes.

>>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3])
>>> spT, mapping = sp.transpose()
>>> spT, mapping
(Sparsity(4x3,4nz), [0, 3, 2, 1])
>> sp = Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
>> [spT, mapping] = sp.transpose(); disp(spT), disp(mapping)
4x3,4nz
0 3 2 1
julia> sp = ca.Sparsity.triplet(3, 4, [0, 2, 1, 0], [0, 0, 2, 3]);
julia> ca.transpose(sp, false)
(4x3,4nz, [0, 3, 2, 1])

See also: T

Extra doc | Doc source | Implementation

static triplet(...)
triplet(int nrow, int ncol, [int] row, [int] col) -> Sparsity
triplet(int nrow, int ncol, [int] row, [int] col, bool invert_mapping) -> (Sparsity, [int])

Create a sparsity pattern from the (row, col) index of every nonzero.

The entries may be given in any order; duplicates are merged. An index out of range or vectors of different length raise an error.

Parameters:
  • nrow -- Number of rows

  • ncol -- Number of columns

  • row -- Row index of each entry, in [0, nrow)

  • col -- Column index of each entry, in [0, ncol), same length as row

  • invert_mapping -- Selects the direction of the returned mapping (see below)

The overload with invert_mapping additionally returns a mapping between the given entries and the nonzeros of the result (which are in column-major order). With invert_mapping false, mapping[k] is the position in the input of nonzero k (length nnz(); for duplicates the first occurrence). With invert_mapping true, mapping[i] is the nonzero index of input entry i (length of the input).

>>> DM(Sparsity.triplet(3, 3, [0, 2, 1], [0, 0, 2]), 1)
DM(
[[1, 00, 00],
 [00, 00, 1],
 [1, 00, 00]])
>>> Sparsity.triplet(2, 2, [0, 0, 1], [0, 0, 1]).nnz()
2
>>> sp, mapping = Sparsity.triplet(3, 3, [2, 0, 1], [1, 0, 0], False)
>>> mapping
[1, 2, 0]
>>> sp, mapping = Sparsity.triplet(3, 3, [2, 0, 1], [1, 0, 0], True)
>>> mapping
[2, 0, 1]
>>> try: Sparsity.triplet(2, 2, [0, 2], [0, 0])
... except Exception as e: print("out of bounds")
out of bounds
>> DM(Sparsity.triplet(3, 3, [0, 2, 1], [0, 0, 2]), 1)
[[1, 00, 00],
[00, 00, 1],
[1, 00, 00]]
>> Sparsity.triplet(2, 2, [0, 0, 1], [0, 0, 1]).nnz()
2
>> [sp, mapping] = Sparsity.triplet(3, 3, [2, 0, 1], [1, 0, 0], false); disp(mapping)
1 2 0
>> [sp, mapping] = Sparsity.triplet(3, 3, [2, 0, 1], [1, 0, 0], true); disp(mapping)
2 0 1
>> try, Sparsity.triplet(2, 2, [0, 2], [0, 0]); catch e, disp('out of bounds'); end
out of bounds
julia> ca.DM(ca.Sparsity.triplet(3, 3, [0, 2, 1], [0, 0, 2]), 1)
DM(
[[1, 00, 00],
 [00, 00, 1],
 [1, 00, 00]])
julia> ca.nnz(ca.Sparsity.triplet(2, 2, [0, 0, 1], [0, 0, 1]))
2
julia> sp, mapping = ca.Sparsity.triplet(3, 3, [2, 0, 1], [1, 0, 0], false);
julia> mapping
3-element Vector{Int64}:
 1
 2
 0
julia> sp, mapping = ca.Sparsity.triplet(3, 3, [2, 0, 1], [1, 0, 0], true);
julia> mapping
3-element Vector{Int64}:
 2
 0
 1
julia> try
           ca.Sparsity.triplet(2, 2, [0, 2], [0, 0])
       catch e
           println("out of bounds")
       end
out of bounds

See also: get_triplet, rowcol, nonzeros, Sparsity(nrow, ncol, colind, row)

Extra doc | Doc source | Implementation

static type_name(...)

Readable name of the public class.

type_name() -> str

Doc source | Implementation

uni_coloring(...)

Unidirectional (column) coloring for compressed Jacobian evaluation.

uni_coloring(self, Sparsity AT, int cutoff) -> Sparsity

Greedy distance-2 coloring (Algorithm 3.1 in Gebremedhin, Manne and Pothen, What Color Is Your Jacobian?, SIAM Rev. 47(4), 2006): columns that have no row in common may share a color, so that one directional derivative per color recovers all nonzeros. This is the coloring used for forward-mode Jacobians (and, applied to the transpose, for reverse mode).

Parameters:
  • AT -- The transpose of this pattern, if already available; a null Sparsity (default) computes it

  • cutoff -- If more than this many colors are needed, a null Sparsity is returned instead

Returns:

column c lists the columns of this pattern that received color c

Return type:

A size2() -by-ncolors pattern

>>> A = Sparsity.triplet(3, 4, [0, 1, 2, 0], [0, 1, 2, 3])
>>> DM(A, 1)
DM(
[[1, 00, 00, 1],
 [00, 1, 00, 00],
 [00, 00, 1, 00]])
>>> c = A.uni_coloring()
>>> DM(c, 1)
DM(
[[1, 00],
 [1, 00],
 [1, 00],
 [00, 1]])
>>> c.size2(), [c.row()[c.colind()[j]:c.colind()[j + 1]] for j in range(c.size2())]
(2, [[0, 1, 2], [3]])
>>> A.uni_coloring(Sparsity(), 1).is_null()
True
>>> Sparsity.dense(3, 3).uni_coloring(), Sparsity.diag(3).uni_coloring()
(Sparsity(3x3,3nz), Sparsity(3x1))
>> A = Sparsity.triplet(3, 4, [0, 1, 2, 0], [0, 1, 2, 3]);
>> DM(A, 1)
[[1, 00, 00, 1],
[00, 1, 00, 00],
[00, 00, 1, 00]]
>> c = A.uni_coloring();
>> DM(c, 1)
[[1, 00],
[1, 00],
[1, 00],
[00, 1]]
>> disp(c.size2()), ci = c.colind(); r = c.row();
2
>> for j = 1:c.size2(), disp(r(ci(j) + 1:ci(j + 1))), end
0 1 2
3
>> A.uni_coloring(Sparsity(), 1).is_null()
1
>> Sparsity.dense(3, 3).uni_coloring(), Sparsity.diag(3).uni_coloring()
3x3,3nz
3x1
julia> A = ca.Sparsity.triplet(3, 4, [0, 1, 2, 0], [0, 1, 2, 3]);
julia> ca.DM(A, 1)
DM(
[[1, 00, 00, 1],
 [00, 1, 00, 00],
 [00, 00, 1, 00]])
julia> c = ca.uni_coloring(A, ca.Sparsity(), 1000);
julia> ca.DM(c, 1)
DM(
[[1, 00],
 [1, 00],
 [1, 00],
 [00, 1]])
julia> ca.size2(c), [ca.row(c)[ca.colind(c)[j]+1:ca.colind(c)[j+1]] for j in 1:ca.size2(c)]
(2, [[0, 1, 2], [3]])
julia> ca.is_null(ca.uni_coloring(A, ca.Sparsity(), 1))
true
julia> ca.uni_coloring(ca.Sparsity.dense(3, 3), ca.Sparsity(), 1000)
Sparsity(3x3,3nz)
julia> ca.uni_coloring(ca.Sparsity.diag(3), ca.Sparsity(), 1000)
Sparsity(3x1)

See also: star_coloring, star_coloring_new

Extra doc | Doc source | Implementation

static unit(...)

Create the pattern of a unit vector: a column of length n with one nonzero.

unit(int n, int el) -> Sparsity
Parameters:
  • n -- Length of the column vector

  • el -- Row of the nonzero, in [0, n); an index outside this range raises an error

>>> DM(Sparsity.unit(4, 1), 1)
DM([00, 1, 00, 00])
>>> Sparsity.unit(4, 1).row()
[1]
>> DM(Sparsity.unit(4, 1), 1)
[00, 1, 00, 00]
>> Sparsity.unit(4, 1).row()
1
julia> ca.DM(ca.Sparsity.unit(4, 1), 1)
DM([00, 1, 00, 00])
julia> ca.row(ca.Sparsity.unit(4, 1))
1-element Vector{Int64}:
 1

See also: nonzeros, triplet

Extra doc | Doc source | Implementation

unite(...)
unite(self, Sparsity y) -> Sparsity
static upper(...)

Create an upper triangular square sparsity pattern.

upper(int n) -> Sparsity

Column j contains the rows 0, ..., j, so the diagonal is included and the pattern has n*(n+1)/2 nonzeros.

Parameters:

n -- Size of the square pattern, nonnegative

>>> DM(Sparsity.upper(3), 1)
DM(
[[1, 1, 1],
 [00, 1, 1],
 [00, 00, 1]])
>>> Sparsity.upper(3).nnz(), Sparsity.upper(3).is_triu()
(6, True)
>> DM(Sparsity.upper(3), 1)
[[1, 1, 1],
[00, 1, 1],
[00, 00, 1]]
>> Sparsity.upper(3).nnz(), Sparsity.upper(3).is_triu()
6
1
julia> ca.DM(ca.Sparsity.upper(3), 1)
DM(
[[1, 1, 1],
 [00, 1, 1],
 [00, 00, 1]])
julia> ca.nnz(ca.Sparsity.upper(3)), ca.is_triu(ca.Sparsity.upper(3))
(6, true)

See also: lower, triu, is_triu

Extra doc | Doc source | Implementation

Function

class Function(...)

Function object.

A Function instance is a general multiple-input, multiple-output function where each input and output can be a sparse matrix. For an introduction to this class, see the CasADi user guide.Function is a reference counted and immutable class; copying a class instance is very cheap and its behavior (with some exceptions) is not affected by calling its member functions. Each input and output has a name (name_in, name_out) and a fixed sparsity pattern (sparsity_in, sparsity_out). The same object can be evaluated numerically (DM arguments) or symbolically (SX or MX arguments), differentiated (jacobian, forward, reverse, factory), transformed (map, mapaccum, fold, expand), code-generated (generate), serialized (serialize, save) and inspected (print_dimensions, stats, info).

Instances are created from expressions (the SX and MX constructors), from a C body (jit), by combining other functions (conditional, if_else, map, mapaccum) or by the solver constructors nlpsol, qpsol, rootfinder, integrator, external. Printing shows the signature and the class name, e.g. f:(x,y[2])->(r[2],s) SXFunction.

The exceptions to immutability are options changed with change_option and the cache of derivative functions.

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
>>> f
Function(f:(x,y[2])->(r[2],s) SXFunction)
>>> r, s = f(2, [3, 4])
>>> r, s
(DM([6, 8]), DM(0.909297))
>>> f(x=2, y=[3, 4])
{'r': DM([6, 8]), 's': DM(0.909297)}
>>> z = MX.sym("z")
>>> f(z, [3, 4])
(MX(f(z, [3, 4]){0}), MX(f(z, [3, 4]){1}))
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y, sin(x)}, {'x', 'y'}, {'r', 's'});
>> f
f:(x,y[2])->(r[2],s) SXFunction
>> [r, s] = f(2, [3; 4]); disp(r), disp(s)
[6, 8]
0.909297
>> res = f('x', 2, 'y', [3; 4]); disp(res.r), disp(res.s)
[6, 8]
0.909297
>> z = MX.sym('z'); [r, s] = f(z, [3; 4]); disp(r), disp(s)
f(z, [3, 4]){0}
f(z, [3, 4]){1}
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
Function(f:(x,y[2])->(r[2],s) SXFunction)
julia> r, s = f(2, [3, 4])
([6, 8], 0.909297)
julia> f(x=2, y=[3, 4])
Dict{String, DM} with 2 entries:
  "r" => [6, 8]
  "s" => 0.909297
julia> z = ca.MX.sym("z");
julia> f(z, [3, 4])
(f(z, [3, 4]){0}, f(z, [3, 4]){1})

Authors: Joel Andersson

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

Extra doc

activity(...)

Output signal activity induced by a given input activity.

activity(self, [bool] arg) -> [bool]

arg is a flat activity mask over all input nonzeros (size nnz_in(), true = active = possibly nonzero); the result is the corresponding mask over all output nonzeros (size nnz_out()). An output that comes out inactive (false) is guaranteed zero for any value of the active inputs. Unlike sparsity propagation this exploits annihilation: an inactive operand of a multiply kills the product.

Extra doc | Doc source | Implementation

assert_size_in(...)

Raise an error unless input i is nrow-by-ncol.

assert_size_in(self, int i, int nrow, int ncol)
>>> f = Function("f", [SX.sym("x", 2)], [SX(1, 3)])
>>> f.assert_size_in(0, 2, 1)
>>> try:
...   f.assert_size_out(0, 2, 1)
... except RuntimeError as e:
...   print("Expected 2-by-1 but got 1-by-3" in str(e))
True
>> f = Function('f', {SX.sym('x', 2)}, {SX(1, 3)});
>> f.assert_size_in(0, 2, 1)
>> try, f.assert_size_out(0, 2, 1); catch e, msg = e.message; end
>> contains(msg, 'Expected 2-by-1 but got 1-by-3')
1
julia> f = ca.Function("f", [ca.SX.sym("x", 2)], [ca.SX(1, 3)]);
julia> ca.assert_size_in(f, 0, 2, 1)
julia> try
           ca.assert_size_out(f, 0, 2, 1)
       catch e
           println(occursin("Expected 2-by-1 but got 1-by-3", sprint(showerror, e)))
       end
true

See also: assert_size_out, size_in

Extra doc | Doc source | Implementation

assert_size_out(...)

Raise an error unless output i is nrow-by-ncol.

assert_size_out(self, int i, int nrow, int ncol)

Doc source | Implementation

assert_sparsity_out(...)

Raise an error unless output i has the sparsity sp repeated n.

assert_sparsity_out(self, int i, Sparsity sp, int n, bool allow_all_zero_sparse)

times horizontally

With allow_all_zero_sparse, an output without nonzeros of the right shape passes. Used to check derivative functions.

Extra doc | Doc source | Implementation

static bspline(...)

Create a function evaluating a B-spline with known coefficients.

bspline(str name, [[float]] knots, [float] coeffs, [int] degree, int m, dict opts) -> Function

The result maps a point of dimension len(knots) (one column vector input) to the m-dimensional spline value. Coefficients are stored flat in coeffs with the value dimension m fastest, then the first spline dimension, etc.; the number of coefficients per dimension is len(knots[d]) - degree[d] - 1. A mismatch between the lengths of knots and degree raises an error. For data-driven splines or general interpolation see interpolant.

Parameters:
  • name -- Name of the result

  • knots -- Knot vector per dimension, non-decreasing, with repeated end knots

  • coeffs -- Flat coefficient list

  • degree -- Polynomial degree per dimension

  • m -- Dimension of the spline value

  • opts -- "lookup_mode" (per dimension: "linear", "exact", "binary") and Function options

>>> f = Function.bspline("f", [[0, 0, 0, 1, 2, 2, 2]], [0, 1, 2, 3], [2])
>>> f
Function(f:(i0)->(o0) MXFunction)
>>> f(0), f(0.5), f(2)
(DM(0), DM(0.875), DM(3))
>>> g = Function.bspline("g", [[0, 0, 1, 1], [0, 0, 1, 1]], [0, 1, 2, 3], [1, 1])
>>> g([0.5, 0.5])
DM(1.5)
>>> try:
...   Function.bspline("f", [[0, 0, 0, 1, 2, 2, 2]], [0, 1, 2, 3], [2, 2])
... except RuntimeError as e:
...   print("must match knot list length" in str(e))
True
>> knots = {[0, 0, 0, 1, 2, 2, 2]};
>> f = Function.bspline('f', knots, [0, 1, 2, 3], 2); disp(f)
f:(i0)->(o0) MXFunction
>> [f(0), f(0.5), f(2)]
[[0, 0.875, 3]]
>> g = Function.bspline('g', {[0, 0, 1, 1], [0, 0, 1, 1]}, [0, 1, 2, 3], [1, 1]);
>> g([0.5; 0.5])
1.5
>> try, Function.bspline('f', knots, [0, 1, 2, 3], [2, 2]); catch e, msg = e.message; end
>> contains(msg, 'must match knot list length')
1
julia> f = ca.Function.bspline("f", [[0, 0, 0, 1, 2, 2, 2]], [0, 1, 2, 3], [2]);
julia> f
Function(f:(i0)->(o0) MXFunction)
julia> f(0), f(0.5), f(2)
(0, 0.875, 3)
julia> g = ca.Function.bspline("g", [[0, 0, 1, 1], [0, 0, 1, 1]], [0, 1, 2, 3], [1, 1]);
julia> g([0.5, 0.5])
DM(1.5)
julia> try
           ca.Function.bspline("f", [[0, 0, 0, 1, 2, 2, 2]], [0, 1, 2, 3], [2, 2])
       catch e
           println(occursin("must match knot list length", sprint(showerror, e)))
       end
true

See also: interpolant, MX.bspline

Extra doc | Doc source | Implementation

buffer()

Create a FunctionBuffer object for evaluating with minimal overhead

cache(...)

Get the derivative and map functions currently cached for this function.

cache(self) -> dict

jacobian, forward, reverse, wrap and serial map store their result in a cache keyed by name (jac_f, fwd1_f, adj1_f, wrap_f, map3_f, ...). The cache holds weak references: an entry stays only while some other reference keeps the function alive. Option "cache" prepopulates it, e.g. with a hand- written Jacobian.

>>> x = SX.sym("x")
>>> f = Function("f", [x], [sin(x)])
>>> f.cache()
{}
>>> J = f.jacobian()
>>> list(f.cache().keys())
['jac_f']
>> x = SX.sym('x');
>> f = Function('f', {x}, {sin(x)});
>> isempty(fieldnames(f.cache()))
1
>> J = f.jacobian(); disp(strjoin(fieldnames(f.cache()), ' '))
jac_f
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [sin(x)]);
julia> ca.cache(f)
Dict{String, Any}()
julia> J = ca.jacobian(f);
julia> collect(keys(ca.cache(f)))
1-element Vector{String}:
 "jac_f"

See also: jacobian, forward, reverse

Extra doc | Doc source | Implementation

call(...)
call(self, dict:DM arg, bool always_inline, bool never_inline) -> dict:DM
call(self, [DM] arg, bool always_inline, bool never_inline) -> [DM]
call(self, [SX] arg, bool always_inline, bool never_inline) -> [SX]
call(self, dict:SX arg, bool always_inline, bool never_inline) -> dict:SX
call(self, dict:MX arg, bool always_inline, bool never_inline) -> dict:MX
call(self, [MX] arg, bool always_inline, bool never_inline) -> [MX]

Evaluate with a list or a dict of arguments; the result has the same form.

This is the general evaluation entry point; the call operator (f(...) in Python, C++ and MATLAB) is a shorthand for it. Argument lists must have exactly n_in() entries. A dict maps input names to values; missing inputs take default_in, unknown names raise an error. The result is a list of n_out() values, or a dict keyed by output name.

The argument type selects the evaluation mode:

  • DM (or anything convertible to DM, such as numbers and numeric arrays): numerical evaluation, returns DM

  • SX: symbolic evaluation producing an SX expression; an MX function is expanded on the fly (fails if it contains non-expandable nodes)

  • MX: symbolic evaluation producing a call node f(args){k} in the MX graph, unless the function is inlined

Shapes: each argument must have the input shape, or be a scalar (broadcast to all entries), a transposed vector, an empty matrix (treated as all zeros), or N-by-(P*M) for an N-by-M input (P evaluations, outputs stacked horizontally; other arguments are repeated). Anything else raises an error that lists these rules. Sparsity is projected: entries outside sparsity_in are ignored. When all inputs are scalar and the arguments are matrices of one common shape, the function is applied elementwise. Numerical evaluation of a function with free variables raises "Cannot evaluate ... since variables [...] are free".

Parameters:
  • arg -- List or dict of arguments, all of the same type

  • res -- Output: list or dict of results

  • always_inline -- MX only: expand the call into the caller's graph instead of creating a call node (SX functions are then inlined as scalar operations); combined with never_inline raises an error

  • never_inline -- SX only: keep the call as an opaque call node inside the SX expression instead of inlining it

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
>>> f.call([2, [3, 4]])
[DM([6, 8]), DM(0.909297)]
>>> f.call({"x": 2})
{'r': DM([0, 0]), 's': DM(0.909297)}
>>> f(2, [3, 4])
(DM([6, 8]), DM(0.909297))
>>> f(x=2, y=[3, 4])
{'r': DM([6, 8]), 's': DM(0.909297)}
>>> f(2, DM([[3, 5], [4, 6]]))
(DM(
[[6, 10],
 [8, 12]]), DM([[0.909297, 0.909297]]))
>>> f(DM(0, 0), 3)
(DM([0, 0]), DM(0))
>>> z = MX.sym("z"); w = MX.sym("w", 2)
>>> f.call([z, w])
[MX(f(z, w){0}), MX(f(z, w){1})]
>>> f.call([z, w], True)
[MX(vertcat((z*w[0]), (z*w[1]))), MX(sin(z))]
>>> a = SX.sym("a")
>>> f.call([a, [1, 2]])
[SX([a, (2.*a)]), SX(sin(a))]
>>> try:
...   f(1)
... except RuntimeError as e:
...   print("Incorrect number of inputs: Expected 2, got 1" in str(e))
True
>>> try:
...   f(1, [1, 2, 3])
... except RuntimeError as e:
...   print("Input 1 (y) has mismatching shape. Got 3-by-1" in str(e))
True
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y, sin(x)}, {'x', 'y'}, {'r', 's'});
>> res = f.call({2, [3; 4]}); disp(res{1}), disp(res{2})
[6, 8]
0.909297
>> res = f.call(struct('x', 2)); disp(res.r), disp(res.s)
[0, 0]
0.909297
>> [r, s] = f(2, [3; 4]); disp(r), disp(s)
[6, 8]
0.909297
>> res = f('x', 2, 'y', [3; 4]); disp(res.r), disp(res.s)
[6, 8]
0.909297
>> [r, s] = f(2, DM([3, 5; 4, 6])); disp(r), disp(s)
[[6, 10],
[8, 12]]
[[0.909297, 0.909297]]
>> [r, s] = f(DM(0, 0), 3); disp(r), disp(s)
[0, 0]
0
>> z = MX.sym('z'); w = MX.sym('w', 2);
>> res = f.call({z, w}); disp(res{1}), disp(res{2})
f(z, w){0}
f(z, w){1}
>> res = f.call({z, w}, true); disp(res{1}), disp(res{2})
vertcat((z*w[0]), (z*w[1]))
sin(z)
>> a = SX.sym('a'); res = f.call({a, [1; 2]}); disp(res{1}), disp(res{2})
[a, (2.*a)]
sin(a)
>> try, f(1); catch e, disp(contains(e.message, 'Expected 2, got 1')); end
1
>> try, f(1, [1; 2; 3]); catch e, disp(contains(e.message, 'Got 3-by-1')); end
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"]);
julia> ca.call(f, [2, [3, 4]])
2-element Vector{DM}:
 DM([6, 8])
 DM(0.909297)
julia> ca.call(f, Dict("x" => 2))
Dict{String, DM} with 2 entries:
  "r" => [0, 0]
  "s" => 0.909297
julia> f(2, [3, 4])
([6, 8], 0.909297)
julia> f(x=2, y=[3, 4])
Dict{String, DM} with 2 entries:
  "r" => [6, 8]
  "s" => 0.909297
julia> r, s = f(2, [3 5; 4 6]);
julia> r
DM(
[[6, 10],
 [8, 12]])
julia> s
DM([[0.909297, 0.909297]])
julia> f(ca.DM(0, 0), 3)
([0, 0], 0)
julia> z = ca.MX.sym("z"); w = ca.MX.sym("w", 2);
julia> ca.call(f, [z, w])
2-element Vector{MX}:
 MX(f(z, w){0})
 MX(f(z, w){1})
julia> ca.call(f, [z, w], true)
2-element Vector{MX}:
 MX(vertcat((z*w[0]), (z*w[1])))
 MX(sin(z))
julia> a = ca.SX.sym("a");
julia> ca.call(f, [a, [1, 2]])
2-element Vector{SX}:
 SX([a, (2.*a)])
 SX(sin(a))
julia> try
           f(1)
       catch e
           msg = sprint(showerror, e)
           println(occursin("Incorrect number of inputs: Expected 2, got 1", msg))
       end
true
julia> try
           f(1, [1, 2, 3])
       catch e
           msg = sprint(showerror, e)
           println(occursin("Input 1 (y) has mismatching shape. Got 3-by-1", msg))
       end
true

See also: default_in, convert_in, map, mapsum

Extra doc | Doc source | Implementation

change_option(...)

Change a debugging option on an existing object.

change_option(self, str option_name, GenericType option_value)

Only options that do not change the numerical result can be changed: "verbose", "regularity_check", "print_in", "print_out", "dump", "dump_in", "dump_out", "dump_trace", "dump_dir", "dump_format", "print_time", "record_time" and "print_instructions". Any other existing option raises "cannot be changed"; an unknown name raises "does not exist".

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.change_option("verbose", False)
>>> try:
...   f.change_option("cse", True)
... except RuntimeError as e:
...   print("Option 'cse' cannot be changed" in str(e))
True
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> f.change_option('verbose', false)
>> try, f.change_option('cse', true); catch e, msg = e.message; end
>> contains(msg, 'Option ''cse'' cannot be changed')
1
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.change_option(f, "verbose", false)
julia> try
           ca.change_option(f, "cse", true)
       catch e
           println(occursin("Option 'cse' cannot be changed", sprint(showerror, e)))
       end
true

See also: has_option

Extra doc | Doc source | Implementation

static check_name(...)

Check whether a string is a valid function name.

check_name(str name) -> bool

A valid name starts with a letter and continues with letters, digits and underscores, with no two consecutive underscores; it may not be one of the keywords "null", "jac", "hess". Constructors and generate raise for invalid names; names must be valid C identifiers because they appear in generated code.

>>> Function.check_name("f_1"), Function.check_name("1f")
(True, False)
>>> Function.check_name("a__b"), Function.check_name("jac"), Function.check_name("")
(False, False, False)
>> fprintf('%d %d\n', Function.check_name('f_1'), Function.check_name('1f'))
1 0
>> fprintf('%d %d\n', Function.check_name('a__b'), Function.check_name('jac'))
0 0
>> Function.check_name('')
0
julia> F = ca.Function;
julia> F.check_name("f_1"), F.check_name("1f")
(true, false)
julia> F.check_name("a__b"), F.check_name("jac"), F.check_name("")
(false, false, false)

See also: fix_name

Extra doc | Doc source | Implementation

checkout(...)

Reserve a memory object for evaluation and return its index.

checkout(self) -> int

Each memory object holds the state of one evaluation context (solver workspace, statistics); ordinary calls use index 0. Reserving separate objects allows concurrent evaluation from several threads with the low-level interface and separate stats. Release it with release when done.

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> m = f.checkout()
>>> m
1
>>> f.release(m)
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> m = f.checkout(); disp(m)
1
>> f.release(m)
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> m = ca.checkout(f)
1
julia> ca.release(f, m)

See also: release, stats, FunctionBuffer

Extra doc | Doc source | Implementation

class_name(...)

Get class name.

class_name(self) -> str

Extra doc | Doc source | Implementation

static conditional(...)

Create a function that calls f when its first input is nonzero and.

conditional(str name, Function f, dict opts) -> Function
conditional(str name, [Function] f, Function f_def, dict opts) -> Function

returns zeros otherwise

Shorthand for if_else with a zero-returning function of the same signature as the false branch; evaluating with a zero condition skips f entirely.

>>> x = SX.sym("x")
>>> f = Function("f", [x], [x**2])
>>> c = Function.conditional("c", f)
>>> c, c(0, 3), c(1, 3)
(Function(c:(i0,i1)->(o0) Switch), DM(0), DM(9))
>> x = SX.sym('x');
>> f = Function('f', {x}, {x^2});
>> c = Function.conditional('c', f); disp(c)
c:(i0,i1)->(o0) Switch
>> [c(0, 3), c(1, 3)]
[[0, 9]]
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [x^2]);
julia> c = ca.Function.conditional("c", f);
julia> println(c); c(0, 3), c(1, 3)
c:(i0,i1)->(o0) Switch
(0, 9)

See also: if_else

Create a function that selects one of several functions by an index input.

The result takes an index as first input followed by the inputs of the branch functions. At evaluation the index is truncated to an integer k; branch f[k] is evaluated when 0 <= k < len(f), otherwise f_def. All branches must have the same number of inputs and outputs; the signature (names, shapes) is taken from f_def and arguments are projected when a branch has a different sparsity. Derivatives are the derivatives of the selected branch. Symbolic MX evaluation gives a call node; unlike if_else on expressions, only the selected branch is evaluated numerically.

Parameters:
  • name -- Name of the result

  • f -- Branch functions, selected by index 0, 1,...

  • f_def -- Default branch for indices out of range

  • opts -- Function options

>>> x = SX.sym("x")
>>> f0 = Function("f0", [x], [x]); f1 = Function("f1", [x], [x**2])
>>> fdef = Function("fdef", [x], [-x])
>>> sw = Function.conditional("sw", [f0, f1], fdef)
>>> sw
Function(sw:(i0,i1)->(o0) Switch)
>>> sw(0, 3), sw(1, 3), sw(1.9, 3), sw(2, 3), sw(-1, 3)
(DM(3), DM(9), DM(9), DM(-3), DM(-3))
>>> sw(MX.sym("k"), MX.sym("v"))
MX(sw(k, v){0})
>> x = SX.sym('x');
>> f0 = Function('f0', {x}, {x}); f1 = Function('f1', {x}, {x^2});
>> fdef = Function('fdef', {x}, {-x});
>> sw = Function.conditional('sw', {f0, f1}, fdef); disp(sw)
sw:(i0,i1)->(o0) Switch
>> [sw(0, 3), sw(1, 3), sw(1.9, 3), sw(2, 3), sw(-1, 3)]
[[3, 9, 9, -3, -3]]
>> sw(MX.sym('k'), MX.sym('v'))
sw(k, v){0}
julia> x = ca.SX.sym("x");
julia> f0 = ca.Function("f0", [x], [x]); f1 = ca.Function("f1", [x], [x^2]);
julia> fdef = ca.Function("fdef", [x], [-x]);
julia> sw = ca.Function.conditional("sw", [f0, f1], fdef);
julia> sw
Function(sw:(i0,i1)->(o0) Switch)
julia> sw(0, 3), sw(1, 3), sw(1.9, 3), sw(2, 3), sw(-1, 3)
(3, 9, 9, -3, -3)
julia> sw(ca.MX.sym("k"), ca.MX.sym("v"))
MX(sw(k, v){0})

See also: if_else

Extra doc | Doc source | Implementation

convert_in(...)
convert_in(self, dict:DM arg) -> [DM]
convert_in(self, [DM] arg) -> dict:DM
convert_in(self, [SX] arg) -> dict:SX
convert_in(self, dict:SX arg) -> [SX]
convert_in(self, dict:MX arg) -> [MX]
convert_in(self, [MX] arg) -> dict:MX

Convert between a list and a dict of inputs or outputs.

convert_in turns a list of n_in() values into a dict keyed by input name, and a dict into a list where absent inputs get default_in. convert_out does the same for outputs; absent outputs become nan. An unknown key or a list of the wrong length raises an error. Values are passed through unchanged (no shape or sparsity check), for any of DM, SX and MX. Useful to prepare arguments for call or generate_in.

>>> f = Function("f", [SX.sym("x"), SX.sym("y")], [SX(0), SX(1)], ["x", "y"], ["a", "b"])
>>> f.convert_in([1, 2])
{'x': DM(1), 'y': DM(2)}
>>> f.convert_in({"y": 2})
[DM(0), DM(2)]
>>> f.convert_out({"b": 5})
[DM(nan), DM(5)]
>>> try:
...   f.convert_in({"z": 1})
... except RuntimeError as e:
...   print('could not find entry "z"' in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('y')}, {SX(0), SX(1)}, {'x', 'y'}, {'a', 'b'});
>> s = f.convert_in({1, 2}); disp(s.x), disp(s.y)
1
2
>> c = f.convert_in(struct('y', 2)); disp(c{1}), disp(c{2})
0
2
>> c = f.convert_out(struct('b', 5)); disp(c{1}), disp(c{2})
nan
5
>> try, f.convert_in(struct('z', 1)); catch e, msg = e.message; end
>> contains(msg, 'could not find entry "z"')
1
julia> f = ca.Function("f", [ca.SX.sym("x"), ca.SX.sym("y")], [ca.SX(0), ca.SX(1)],
                       ["x", "y"], ["a", "b"]);
julia> ca.convert_in(f, Dict("y" => 2))
2-element Vector{DM}:
 DM(0)
 DM(2)
julia> ca.convert_out(f, Dict("b" => 5))
2-element Vector{DM}:
 DM(nan)
 DM(5)
julia> try
           ca.convert_in(f, Dict("z" => 1))
       catch e
           println(occursin("could not find entry \"z\"", sprint(showerror, e)))
       end
true

See also: call, default_in, nz_from_in

Extra doc | Doc source | Implementation

convert_out(...)
convert_out(self, dict:DM arg) -> [DM]
convert_out(self, [DM] arg) -> dict:DM
convert_out(self, [SX] arg) -> dict:SX
convert_out(self, dict:SX arg) -> [SX]
convert_out(self, dict:MX arg) -> [MX]
convert_out(self, [MX] arg) -> dict:MX

Convert between a list and a dict of inputs or outputs.

convert_in turns a list of n_in() values into a dict keyed by input name, and a dict into a list where absent inputs get default_in. convert_out does the same for outputs; absent outputs become nan. An unknown key or a list of the wrong length raises an error. Values are passed through unchanged (no shape or sparsity check), for any of DM, SX and MX. Useful to prepare arguments for call or generate_in.

>>> f = Function("f", [SX.sym("x"), SX.sym("y")], [SX(0), SX(1)], ["x", "y"], ["a", "b"])
>>> f.convert_in([1, 2])
{'x': DM(1), 'y': DM(2)}
>>> f.convert_in({"y": 2})
[DM(0), DM(2)]
>>> f.convert_out({"b": 5})
[DM(nan), DM(5)]
>>> try:
...   f.convert_in({"z": 1})
... except RuntimeError as e:
...   print('could not find entry "z"' in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('y')}, {SX(0), SX(1)}, {'x', 'y'}, {'a', 'b'});
>> s = f.convert_in({1, 2}); disp(s.x), disp(s.y)
1
2
>> c = f.convert_in(struct('y', 2)); disp(c{1}), disp(c{2})
0
2
>> c = f.convert_out(struct('b', 5)); disp(c{1}), disp(c{2})
nan
5
>> try, f.convert_in(struct('z', 1)); catch e, msg = e.message; end
>> contains(msg, 'could not find entry "z"')
1
julia> f = ca.Function("f", [ca.SX.sym("x"), ca.SX.sym("y")], [ca.SX(0), ca.SX(1)],
                       ["x", "y"], ["a", "b"]);
julia> ca.convert_in(f, Dict("y" => 2))
2-element Vector{DM}:
 DM(0)
 DM(2)
julia> ca.convert_out(f, Dict("b" => 5))
2-element Vector{DM}:
 DM(nan)
 DM(5)
julia> try
           ca.convert_in(f, Dict("z" => 1))
       catch e
           println(occursin("could not find entry \"z\"", sprint(showerror, e)))
       end
true

See also: call, default_in, nz_from_in

Extra doc | Doc source | Implementation

debug_repr(...)
debug_repr(self) -> str
default_in(...)

Get the value used for input ind when a call by name omits it.

default_in(self, int ind) -> float

When calling with a dict (or keyword arguments), every input that is not given is filled with this scalar, broadcast to the input shape. For functions built from expressions it is 0 unless option "default_in" was set at construction. Solvers define their own: nlpsol uses -inf for lbx and lbg, inf for ubx and ubg, 0 for the rest.

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x + y], ["x", "y"], ["r"])
>>> f.default_in(0), f(x=3)
(0.0, {'r': DM([3, 3])})
>>> g = Function("g", [x, y], [x + y], ["x", "y"], ["r"], {"default_in": [1, 2]})
>>> g.default_in(1), g(x=3), g(y=[0, 1])
(2.0, {'r': DM([5, 5])}, {'r': DM([1, 2])})
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x + y}, {'x', 'y'}, {'r'});
>> disp(f.default_in(0)), res = f('x', 3); disp(res.r)
0
[3, 3]
>> opts = struct('default_in', [1, 2]);
>> g = Function('g', {x, y}, {x + y}, {'x', 'y'}, {'r'}, opts);
>> disp(g.default_in(1)), res = g('x', 3); disp(res.r), res = g('y', [0; 1]); disp(res.r)
2
[5, 5]
[1, 2]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x + y], ["x", "y"], ["r"]);
julia> ca.default_in(f, 0), f(x=3)["r"]
(0.0, [3, 3])
julia> opts = Dict("default_in" => [1, 2]);
julia> g = ca.Function("g", [x, y], [x + y], ["x", "y"], ["r"], opts);
julia> ca.default_in(g, 1), g(x=3)["r"], g(y=[0, 1])["r"]
(2.0, [5, 5], [1, 2])

See also: max_in, min_in, nominal_in, convert_in

Extra doc | Doc source | Implementation

static deserialize(...)

Build a function from a DeserializingStream (C++ serialization API)

deserialize(std::istream & stream) -> Function
deserialize(casadi::DeserializingStream & s) -> Function
deserialize(str s) -> Function

Overload: deserialize(std::istream & stream)

Build a function from a serialization stream.

Overload: deserialize(str s)

Build a function from a string produced by serialize.

Raises "DeserializingStream sanity check failed" for data that is not a serialized CasADi object.

>>> x = SX.sym("x")
>>> f = Function.deserialize(Function("f", [x], [2*x]).serialize())
>>> f(3)
DM(6)
>>> try:
...   Function.deserialize("not a function")
... except RuntimeError as e:
...   print("sanity check failed" in str(e))
True
>> x = SX.sym('x');
>> f = Function.deserialize(Function('f', {x}, {2*x}).serialize());
>> f(3)
6
>> try, Function.deserialize('not a function'); catch e, msg = e.message; end
>> contains(msg, 'sanity check failed')
1
julia> x = ca.SX.sym("x");
julia> f = ca.Function.deserialize(ca.serialize(ca.Function("f", [x], [2x])));
julia> f(3)
DM(6)
julia> try
           ca.Function.deserialize("not a function")
       catch e
           println(occursin("sanity check failed", sprint(showerror, e)))
       end
true

See also: serialize, load

Extra doc | Doc source | Implementation

disp(...)

Print a description of the object.

disp(self, bool more)

Doc source | Implementation

expand(...)
expand(self) -> Function
expand(self, str name, dict opts) -> Function

Convert an MXFunction into an equivalent SXFunction.

Evaluates the function symbolically with SX inputs and builds an SXFunction from the result: every matrix node is unrolled into scalar instructions. Evaluation of the result is typically faster per operation, at the cost of memory proportional to the number of scalar operations. The name, input/output names and the options of the original function (other than the SX-specific ones given in opts) are kept.

Fails when the graph contains a node that has no scalar expansion, with "eval_sx not defined for ...": for example calls to external functions or linear solves (solve, inv) with a numerical plugin; use the "symbolicqr" plugin for those. Fails when the function has free variables. An SXFunction is returned unchanged (as a copy).

Parameters:
  • name -- Name of the new function; defaults to the current name

  • opts -- Options for the SXFunction constructor, e.g. "live_variables", "cse"

Returns:

SXFunction

>>> x = MX.sym("x", 2)
>>> f = Function("f", [x], [x.T @ x, 2*x], ["x"], ["q", "y"])
>>> f, f.n_instructions()
(Function(f:(x[2])->(q,y[2]) MXFunction), 7)
>>> g = f.expand()
>>> g, g.n_instructions()
(Function(f:(x[2])->(q,y[2]) SXFunction), 10)
>>> f([1, 2]), g([1, 2])
((DM(5), DM([2, 4])), (DM(5), DM([2, 4])))
>>> f.expand("f_sx", {"live_variables": False})
Function(f_sx:(x[2])->(q,y[2]) SXFunction)
>>> A = MX.sym("A", 2, 2)
>>> h = Function("h", [A, x], [solve(A, x)])
>>> try:
...   h.expand()
... except RuntimeError as e:
...   print("eval_sx not defined" in str(e))
True
>>> Function("h", [A, x], [solve(A, x, "symbolicqr")]).expand().class_name()
'SXFunction'
>> x = MX.sym('x', 2);
>> f = Function('f', {x}, {x'*x, 2*x}, {'x'}, {'q', 'y'});
>> f, f.n_instructions()
f:(x[2])->(q,y[2]) MXFunction
7
>> g = f.expand(); disp(g), disp(g.n_instructions())
f:(x[2])->(q,y[2]) SXFunction
10
>> [q, y] = g([1; 2]); disp(q), disp(y)
5
[2, 4]
>> f.expand('f_sx', struct('live_variables', false))
f_sx:(x[2])->(q,y[2]) SXFunction
>> A = MX.sym('A', 2, 2); h = Function('h', {A, x}, {solve(A, x)});
>> try, h.expand(); catch e, disp(contains(e.message, 'eval_sx not defined')); end
1
>> Function('h', {A, x}, {solve(A, x, 'symbolicqr')}).expand().class_name()
SXFunction
julia> x = ca.MX.sym("x", 2);
julia> f = ca.Function("f", [x], [x' * x, 2x], ["x"], ["q", "y"]);
julia> println(f); ca.n_instructions(f)
f:(x[2])->(q,y[2]) MXFunction
7
julia> g = ca.expand(f);
julia> println(g); ca.n_instructions(g)
f:(x[2])->(q,y[2]) SXFunction
10
julia> f([1, 2]), g([1, 2])
((5, [2, 4]), (5, [2, 4]))
julia> ca.expand(f, "f_sx", Dict("live_variables" => false))
Function(f_sx:(x[2])->(q,y[2]) SXFunction)
julia> A = ca.MX.sym("A", 2, 2);
julia> h = ca.Function("h", [A, x], [A \ x]);
julia> try
           ca.expand(h)
       catch e
           println(occursin("eval_sx not defined", sprint(showerror, e)))
       end
true
julia> ca.class_name(ca.expand(ca.Function("h", [A, x], [ca.solve(A, x, "symbolicqr")])))
"SXFunction"

See also: Function.Function, transform

Extra doc | Doc source | Implementation

export_code(...)
export_code(self, str lang, dict options) -> str
export_code(self, str lang, str fname, dict options)

Export the algorithm as source code in another language.

Only "matlab" is supported, and only for SXFunction and MXFunction without free variables; other classes or languages raise an error. The code is a plain MATLAB function with the same name that evaluates the algorithm on numeric arguments, without any CasADi dependency. The file overload writes to fname, the other returns the code as a string.

Parameters:
  • lang -- "matlab"

  • options -- "indent_level" (integer)

>>> x = SX.sym("x")
>>> f = Function("f", [x], [sin(x)])
>>> f.export_code("matlab").splitlines()[0]
'function [varargout] = f(varargin)'
>>> try:
...   f.export_code("python")
... except RuntimeError as e:
...   print("Only matlab language supported" in str(e))
True
>> x = SX.sym('x');
>> f = Function('f', {x}, {sin(x)});
>> code = strsplit(f.export_code('matlab'), newline); disp(code{1})
function [varargout] = f(varargin)
>> try, f.export_code('python'); catch e, disp(contains(e.message, 'Only matlab')); end
1
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [sin(x)]);
julia> first(split(ca.export_code(f, "matlab"), "\n"))
"function [varargout] = f(varargin)"
julia> try
           ca.export_code(f, "python")
       catch e
           println(occursin("Only matlab language supported", sprint(showerror, e)))
       end
true

See also: generate

Extra doc | Doc source | Implementation

export_graph(...)

Return the .casadi_viz JSON bundle without writing a file.

export_graph(self, dict opts) -> str
export_graph(self, str fname, dict opts)

Uses the same graph options as the filename overload.

Export a Function graph as .html, .dot, or .casadi_viz.

HTML and .casadi_viz embed the serialized Function, decoded by the browser viewer; any serializable Function works, and helpers such as nlp_hess_l can be explored. include_functions (default true) shows called and helper Functions in the viewer. DOT is standalone Graphviz of an SX/MX root graph only. Options show_matrix_contents and show_matrix_sizes (both default true) control matrix detail and dimensions. Load dump_trace JSONL files in the viewer to replay numerical evaluation. Options: view (function, expression; default function), direction (LR, RL, TB, BT; expression view only; default TB), viz_js (local Viz.js global bundle to embed; by default uses the viewer package renderer). viewer_url (string) overrides the HTML viewer ESM module URL; default is https://unpkg.com/@casadi/casadi- viz@MAJOR.MINOR/dist/index.js for this CasADi version.

Extra doc | Doc source | Implementation

factory(...)

Build a function computing derivatives by naming inputs and outputs.

factory(self, str name, [str] s_in, [str] s_out, dict:[str] aux, dict opts) -> Function

Only defined for SXFunction and MXFunction (other classes raise an error). The new function takes the inputs listed in s_in and returns the outputs listed in s_out, in that order. Each entry is either an existing name or a derivative request built from existing names with ':' separators:

  • inputs: "fwd:x" a forward seed for input x, "adj:r" an adjoint seed for output r, "lam:r" a multiplier for output r (used by aux)

  • outputs: "fwd:r" forward sensitivity, "adj:x" adjoint sensitivity, "jac:r:x" the Jacobian of r with respect to x, "grad:r:x" its gradient (r must be scalar), "hess:r:x:y" the Hessian of scalar r with respect to x and y

  • an output may be prefixed with "triu:", "tril:" or "sym:" to return only the upper or lower triangle of a Hessian, or to symmetrize it

The output names of the result have ':' replaced by '_' (jac:r:x becomes jac_r_x). Non-differentiable inputs and outputs (is_diff_in/is_diff_out) give all-zero blocks. An input that is needed by an output but not listed in s_in is treated as zero. An unknown name raises an error listing the available names.

Parameters:
  • name -- Name of the new function

  • s_in -- Input requests, see above

  • s_out -- Output requests, see above

  • aux -- Extra scalar outputs defined as linear combinations: {"gamma": ["f", "g"]} defines gamma = lam_f'*f + lam_g'*g, so that "grad:gamma:x" and "hess:gamma:x:x" are the Lagrangian gradient and Hessian with inputs "lam:f" and "lam:g"

  • opts -- "helper_options" and "final_options" (dicts for the intermediate and the returned function) and any Function option for the result

>>> x = SX.sym("x", 2); p = SX.sym("p")
>>> f = Function("f", [x, p], [p*dot(x, x), x[0]*x[1]], ["x", "p"], ["f", "g"])
>>> g = f.factory("g", ["x", "p"], ["jac:f:x", "hess:f:x:x", "jac:g:x"])
>>> g
Function(g:(x[2],p)->(jac_f_x[1x2],hess_f_x_x[2x2,2nz],jac_g_x[1x2]) SXFunction)
>>> g([1, 2], 3)
(DM([[6, 12]]), DM(
[[6, 00],
 [00, 6]]), DM([[2, 1]]))
>>> L = f.factory("L", ["x", "p", "lam:f", "lam:g"], ["grad:gamma:x"],
...               {"gamma": ["f", "g"]})
>>> L, L([1, 2], 3, 1, 2)
(Function(L:(x[2],p,lam_f,lam_g)->(grad_gamma_x[2]) SXFunction), DM([10, 14]))
>>> h = f.factory("h", ["x", "p", "fwd:x", "fwd:p"], ["fwd:f"])
>>> h([1, 2], 3, [1, 0], 0)
DM(6)
>>> try:
...   f.factory("bad", ["x"], ["jac:q:x"])
... except RuntimeError as e:
...   print('Cannot process "q" as output. Available: f,g.' in str(e))
True
>> x = SX.sym('x', 2); p = SX.sym('p');
>> f = Function('f', {x, p}, {p*dot(x, x), x(1)*x(2)}, {'x', 'p'}, {'f', 'g'});
>> g = f.factory('g', {'x', 'p'}, {'jac:f:x', 'hess:f:x:x', 'jac:g:x'}); disp(g)
g:(x[2],p)->(jac_f_x[1x2],hess_f_x_x[2x2,2nz],jac_g_x[1x2]) SXFunction
>> [jac_f_x, hess_f_x_x, jac_g_x] = g([1; 2], 3);
>> jac_f_x, hess_f_x_x, jac_g_x
[[6, 12]]
[[6, 00],
[00, 6]]
[[2, 1]]
>> aux = struct('gamma', {{'f', 'g'}});
>> L = f.factory('L', {'x', 'p', 'lam:f', 'lam:g'}, {'grad:gamma:x'}, aux);
>> L, L([1; 2], 3, 1, 2)
L:(x[2],p,lam_f,lam_g)->(grad_gamma_x[2]) SXFunction
[10, 14]
>> h = f.factory('h', {'x', 'p', 'fwd:x', 'fwd:p'}, {'fwd:f'});
>> h([1; 2], 3, [1; 0], 0)
6
>> try, f.factory('bad', {'x'}, {'jac:q:x'}); catch e, msg = e.message; end
>> contains(msg, 'Cannot process "q" as output. Available: f,g.')
1
julia> x = ca.SX.sym("x", 2); p = ca.SX.sym("p");
julia> f = ca.Function("f", [x, p], [p * ca.dot(x, x), x[1] * x[2]],
                       ["x", "p"], ["f", "g"]);
julia> g = ca.factory(f, "g", ["x", "p"], ["jac:f:x", "hess:f:x:x", "jac:g:x"]);
julia> g
Function(g:(x[2],p)->(jac_f_x[1x2],hess_f_x_x[2x2,2nz],jac_g_x[1x2]) SXFunction)
julia> jac_f_x, hess_f_x_x, jac_g_x = g([1, 2], 3);
julia> jac_f_x
DM([[6, 12]])
julia> hess_f_x_x
DM(
[[6, 00],
 [00, 6]])
julia> jac_g_x
DM([[2, 1]])
julia> L = ca.factory(f, "L", ["x", "p", "lam:f", "lam:g"], ["grad:gamma:x"],
                     Dict("gamma" => ["f", "g"]));
julia> println(L); L([1, 2], 3, 1, 2)
L:(x[2],p,lam_f,lam_g)->(grad_gamma_x[2]) SXFunction
DM([10, 14])
julia> h = ca.factory(f, "h", ["x", "p", "fwd:x", "fwd:p"], ["fwd:f"]);
julia> h([1, 2], 3, [1, 0], 0)
DM(6)
julia> try
           ca.factory(f, "bad", ["x"], ["jac:q:x"])
       catch e
           msg = sprint(showerror, e)
           println(occursin("Cannot process \"q\" as output. Available: f,g.", msg))
       end
true

See also: jacobian, forward, reverse, which_depends

Extra doc | Doc source | Implementation

find_function(...)

Get an embedded function by name, searching recursively.

find_function(self, str name, int max_depth) -> Function
Parameters:
  • name -- Name of the function; raises "'name' not found" when absent

  • max_depth -- Maximum nesting depth, negative for no limit

See also: find_functions

Extra doc | Doc source | Implementation

find_functions(...)

Get all functions embedded in this function, recursively.

find_functions(self, int max_depth) -> [Function]

Walks the owned functions (get_function) and their owned functions in turn, returning each distinct Function once, in depth-first discovery order.

Parameters:

max_depth -- Maximum nesting depth to descend; 0 returns only the directly owned functions, a negative number means no limit

Returns:

Unique list of embedded functions

>>> x = MX.sym("x")
>>> inner = Function("inner", [x], [sin(x)]).expand()
>>> middle = Function("middle", [x], [inner(x) + 1])
>>> outer = Function("outer", [x], [middle.call([x], False, True)[0]*2])
>>> [g.name() for g in outer.find_functions()]
['middle', 'inner']
>>> [g.name() for g in outer.find_functions(0)]
['middle']
>>> outer.find_function("inner")
Function(inner:(i0)->(o0) SXFunction)
>>> Function("o2", [x], [middle(x)*2]).get_function()
['inner']
>> x = MX.sym('x');
>> inner = Function('inner', {x}, {sin(x)}).expand();
>> middle = Function('middle', {x}, {inner(x) + 1});
>> res = middle.call({x}, false, true); outer = Function('outer', {x}, {res{1}*2});
>> fs = outer.find_functions(); cellfun(@(g) disp(g.name()), fs)
middle
inner
>> fs = outer.find_functions(0); disp(fs{1}.name())
middle
>> outer.find_function('inner')
inner:(i0)->(o0) SXFunction
>> Function('o2', {x}, {middle(x)*2}).get_function()
inner
julia> x = ca.MX.sym("x");
julia> inner = ca.expand(ca.Function("inner", [x], [sin(x)]));
julia> middle = ca.Function("middle", [x], [inner(x) + 1]);
julia> outer = ca.Function("outer", [x], [ca.call(middle, [x], false, true)[1] * 2]);
julia> [ca.name(g) for g in ca.find_functions(outer)]
2-element Vector{String}:
 "middle"
 "inner"
julia> [ca.name(g) for g in ca.find_functions(outer, 0)]
1-element Vector{String}:
 "middle"
julia> ca.find_function(outer, "inner")
Function(inner:(i0)->(o0) SXFunction)
julia> ca.get_function(ca.Function("o2", [x], [middle(x) * 2]))
1-element Vector{String}:
 "inner"

See also: find_function, get_function

Extra doc | Doc source | Implementation

static fix_name(...)

Turn any string into a valid function name as defined by check_name.

fix_name(str name) -> str

Runs of non-alphanumeric characters become a single underscore, a leading non-letter gets an "a" prepended, the empty string becomes "unnamed" and a keyword gets "1" appended. A valid name is returned unchanged.

>>> Function.fix_name("my func!"), Function.fix_name("1f"), Function.fix_name("")
('my_func_', 'a1f', 'unnamed')
>>> Function.fix_name("jac"), Function.fix_name("ok")
('jac1', 'ok')
>> Function.fix_name('my func!'), Function.fix_name('1f')
my_func_
a1f
>> Function.fix_name(''), Function.fix_name('jac')
unnamed
jac1
>> Function.fix_name('ok')
ok
julia> F = ca.Function;
julia> F.fix_name("my func!"), F.fix_name("1f"), F.fix_name("")
("my_func_", "a1f", "unnamed")
julia> F.fix_name("jac"), F.fix_name("ok")
("jac1", "ok")

See also: check_name

Extra doc | Doc source | Implementation

fold(...)

Create a function that applies this function N times, feeding outputs back.

fold(self, int N, dict opts) -> Function

as inputs

The first n_accum inputs are accumulators: in every step they take the value of the first n_accum outputs of the previous step. For a step f:(x, u)->(x_next, y) the result is F:(x0, U)->(X, Y) with U = horzcat(u0, ..., u_(N-1)), X = horzcat(x1, ..., x_N), Y = horzcat(y0, ..., y_(N-1)) and x_(k+1), y_k = f(x_k, u_k). Non-accumulated inputs and all outputs are stacked horizontally over the N steps; the accumulator inputs keep their original shape. An accumulator output may be wider than its input (e.g. 1-by-2 feeding a 1-by-1 input): only the last columns are fed back.

Compared with writing the loop in the host language the construction is much faster and the graph is a tower of nested unrolled loops of at most base iterations (option "base", default 10; -1 unrolls completely). This keeps memory use proportional to base rather than N at a small evaluation cost.

The overloads differ in how accumulators are selected: a count n_accum (default 1), or explicit index/name lists accum_in and accum_out of equal length that may pick arbitrary inputs and outputs. The unnamed overload names the result "mapaccum_" + name(). fold is mapaccum returning only the final accumulator state.

Parameters:
  • name -- Name of the result

  • N -- Number of steps, must be positive

  • n_accum -- Number of leading inputs/outputs that are accumulated; at most min(n_in, n_out)

  • opts -- "base" plus options for the resulting MXFunction

>>> x = SX.sym("x"); u = SX.sym("u")
>>> step = Function("step", [x, u], [x + u, x*u], ["x", "u"], ["x_next", "y"])
>>> F = step.mapaccum(3)
>>> F
Function(mapaccum_step:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
>>> F(1, DM([[1, 2, 3]]))
(DM([[2, 4, 7]]), DM([[1, 4, 12]]))
>>> step.mapaccum("F", 3, ["x"], ["x_next"])
Function(F:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
>>> step.fold(3)
Function(fold_step:(x,u[1x3])->(x_next,y[1x3]) MXFunction)
>>> step.fold(3)(1, DM([[1, 2, 3]]))
(DM(7), DM([[1, 4, 12]]))
>>> try:
...   step.mapaccum(0)
... except RuntimeError as e:
...   print("mapaccum: N must be positive" in str(e))
True
>> x = SX.sym('x'); u = SX.sym('u');
>> step = Function('step', {x, u}, {x + u, x*u}, {'x', 'u'}, {'x_next', 'y'});
>> F = step.mapaccum(3); disp(F)
mapaccum_step:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction
>> [X, Y] = F(1, DM([1, 2, 3])); disp(X), disp(Y)
[[2, 4, 7]]
[[1, 4, 12]]
>> step.mapaccum('F', 3, {'x'}, {'x_next'})
F:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction
>> G = step.fold(3); disp(G)
fold_step:(x,u[1x3])->(x_next,y[1x3]) MXFunction
>> [X, Y] = G(1, DM([1, 2, 3])); disp(X), disp(Y)
7
[[1, 4, 12]]
>> try, step.mapaccum(0); catch e, disp(contains(e.message, 'N must be positive')); end
1
julia> x = ca.SX.sym("x"); u = ca.SX.sym("u");
julia> step = ca.Function("step", [x, u], [x + u, x*u], ["x", "u"], ["x_next", "y"]);
julia> F = ca.mapaccum(step, 3);
julia> F
Function(mapaccum_step:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
julia> F(1, [1 2 3])
([[2, 4, 7]], [[1, 4, 12]])
julia> ca.mapaccum(step, "F", 3, ["x"], ["x_next"])
Function(F:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
julia> ca.fold(step, 3)
Function(fold_step:(x,u[1x3])->(x_next,y[1x3]) MXFunction)
julia> ca.fold(step, 3)(1, [1 2 3])
(7, [[1, 4, 12]])
julia> try
           ca.mapaccum(step, 0)
       catch e
           println(occursin("mapaccum: N must be positive", sprint(showerror, e)))
       end
true

See also: map, fold

Extra doc | Doc source | Implementation

forward(...)

Get a function computing nfwd forward directional derivatives.

forward(self, int nfwd) -> Function

The result is named fwd<nfwd>_<name> and has n_in + n_out + n_in inputs: the original inputs, the original outputs (out_<name>, read only when uses_output() is true) and the forward seeds fwd_<input>, each with nfwd times the columns of the input. Its n_out outputs fwd_<output> are the forward sensitivities, nfwd stacked horizontally. Uses the class' own forward mode when available ("enable_forward"), finite differences when "enable_fd" is set, or otherwise the full Jacobian; raises "Derivatives cannot be calculated" when none applies. Results are cached while alive. nfwd must be positive.

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
>>> F = f.forward(1)
>>> print(F)
fwd1_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],fwd_x,fwd_y[2])->(...) SXFunction
>>> F(1, [2, 3], 0, 0, 1, [0, 0])
(DM([2, 3]), DM(0.540302))
>>> print(f.forward(2))
fwd2_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],fwd_x[1x2],fwd_y[2x2])->(...) SXFunction
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y, sin(x)}, {'x', 'y'}, {'r', 's'});
>> F = f.forward(1); disp(F)
fwd1_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],fwd_x,fwd_y[2])->(...) SXFunction
>> [fwd_r, fwd_s] = F(1, [2; 3], 0, 0, 1, [0; 0]); disp(fwd_r), disp(fwd_s)
[2, 3]
0.540302
>> f.forward(2)
fwd2_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],fwd_x[1x2],fwd_y[2x2])->(...) SXFunction
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"]);
julia> F = ca.forward(f, 1);
julia> F
Function(fwd1_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],fwd_x,fwd_y[2])->(fwd_r[2],fwd_s) SXFunction)
julia> F(1, [2, 3], 0, 0, 1, [0, 0])
([2, 3], 0.540302)
julia> F2 = ca.forward(f, 2);
julia> ca.name(F2), ca.size_in(F2, 4), ca.size_in(F2, 5)
("fwd2_f", (1, 2), (2, 2))

See also: reverse, jacobian, factory

Extra doc | Doc source | Implementation

free_mx(...)

Get the free variables of an MXFunction as MX symbols; other classes raise.

free_mx(self) -> [MX]
>>> x = MX.sym("x"); p = MX.sym("p")
>>> f = Function("f", [x], [x*p], {"allow_free": True})
>>> f.free_mx()
[MX(p)]
>> x = MX.sym('x'); p = MX.sym('p');
>> f = Function('f', {x}, {x*p}, struct('allow_free', true));
>> fr = f.free_mx(); disp(fr{1})
p
julia> x = ca.MX.sym("x"); p = ca.MX.sym("p");
julia> f = ca.Function("f", [x], [x*p], Dict("allow_free" => true));
julia> ca.free_mx(f)
1-element Vector{MX}:
 MX(p)

See also: has_free, free_sx

Extra doc | Doc source | Implementation

free_sx(...)

Get the free variables of an SXFunction as SX symbols; other classes raise.

free_sx(self) -> [SX]

See also: has_free, free_mx

Extra doc | Doc source | Implementation

generate(...)

Generate C code into a file named after the function (name() + ".c")

generate(self, dict opts) -> str
generate(self, str fname, dict opts) -> str

Generate self-contained C code for the function.

Writes fname (a ".c" suffix is added when missing; the base name must satisfy check_name) in the current directory and returns the file name. The generated file exports, for a function named f, the evaluation routine int f(const casadi_real** arg, casadi_real** res, casadi_int* iw, casadi_real* w, int mem) plus f_n_in, f_n_out, f_name_in, f_name_out, f_sparsity_in, f_sparsity_out, f_work, f_checkout, f_release, f_incref, f_decref and f_default_in. The arrays hold the nonzeros of each input and output in column-major order; work vector sizes come from f_work. Functions embedded in the graph (solvers, maps, ...) are generated too when they support code generation; otherwise an error is raised. The same file can hold several functions via the CodeGenerator class.

Parameters:
  • fname -- File name, e.g. "f.c" or "f"

  • opts -- Code generator options: "with_header" (also write a.h file), "main" (add a main() reading inputs from a file written by generate_in), "casadi_real" (scalar type, default "double"), "casadi_int" (integer type), "with_mem" (simplified memory API), "mex", "cpp", "indent", "prefix", "verbose", "with_export", "with_import", "include_math", "infinity", "nan", "real_min", "unroll_args", "codegen_scalars", "avoid_stack", "thread_safe", "force_canonical"

>>> import os
>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
>>> fname = f.generate("f.c")
>>> fname, os.path.isfile("f.c")
('f.c', True)
>>> src = open("f.c").read()
>>> print("int f(const casadi_real** arg, casadi_real** res" in src, "f_n_in" in src)
True True
>>> os.remove("f.c")
>>> f.generate("g", {"with_header": True}), sorted(os.listdir(".")).count("g.h")
('g.c', 1)
>>> os.remove("g.c"); os.remove("g.h")
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y, sin(x)}, {'x', 'y'}, {'r', 's'});
>> fname = f.generate('f.c'); disp(fname), disp(isfile('f.c'))
f.c
1
>> src = fileread('f.c');
>> disp(contains(src, 'int f(const casadi_real** arg, casadi_real** res'))
1
>> contains(src, 'f_n_in')
1
>> delete('f.c');
>> f.generate('g', struct('with_header', true)), isfile('g.h')
g.c
1
>> delete('g.c'); delete('g.h');
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"]);
julia> fname = ca.generate(f, "f.c")
"f.c"
julia> isfile("f.c")
true
julia> src = read("f.c", String);
julia> occursin("int f(const casadi_real** arg, casadi_real** res", src)
true
julia> occursin("f_n_in", src)
true
julia> rm("f.c")
julia> ca.generate(f, "g", Dict("with_header" => true)), isfile("g.h")
("g.c", true)
julia> rm("g.c"); rm("g.h")

See also: CodeGenerator, generate_in, generate_out, jit, external

Extra doc | Doc source | Implementation

generate_dependencies(...)

Generate C code for the problem functions of a solver object.

generate_dependencies(self, str fname, dict opts) -> str

Only defined for solver classes built on an oracle (nlpsol, rootfinder, integrator, ...): writes code for the helper functions (e.g. nlp_f, nlp_jac_g) into fname and returns the file name. Other classes raise an error. The library compiled from this file can be loaded with external and passed back to the solver constructor in place of the symbolic problem.

Parameters:
  • fname -- File name

  • opts -- Code generator options, as for generate

See also: generate, external

Extra doc | Doc source | Implementation

generate_in(...)
generate_in(self, str fname) -> [DM]
generate_in(self, str fname, [DM] arg)

Write or read a text file with the nonzeros of all inputs.

With arguments, writes the nonzeros of arg (one value per line, in input order) to fname; this is the input format read by code generated with option "main". Without arguments, reads such a file back into a list of DM with the input sparsities. The arguments follow the shape rules of call (scalars are broadcast); a file with the wrong number of values raises a dimension error.

>>> import os
>>> f = Function("f", [SX.sym("x"), SX.sym("y", 2)], [SX(0)])
>>> f.generate_in("f_in.txt", [1, [2, 3]])
>>> open("f_in.txt").read().split()
['1.0000000000000000e+00', '2.0000000000000000e+00', '3.0000000000000000e+00']
>>> f.generate_in("f_in.txt")
[DM(1), DM([2, 3])]
>>> os.remove("f_in.txt")
>> f = Function('f', {SX.sym('x'), SX.sym('y', 2)}, {SX(0)});
>> f.generate_in('f_in.txt', {1, [2; 3]});
>> fileread('f_in.txt')
1.0000000000000000e+00
2.0000000000000000e+00
3.0000000000000000e+00
>> arg = f.generate_in('f_in.txt'); disp(arg{1}), disp(arg{2})
1
[2, 3]
>> delete('f_in.txt');
julia> f = ca.Function("f", [ca.SX.sym("x"), ca.SX.sym("y", 2)], [ca.SX(0)]);
julia> ca.generate_in(f, "f_in.txt", [1, [2, 3]])
julia> split(read("f_in.txt", String))
3-element Vector{SubString{String}}:
 "1.0000000000000000e+00"
 "2.0000000000000000e+00"
 "3.0000000000000000e+00"
julia> ca.generate_in(f, "f_in.txt")
2-element Vector{DM}:
 DM(1)
 DM([2, 3])
julia> rm("f_in.txt")

See also: generate_out, nz_from_in, nz_to_in, generate

Extra doc | Doc source | Implementation

generate_lifted(...)

Extract the functions needed for the Lifted Newton method (MXFunction only)

generate_lifted(self) -> (Function, Function)

Returns two functions: one defining the lifted variables and one for their initialization. Raises for other classes.

Extra doc | Doc source | Implementation

generate_out(...)
generate_out(self, str fname) -> [DM]
generate_out(self, str fname, [DM] arg)

Write or read a text file with the nonzeros of all outputs.

Same format as generate_in, for the outputs: the file written by generated code with option "main" can be read back and compared with the result of call.

>>> import os
>>> x = SX.sym("x")
>>> f = Function("f", [x], [x, 2*x])
>>> f.generate_out("f_out.txt", f.call([1.5]))
>>> f.generate_out("f_out.txt")
[DM(1.5), DM(3)]
>>> os.remove("f_out.txt")
>> x = SX.sym('x');
>> f = Function('f', {x}, {x, 2*x});
>> f.generate_out('f_out.txt', f.call({1.5}));
>> res = f.generate_out('f_out.txt'); disp(res{1}), disp(res{2})
1.5
3
>> delete('f_out.txt');
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [x, 2x]);
julia> ca.generate_out(f, "f_out.txt", ca.call(f, [1.5]))
julia> ca.generate_out(f, "f_out.txt")
2-element Vector{DM}:
 DM(1.5)
 DM(3)
julia> rm("f_out.txt")

See also: generate_in, nz_from_out, nz_to_out

Extra doc | Doc source | Implementation

get_free(...)

Get the names of the free variables; empty when there are none.

get_free(self) -> [str]

See also: has_free, free_sx, free_mx

Extra doc | Doc source | Implementation

get_function(...)

Get a directly owned function by name; unknown names raise an error.

get_function(self) -> [str]
get_function(self, str name) -> Function

See also: has_function, find_function

Get the names of the functions this function directly owns.

For an SXFunction or MXFunction: the functions called in its graph (an MXFunction called with MX arguments is inlined and does not appear; SX functions, solvers and calls made with never_inline do); for a map: the mapped function; for a solver: its helper functions (e.g. nlp_f, nlp_jac_g for nlpsol, which can also be code-generated with generate_dependencies). Empty for leaf classes. Note that has_function only answers true for solver objects; for SX and MX functions it is false even for names in this list.

>>> x = MX.sym("x")
>>> f = Function("f", [x], [sin(x)]).expand()
>>> g = Function("g", [x], [f(x) + 1])
>>> g.get_function(), g.has_function("f")
(['f'], True)
>>> g.get_function("f")
Function(f:(i0)->(o0) SXFunction)
>>> try:
...   g.get_function("h")
... except RuntimeError as e:
...   print("No such function 'h'" in str(e))
True
>> x = MX.sym('x');
>> f = Function('f', {x}, {sin(x)}).expand();
>> g = Function('g', {x}, {f(x) + 1});
>> g.get_function(), g.has_function('f')
f
1
>> g.get_function('f')
f:(i0)->(o0) SXFunction
>> try, g.get_function('h'); catch e, disp(contains(e.message, 'No such function')); end
1
julia> x = ca.MX.sym("x");
julia> f = ca.expand(ca.Function("f", [x], [sin(x)]));
julia> g = ca.Function("g", [x], [f(x) + 1]);
julia> ca.get_function(g), ca.has_function(g, "f")
(["f"], true)
julia> ca.get_function(g, "f")
Function(f:(i0)->(o0) SXFunction)
julia> try
           ca.get_function(g, "h")
       catch e
           println(occursin("No such function 'h'", sprint(showerror, e)))
       end
true

See also: has_function, find_functions, oracle

Extra doc | Doc source | Implementation

has_free(...)

Check whether the outputs contain symbols that are not inputs.

has_free(self) -> bool

Only possible for SXFunction and MXFunction constructed with "allow_free". Such a function can be called symbolically but not numerically, expanded, code-generated or differentiated into a numerically usable form.

>>> x = SX.sym("x"); p = SX.sym("p")
>>> f = Function("f", [x], [x*p], {"allow_free": True})
>>> f.has_free(), f.get_free(), f.free_sx()
(True, ['p'], [SX(p)])
>>> try:
...   f(1)
... except RuntimeError as e:
...   print("since variables [p] are free" in str(e))
True
>>> f(SX.sym("q"))
SX((q*p))
>>> Function("g", [x], [x]).has_free()
False
>> x = SX.sym('x'); p = SX.sym('p');
>> f = Function('f', {x}, {x*p}, struct('allow_free', true));
>> disp(f.has_free()), disp(f.get_free()), fr = f.free_sx(); disp(fr{1})
1
p
p
>> try, f(1); catch e, disp(contains(e.message, 'variables [p] are free')); end
1
>> f(SX.sym('q'))
(q*p)
>> Function('g', {x}, {x}).has_free()
0
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> f = ca.Function("f", [x], [x*p], Dict("allow_free" => true));
julia> ca.has_free(f), ca.get_free(f), ca.free_sx(f)
(true, ["p"], SX[p])
julia> try
           f(1)
       catch e
           println(occursin("since variables [p] are free", sprint(showerror, e)))
       end
true
julia> f(ca.SX.sym("q"))
SX((q*p))
julia> ca.has_free(ca.Function("g", [x], [x]))
false

See also: get_free, free_sx, free_mx

Extra doc | Doc source | Implementation

has_function(...)

Check if a particular dependency exists.

has_function(self, str fname) -> bool

True if fname is among the names returned by get_function().

See also: get_function

Extra doc | Doc source | Implementation

has_in(...)

Check whether an input with the given name exists.

has_in(self, str name) -> bool
>>> f = Function("f", [SX.sym("x")], [SX(0)], ["x"], ["r"])
>>> f.has_in("x"), f.has_in("r"), f.has_out("r"), f.has_out("x")
(True, False, True, False)
>> f = Function('f', {SX.sym('x')}, {SX(0)}, {'x'}, {'r'});
>> fprintf('%d %d %d %d\n', f.has_in('x'), f.has_in('r'), f.has_out('r'), f.has_out('x'))
1 0 1 0
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)], ["x"], ["r"]);
julia> ca.has_in(f, "x"), ca.has_in(f, "r"), ca.has_out(f, "r"), ca.has_out(f, "x")
(true, false, true, false)

See also: has_out, index_in

Extra doc | Doc source | Implementation

has_option(...)

Check whether this class accepts an option with the given name.

has_option(self, str option_name) -> bool
>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.has_option("live_variables"), f.has_option("ipopt")
(True, False)
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> fprintf('%d %d\n', f.has_option('live_variables'), f.has_option('ipopt'))
1 0
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.has_option(f, "live_variables"), ca.has_option(f, "ipopt")
(true, false)

See also: print_options, change_option

Extra doc | Doc source | Implementation

has_out(...)

Check whether an output with the given name exists.

has_out(self, str name) -> bool

See also: has_in, index_out

Extra doc | Doc source | Implementation

has_spfwd(...)

Check whether the class supports forward (has_spfwd) or reverse (has_sprev)

has_spfwd(self) -> bool

sparsity propagation

Both are true for SXFunction and MXFunction; classes without it fall back to dense Jacobian sparsity patterns.

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.has_spfwd(), f.has_sprev()
(True, True)
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> fprintf('%d %d\n', f.has_spfwd(), f.has_sprev())
1 1
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.has_spfwd(f), ca.has_sprev(f)
(true, true)

See also: jac_sparsity

Extra doc | Doc source | Implementation

has_sprev(...)

Check whether the class supports forward (has_spfwd) or reverse (has_sprev)

has_sprev(self) -> bool

sparsity propagation

Both are true for SXFunction and MXFunction; classes without it fall back to dense Jacobian sparsity patterns.

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.has_spfwd(), f.has_sprev()
(True, True)
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> fprintf('%d %d\n', f.has_spfwd(), f.has_sprev())
1 1
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.has_spfwd(f), ca.has_sprev(f)
(true, true)

See also: jac_sparsity

Extra doc | Doc source | Implementation

hessian_old(...)

[DEPRECATED] Hessian and gradient of scalar output oind w.r.t. input

hessian_old(self, int iind, int oind) -> Function

iind, followed by all outputs; use factory with "hess:out:in:in" instead

Extra doc | Doc source | Implementation

static if_else(...)

Create a function that evaluates f_true or f_false depending on.

if_else(str name, Function f_true, Function f_false, dict opts) -> Function

a condition input

The result takes the condition as first input followed by the inputs of the branches; a nonzero condition (truncated to integer) selects f_true, zero selects f_false. Only the selected branch is evaluated numerically. The signature is taken from f_false (see conditional).

>>> x = SX.sym("x")
>>> f = Function.if_else("f", Function("t", [x], [x**2]), Function("e", [x], [x]))
>>> f
Function(f:(i0,i1)->(o0) Switch)
>>> f(1, 3), f(0, 3), f(5, 3)
(DM(9), DM(3), DM(9))
>> x = SX.sym('x');
>> f_true = Function('t', {x}, {x^2}); f_false = Function('e', {x}, {x});
>> f = Function.if_else('f', f_true, f_false); disp(f)
f:(i0,i1)->(o0) Switch
>> [f(1, 3), f(0, 3), f(5, 3)]
[[9, 3, 9]]
julia> x = ca.SX.sym("x");
julia> f_true = ca.Function("t", [x], [x^2]); f_false = ca.Function("e", [x], [x]);
julia> f = ca.Function.if_else("f", f_true, f_false);
julia> f
Function(f:(i0,i1)->(o0) Switch)
julia> f(1, 3), f(0, 3), f(5, 3)
(9, 3, 9)

See also: conditional

Extra doc | Doc source | Implementation

index_in(...)

Get the index of the input with a given name.

index_in(self, str name) -> int

Raises an error listing the available names when no input is called name. Use has_in to test without raising.

>>> f = Function("f", [SX.sym("x"), SX.sym("y")], [SX(0)], ["x", "y"], ["r"])
>>> f.index_in("y"), f.index_out("r")
(1, 0)
>>> try:
...   f.index_in("z")
... except RuntimeError as e:
...   print('could not find entry "z". Available names are: [x, y]' in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('y')}, {SX(0)}, {'x', 'y'}, {'r'});
>> fprintf('%d %d\n', f.index_in('y'), f.index_out('r'))
1 0
>> try, f.index_in('z'); catch e, disp(contains(e.message, 'find entry "z"')); end
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> f = ca.Function("f", [x, y], [ca.SX(0)], ["x", "y"], ["r"]);
julia> ca.index_in(f, "y"), ca.index_out(f, "r")
(1, 0)
julia> try
           ca.index_in(f, "z")
       catch e
           msg = sprint(showerror, e)
           println(occursin("could not find entry \"z\". Available names are: [x, y]", msg))
       end
true

See also: index_out, has_in, name_in

Extra doc | Doc source | Implementation

index_out(...)

Get the index of the output with a given name; unknown names raise an error.

index_out(self, str name) -> int

See also: index_in, has_out, name_out

Extra doc | Doc source | Implementation

info(...)

Get class-specific information as a dict.

info(self) -> dict

Empty for most classes; e.g. a Switch (conditional, if_else) reports its branch functions.

>>> x = SX.sym("x")
>>> Function("f", [x], [x]).info()
{}
>> x = SX.sym('x');
>> isempty(fieldnames(Function('f', {x}, {x}).info()))
1
julia> x = ca.SX.sym("x");
julia> ca.info(ca.Function("f", [x], [x]))
Dict{String, Any}()

Extra doc | Doc source | Implementation

instruction_MX(...)

Get the MX expression computed by instruction k of an MXFunction.

instruction_MX(self, int k) -> MX

SXFunction raises; use instructions_sx instead.

>>> x = MX.sym("x")
>>> f = Function("f", [x], [2*sin(x)])
>>> [str(f.instruction_MX(k)) for k in range(f.n_instructions())]
['input[0][0]', 'sin(x)', '(2.*sin(x))', 'output[0][0]']
>> x = MX.sym('x');
>> f = Function('f', {x}, {2*sin(x)});
>> for k = 0:f.n_instructions()-1, disp(f.instruction_MX(k)); end
input[0][0]
sin(x)
(2.*sin(x))
output[0][0]
julia> x = ca.MX.sym("x");
julia> f = ca.Function("f", [x], [2sin(x)]);
julia> [string(ca.instruction_MX(f, k)) for k in 0:ca.n_instructions(f)-1]
4-element Vector{String}:
 "input[0][0]"
 "sin(x)"
 "(2.*sin(x))"
 "output[0][0]"

See also: n_instructions, instructions_sx

Extra doc | Doc source | Implementation

instruction_constant(...)

Get the value of a constant instruction (OP_CONST) of an SXFunction.

instruction_constant(self, int k) -> float

Only meaningful for constant instructions; MXFunction raises.

See also: instruction_id, n_instructions

Extra doc | Doc source | Implementation

instruction_id(...)

Get the operation code of instruction k (SXFunction and MXFunction)

instruction_id(self, int k) -> int

The codes are the OP_* constants (OP_INPUT, OP_OUTPUT, OP_CONST, OP_ADD, OP_MUL, OP_SIN, ...; OP_CALL for a call node in an MXFunction).

See also: n_instructions, instruction_input, instruction_output

Extra doc | Doc source | Implementation

instruction_input(...)

Get the work-vector locations read by instruction k.

instruction_input(self, int k) -> [int]

For an input instruction (OP_INPUT) the pair is [input index, nonzero index]. (SXFunction and MXFunction)

See also: instruction_output, n_instructions

Extra doc | Doc source | Implementation

instruction_output(...)

Get the work-vector locations written by instruction k.

instruction_output(self, int k) -> [int]

For an output instruction (OP_OUTPUT) the pair is [output index, nonzero index]. (SXFunction and MXFunction)

See also: instruction_input, n_instructions

Extra doc | Doc source | Implementation

instructions_sx(...)

Get the SX expression of every instruction of an SXFunction, as one vector.

instructions_sx(self) -> SX

Entry k is the expression computed by instruction k; input and output instructions have no expression and are nan. MXFunction raises.

>>> x = SX.sym("x")
>>> f = Function("f", [x], [2*sin(x)])
>>> f.instructions_sx()
SX(@1=nan, @2=sin(x), [@1, @2, (2.*@2), @1])
>> x = SX.sym('x');
>> f = Function('f', {x}, {2*sin(x)});
>> f.instructions_sx()
@1=nan, @2=sin(x), [@1, @2, (2.*@2), @1]
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [2sin(x)]);
julia> ca.instructions_sx(f)
SX(@1=nan, @2=sin(x), [@1, @2, (2.*@2), @1])

See also: n_instructions, instruction_MX

Extra doc | Doc source | Implementation

is_a(...)

Check whether the function is of a given class.

is_a(self, str type, bool recursive) -> bool

type is a class name as printed after the signature: "SXFunction", "MXFunction", "Map", "Switch", "External", "Nlpsol", "Conic", "Integrator", "Rootfinder" and the plugin names (e.g. "Ipopt"). With recursive true (default) base classes match as well ("Nlpsol" for an Ipopt solver, "Map" for a ThreadMap, "FunctionInternal" for everything).

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.is_a("SXFunction"), f.is_a("MXFunction"), f.class_name()
(True, False, 'SXFunction')
>>> f.map(2, "thread").is_a("Map"), f.map(2, "thread").is_a("Map", False)
(True, False)
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> fprintf('%d %d %s\n', f.is_a('SXFunction'), f.is_a('MXFunction'), f.class_name())
1 0 SXFunction
>> F = f.map(2, 'thread'); fprintf('%d %d\n', F.is_a('Map'), F.is_a('Map', false))
1 0
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.is_a(f, "SXFunction"), ca.is_a(f, "MXFunction"), ca.class_name(f)
(true, false, "SXFunction")
julia> F = f.map(2, "thread");
julia> ca.is_a(F, "Map"), ca.is_a(F, "Map", false)
(true, false)

See also: class_name

Extra doc | Doc source | Implementation

is_diff_in(...)
is_diff_in(self) -> [bool]
is_diff_in(self, int ind) -> bool

Check which inputs or outputs are marked differentiable.

All true by default; set with options "is_diff_in" and "is_diff_out". A non-differentiable input or output is skipped by jacobian, forward, reverse and factory: the corresponding derivative blocks are all-zero sparse. The signature printout marks them with a '#'. Without argument, the list for all inputs or outputs is returned.

>>> x = SX.sym("x"); n = SX.sym("n")
>>> f = Function("f", [x, n], [x*n], ["x", "n"], ["r"], {"is_diff_in": [True, False]})
>>> f
Function(f:(x,#n)->(r) SXFunction)
>>> f.is_diff_in(), f.is_diff_in(1), f.is_diff_out()
([True, False], False, [True])
>>> f.jacobian()
Function(jac_f:(x,#n,out_r[1x1,0nz])->(jac_r_x,#jac_r_n[1x1,0nz]) SXFunction)
>> x = SX.sym('x'); n = SX.sym('n');
>> opts = struct('is_diff_in', [true, false]);
>> f = Function('f', {x, n}, {x*n}, {'x', 'n'}, {'r'}, opts); disp(f)
f:(x,#n)->(r) SXFunction
>> f.is_diff_in(), f.is_diff_in(1), f.is_diff_out()
1 0
0
1
>> f.jacobian()
jac_f:(x,#n,out_r[1x1,0nz])->(jac_r_x,#jac_r_n[1x1,0nz]) SXFunction
julia> x = ca.SX.sym("x"); n = ca.SX.sym("n");
julia> opts = Dict("is_diff_in" => [true, false]);
julia> f = ca.Function("f", [x, n], [x*n], ["x", "n"], ["r"], opts);
julia> f
Function(f:(x,#n)->(r) SXFunction)
julia> ca.is_diff_in(f), ca.is_diff_in(f, 1), ca.is_diff_out(f)
(Bool[1, 0], false, Bool[1])
julia> ca.jacobian(f)
Function(jac_f:(x,#n,out_r[1x1,0nz])->(jac_r_x,#jac_r_n[1x1,0nz]) SXFunction)

See also: jacobian

Extra doc | Doc source | Implementation

is_diff_out(...)
is_diff_out(self) -> [bool]
is_diff_out(self, int ind) -> bool

Check which inputs or outputs are marked differentiable.

All true by default; set with options "is_diff_in" and "is_diff_out". A non-differentiable input or output is skipped by jacobian, forward, reverse and factory: the corresponding derivative blocks are all-zero sparse. The signature printout marks them with a '#'. Without argument, the list for all inputs or outputs is returned.

>>> x = SX.sym("x"); n = SX.sym("n")
>>> f = Function("f", [x, n], [x*n], ["x", "n"], ["r"], {"is_diff_in": [True, False]})
>>> f
Function(f:(x,#n)->(r) SXFunction)
>>> f.is_diff_in(), f.is_diff_in(1), f.is_diff_out()
([True, False], False, [True])
>>> f.jacobian()
Function(jac_f:(x,#n,out_r[1x1,0nz])->(jac_r_x,#jac_r_n[1x1,0nz]) SXFunction)
>> x = SX.sym('x'); n = SX.sym('n');
>> opts = struct('is_diff_in', [true, false]);
>> f = Function('f', {x, n}, {x*n}, {'x', 'n'}, {'r'}, opts); disp(f)
f:(x,#n)->(r) SXFunction
>> f.is_diff_in(), f.is_diff_in(1), f.is_diff_out()
1 0
0
1
>> f.jacobian()
jac_f:(x,#n,out_r[1x1,0nz])->(jac_r_x,#jac_r_n[1x1,0nz]) SXFunction
julia> x = ca.SX.sym("x"); n = ca.SX.sym("n");
julia> opts = Dict("is_diff_in" => [true, false]);
julia> f = ca.Function("f", [x, n], [x*n], ["x", "n"], ["r"], opts);
julia> f
Function(f:(x,#n)->(r) SXFunction)
julia> ca.is_diff_in(f), ca.is_diff_in(f, 1), ca.is_diff_out(f)
(Bool[1, 0], false, Bool[1])
julia> ca.jacobian(f)
Function(jac_f:(x,#n,out_r[1x1,0nz])->(jac_r_x,#jac_r_n[1x1,0nz]) SXFunction)

See also: jacobian

Extra doc | Doc source | Implementation

is_null(...)
is_null(self) -> bool
jac_sparsity(...)

Get the sparsity pattern of the Jacobian of output oind w.r.t. input.

jac_sparsity(self, bool compact) -> [Sparsity]
jac_sparsity(self, int oind, int iind, bool compact) -> Sparsity

iind

>>> x = SX.sym("x"); D = SX.sym("D", Sparsity.diag(2))
>>> f = Function("f", [x, D], [x*D, sin(x)])
>>> f.jac_sparsity(0, 1), f.jac_sparsity(0, 1, True), f.jac_sparsity(1, 1)
(Sparsity(4x4,2nz), Sparsity(2x2,2nz), Sparsity(1x4,0nz))
>> x = SX.sym('x'); D = SX.sym('D', Sparsity.diag(2));
>> f = Function('f', {x, D}, {x*D, sin(x)});
>> f.jac_sparsity(0, 1), f.jac_sparsity(0, 1, true), f.jac_sparsity(1, 1)
4x4,2nz
2x2,2nz
1x4,0nz
julia> x = ca.SX.sym("x"); D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [x, D], [x*D, sin(x)]);
julia> ca.jac_sparsity(f, 0, 1), ca.jac_sparsity(f, 0, 1, true), ca.jac_sparsity(f, 1, 1)
(4x4,2nz, 2x2,2nz, 1x4,0nz)

See also: jacobian

Get the sparsity patterns of all Jacobian blocks.

One pattern per (output, input) pair, ordered by output first, as in jacobian. Patterns are computed by sparsity propagation the first time and cached.

Parameters:

compact -- When true, the pattern is over the nonzeros of output and input (nnz_out-by-nnz_in) rather than over all elements (numel_out-by-numel_in)

>>> x = SX.sym("x"); D = SX.sym("D", Sparsity.diag(2))
>>> f = Function("f", [x, D], [x*D, sin(x)])
>>> f.jac_sparsity()
[Sparsity(4x1,2nz), Sparsity(4x4,2nz), Sparsity(1x1), Sparsity(1x4,0nz)]
>>> f.jac_sparsity(True)
[Sparsity(2x1), Sparsity(2x2,2nz), Sparsity(1x1), Sparsity(1x2,0nz)]
>> x = SX.sym('x'); D = SX.sym('D', Sparsity.diag(2));
>> f = Function('f', {x, D}, {x*D, sin(x)});
>> sp = f.jac_sparsity(); disp(numel(sp)), cellfun(@disp, sp)
4
4x1,2nz
4x4,2nz
1x1
1x4,0nz
>> cellfun(@disp, f.jac_sparsity(true))
2x1
2x2,2nz
1x1
1x2,0nz
julia> x = ca.SX.sym("x"); D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [x, D], [x*D, sin(x)]);
julia> ca.jac_sparsity(f)
4-element Vector{Sparsity}:
 Sparsity(4x1,2nz)
 Sparsity(4x4,2nz)
 Sparsity(1x1)
 Sparsity(1x4,0nz)
julia> ca.jac_sparsity(f, true)
4-element Vector{Sparsity}:
 Sparsity(2x1)
 Sparsity(2x2,2nz)
 Sparsity(1x1)
 Sparsity(1x2,0nz)

See also: jacobian, which_depends

Extra doc | Doc source | Implementation

jacobian(...)

Get a function computing all Jacobian blocks at once.

jacobian(self) -> Function

The result is named jac_<name> and takes all inputs followed by all outputs (named out_<output>); the output values are only read when uses_output() is true and may be passed as 0 otherwise. It returns one block per (output, input) pair, ordered by output first: for f:(x,y)->(r,s) the outputs are jac_r_x, jac_r_y, jac_s_x, jac_s_y. Blocks involving a non-differentiable input or output are all-zero sparse. Each block is a size_out(o)-times- size_in(i) matrix where the output and input are vectorized column-major; blocks that are structurally zero have an all-zero sparsity pattern.

The result is cached: calling jacobian again returns the same object as long as it is alive. The derivative itself is built by symbolic AD for SX and MX functions, by the solver's own sensitivity method for solver objects, or raises "Derivatives cannot be calculated" for classes without any derivative support. For a single block, factory("...", ..., ["jac:r:x"]) avoids computing the others.

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
>>> J = f.jacobian()
>>> print(J)
jac_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz])->(jac_r_x[2],jac_r_y[2x2,2nz],...) SXFunction
>>> J(1, [2, 3], 0, 0)
(DM([2, 3]), DM(
[[1, 00],
 [00, 1]]), DM(0.540302), DM([[00, 00]]))
>>> f.jacobian().name_out()
['jac_r_x', 'jac_r_y', 'jac_s_x', 'jac_s_y']
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y, sin(x)}, {'x', 'y'}, {'r', 's'});
>> J = f.jacobian(); disp(J)
jac_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz])->(jac_r_x[2],jac_r_y[2x2,2nz],...) SXFunction
>> [jac_r_x, jac_r_y, jac_s_x, jac_s_y] = J(1, [2; 3], 0, 0);
>> jac_r_x, jac_r_y, jac_s_x, jac_s_y
[2, 3]
[[1, 00],
[00, 1]]
0.540302
[[00, 00]]
>> J.name_out()
jac_r_x
jac_r_y
jac_s_x
jac_s_y
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"]);
julia> J = ca.jacobian(f);
julia> ca.name(J), ca.n_in(J), ca.n_out(J)
("jac_f", 4, 4)
julia> jac_r_x, jac_r_y, jac_s_x, jac_s_y = J(1, [2, 3], 0, 0);
julia> jac_r_x, jac_s_x, jac_s_y
([2, 3], 0.540302, [[00, 00]])
julia> jac_r_y
DM(
[[1, 00],
 [00, 1]])
julia> ca.name_out(J)
4-element Vector{String}:
 "jac_r_x"
 "jac_r_y"
 "jac_s_x"
 "jac_s_y"

See also: factory, forward, reverse, jac_sparsity, uses_output

Extra doc | Doc source | Implementation

jacobian_old(...)

[DEPRECATED] Jacobian of output oind w.r.t. input iind, followed by

jacobian_old(self, int iind, int oind) -> Function

all outputs; use factory with "jac:out:in" instead

Extra doc | Doc source | Implementation

static jit(...)
jit(str name, str body, [str] name_in, [str] name_out, dict opts) -> Function
jit(str name, str body, [str] name_in, [str] name_out, [Sparsity] sparsity_in, [Sparsity] sparsity_out, dict opts) -> Function

Create a just-in-time compiled function from a C language string.

body is the body of a C function that is compiled with the "compiler" plugin (option "compiler", default "shell" i.e. the system C compiler on most builds, or "clang") and loaded as an external function. This needs a working C compiler at run time; the source and library files are removed afterwards unless "jit_cleanup" is false.

Inside the body, the nonzeros of input k are available through a pointer named name_in[k] (type const casadi_real*) and the nonzeros of output k must be written through a pointer named name_out[k] (type casadi_real*), in column-major order of the sparsity pattern. casadi_real is double unless the code generator is told otherwise. By default (option "buffered": true) inputs and outputs are copied through a work vector, so the pointers are never null; with "buffered": false a null input means all-zero and a null output may be skipped. Write "return 1;" to signal an evaluation failure.

The result has no derivatives unless option "enable_fd": true (finite differences) is passed or a C body for the Jacobian is supplied with option "jac" (and "hess" for its Jacobian).

Parameters:
  • name -- Function name

  • body -- C code of the function body, without the enclosing braces

  • name_in -- Input names, also the C variable names

  • name_out -- Output names, also the C variable names

  • sparsity_in -- Sparsity of each input; all scalar when omitted

  • sparsity_out -- Sparsity of each output; all scalar when omitted

  • opts -- Options; "compiler", "jit_options", "buffered", "jac", "hess" and the common Function options

Example (not run here because it invokes a compiler): f = Function.jit("f", "r[0] = x[0]*x[0] + y[0];", ["x", "y"], ["r"]) gives a function f:(x,y)->(r) that evaluates like any other Function.

See also: external

Extra doc | Doc source | Implementation

static load(...)

Read a function from a file written by save.

load(str filename) -> Function

The file must contain exactly one Function (as written by save); a file written by FileSerializer with other objects raises an error pointing to FileDeserializer, a missing file raises "Could not open".

See also: save, deserialize, FileDeserializer

Extra doc | Doc source | Implementation

map(...)
map(self, int n, str parallelization) -> Function
map(self, int n, [bool] reduce_in, [bool] reduce_out, dict opts) -> Function
map(self, int n, str parallelization, int max_num_threads) -> Function
map(self, str name, str parallelization, int n, [str] reduce_in, [str] reduce_out, dict opts) -> Function
map(self, str name, str parallelization, int n, [int] reduce_in, [int] reduce_out, dict opts) -> Function

Overload: map(self, int n, str parallelization)

Create a function that evaluates this function n times on stacked arguments.

For f:(a, p)->(s) the result is F:(A, P)->(S) with A = horzcat(a0, ..., a_(n-1)), the same for P, and S = horzcat(f(a0, p0), ..., f(a_(n-1), p_(n-1))). Every input and output is widened to n times its number of columns; when calling, a non-widened argument is repeated for all evaluations. The graph size and construction time are independent of n. For n == 1 the function itself is returned; n < 1 raises "Degenerate map operation".

Parameters:
  • n -- Number of evaluations

  • parallelization -- How the evaluations are run: "serial" (a Map node evaluated in a loop; cached, so repeated calls return the same object), "openmp" (OpenMP parallel loop, requires an OpenMP build), "thread" (std::thread per evaluation), "unroll" (n explicit calls in an MXFunction), "inline" (like unroll with the calls inlined). Other values raise an error.

  • max_num_threads -- With "thread" or "openmp": split the n evaluations into at most this many parallel chunks, each a serial map

>>> x = SX.sym("x"); p = SX.sym("p")
>>> f = Function("f", [x, p], [p*x**2], ["x", "p"], ["y"])
>>> F = f.map(3)
>>> F
Function(map3_f:(x[1x3],p[1x3])->(y[1x3]) Map)
>>> F(DM([[1, 2, 3]]), 2)
DM([[2, 8, 18]])
>>> f.map(4, "thread", 2)
Function(threadmap2_map2_f:(x[1x4],p[1x4])->(y[1x4]) ThreadMap)
>>> f.map(3, "unroll")
Function(f_3:(x[1x3],p[1x3])->(y[1x3]) MXFunction)
>>> f.map(1) is f, f.map(1).name()
(False, 'f')
>> x = SX.sym('x'); p = SX.sym('p');
>> f = Function('f', {x, p}, {p*x^2}, {'x', 'p'}, {'y'});
>> F = f.map(3); disp(F)
map3_f:(x[1x3],p[1x3])->(y[1x3]) Map
>> F(DM([1, 2, 3]), 2)
[[2, 8, 18]]
>> f.map(4, 'thread', 2)
threadmap2_map2_f:(x[1x4],p[1x4])->(y[1x4]) ThreadMap
>> f.map(3, 'unroll')
f_3:(x[1x3],p[1x3])->(y[1x3]) MXFunction
>> f.map(1).name()
f
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> f = ca.Function("f", [x, p], [p*x^2], ["x", "p"], ["y"]);
julia> F = f.map(3);
julia> F
Function(map3_f:(x[1x3],p[1x3])->(y[1x3]) Map)
julia> F([1 2 3], 2)
DM([[2, 8, 18]])
julia> f.map(4, "thread", 2)
Function(threadmap2_map2_f:(x[1x4],p[1x4])->(y[1x4]) ThreadMap)
julia> f.map(3, "unroll")
Function(f_3:(x[1x3],p[1x3])->(y[1x3]) MXFunction)
julia> f.map(1) === f, ca.name(f.map(1))
(false, "f")

See also: mapaccum, mapsum, call

Overload: map(self, str name, str parallelization, int n, [int] reduce_in, [int] reduce_out, dict opts)

Map where some inputs are shared and some outputs are summed.

Inputs listed in reduce_in are not widened: the same value is used in all n evaluations. Outputs listed in reduce_out are summed over the evaluations instead of stacked. The index and name overloads build an MXFunction around a plain map (parallelization as in map; opts is currently ignored). The boolean-mask overload creates a dedicated serial MapSum node wrapped in an MXFunction built with opts; masks must have length n_in and n_out (an empty reduce_out means no reduction).

>>> x = SX.sym("x"); p = SX.sym("p")
>>> f = Function("f", [x, p], [p*x, x], ["x", "p"], ["y", "z"])
>>> F = f.map("F", "serial", 3, ["p"], ["y"])
>>> F
Function(F:(x[1x3],p)->(y,z[1x3]) MXFunction)
>>> F(DM([[1, 2, 3]]), 2)
(DM(12), DM([[1, 2, 3]]))
>>> f.map(3, [False, True], [True, False])(DM([[1, 2, 3]]), 2)
(DM(12), DM([[1, 2, 3]]))
>> x = SX.sym('x'); p = SX.sym('p');
>> f = Function('f', {x, p}, {p*x, x}, {'x', 'p'}, {'y', 'z'});
>> F = f.map('F', 'serial', 3, {'p'}, {'y'}); disp(F)
F:(x[1x3],p)->(y,z[1x3]) MXFunction
>> [y, z] = F(DM([1, 2, 3]), 2); disp(y), disp(z)
12
[[1, 2, 3]]
>> G = f.map(3, [false, true], [true, false]);
>> [y, z] = G(DM([1, 2, 3]), 2); disp(y), disp(z)
12
[[1, 2, 3]]
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> f = ca.Function("f", [x, p], [p*x, x], ["x", "p"], ["y", "z"]);
julia> F = f.map("F", "serial", 3, ["p"], ["y"]);
julia> F
Function(F:(x[1x3],p)->(y,z[1x3]) MXFunction)
julia> F([1 2 3], 2)
(12, [[1, 2, 3]])
julia> f.map(3, [false, true], [true, false])([1 2 3], 2)
(12, [[1, 2, 3]])

See also: map, mapsum

Extra doc | Doc source | Implementation

mapaccum(...)
mapaccum(self, int N, dict opts) -> Function
mapaccum(self, str name, int N, dict opts) -> Function
mapaccum(self, str name, int N, int n_accum, dict opts) -> Function
mapaccum(self, str name, int n, [str] accum_in, [str] accum_out, dict opts) -> Function
mapaccum(self, str name, int n, [int] accum_in, [int] accum_out, dict opts) -> Function

Create a function that applies this function N times, feeding outputs back.

as inputs

The first n_accum inputs are accumulators: in every step they take the value of the first n_accum outputs of the previous step. For a step f:(x, u)->(x_next, y) the result is F:(x0, U)->(X, Y) with U = horzcat(u0, ..., u_(N-1)), X = horzcat(x1, ..., x_N), Y = horzcat(y0, ..., y_(N-1)) and x_(k+1), y_k = f(x_k, u_k). Non-accumulated inputs and all outputs are stacked horizontally over the N steps; the accumulator inputs keep their original shape. An accumulator output may be wider than its input (e.g. 1-by-2 feeding a 1-by-1 input): only the last columns are fed back.

Compared with writing the loop in the host language the construction is much faster and the graph is a tower of nested unrolled loops of at most base iterations (option "base", default 10; -1 unrolls completely). This keeps memory use proportional to base rather than N at a small evaluation cost.

The overloads differ in how accumulators are selected: a count n_accum (default 1), or explicit index/name lists accum_in and accum_out of equal length that may pick arbitrary inputs and outputs. The unnamed overload names the result "mapaccum_" + name(). fold is mapaccum returning only the final accumulator state.

Parameters:
  • name -- Name of the result

  • N -- Number of steps, must be positive

  • n_accum -- Number of leading inputs/outputs that are accumulated; at most min(n_in, n_out)

  • opts -- "base" plus options for the resulting MXFunction

>>> x = SX.sym("x"); u = SX.sym("u")
>>> step = Function("step", [x, u], [x + u, x*u], ["x", "u"], ["x_next", "y"])
>>> F = step.mapaccum(3)
>>> F
Function(mapaccum_step:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
>>> F(1, DM([[1, 2, 3]]))
(DM([[2, 4, 7]]), DM([[1, 4, 12]]))
>>> step.mapaccum("F", 3, ["x"], ["x_next"])
Function(F:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
>>> step.fold(3)
Function(fold_step:(x,u[1x3])->(x_next,y[1x3]) MXFunction)
>>> step.fold(3)(1, DM([[1, 2, 3]]))
(DM(7), DM([[1, 4, 12]]))
>>> try:
...   step.mapaccum(0)
... except RuntimeError as e:
...   print("mapaccum: N must be positive" in str(e))
True
>> x = SX.sym('x'); u = SX.sym('u');
>> step = Function('step', {x, u}, {x + u, x*u}, {'x', 'u'}, {'x_next', 'y'});
>> F = step.mapaccum(3); disp(F)
mapaccum_step:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction
>> [X, Y] = F(1, DM([1, 2, 3])); disp(X), disp(Y)
[[2, 4, 7]]
[[1, 4, 12]]
>> step.mapaccum('F', 3, {'x'}, {'x_next'})
F:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction
>> G = step.fold(3); disp(G)
fold_step:(x,u[1x3])->(x_next,y[1x3]) MXFunction
>> [X, Y] = G(1, DM([1, 2, 3])); disp(X), disp(Y)
7
[[1, 4, 12]]
>> try, step.mapaccum(0); catch e, disp(contains(e.message, 'N must be positive')); end
1
julia> x = ca.SX.sym("x"); u = ca.SX.sym("u");
julia> step = ca.Function("step", [x, u], [x + u, x*u], ["x", "u"], ["x_next", "y"]);
julia> F = ca.mapaccum(step, 3);
julia> F
Function(mapaccum_step:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
julia> F(1, [1 2 3])
([[2, 4, 7]], [[1, 4, 12]])
julia> ca.mapaccum(step, "F", 3, ["x"], ["x_next"])
Function(F:(x,u[1x3])->(x_next[1x3],y[1x3]) MXFunction)
julia> ca.fold(step, 3)
Function(fold_step:(x,u[1x3])->(x_next,y[1x3]) MXFunction)
julia> ca.fold(step, 3)(1, [1 2 3])
(7, [[1, 4, 12]])
julia> try
           ca.mapaccum(step, 0)
       catch e
           println(occursin("mapaccum: N must be positive", sprint(showerror, e)))
       end
true

See also: map, fold

Extra doc | Doc source | Implementation

mapsum(...)

Evaluate on horizontally stacked MX arguments and sum the results.

mapsum(self, [MX] x, str parallelization) -> [MX]

Each argument is either the input itself or n copies stacked horizontally (N-by-(n*M) for an N-by-M input); the largest such n sets the number of evaluations and non-stacked arguments are shared across evaluations. Returns the sum over the n evaluations of each output, as MX expressions calling an internal map-and-reduce function.

Parameters:
  • x -- List of n_in() MX arguments

  • parallelization -- "serial" only; other values raise an error

>>> x = SX.sym("x"); y = SX.sym("y")
>>> f = Function("f", [x, y], [x*y, x - y], ["x", "y"], ["p", "d"])
>>> p, d = f.mapsum([MX.sym("a"), MX.sym("b", 1, 3)])
>>> p
MX(mapsum(a, b){0})
>>> f.mapsum([2, DM([[1, 2, 3]])])
[MX(mapsum(2, [[1, 2, 3]]){0}), MX(mapsum(2, [[1, 2, 3]]){1})]
>>> evalf(f.mapsum([2, DM([[1, 2, 3]])])[0])
DM(12)
>> x = SX.sym('x'); y = SX.sym('y');
>> f = Function('f', {x, y}, {x*y, x - y}, {'x', 'y'}, {'p', 'd'});
>> res = f.mapsum({MX.sym('a'), MX.sym('b', 1, 3)}); disp(res{1})
mapsum(a, b){0}
>> res = f.mapsum({2, DM([1, 2, 3])}); disp(res{1}), disp(res{2})
mapsum(2, [[1, 2, 3]]){0}
mapsum(2, [[1, 2, 3]]){1}
>> evalf(res{1})
12
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> f = ca.Function("f", [x, y], [x*y, x - y], ["x", "y"], ["p", "d"]);
julia> p, d = ca.mapsum(f, [ca.MX.sym("a"), ca.MX.sym("b", 1, 3)]);
julia> p
MX(mapsum(a, b){0})
julia> ca.mapsum(f, [2, ca.DM([1 2 3])])
2-element Vector{MX}:
 MX(mapsum(2, [[1, 2, 3]]){0})
 MX(mapsum(2, [[1, 2, 3]]){1})
julia> ca.evalf(ca.mapsum(f, [2, ca.DM([1 2 3])])[1])
DM(12)

See also: map, call

Extra doc | Doc source | Implementation

max_in(...)

Get the largest admissible value of input ind (inf unless a solver.

max_in(self, int ind) -> float

restricts it)

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.max_in(0), f.min_in(0)
(inf, -inf)
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> fprintf('%g %g\n', f.max_in(0), f.min_in(0))
Inf -Inf
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.max_in(f, 0), ca.min_in(f, 0)
(Inf, -Inf)

See also: min_in, default_in

Extra doc | Doc source | Implementation

min_in(...)

Get the smallest admissible value of input ind (-inf unless a solver.

min_in(self, int ind) -> float

restricts it)

See also: max_in, default_in

Extra doc | Doc source | Implementation

mx_in(...)
mx_in(self) -> [MX]
mx_in(self, int ind) -> MX
mx_in(self, str iname) -> MX

Create fresh symbols with the names and sparsity patterns of the inputs.

Convenient for calling the function symbolically or for building a wrapper: f(f.mx_in()) is an MX expression of the outputs. Each call creates new symbols; they are not the symbols the function was constructed from. All inputs (no argument), one by index, or one by name.

>>> f = Function("f", [SX.sym("a"), SX.sym("B", Sparsity.diag(2))], [SX(0)],
...              ["a", "B"], ["r"])
>>> f.sx_in()
[SX(a), SX(
[[B_0, 00],
 [00, B_1]])]
>>> f.mx_in(1), f.mx_in("a").shape
(MX(B), (1, 1))
>>> f.sx_out(), f.mx_out(0)
([SX(r)], MX(r))
>> a = SX.sym('a'); B = SX.sym('B', Sparsity.diag(2));
>> f = Function('f', {a, B}, {SX(0)}, {'a', 'B'}, {'r'});
>> in = f.sx_in(); disp(in{1}), disp(in{2})
a
[[B_0, 00],
[00, B_1]]
>> f.mx_in(1), size(f.mx_in('a'))
B
1 1
>> out = f.sx_out(); disp(out{1}), disp(f.mx_out(0))
r
r
julia> a = ca.SX.sym("a"); B = ca.SX.sym("B", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [a, B], [ca.SX(0)], ["a", "B"], ["r"]);
julia> a_in, B_in = ca.sx_in(f);
julia> a_in
SX(a)
julia> B_in
SX(
[[B_0, 00],
 [00, B_1]])
julia> ca.mx_in(f, 1), size(ca.mx_in(f, "a"))
(B, (1, 1))
julia> ca.sx_out(f), ca.mx_out(f, 0)
(SX[r], r)

See also: sx_out, mx_out, sparsity_in

Extra doc | Doc source | Implementation

mx_out(...)
mx_out(self) -> [MX]
mx_out(self, int ind) -> MX
mx_out(self, str oname) -> MX

Create fresh symbols with the names and sparsity patterns of the outputs.

Useful as adjoint seeds or placeholders; see sx_in.

Extra doc | Doc source | Implementation

n_in(...)

Get the number of function inputs.

n_in(self) -> int
>>> x = SX.sym("x"); y = SX.sym("y")
>>> f = Function("f", [x, y], [x+y, x-y, x*y])
>>> f.n_in(), f.n_out()
(2, 3)
>>> Function("g", [], [DM(1)]).n_in()
0
>> x = SX.sym('x'); y = SX.sym('y');
>> f = Function('f', {x, y}, {x+y, x-y, x*y});
>> fprintf('%d %d\n', f.n_in(), f.n_out())
2 3
>> Function('g', {}, {DM(1)}).n_in()
0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> f = ca.Function("f", [x, y], [x + y, x - y, x*y]);
julia> ca.n_in(f), ca.n_out(f)
(2, 3)
julia> ca.n_in(ca.Function("g", [], [ca.DM(1)]))
0

See also: n_out, name_in, size_in

Extra doc | Doc source | Implementation

n_instructions(...)

Get the number of instructions of the algorithm (SXFunction and MXFunction)

n_instructions(self) -> int

The algorithm is the sequence of operations evaluated for a call, including the input and output instructions; instruction_id, instruction_input, instruction_output, instruction_constant and instruction_MX inspect them by index. Other classes raise.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> f = Function("f", [x, y], [x*y + 1])
>>> f.n_instructions()
6
>>> for k in range(f.n_instructions()):
...   print(f.instruction_id(k), f.instruction_input(k), f.instruction_output(k))
45 [0, 0] [0]
45 [1, 0] [1]
3 [0, 1] [0]
44 [] [1]
1 [0, 1] [0]
46 [0] [0, 0]
>>> f.instruction_id(3) == OP_CONST, f.instruction_constant(3)
(True, 1.0)
>> x = SX.sym('x'); y = SX.sym('y');
>> f = Function('f', {x, y}, {x*y + 1});
>> f.n_instructions()
6
>> arrayfun(@(k) f.instruction_id(k), 0:5)
45 45 3 44 1 46
>> f.instruction_input(2), f.instruction_output(2)
0 1
0
>> f.instruction_id(3) == OP_CONST, f.instruction_constant(3)
1
1
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> f = ca.Function("f", [x, y], [x*y + 1]);
julia> ca.n_instructions(f)
6
julia> for k in 0:ca.n_instructions(f)-1
           println(ca.instruction_id(f, k), " ", ca.instruction_input(f, k), " ",
                   ca.instruction_output(f, k))
       end
45 [0, 0] [0]
45 [1, 0] [1]
3 [0, 1] [0]
44 Int64[] [1]
1 [0, 1] [0]
46 [0] [0, 0]
julia> ca.instruction_id(f, 3) == ca.OP_CONST, ca.instruction_constant(f, 3)
(true, 1.0)

See also: instruction_id, instructions_sx, n_nodes

Extra doc | Doc source | Implementation

n_nodes(...)

Get the number of nodes in the expression graph (SXFunction and MXFunction)

n_nodes(self) -> int

Counts the unique nodes of the output expressions, inputs included; a cheap measure of graph size for comparing transformations. Other classes raise.

>>> x = MX.sym("x")
>>> Function("f", [x], [sin(x) + sin(x)]).n_nodes()
4
>> x = MX.sym('x');
>> Function('f', {x}, {sin(x) + sin(x)}).n_nodes()
4
julia> x = ca.MX.sym("x");
julia> ca.n_nodes(ca.Function("f", [x], [sin(x) + sin(x)]))
4

See also: n_instructions

Extra doc | Doc source | Implementation

n_out(...)

Get the number of function outputs.

n_out(self) -> int
>>> x = SX.sym("x")
>>> Function("f", [x], [x, 2*x]).n_out()
2
>> x = SX.sym('x');
>> Function('f', {x}, {x, 2*x}).n_out()
2
julia> x = ca.SX.sym("x");
julia> ca.n_out(ca.Function("f", [x], [x, 2x]))
2

See also: n_in, name_out, size_out

Extra doc | Doc source | Implementation

name(...)

Get the name given at construction ("null" for a null object)

name(self) -> str
>>> Function("f", [SX.sym("x")], [SX(0)]).name()
'f'
>> Function('f', {SX.sym('x')}, {SX(0)}).name()
f
julia> ca.name(ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]))
"f"

See also: check_name

Extra doc | Doc source | Implementation

name_in(...)

Get the name of input ind; out of range raises an error.

name_in(self) -> [str]
name_in(self, int ind) -> str

Get the names of all inputs, in order.

Names come from the constructor; when none were given they are i0, i1, ... Solver objects have fixed schemes, e.g. x0, p, lbx, ubx, lbg, ubg, lam_x0, lam_g0 for nlpsol.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> Function("f", [x, y], [x+y]).name_in()
['i0', 'i1']
>>> f = Function("f", [x, y], [x+y], ["x", "y"], ["r"])
>>> f.name_in(), f.name_in(1), f.name_out()
(['x', 'y'], 'y', ['r'])
>> x = SX.sym('x'); y = SX.sym('y');
>> Function('f', {x, y}, {x+y}).name_in()
i0
i1
>> f = Function('f', {x, y}, {x+y}, {'x', 'y'}, {'r'});
>> f.name_in(), f.name_in(1), f.name_out()
x
y
y
r
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> ca.name_in(ca.Function("f", [x, y], [x + y]))
2-element Vector{String}:
 "i0"
 "i1"
julia> f = ca.Function("f", [x, y], [x + y], ["x", "y"], ["r"]);
julia> ca.name_in(f), ca.name_in(f, 1), ca.name_out(f)
(["x", "y"], "y", ["r"])

See also: name_out, index_in, has_in

Extra doc | Doc source | Implementation

name_out(...)

Get the name of output ind; out of range raises an error.

name_out(self) -> [str]
name_out(self, int ind) -> str

Get the names of all outputs, in order.

Defaults are o0, o1, ... when the constructor was given no names.

>>> x = SX.sym("x")
>>> Function("f", [x], [x, 2*x]).name_out()
['o0', 'o1']
>> x = SX.sym('x');
>> Function('f', {x}, {x, 2*x}).name_out()
o0
o1
julia> x = ca.SX.sym("x");
julia> ca.name_out(ca.Function("f", [x], [x, 2x]))
2-element Vector{String}:
 "o0"
 "o1"

See also: name_in, index_out, has_out

Extra doc | Doc source | Implementation

nnz_in(...)
nnz_in(self) -> int
nnz_in(self, int ind) -> int
nnz_in(self, str iname) -> int

Get the number of structural nonzeros of one input, or of all inputs.

Without argument, the sum over all inputs. The nonzero count is what numerical evaluation reads for the input; it is smaller than numel_in for sparse inputs.

>>> f = Function("f", [SX.sym("x", 2), SX.sym("D", Sparsity.diag(3))], [SX(1)])
>>> f.nnz_in(0), f.nnz_in(1), f.nnz_in()
(2, 3, 5)
>>> f.numel_in(0), f.numel_in(1), f.numel_in()
(2, 9, 11)
>> f = Function('f', {SX.sym('x', 2), SX.sym('D', Sparsity.diag(3))}, {SX(1)});
>> fprintf('%d %d %d\n', f.nnz_in(0), f.nnz_in(1), f.nnz_in())
2 3 5
>> fprintf('%d %d %d\n', f.numel_in(0), f.numel_in(1), f.numel_in())
2 9 11
julia> D = ca.SX.sym("D", ca.Sparsity.diag(3));
julia> f = ca.Function("f", [ca.SX.sym("x", 2), D], [ca.SX(1)]);
julia> ca.nnz_in(f, 0), ca.nnz_in(f, 1), ca.nnz_in(f)
(2, 3, 5)
julia> ca.numel_in(f, 0), ca.numel_in(f, 1), ca.numel_in(f)
(2, 9, 11)

See also: nnz_out, numel_in, sparsity_in

Extra doc | Doc source | Implementation

nnz_out(...)
nnz_out(self) -> int
nnz_out(self, int ind) -> int
nnz_out(self, str oname) -> int

Get the number of structural nonzeros of one output, or of all outputs.

Without argument, the sum over all outputs.

>>> x = SX.sym("x", 2)
>>> f = Function("f", [x], [x, diag(x), SX(1, 1)])
>>> f.nnz_out(0), f.nnz_out(1), f.nnz_out(2), f.nnz_out()
(2, 2, 0, 4)
>> x = SX.sym('x', 2);
>> f = Function('f', {x}, {x, diag(x), SX(1, 1)});
>> fprintf('%d %d %d %d\n', f.nnz_out(0), f.nnz_out(1), f.nnz_out(2), f.nnz_out())
2 2 0 4
julia> x = ca.SX.sym("x", 2);
julia> f = ca.Function("f", [x], [x, ca.diag(x), ca.SX(1, 1)]);
julia> ca.nnz_out(f, 0), ca.nnz_out(f, 1), ca.nnz_out(f, 2), ca.nnz_out(f)
(2, 2, 0, 4)

See also: nnz_in, numel_out, sparsity_out

Extra doc | Doc source | Implementation

nominal_in(...)

Get the nominal value of each nonzero of input ind.

nominal_in(self, int ind) -> [float]

A list of length nnz_in(ind), all ones unless the class defines scaling.

>>> x = SX.sym("x", 2)
>>> f = Function("f", [x], [vertcat(x, 1)])
>>> f.nominal_in(0), f.nominal_out(0)
([1.0, 1.0], [1.0, 1.0, 1.0])
>> x = SX.sym('x', 2);
>> f = Function('f', {x}, {vertcat(x, 1)});
>> f.nominal_in(0), f.nominal_out(0)
1 1
1 1 1
julia> x = ca.SX.sym("x", 2);
julia> f = ca.Function("f", [x], [[x; 1]]);
julia> ca.nominal_in(f, 0), ca.nominal_out(f, 0)
([1.0, 1.0], [1.0, 1.0, 1.0])

See also: nominal_out, default_in

Extra doc | Doc source | Implementation

nominal_out(...)

Get the nominal value of each nonzero of output ind; all ones by

nominal_out(self, int ind) -> [float]

default.

See also: nominal_in

Extra doc | Doc source | Implementation

numel_in(...)
numel_in(self) -> int
numel_in(self, int ind) -> int
numel_in(self, str iname) -> int

Get the number of elements (rows times columns) of one input, or of all.

Counts structural zeros too, unlike nnz_in.

>>> f = Function("f", [SX.sym("D", Sparsity.diag(3))], [SX(1)])
>>> f.numel_in(0), f.nnz_in(0), f.numel_in("i0")
(9, 3, 9)
>> f = Function('f', {SX.sym('D', Sparsity.diag(3))}, {SX(1)});
>> fprintf('%d %d %d\n', f.numel_in(0), f.nnz_in(0), f.numel_in('i0'))
9 3 9
julia> f = ca.Function("f", [ca.SX.sym("D", ca.Sparsity.diag(3))], [ca.SX(1)]);
julia> ca.numel_in(f, 0), ca.nnz_in(f, 0), ca.numel_in(f, "i0")
(9, 3, 9)

See also: nnz_in, numel_out

Extra doc | Doc source | Implementation

numel_out(...)
numel_out(self) -> int
numel_out(self, int ind) -> int
numel_out(self, str oname) -> int

Get the number of elements (rows times columns) of one output, or of all.

>>> x = SX.sym("x", 2)
>>> f = Function("f", [x], [SX(2, 2), x])
>>> f.numel_out(0), f.numel_out(1), f.numel_out()
(4, 2, 6)
>> x = SX.sym('x', 2);
>> f = Function('f', {x}, {SX(2, 2), x});
>> fprintf('%d %d %d\n', f.numel_out(0), f.numel_out(1), f.numel_out())
4 2 6
julia> x = ca.SX.sym("x", 2);
julia> f = ca.Function("f", [x], [ca.SX(2, 2), x]);
julia> ca.numel_out(f, 0), ca.numel_out(f, 1), ca.numel_out(f)
(4, 2, 6)

See also: nnz_out, numel_in

Extra doc | Doc source | Implementation

nz_from_in(...)

Convert between a list of input/output matrices and one flat list of.

nz_from_in(self, [DM] arg) -> [float]

nonzeros

nz_from_in flattens a list of n_in() DM arguments (shape rules as in call) into the concatenated nonzeros, in input order and column-major within each input; nz_to_in does the reverse, the list must have exactly nnz_in() entries. nz_from_out and nz_to_out do the same for the outputs with nnz_out(). This is the memory layout that generated C code and FunctionBuffer use.

>>> f = Function("f", [SX.sym("x"), SX.sym("D", Sparsity.diag(2))], [SX(0)])
>>> f.nz_from_in([1, DM([[2, 0], [0, 3]])])
[1.0, 2.0, 3.0]
>>> f.nz_to_in([1, 2, 3])
[DM(1), DM(
[[2, 00],
 [00, 3]])]
>>> try:
...   f.nz_to_in([1, 2])
... except RuntimeError as e:
...   print("Dimension mismatch. Expecting 3, got 2" in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('D', Sparsity.diag(2))}, {SX(0)});
>> f.nz_from_in({1, DM([2, 0; 0, 3])})
1 2 3
>> arg = f.nz_to_in([1, 2, 3]); disp(arg{1}), disp(arg{2})
1
[[2, 00],
[00, 3]]
>> try, f.nz_to_in([1, 2]); catch e, disp(contains(e.message, 'Expecting 3, got 2')); end
1
julia> D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [ca.SX.sym("x"), D], [ca.SX(0)]);
julia> ca.nz_from_in(f, [1, ca.DM([2 0; 0 3])])
3-element Vector{Float64}:
 1.0
 2.0
 3.0
julia> x_in, D_in = ca.nz_to_in(f, [1, 2, 3]);
julia> x_in
DM(1)
julia> D_in
DM(
[[2, 00],
 [00, 3]])
julia> try
           ca.nz_to_in(f, [1, 2])
       catch e
           println(occursin("Dimension mismatch. Expecting 3, got 2", sprint(showerror, e)))
       end
true

See also: convert_in, generate_in, FunctionBuffer

Extra doc | Doc source | Implementation

nz_from_out(...)

Convert between a list of input/output matrices and one flat list of.

nz_from_out(self, [DM] arg) -> [float]

nonzeros

nz_from_in flattens a list of n_in() DM arguments (shape rules as in call) into the concatenated nonzeros, in input order and column-major within each input; nz_to_in does the reverse, the list must have exactly nnz_in() entries. nz_from_out and nz_to_out do the same for the outputs with nnz_out(). This is the memory layout that generated C code and FunctionBuffer use.

>>> f = Function("f", [SX.sym("x"), SX.sym("D", Sparsity.diag(2))], [SX(0)])
>>> f.nz_from_in([1, DM([[2, 0], [0, 3]])])
[1.0, 2.0, 3.0]
>>> f.nz_to_in([1, 2, 3])
[DM(1), DM(
[[2, 00],
 [00, 3]])]
>>> try:
...   f.nz_to_in([1, 2])
... except RuntimeError as e:
...   print("Dimension mismatch. Expecting 3, got 2" in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('D', Sparsity.diag(2))}, {SX(0)});
>> f.nz_from_in({1, DM([2, 0; 0, 3])})
1 2 3
>> arg = f.nz_to_in([1, 2, 3]); disp(arg{1}), disp(arg{2})
1
[[2, 00],
[00, 3]]
>> try, f.nz_to_in([1, 2]); catch e, disp(contains(e.message, 'Expecting 3, got 2')); end
1
julia> D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [ca.SX.sym("x"), D], [ca.SX(0)]);
julia> ca.nz_from_in(f, [1, ca.DM([2 0; 0 3])])
3-element Vector{Float64}:
 1.0
 2.0
 3.0
julia> x_in, D_in = ca.nz_to_in(f, [1, 2, 3]);
julia> x_in
DM(1)
julia> D_in
DM(
[[2, 00],
 [00, 3]])
julia> try
           ca.nz_to_in(f, [1, 2])
       catch e
           println(occursin("Dimension mismatch. Expecting 3, got 2", sprint(showerror, e)))
       end
true

See also: convert_in, generate_in, FunctionBuffer

Extra doc | Doc source | Implementation

nz_to_in(...)

Convert between a list of input/output matrices and one flat list of.

nz_to_in(self, [float] arg) -> [DM]

nonzeros

nz_from_in flattens a list of n_in() DM arguments (shape rules as in call) into the concatenated nonzeros, in input order and column-major within each input; nz_to_in does the reverse, the list must have exactly nnz_in() entries. nz_from_out and nz_to_out do the same for the outputs with nnz_out(). This is the memory layout that generated C code and FunctionBuffer use.

>>> f = Function("f", [SX.sym("x"), SX.sym("D", Sparsity.diag(2))], [SX(0)])
>>> f.nz_from_in([1, DM([[2, 0], [0, 3]])])
[1.0, 2.0, 3.0]
>>> f.nz_to_in([1, 2, 3])
[DM(1), DM(
[[2, 00],
 [00, 3]])]
>>> try:
...   f.nz_to_in([1, 2])
... except RuntimeError as e:
...   print("Dimension mismatch. Expecting 3, got 2" in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('D', Sparsity.diag(2))}, {SX(0)});
>> f.nz_from_in({1, DM([2, 0; 0, 3])})
1 2 3
>> arg = f.nz_to_in([1, 2, 3]); disp(arg{1}), disp(arg{2})
1
[[2, 00],
[00, 3]]
>> try, f.nz_to_in([1, 2]); catch e, disp(contains(e.message, 'Expecting 3, got 2')); end
1
julia> D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [ca.SX.sym("x"), D], [ca.SX(0)]);
julia> ca.nz_from_in(f, [1, ca.DM([2 0; 0 3])])
3-element Vector{Float64}:
 1.0
 2.0
 3.0
julia> x_in, D_in = ca.nz_to_in(f, [1, 2, 3]);
julia> x_in
DM(1)
julia> D_in
DM(
[[2, 00],
 [00, 3]])
julia> try
           ca.nz_to_in(f, [1, 2])
       catch e
           println(occursin("Dimension mismatch. Expecting 3, got 2", sprint(showerror, e)))
       end
true

See also: convert_in, generate_in, FunctionBuffer

Extra doc | Doc source | Implementation

nz_to_out(...)

Convert between a list of input/output matrices and one flat list of.

nz_to_out(self, [float] arg) -> [DM]

nonzeros

nz_from_in flattens a list of n_in() DM arguments (shape rules as in call) into the concatenated nonzeros, in input order and column-major within each input; nz_to_in does the reverse, the list must have exactly nnz_in() entries. nz_from_out and nz_to_out do the same for the outputs with nnz_out(). This is the memory layout that generated C code and FunctionBuffer use.

>>> f = Function("f", [SX.sym("x"), SX.sym("D", Sparsity.diag(2))], [SX(0)])
>>> f.nz_from_in([1, DM([[2, 0], [0, 3]])])
[1.0, 2.0, 3.0]
>>> f.nz_to_in([1, 2, 3])
[DM(1), DM(
[[2, 00],
 [00, 3]])]
>>> try:
...   f.nz_to_in([1, 2])
... except RuntimeError as e:
...   print("Dimension mismatch. Expecting 3, got 2" in str(e))
True
>> f = Function('f', {SX.sym('x'), SX.sym('D', Sparsity.diag(2))}, {SX(0)});
>> f.nz_from_in({1, DM([2, 0; 0, 3])})
1 2 3
>> arg = f.nz_to_in([1, 2, 3]); disp(arg{1}), disp(arg{2})
1
[[2, 00],
[00, 3]]
>> try, f.nz_to_in([1, 2]); catch e, disp(contains(e.message, 'Expecting 3, got 2')); end
1
julia> D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [ca.SX.sym("x"), D], [ca.SX(0)]);
julia> ca.nz_from_in(f, [1, ca.DM([2 0; 0 3])])
3-element Vector{Float64}:
 1.0
 2.0
 3.0
julia> x_in, D_in = ca.nz_to_in(f, [1, 2, 3]);
julia> x_in
DM(1)
julia> D_in
DM(
[[2, 00],
 [00, 3]])
julia> try
           ca.nz_to_in(f, [1, 2])
       catch e
           println(occursin("Dimension mismatch. Expecting 3, got 2", sprint(showerror, e)))
       end
true

See also: convert_in, generate_in, FunctionBuffer

Extra doc | Doc source | Implementation

oracle(...)

Get the user-supplied problem function behind a solver object.

oracle(self) -> Function

For nlpsol, qpsol, rootfinder and integrator objects this is the Function with the problem expressions (e.g. nlp:(x,p)->(f,g)); for other classes an error is raised.

>>> x = SX.sym("x")
>>> opts = {"qpsol": "qrqp", "print_header": False, "print_iteration": False,
...         "print_time": False, "qpsol_options": {"print_header": False}}
>>> S = nlpsol("S", "sqpmethod", {"x": x, "f": x**2}, opts)
>>> S.oracle()
Function(nlp:(x,p[])->(f,g[0]) SXFunction)
>>> try:
...   S.oracle().oracle()
... except RuntimeError as e:
...   print("'oracle' not defined for SXFunction" in str(e))
True
>> x = SX.sym('x');
>> opts = struct('qpsol', 'qrqp', 'print_header', false, 'print_iteration', false);
>> opts.print_time = false; opts.qpsol_options = struct('print_header', false);
>> S = nlpsol('S', 'sqpmethod', struct('x', x, 'f', x^2), opts);
>> S.oracle()
nlp:(x,p[])->(f,g[0]) SXFunction
>> try, S.oracle().oracle(); catch e, disp(contains(e.message, 'not defined')); end
1
julia> x = ca.SX.sym("x");
julia> opts = Dict("qpsol" => "qrqp", "print_header" => false, "print_iteration" => false,
                   "print_time" => false, "qpsol_options" => Dict("print_header" => false));
julia> S = ca.nlpsol("S", "sqpmethod", Dict("x" => x, "f" => x^2), opts);
julia> ca.oracle(S)
Function(nlp:(x,p[])->(f,g[0]) SXFunction)
julia> try
           ca.oracle(ca.oracle(S))
       catch e
           println(occursin("'oracle' not defined for SXFunction", sprint(showerror, e)))
       end
true

See also: get_function, find_functions

Extra doc | Doc source | Implementation

print_dimensions(...)

Print the name and shape of every input and output.

print_dimensions(self)
>>> f = Function("f", [SX.sym("x", 2), SX.sym("p")], [SX(1, 3)], ["x", "p"], ["r"])
>>> f.print_dimensions()
Number of inputs: 2
Input 0 ("x"): 2x1
Input 1 ("p"): 1x1
Number of outputs: 1
Output 0 ("r"): 1x3
>> f = Function('f', {SX.sym('x', 2), SX.sym('p')}, {SX(1, 3)}, {'x', 'p'}, {'r'});
>> f.print_dimensions()
Number of inputs: 2
Input 0 ("x"): 2x1
Input 1 ("p"): 1x1
Number of outputs: 1
Output 0 ("r"): 1x3
julia> x = ca.SX.sym("x", 2); p = ca.SX.sym("p");
julia> f = ca.Function("f", [x, p], [ca.SX(1, 3)], ["x", "p"], ["r"]);
julia> ca.print_dimensions(f)
 Number of inputs: 2
  Input 0 ("x"): 2x1
  Input 1 ("p"): 1x1
 Number of outputs: 1
  Output 0 ("r"): 1x3

See also: size_in, sparsity_in

Extra doc | Doc source | Implementation

print_option(...)

Print the type and description of one option; unknown names print a.

print_option(self, str name)

notice

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.print_option("verbose")
> "verbose"          [OT_BOOL]      "Verbose evaluation -- for debugging"
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> f.print_option('verbose')
> "verbose"          [OT_BOOL]      "Verbose evaluation -- for debugging"
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.print_option(f, "verbose")
> "verbose"          [OT_BOOL]      "Verbose evaluation -- for debugging"

See also: print_options, has_option

Extra doc | Doc source | Implementation

print_options(...)

Print the name, type and description of every option of this class.

print_options(self)

The list depends on the class (SXFunction, MXFunction, a solver plugin, ...). Options are set at construction; see change_option for the few that can be changed afterwards.

See also: print_option, has_option

Extra doc | Doc source | Implementation

print_ptr(...)
print_ptr(self)
release(...)

Give back a memory object obtained with checkout.

release(self, int mem)

Doc source | Implementation

reset_dump_count(...)

Reset to zero the counter that numbers the files written by dump_in,.

reset_dump_count(self)

dump_out and dump_trace

Extra doc | Doc source | Implementation

reverse(...)

Get a function computing nadj reverse (adjoint) directional derivatives.

reverse(self, int nadj) -> Function

The result is named adj<nadj>_<name> and has n_in + n_out + n_out inputs: the original inputs, the original outputs (out_<name>) and the adjoint seeds adj_<output>, each with nadj times the columns of the output. Its n_in outputs adj_<input> are the adjoint sensitivities, nadj stacked horizontally. Falls back to the full Jacobian when the class has no reverse mode; raises when it has no derivatives at all. Results are cached while alive. nadj must be positive.

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"])
>>> R = f.reverse(1)
>>> R
Function(adj1_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],adj_r[2],adj_s)->(adj_x,adj_y[2])
SXFunction)
>>> R(1, [2, 3], 0, 0, [1, 1], 0)
(DM(5), DM([1, 1]))
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y, sin(x)}, {'x', 'y'}, {'r', 's'});
>> R = f.reverse(1); disp(R)
adj1_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],adj_r[2],adj_s)->(adj_x,adj_y[2]) SXFunction
>> [adj_x, adj_y] = R(1, [2; 3], 0, 0, [1; 1], 0); disp(adj_x), disp(adj_y)
5
[1, 1]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y, sin(x)], ["x", "y"], ["r", "s"]);
julia> R = f.reverse(1);
julia> R
Function(adj1_f:(x,y[2],out_r[2x1,0nz],out_s[1x1,0nz],adj_r[2],adj_s)->(adj_x,adj_y[2]) SXFunction)
julia> R(1, [2, 3], 0, 0, [1, 1], 0)
(5, [1, 1])

See also: forward, jacobian, factory

Extra doc | Doc source | Implementation

save(...)

Save the function to a file that load reads back.

save(self, str fname, dict opts)

Writes a serialization of the function to fname (conventionally with the extension .casadi). The file is portable across platforms and languages (Python, MATLAB, C++); it is compatible across CasADi versions as far as the serialization format allows.

Parameters:
  • fname -- File name

  • opts -- Serializer options, e.g. "debug"

>>> import os
>>> x = SX.sym("x")
>>> f = Function("f", [x], [x**2])
>>> f.save("f.casadi")
>>> g = Function.load("f.casadi")
>>> g, g(3)
(Function(f:(i0)->(o0) SXFunction), DM(9))
>>> os.remove("f.casadi")
>> x = SX.sym('x');
>> f = Function('f', {x}, {x^2});
>> f.save('f.casadi'); g = Function.load('f.casadi'); disp(g), disp(g(3))
f:(i0)->(o0) SXFunction
9
>> delete('f.casadi');
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [x^2]);
julia> ca.save(f, "f.casadi")
julia> g = ca.Function.load("f.casadi");
julia> println(g); g(3)
f:(i0)->(o0) SXFunction
DM(9)
julia> rm("f.casadi")

See also: load, serialize, FileSerializer

Extra doc | Doc source | Implementation

serialize(...)

Serialize to a string that deserialize turns back into an equal function.

serialize(self, dict opts) -> str

Any Function can be serialized, including solvers and functions with embedded calls; a just-in-time compiled function is stored according to option "jit_serialize". The string is binary-safe text; it is also what the Python pickle protocol and MATLAB save use.

Parameters:

opts -- "debug" (bool) adds consistency markers to the stream

>>> x = SX.sym("x")
>>> f = Function("f", [x], [sin(x)], ["x"], ["y"])
>>> s = f.serialize()
>>> g = Function.deserialize(s)
>>> g, g(1)
(Function(f:(x)->(y) SXFunction), DM(0.841471))
>> x = SX.sym('x');
>> f = Function('f', {x}, {sin(x)}, {'x'}, {'y'});
>> s = f.serialize(); g = Function.deserialize(s); disp(g), disp(g(1))
f:(x)->(y) SXFunction
0.841471
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [sin(x)], ["x"], ["y"]);
julia> s = ca.serialize(f);
julia> g = ca.Function.deserialize(s);
julia> println(g); g(1)
f:(x)->(y) SXFunction
DM(0.841471)

See also: deserialize, save, load

Extra doc | Doc source | Implementation

size1_in(...)
size1_in(self, int ind) -> int
size1_in(self, str iname) -> int

Get the shape of an input: rows, columns or both.

size1_in is the number of rows, size2_in the number of columns and size_in the pair (rows, columns). The input is selected by index or by name; an unknown name raises an error listing the available names, an index out of range raises an error.

>>> f = Function("f", [SX.sym("A", 2, 3), SX.sym("b", 2)], [SX(0)], ["A", "b"], ["c"])
>>> f.size_in(0), f.size1_in("A"), f.size2_in("A")
((2, 3), 2, 3)
>>> f.size_in("b")
(2, 1)
>>> try:
...   f.size_in("nope")
... except RuntimeError as e:
...   print("Available names are: [A, b]" in str(e))
True
>> f = Function('f', {SX.sym('A', 2, 3), SX.sym('b', 2)}, {SX(0)}, {'A', 'b'}, {'c'});
>> disp(f.size_in(0)), fprintf('%d %d\n', f.size1_in('A'), f.size2_in('A'))
2 3
2 3
>> f.size_in('b')
2 1
>> try, f.size_in('nope'); catch e, disp(contains(e.message, 'Available names')); end
1
julia> A = ca.SX.sym("A", 2, 3); b = ca.SX.sym("b", 2);
julia> f = ca.Function("f", [A, b], [ca.SX(0)], ["A", "b"], ["c"]);
julia> ca.size_in(f, 0), ca.size1_in(f, "A"), ca.size2_in(f, "A")
((2, 3), 2, 3)
julia> ca.size_in(f, "b")
(2, 1)
julia> try
           ca.size_in(f, "nope")
       catch e
           println(occursin("Available names are: [A, b]", sprint(showerror, e)))
       end
true

See also: size_out, sparsity_in, nnz_in, numel_in

Extra doc | Doc source | Implementation

size1_out(...)
size1_out(self, int ind) -> int
size1_out(self, str oname) -> int

Get the shape of an output: rows, columns or both.

Same conventions as size_in, size1_in and size2_in.

>>> x = SX.sym("x", 3)
>>> f = Function("f", [x], [x.T, SX(2, 2)])
>>> f.size_out(0), f.size_out("o1"), f.size1_out(0), f.size2_out(1)
((1, 3), (2, 2), 1, 2)
>> x = SX.sym('x', 3);
>> f = Function('f', {x}, {x', SX(2, 2)});
>> f.size_out(0), f.size_out('o1')
1 3
2 2
>> fprintf('%d %d\n', f.size1_out(0), f.size2_out(1))
1 2
julia> x = ca.SX.sym("x", 3);
julia> f = ca.Function("f", [x], [x', ca.SX(2, 2)]);
julia> ca.size_out(f, 0), ca.size_out(f, "o1"), ca.size1_out(f, 0), ca.size2_out(f, 1)
((1, 3), (2, 2), 1, 2)

See also: size_in, sparsity_out

Extra doc | Doc source | Implementation

size2_in(...)
size2_in(self, int ind) -> int
size2_in(self, str iname) -> int

Get the shape of an input: rows, columns or both.

size1_in is the number of rows, size2_in the number of columns and size_in the pair (rows, columns). The input is selected by index or by name; an unknown name raises an error listing the available names, an index out of range raises an error.

>>> f = Function("f", [SX.sym("A", 2, 3), SX.sym("b", 2)], [SX(0)], ["A", "b"], ["c"])
>>> f.size_in(0), f.size1_in("A"), f.size2_in("A")
((2, 3), 2, 3)
>>> f.size_in("b")
(2, 1)
>>> try:
...   f.size_in("nope")
... except RuntimeError as e:
...   print("Available names are: [A, b]" in str(e))
True
>> f = Function('f', {SX.sym('A', 2, 3), SX.sym('b', 2)}, {SX(0)}, {'A', 'b'}, {'c'});
>> disp(f.size_in(0)), fprintf('%d %d\n', f.size1_in('A'), f.size2_in('A'))
2 3
2 3
>> f.size_in('b')
2 1
>> try, f.size_in('nope'); catch e, disp(contains(e.message, 'Available names')); end
1
julia> A = ca.SX.sym("A", 2, 3); b = ca.SX.sym("b", 2);
julia> f = ca.Function("f", [A, b], [ca.SX(0)], ["A", "b"], ["c"]);
julia> ca.size_in(f, 0), ca.size1_in(f, "A"), ca.size2_in(f, "A")
((2, 3), 2, 3)
julia> ca.size_in(f, "b")
(2, 1)
julia> try
           ca.size_in(f, "nope")
       catch e
           println(occursin("Available names are: [A, b]", sprint(showerror, e)))
       end
true

See also: size_out, sparsity_in, nnz_in, numel_in

Extra doc | Doc source | Implementation

size2_out(...)
size2_out(self, int ind) -> int
size2_out(self, str oname) -> int

Get the shape of an output: rows, columns or both.

Same conventions as size_in, size1_in and size2_in.

>>> x = SX.sym("x", 3)
>>> f = Function("f", [x], [x.T, SX(2, 2)])
>>> f.size_out(0), f.size_out("o1"), f.size1_out(0), f.size2_out(1)
((1, 3), (2, 2), 1, 2)
>> x = SX.sym('x', 3);
>> f = Function('f', {x}, {x', SX(2, 2)});
>> f.size_out(0), f.size_out('o1')
1 3
2 2
>> fprintf('%d %d\n', f.size1_out(0), f.size2_out(1))
1 2
julia> x = ca.SX.sym("x", 3);
julia> f = ca.Function("f", [x], [x', ca.SX(2, 2)]);
julia> ca.size_out(f, 0), ca.size_out(f, "o1"), ca.size1_out(f, 0), ca.size2_out(f, 1)
((1, 3), (2, 2), 1, 2)

See also: size_in, sparsity_out

Extra doc | Doc source | Implementation

size_in(...)
size_in(self, int ind) -> (int,int)
size_in(self, str iname) -> (int,int)

Get the shape of an input: rows, columns or both.

size1_in is the number of rows, size2_in the number of columns and size_in the pair (rows, columns). The input is selected by index or by name; an unknown name raises an error listing the available names, an index out of range raises an error.

>>> f = Function("f", [SX.sym("A", 2, 3), SX.sym("b", 2)], [SX(0)], ["A", "b"], ["c"])
>>> f.size_in(0), f.size1_in("A"), f.size2_in("A")
((2, 3), 2, 3)
>>> f.size_in("b")
(2, 1)
>>> try:
...   f.size_in("nope")
... except RuntimeError as e:
...   print("Available names are: [A, b]" in str(e))
True
>> f = Function('f', {SX.sym('A', 2, 3), SX.sym('b', 2)}, {SX(0)}, {'A', 'b'}, {'c'});
>> disp(f.size_in(0)), fprintf('%d %d\n', f.size1_in('A'), f.size2_in('A'))
2 3
2 3
>> f.size_in('b')
2 1
>> try, f.size_in('nope'); catch e, disp(contains(e.message, 'Available names')); end
1
julia> A = ca.SX.sym("A", 2, 3); b = ca.SX.sym("b", 2);
julia> f = ca.Function("f", [A, b], [ca.SX(0)], ["A", "b"], ["c"]);
julia> ca.size_in(f, 0), ca.size1_in(f, "A"), ca.size2_in(f, "A")
((2, 3), 2, 3)
julia> ca.size_in(f, "b")
(2, 1)
julia> try
           ca.size_in(f, "nope")
       catch e
           println(occursin("Available names are: [A, b]", sprint(showerror, e)))
       end
true

See also: size_out, sparsity_in, nnz_in, numel_in

Extra doc | Doc source | Implementation

size_out(...)
size_out(self, int ind) -> (int,int)
size_out(self, str oname) -> (int,int)

Get the shape of an output: rows, columns or both.

Same conventions as size_in, size1_in and size2_in.

>>> x = SX.sym("x", 3)
>>> f = Function("f", [x], [x.T, SX(2, 2)])
>>> f.size_out(0), f.size_out("o1"), f.size1_out(0), f.size2_out(1)
((1, 3), (2, 2), 1, 2)
>> x = SX.sym('x', 3);
>> f = Function('f', {x}, {x', SX(2, 2)});
>> f.size_out(0), f.size_out('o1')
1 3
2 2
>> fprintf('%d %d\n', f.size1_out(0), f.size2_out(1))
1 2
julia> x = ca.SX.sym("x", 3);
julia> f = ca.Function("f", [x], [x', ca.SX(2, 2)]);
julia> ca.size_out(f, 0), ca.size_out(f, "o1"), ca.size1_out(f, 0), ca.size2_out(f, 1)
((1, 3), (2, 2), 1, 2)

See also: size_in, sparsity_out

Extra doc | Doc source | Implementation

slice(...)

Create a function with a subset or reordering of the inputs and outputs.

slice(self, str name, [int] order_in, [int] order_out, dict opts) -> Function

The expressions are unchanged; only the lists of inputs and outputs are rearranged. Indices may be repeated or omitted. An omitted input that an output depends on makes the result have free variables (construction then fails unless "allow_free" is in opts). Classes other than SXFunction and MXFunction are wrapped first.

Parameters:
  • name -- Name of the result

  • order_in -- Indices of the original inputs to keep, in the new order

  • order_out -- Indices of the original outputs to keep, in the new order

  • opts -- Options for the new function

>>> x = SX.sym("x"); y = SX.sym("y")
>>> f = Function("f", [x, y], [x + y, x - y, 2*x], ["x", "y"], ["a", "b", "c"])
>>> g = f.slice("g", [1, 0], [2, 0])
>>> g, g(1, 2)
(Function(g:(y,x)->(c,a) SXFunction), (DM(4), DM(3)))
>>> f.slice("h", [0], [2])
Function(h:(x)->(c) SXFunction)
>> x = SX.sym('x'); y = SX.sym('y');
>> f = Function('f', {x, y}, {x + y, x - y, 2*x}, {'x', 'y'}, {'a', 'b', 'c'});
>> g = f.slice('g', [1, 0], [2, 0]); disp(g)
g:(y,x)->(c,a) SXFunction
>> [c, a] = g(1, 2); disp(c), disp(a)
4
3
>> f.slice('h', 0, 2)
h:(x)->(c) SXFunction
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> f = ca.Function("f", [x, y], [x + y, x - y, 2x], ["x", "y"], ["a", "b", "c"]);
julia> g = ca.slice(f, "g", [1, 0], [2, 0]);
julia> println(g); g(1, 2)
g:(y,x)->(c,a) SXFunction
(4, 3)
julia> ca.slice(f, "h", [0], [2])
Function(h:(x)->(c) SXFunction)

See also: factory

Extra doc | Doc source | Implementation

sparsity_in(...)
sparsity_in(self, int ind) -> Sparsity
sparsity_in(self, str iname) -> Sparsity

Get the sparsity pattern of an input, by index or name.

Numerical arguments are projected onto this pattern before evaluation: entries outside it are dropped silently. Symbolic inputs keep the pattern of the expression passed to the constructor.

>>> f = Function("f", [SX.sym("D", Sparsity.diag(2))], [SX(0)], ["D"], ["r"])
>>> f.sparsity_in(0)
Sparsity(2x2,2nz)
>>> f.sparsity_in("D").is_diag()
True
>>> f.sparsity_out(0)
Sparsity(1x1)
>> f = Function('f', {SX.sym('D', Sparsity.diag(2))}, {SX(0)}, {'D'}, {'r'});
>> f.sparsity_in(0)
2x2,2nz
>> f.sparsity_in('D').is_diag()
1
>> f.sparsity_out(0)
1x1
julia> D = ca.SX.sym("D", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [D], [ca.SX(0)], ["D"], ["r"]);
julia> ca.sparsity_in(f, 0)
Sparsity(2x2,2nz)
julia> ca.is_diag(ca.sparsity_in(f, "D"))
true
julia> ca.sparsity_out(f, 0)
Sparsity(1x1)

See also: sparsity_out, size_in, nnz_in

Extra doc | Doc source | Implementation

sparsity_jac(...)
sparsity_jac(self, str iind, int oind, bool compact, bool symmetric) -> Sparsity
sparsity_jac(self, int iind, int oind, bool compact, bool symmetric) -> Sparsity
sparsity_jac(self, int iind, str oind, bool compact, bool symmetric) -> Sparsity
sparsity_jac(self, str iind, str oind, bool compact, bool symmetric) -> Sparsity

[DEPRECATED] Sparsity of the Jacobian of output oind w.r.t. input iind; use jac_sparsity(oind, iind) (note the reversed argument order)

Doc source | Implementation

sparsity_out(...)
sparsity_out(self, int ind) -> Sparsity
sparsity_out(self, str iname) -> Sparsity

Get the sparsity pattern of an output, by index or name.

Results of a numerical call are DM objects with exactly this pattern.

See also: sparsity_in, size_out, nnz_out

Extra doc | Doc source | Implementation

stats(...)

Get the statistics recorded by the last numerical evaluation.

stats(self, int mem) -> dict

The content depends on the class: solvers report e.g. "success", "return_status", "iter_count"; with option "record_time" every function reports "t_wall_total", "t_proc_total" and "n_call_total". Raises an error when the function has not been evaluated numerically yet.

Parameters:

mem -- Memory object (from checkout) whose statistics to return; 0 is the memory used by ordinary calls

>>> x = SX.sym("x")
>>> f = Function("f", [x], [x**2], {"record_time": True})
>>> try:
...   f.stats()
... except RuntimeError as e:
...   print("first evaluate it numerically" in str(e))
True
>>> r = f(2)
>>> sorted(f.stats().keys())
['n_call_total', 't_proc_total', 't_wall_total']
>> x = SX.sym('x');
>> f = Function('f', {x}, {x^2}, struct('record_time', true));
>> try, f.stats(); catch e, disp(contains(e.message, 'first evaluate it numerically')); end
1
>> r = f(2); disp(strjoin(sort(fieldnames(f.stats()))', ' '))
n_call_total t_proc_total t_wall_total
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [x^2], Dict("record_time" => true));
julia> try
           ca.stats(f)
       catch e
           println(occursin("first evaluate it numerically", sprint(showerror, e)))
       end
true
julia> r = f(2);
julia> sort(collect(keys(ca.stats(f))))
3-element Vector{String}:
 "n_call_total"
 "t_proc_total"
 "t_wall_total"

See also: checkout

Extra doc | Doc source | Implementation

str(...)

Get string representation.

str(self, bool more) -> str

Doc source | Implementation

sx_in(...)
sx_in(self) -> [SX]
sx_in(self, int iind) -> SX
sx_in(self, str iname) -> SX

Create fresh symbols with the names and sparsity patterns of the inputs.

Convenient for calling the function symbolically or for building a wrapper: f(f.mx_in()) is an MX expression of the outputs. Each call creates new symbols; they are not the symbols the function was constructed from. All inputs (no argument), one by index, or one by name.

>>> f = Function("f", [SX.sym("a"), SX.sym("B", Sparsity.diag(2))], [SX(0)],
...              ["a", "B"], ["r"])
>>> f.sx_in()
[SX(a), SX(
[[B_0, 00],
 [00, B_1]])]
>>> f.mx_in(1), f.mx_in("a").shape
(MX(B), (1, 1))
>>> f.sx_out(), f.mx_out(0)
([SX(r)], MX(r))
>> a = SX.sym('a'); B = SX.sym('B', Sparsity.diag(2));
>> f = Function('f', {a, B}, {SX(0)}, {'a', 'B'}, {'r'});
>> in = f.sx_in(); disp(in{1}), disp(in{2})
a
[[B_0, 00],
[00, B_1]]
>> f.mx_in(1), size(f.mx_in('a'))
B
1 1
>> out = f.sx_out(); disp(out{1}), disp(f.mx_out(0))
r
r
julia> a = ca.SX.sym("a"); B = ca.SX.sym("B", ca.Sparsity.diag(2));
julia> f = ca.Function("f", [a, B], [ca.SX(0)], ["a", "B"], ["r"]);
julia> a_in, B_in = ca.sx_in(f);
julia> a_in
SX(a)
julia> B_in
SX(
[[B_0, 00],
 [00, B_1]])
julia> ca.mx_in(f, 1), size(ca.mx_in(f, "a"))
(B, (1, 1))
julia> ca.sx_out(f), ca.mx_out(f, 0)
(SX[r], r)

See also: sx_out, mx_out, sparsity_in

Extra doc | Doc source | Implementation

sx_out(...)
sx_out(self) -> [SX]
sx_out(self, int oind) -> SX
sx_out(self, str oname) -> SX

Create fresh symbols with the names and sparsity patterns of the outputs.

Useful as adjoint seeds or placeholders; see sx_in.

Extra doc | Doc source | Implementation

sz_arg(...)

Get the length of the input pointer array needed to evaluate (at least n_in)

sz_arg(self) -> size_t

sz_arg, sz_res, sz_iw and sz_w are the sizes of the arg, res, iw and w arrays of the low-level evaluation interface used by generated code and FunctionBuffer.

>>> f = Function("f", [SX.sym("x"), SX.sym("y")], [SX(0)])
>>> f.sz_arg(), f.sz_res(), f.sz_iw(), f.sz_w()
(2, 1, 0, 1)
>> f = Function('f', {SX.sym('x'), SX.sym('y')}, {SX(0)});
>> fprintf('%d %d %d %d\n', f.sz_arg(), f.sz_res(), f.sz_iw(), f.sz_w())
2 1 0 1
julia> f = ca.Function("f", [ca.SX.sym("x"), ca.SX.sym("y")], [ca.SX(0)]);
julia> ca.sz_arg(f), ca.sz_res(f), ca.sz_iw(f), ca.sz_w(f)
(2, 1, 0, 1)

See also: sz_res, sz_iw, sz_w, FunctionBuffer

Extra doc | Doc source | Implementation

sz_iw(...)

Get the length of the integer work vector needed to evaluate.

sz_iw(self) -> size_t

Extra doc | Doc source | Implementation

sz_res(...)

Get the length of the output pointer array needed to evaluate (at least.

sz_res(self) -> size_t

n_out)

Extra doc | Doc source | Implementation

sz_w(...)

Get the length of the real work vector needed to evaluate.

sz_w(self) -> size_t

Extra doc | Doc source | Implementation

transform(...)
transform(self, dict opts) -> Function
transform(self, str fname, dict opts) -> Function
transform(self, [[GenericType]] passes, dict opts) -> Function
transform(self, str fname, [[GenericType]] passes, dict opts) -> Function

Rebuild the function after graph simplification or other passes.

Only defined for SXFunction and MXFunction. The result has the same signature, names and options; only the expression graph differs.

The dict form runs a single "simplify" pass whose tasks are selected with boolean options, all defaulting to on except combine_terms:

  • empty_inputs: an input whose symbols do not occur in any output is replaced by an all-zero sparse matrix of the same shape (its nnz becomes 0)

  • cse: common subexpression elimination

  • ref_count: drop unreferenced nodes, repeated until a fixed point

  • const_folding: evaluate constant subexpressions

  • combine_terms: merge like terms of sums

Unknown keys raise an error.

The passes form runs an explicit list of passes in order. Each pass is a list whose first entry is the verb:

  • ["simplify", task,...] with tasks from the list above; an integer before a task is its run count (N>0: N times, 0: until the graph stops shrinking)

  • ["expand"]: expand to an SXFunction

  • ["external", library, operation] or [..., opts]: a transform from a plugin library

Here opts accepts only "verbose"; passing the boolean task options raises an error. With "verbose": true the node and instruction counts after each pass are printed.

Parameters:
  • fname -- Name of the result; defaults to the current name

  • passes -- Explicit list of passes

  • opts -- Dict form: task booleans and "verbose"; passes form: "verbose" only

>>> z = MX.sym("z"); w = MX.sym("w")
>>> f = Function("f", [z, w], [sin(z)*cos(z) + sin(z)*cos(z)], ["z", "w"], ["r"])
>>> f, f.n_instructions()
(Function(f:(z,w)->(r) MXFunction), 9)
>>> g = f.transform()
>>> g, g.n_instructions()
(Function(f:(z,w[1x1,0nz])->(r) MXFunction), 6)
>>> f.transform([["simplify", "cse"]]).n_instructions()
6
>>> f.transform("fe", [["expand"]])
Function(fe:(z,w)->(r) SXFunction)
>>> try:
...   f.transform([["nope"]])
... except RuntimeError as e:
...   print("unknown pass verb" in str(e))
True
>> z = MX.sym('z'); w = MX.sym('w');
>> f = Function('f', {z, w}, {sin(z)*cos(z) + sin(z)*cos(z)}, {'z', 'w'}, {'r'});
>> f, f.n_instructions()
f:(z,w)->(r) MXFunction
9
>> g = f.transform(); disp(g), disp(g.n_instructions())
f:(z,w[1x1,0nz])->(r) MXFunction
6
>> f.transform({{'simplify', 'cse'}}).n_instructions()
6
>> f.transform('fe', {{'expand'}})
fe:(z,w)->(r) SXFunction
>> try, f.transform({{'nope'}}); catch e, disp(contains(e.message, 'unknown pass')); end
1
julia> z = ca.MX.sym("z"); w = ca.MX.sym("w");
julia> f = ca.Function("f", [z, w], [sin(z)*cos(z) + sin(z)*cos(z)], ["z", "w"], ["r"]);
julia> println(f); ca.n_instructions(f)
f:(z,w)->(r) MXFunction
9
julia> g = ca.transform(f);
julia> println(g); ca.n_instructions(g)
f:(z,w[1x1,0nz])->(r) MXFunction
6
julia> ca.n_instructions(ca.transform(f, [["simplify", "cse"]]))
6
julia> ca.transform(f, "fe", [["expand"]])
Function(fe:(z,w)->(r) SXFunction)
julia> try
           ca.transform(f, [["nope"]])
       catch e
           println(occursin("unknown pass verb", sprint(showerror, e)))
       end
true

See also: expand

Extra doc | Doc source | Implementation

static type_name(...)

Get the type name, always "Function".

type_name() -> str
>>> Function.type_name()
'Function'
>> Function.type_name()
Function
julia> ca.Function.type_name()
"Function"

Extra doc | Doc source | Implementation

uses_output(...)

Check whether the derivative functions read the nondifferentiated outputs.

uses_output(self) -> bool

The functions returned by jacobian, forward and reverse always accept the original outputs as extra inputs (out_r, ...). For most classes those inputs are ignored and this returns false; it is true for classes that reuse the outputs, for example to avoid recomputing a solver solution.

>>> f = Function("f", [SX.sym("x")], [SX(0)])
>>> f.uses_output()
False
>> f = Function('f', {SX.sym('x')}, {SX(0)});
>> f.uses_output()
0
julia> f = ca.Function("f", [ca.SX.sym("x")], [ca.SX(0)]);
julia> ca.uses_output(f)
false

See also: jacobian, forward, reverse

Extra doc | Doc source | Implementation

which_depends(...)

Find which entries of an input the outputs depend on, linearly or not.

which_depends(self, str s_in, [str] s_out, int order, bool tr) -> [bool]

Returns one boolean per nonzero of input s_in: true when at least one of the outputs s_out depends on that entry (order 1) or depends on it nonlinearly (order 2). With tr true the relation is flipped: one boolean per nonzero of the vertically concatenated outputs, true when it depends on any entry of s_in. The analysis is structural (it follows the graph, not the values).

Parameters:
  • s_in -- Name of one input

  • s_out -- Names of the outputs to inspect

  • order -- 1 (any dependence) or 2 (nonlinear dependence); other values raise

  • tr -- Transpose the relation, see above

>>> x = SX.sym("x"); y = SX.sym("y", 2)
>>> f = Function("f", [x, y], [x*y[0], y[1]**2 + x, 3], ["x", "y"], ["a", "b", "c"])
>>> f.which_depends("y", ["a", "b"])
[True, True]
>>> f.which_depends("y", ["a", "b"], 2)
[False, True]
>>> f.which_depends("y", ["a", "b", "c"], 1, True)
[True, True, False]
>>> f.which_depends("x", ["a"], 2)
[False]
>> x = SX.sym('x'); y = SX.sym('y', 2);
>> f = Function('f', {x, y}, {x*y(1), y(2)^2 + x, 3}, {'x', 'y'}, {'a', 'b', 'c'});
>> f.which_depends('y', {'a', 'b'})
1 1
>> f.which_depends('y', {'a', 'b'}, 2)
0 1
>> f.which_depends('y', {'a', 'b', 'c'}, 1, true)
1 1 0
>> f.which_depends('x', {'a'}, 2)
0
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y", 2);
julia> f = ca.Function("f", [x, y], [x*y[1], y[2]^2 + x, 3], ["x", "y"], ["a", "b", "c"]);
julia> ca.which_depends(f, "y", ["a", "b"])
2-element Vector{Bool}:
 1
 1
julia> ca.which_depends(f, "y", ["a", "b"], 2)
2-element Vector{Bool}:
 0
 1
julia> ca.which_depends(f, "y", ["a", "b", "c"], 1, true)
3-element Vector{Bool}:
 1
 1
 0
julia> ca.which_depends(f, "x", ["a"], 2)
1-element Vector{Bool}:
 0

See also: factory, jac_sparsity

Extra doc | Doc source | Implementation

wrap(...)
wrap(self) -> Function
wrap(self, str name) -> Function

Wrap in an MXFunction whose graph is a single call to this function.

The wrapper has the same signature and names, carries over the derivative options (ad_weight, ad_weight_sp, max_num_dir, is_diff_in/out, derivative_of) and is cached by name. Classes without their own derivative or slice implementation use it internally; it is also a way to give any function a plain MX graph.

Parameters:

name -- Name of the wrapper; defaults to "wrap_" + name()

>>> x = SX.sym("x")
>>> f = Function("f", [x], [sin(x)], ["x"], ["y"])
>>> w = f.wrap()
>>> w, w.n_instructions(), w.get_function()
(Function(wrap_f:(x)->(y) MXFunction), 3, ['f'])
>>> f.wrap("g").name()
'g'
>> x = SX.sym('x');
>> f = Function('f', {x}, {sin(x)}, {'x'}, {'y'});
>> w = f.wrap(); disp(w), disp(w.n_instructions()), disp(w.get_function())
wrap_f:(x)->(y) MXFunction
3
f
>> f.wrap('g').name()
g
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [sin(x)], ["x"], ["y"]);
julia> w = ca.wrap(f);
julia> println(w); ca.n_instructions(w), ca.get_function(w)
wrap_f:(x)->(y) MXFunction
(3, ["f"])
julia> ca.name(ca.wrap(f, "g"))
"g"

See also: wrap_as_needed, expand

Extra doc | Doc source | Implementation

wrap_as_needed(...)
wrap_as_needed(self, dict opts) -> Function
wrap_as_needed(self, str name, dict opts) -> Function

Wrap in an MXFunction constructed with the given options.

Like wrap, but the wrapper is built with opts (merged with the derivative options of this function) and is not cached. The named overload returns this function itself when opts is empty and name equals its current name; the unnamed overload always wraps, under the name "wrap_" + name().

>>> x = SX.sym("x")
>>> f = Function("f", [x], [sin(x)])
>>> f.wrap_as_needed("f", {}).class_name(), f.wrap_as_needed({}).class_name()
('SXFunction', 'MXFunction')
>>> f.wrap_as_needed("g", {"ad_weight": 1}).name()
'g'
>> x = SX.sym('x');
>> f = Function('f', {x}, {sin(x)});
>> f.wrap_as_needed('f', struct()).class_name()
SXFunction
>> f.wrap_as_needed(struct()).class_name()
MXFunction
>> f.wrap_as_needed('g', struct('ad_weight', 1)).name()
g
julia> x = ca.SX.sym("x");
julia> f = ca.Function("f", [x], [sin(x)]);
julia> ca.class_name(ca.wrap_as_needed(f, "f", Dict()))
"SXFunction"
julia> ca.class_name(ca.wrap_as_needed(f, Dict()))
"MXFunction"
julia> ca.name(ca.wrap_as_needed(f, "g", Dict("ad_weight" => 1)))
"g"

See also: wrap

Extra doc | Doc source | Implementation

Solvers

NLP

nlpsol(...)
nlpsol(str name, str solver, Importer compiler, dict opts) -> Function
nlpsol(str name, str solver, NlpBuilder nl, dict opts) -> Function
nlpsol(str name, str solver, dict:SX nlp, dict opts) -> Function
nlpsol(str name, str solver, dict:MX nlp, dict opts) -> Function
nlpsol(str name, str solver, str fname, dict opts) -> Function
nlpsol(str name, str solver, Function nlp, dict opts) -> Function

Create an NLP solver

Returns a Function that solves the parametric nonlinear program (NLP)

min          F(x, p)
x

subject to
LBX <=   x    <= UBX
LBG <= G(x, p) <= UBG
p  == P

nx: number of decision variables
ng: number of constraints
np: number of parameters

The problem is given as a dictionary with fields "x" (decision variables, a dense vector), "f" (scalar objective), and optionally "p" (parameters, dense vector) and "g" (constraint expression, dense vector). All entries must be of one symbolic type (SX or MX). A missing "f" is taken as 0 and a missing "g" as an empty vector; any other field name is an error, as is a symbol in "f" or "g" that is not part of "x" or "p". The problem can also be given as a Function with inputs "x", "p" and outputs "f", "g" (for instance one created with external), as the name of a shared library or a ".c" file (compiled on the fly with clang) containing such a function named "nlp", as an Importer, or as an NlpBuilder (an .nl file).

The returned Function has inputs x0, p, lbx, ubx, lbg, ubg, lam_x0, lam_g0 (see nlpsol_in) and outputs x, f, g, lam_x, lam_g, lam_p (see nlpsol_out). Call it with keyword arguments (returns a dictionary) or positionally with all 8 inputs (returns a tuple). Omitted inputs take their defaults: -inf for lbx and lbg, +inf for ubx and ubg, 0 otherwise (see nlpsol_default_in). A scalar passed for a vector input is broadcast to every entry. An input with lb > ub, lb = +inf or ub = -inf raises an "Ill-posed problem" error.

Multiplier convention: lam_x and lam_g are the Lagrange multipliers of the bound constraints on x and g; a multiplier is negative when the lower bound is active and positive when the upper bound is active, such that grad_x f + jac_x(g)' lam_g + lam_x = 0 at the solution. lam_p is the multiplier of p == P, i.e. minus the gradient of the optimal objective with respect to p. lam_x0 and lam_g0 are only used by solvers that support warm starts.

When the solver does not converge, the result still holds the last iterate and stats() reports "success" False and the plugin-specific "return_status"; with option "error_on_fail" True an exception is raised instead (default False for nlpsol).

Options common to all plugins (the plugin options follow in the tables below):

  • "expand": convert an MX problem to SX before creating the derivative functions (default false). Usually faster evaluation; fails on nodes without SX support.

  • "print_time": print a timing table after each call (default true for nlpsol).

  • "error_on_fail": raise on an unsuccessful solve (default false).

  • "calc_lam_x", "calc_lam_p", "calc_f", "calc_g": recompute lam_x (from the stationarity condition), lam_p, f and g in the base class from the solution returned by the plugin (defaults false, true, false, false). "calc_multipliers" sets calc_lam_x and calc_lam_p.

  • "bound_consistency": after the solve, clip x and g to their bounds and set each multiplier to the sign of its active bound, or 0 when both bounds are infinite (default false).

  • "discrete": list of nx booleans marking integer variables; requires a plugin with integer support, otherwise an error at construction.

  • "equality": list of ng booleans hinting which constraints have equal bounds.

  • "warn_initial_bounds": warn when x0 violates lbx or ubx (default false).

  • "iteration_callback": a Function (typically a Callback) with the nlpsol output scheme as inputs, called every "iteration_callback_step" iterations with the current iterate.

  • "detect_simple_bounds": move entries of g that are bounds on a single variable into the simple bounds lbx/ubx (default false).

  • "verbose", "monitor", "show_eval_warnings", "common_options", "specific_options": control diagnostics and the options of the generated derivative functions.

Plugin options are passed in a nested dictionary under the plugin name (e.g. {"ipopt": {"print_level": 0}}) or dotted ("ipopt.print_level"). The call to the returned Function can be embedded in an MX expression and differentiated: the sensitivities of the primal-dual solution with respect to any input follow from the KKT conditions.

>>> x = SX.sym("x"); y = SX.sym("y"); p = SX.sym("p")
>>> nlp = {"x": vertcat(x, y), "p": p, "f": (1 - x)**2 + p*(y - x**2)**2, "g": x + y}
>>> opts = {"ipopt.print_level": 0, "ipopt.sb": "yes", "print_time": False}
>>> S = nlpsol("S", "ipopt", nlp, opts)
>>> print(S)
S:(x0[2],p,lbx[2],ubx[2],lbg,ubg,lam_x0[2],lam_g0)->(x[2],f,g,lam_x[2],lam_g,lam_p) ...
>>> sol = S(x0=[2.5, 3.0], p=100, lbg=-1, ubg=1)
>>> sol["f"], sol["x"]
(DM(0.1456), DM([0.6188, 0.3812]))
>>> S.stats()["success"], S.stats()["return_status"]
(True, 'Solve_Succeeded')
>>> x_opt, f_opt, g_opt, lam_x, lam_g, lam_p = S([2.5, 3.0], 100, -inf, inf, -1, 1, 0, 0)
>>> f_opt, lam_g
(DM(0.1456), DM(0.3407))
>>> S(p=100)["x"]
DM([1, 1])
>> x = SX.sym('x'); y = SX.sym('y'); p = SX.sym('p');
>> nlp = struct('x', vertcat(x, y), 'p', p, 'f', (1 - x)^2 + p*(y - x^2)^2, 'g', x + y);
>> opts = struct('print_time', false, 'ipopt', struct('print_level', 0, 'sb', 'yes'));
>> S = nlpsol('S', 'ipopt', nlp, opts); disp(S)
S:(x0[2],p,lbx[2],ubx[2],lbg,ubg,lam_x0[2],lam_g0)->(x[2],f,g,lam_x[2],lam_g,lam_p) ...
>> sol = S('x0', [2.5; 3.0], 'p', 100, 'lbg', -1, 'ubg', 1);
>> sol.f, sol.x
0.1456
[0.6188, 0.3812]
>> st = S.stats(); disp(st.success), disp(st.return_status)
1
Solve_Succeeded
>> [x_opt, f_opt, g_opt, lam_x, lam_g, lam_p] = S([2.5; 3.0], 100, -inf, inf, -1, 1, 0, 0);
>> f_opt, lam_g
0.1456
0.3407
>> sol = S('p', 100); disp(sol.x)
[1, 1]
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y"); p = ca.SX.sym("p");
julia> nlp = Dict("x" => [x; y], "p" => p, "f" => (1 - x)^2 + p*(y - x^2)^2, "g" => x + y);
julia> opts = Dict("ipopt.print_level" => 0, "ipopt.sb" => "yes", "print_time" => false);
julia> S = ca.nlpsol("S", "ipopt", nlp, opts);
julia> print(ca.name_in(S))
["x0", "p", "lbx", "ubx", "lbg", "ubg", "lam_x0", "lam_g0"]
julia> print(ca.name_out(S))
["x", "f", "g", "lam_x", "lam_g", "lam_p"]
julia> sol = S(x0=[2.5, 3.0], p=100, lbg=-1, ubg=1);
julia> sol["f"]
DM(0.1456)
julia> sol["x"]
DM([0.6188, 0.3812])
julia> ca.stats(S)["success"], ca.stats(S)["return_status"]
(true, "Solve_Succeeded")
julia> x_opt, f_opt, g_opt, lam_x, lam_g, lam_p = S([2.5, 3.0], 100, -Inf, Inf, -1, 1, 0, 0);
julia> f_opt, lam_g
(0.1456, 0.3407)
julia> S(p=100)["x"]
DM([1, 1])
>>> x = SX.sym("x"); p = SX.sym("p")
>>> opts = {"ipopt.print_level": 0, "ipopt.sb": "yes", "print_time": False}
>>> S = nlpsol("S", "ipopt", {"x": x, "p": p, "f": (x - p)**2 + 3*p, "g": 2*x}, opts)
>>> sol = S(p=1, lbg=4)
>>> sol["x"], sol["lam_g"]
(DM(2), DM(-1))
>>> sol["lam_p"]
DM(-1)
>>> S(p=1, ubx=0)["lam_x"]
DM(2)
>>> pm = MX.sym("p")
>>> dxdp = Function("dxdp", [pm], [jacobian(S(p=pm)["x"], pm)])
>>> dxdp(5)
DM(1)
>> x = SX.sym('x'); p = SX.sym('p');
>> opts = struct('print_time', false, 'ipopt', struct('print_level', 0, 'sb', 'yes'));
>> S = nlpsol('S', 'ipopt', struct('x', x, 'p', p, 'f', (x - p)^2 + 3*p, 'g', 2*x), opts);
>> sol = S('p', 1, 'lbg', 4); sol.x, sol.lam_g
2
-1
>> sol.lam_p
-1
>> sol = S('p', 1, 'ubx', 0); sol.lam_x
2
>> pm = MX.sym('p'); sol = S('p', pm);
>> dxdp = Function('dxdp', {pm}, {jacobian(sol.x, pm)}); disp(dxdp(5))
1
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> opts = Dict("ipopt.print_level" => 0, "ipopt.sb" => "yes", "print_time" => false);
julia> nlp = Dict("x" => x, "p" => p, "f" => (x - p)^2 + 3*p, "g" => 2*x);
julia> S = ca.nlpsol("S", "ipopt", nlp, opts);
julia> sol = S(p=1, lbg=4);
julia> sol["x"], sol["lam_g"]
(2, -1)
julia> sol["lam_p"]
DM(-1)
julia> S(p=1, ubx=0)["lam_x"]
DM(2)
julia> pm = ca.MX.sym("p");
julia> dxdp = ca.Function("dxdp", [pm], [ca.jacobian(S(p=pm)["x"], pm)]);
julia> dxdp(5)
DM(1)
>>> x = SX.sym("x")
>>> opts = {"ipopt.print_level": 0, "ipopt.sb": "yes", "print_time": False}
>>> S = nlpsol("S", "ipopt", {"x": x, "f": x, "g": x}, opts)
>>> sol = S(lbx=0, ubx=1, lbg=2, ubg=3)
>>> S.stats()["success"], S.stats()["return_status"]
(False, 'Infeasible_Problem_Detected')
>>> S = nlpsol("S", "ipopt", {"x": x, "f": x, "g": x}, dict(opts, error_on_fail=True))
>>> try:
...     S(lbx=0, ubx=1, lbg=2, ubg=3)
... except RuntimeError as e:
...     print("nlpsol process failed" in str(e))
True
>>> try:
...     S(lbx=1, ubx=0)
... except RuntimeError as e:
...     print(str(e).splitlines()[-1])
Ill-posed problem detected: LBX[0] <= UBX[0] was violated. Got LBX[0]=1 and UBX[0] = 0.
>>> try:
...     nlpsol("S", "ipopt", {"x": x, "f": x, "h": x}, opts)
... except RuntimeError as e:
...     print("No such field: h" in str(e))
True
>> x = SX.sym('x');
>> opts = struct('print_time', false, 'ipopt', struct('print_level', 0, 'sb', 'yes'));
>> S = nlpsol('S', 'ipopt', struct('x', x, 'f', x, 'g', x), opts);
>> sol = S('lbx', 0, 'ubx', 1, 'lbg', 2, 'ubg', 3);
>> st = S.stats(); disp(st.success), disp(st.return_status)
0
Infeasible_Problem_Detected
>> opts.error_on_fail = true;
>> S = nlpsol('S', 'ipopt', struct('x', x, 'f', x, 'g', x), opts);
>> try, S('lbx', 0, 'ubx', 1, 'lbg', 2, 'ubg', 3); catch e, msg = e.message; end
>> contains(msg, 'nlpsol process failed')
1
>> try, S('lbx', 1, 'ubx', 0); catch e, msg = e.message; end
>> contains(msg, 'Ill-posed problem detected: LBX[0] <= UBX[0] was violated')
1
>> nlp = struct('x', x, 'f', x, 'h', x);
>> try, nlpsol('S', 'ipopt', nlp, opts); catch e, msg = e.message; end
>> contains(msg, 'No such field: h')
1
julia> x = ca.SX.sym("x");
julia> opts = Dict("ipopt.print_level" => 0, "ipopt.sb" => "yes", "print_time" => false);
julia> S = ca.nlpsol("S", "ipopt", Dict("x" => x, "f" => x, "g" => x), opts);
julia> sol = S(lbx=0, ubx=1, lbg=2, ubg=3);
julia> ca.stats(S)["success"], ca.stats(S)["return_status"]
(false, "Infeasible_Problem_Detected")
julia> S = ca.nlpsol("S", "ipopt", Dict("x" => x, "f" => x, "g" => x),
                     merge(opts, Dict("error_on_fail" => true)));
julia> try
           S(lbx=0, ubx=1, lbg=2, ubg=3)
       catch e
           println(occursin("nlpsol process failed", sprint(showerror, e)))
       end
true
julia> try
           S(lbx=1, ubx=0)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Ill-posed problem detected: LBX[0] <= UBX[0] was violated. Got LBX[0]=1 and UBX[0] = 0.
julia> try
           ca.nlpsol("S", "ipopt", Dict("x" => x, "f" => x, "h" => x), opts)
       catch e
           println(occursin("No such field: h", sprint(showerror, e)))
       end
true

General information

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

bound_consistenc y

OT_BOOL

Ensure that primal-dual solution is consistent with the bounds

casadi::Nlpsol

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

calc_f

OT_BOOL

Calculate 'f' in the Nlpsol base class

casadi::Nlpsol

calc_g

OT_BOOL

Calculate 'g' in the Nlpsol base class

casadi::Nlpsol

calc_lam_p

OT_BOOL

Calculate 'lam_p' in the Nlpsol base class

casadi::Nlpsol

calc_lam_x

OT_BOOL

Calculate 'lam_x' in the Nlpsol base class

casadi::Nlpsol

calc_multipliers

OT_BOOL

Calculate Lagrange multipliers in the Nlpsol base class

casadi::Nlpsol

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

common_options

OT_DICT

Options for auto-generated functions

casadi::OracleFu nction

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

detect_simple_bo unds

OT_BOOL

Automatically detect simple bounds (lbx/ubx) (default false). This is hopefully beneficial to speed and robustness but may also have adverse affects: 1) Subtleties in heuristics and stopping criteria may change the solution, 2) IPOPT may lie about multipliers of simple equality bounds unless 'f ixed_variable_tr eatment' is set to 'relax_bounds'.

casadi::Nlpsol

detect_simple_bo unds_is_simple

OT_BOOLVECTOR

For internal use only.

casadi::Nlpsol

detect_simple_bo unds_parts

OT_FUNCTION

For internal use only.

casadi::Nlpsol

detect_simple_bo unds_target_x

OT_INTVECTOR

For internal use only.

casadi::Nlpsol

discrete

OT_BOOLVECTOR

Indicates which of the variables are discrete, i.e. integer- valued

casadi::Nlpsol

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

equality

OT_BOOLVECTOR

Indicate an upfront hint which of the constraints are equalities. Some solvers may be able to exploit this knowledge. When true, the corresponding lower and upper bounds are assumed equal. When false, the corresponding bounds may be equal or different.

casadi::Nlpsol

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

eval_errors_fata l

OT_BOOL

When errors occur during evaluation of f,g,...,stop the iterations

casadi::Nlpsol

expand

OT_BOOL

Replace MX with SX expressions in problem formulation [false] This happens before creating derivatives unless indicated by postpone_expand

casadi::OracleFu nction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

ignore_check_vec

OT_BOOL

If set to true, the input shape of F will not be checked.

casadi::Nlpsol

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

iteration_callba ck

OT_FUNCTION

A function that will be called at each iteration with the solver as input. Check documentation of Callback.

casadi::Nlpsol

iteration_callba ck_ignore_errors

OT_BOOL

If set to true, errors thrown by iteration_callba ck will be ignored.

casadi::Nlpsol

iteration_callba ck_step

OT_INT

Only call the callback function every few iterations.

casadi::Nlpsol

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

min_lam

OT_DOUBLE

Minimum allowed multiplier value

casadi::Nlpsol

monitor

OT_STRINGVECTOR

Set of user problem functions to be monitored

casadi::OracleFu nction

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

no_nlp_grad

OT_BOOL

Prevent the creation of the 'nlp_grad' function

casadi::Nlpsol

oracle_options

OT_DICT

Options to be passed to the oracle function

casadi::Nlpsol

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

postpone_expand

OT_BOOL

When expand is active, postpone it until after creation of derivatives. Default: False

casadi::OracleFu nction

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

sens_force_equal ity

OT_BOOL

Treat constraints with equal bounds as active in parametric sensitivities, regardless of the multiplier, see issue #2545 [false].

casadi::Nlpsol

sens_linsol

OT_STRING

Linear solver used for parametric sensitivities (default 'qr').

casadi::Nlpsol

sens_linsol_opti ons

OT_DICT

Linear solver options used for parametric sensitivities.

casadi::Nlpsol

show_eval_warnin gs

OT_BOOL

Show warnings generated from function evaluations [true]

casadi::OracleFu nction

specific_options

OT_DICT

Options for specific auto- generated functions, overwriting the defaults from common_options. Nested dictionary.

casadi::OracleFu nction

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

verbose_init

OT_BOOL

Print out timing information about the different stages of initialization

casadi::Nlpsol

warn_initial_bou nds

OT_BOOL

Warn if the initial guess does not satisfy LBX and UBX

casadi::Nlpsol

>Input scheme: casadi::NlpsolInput (NLPSOL_NUM_IN = 8)

Full name

Short

Description

NLPSOL_X0

x0

Decision variables, initial guess (nx x 1), default 0.

NLPSOL_P

p

Value of fixed parameters (np x 1), default 0.

NLPSOL_LBX

lbx

Decision variables lower bound (nx x 1), default -inf.

NLPSOL_UBX

ubx

Decision variables upper bound (nx x 1), default +inf.

NLPSOL_LBG

lbg

Constraints lower bound (ng x 1), default -inf.

NLPSOL_UBG

ubg

Constraints upper bound (ng x 1), default +inf.

NLPSOL_LAM_X0

lam_x0

Lagrange multipliers for bounds on X, initial guess (nx x 1), default 0.

NLPSOL_LAM_G0

lam_g0

Lagrange multipliers for bounds on G, initial guess (ng x 1), default 0.

>Output scheme: casadi::NlpsolOutput (NLPSOL_NUM_OUT = 6)

Full name

Short

Description

NLPSOL_X

x

Decision variables at the optimal solution (nx x 1)

NLPSOL_F

f

Cost function value at the optimal solution (1 x 1)

NLPSOL_G

g

Constraints function at the optimal solution (ng x 1)

NLPSOL_LAM_X

lam_x

Lagrange multipliers for bounds on X at the solution (nx x 1); negative for an active lower bound, positive for an active upper bound

NLPSOL_LAM_G

lam_g

Lagrange multipliers for bounds on G at the solution (ng x 1); same sign convention.

NLPSOL_LAM_P

lam_p

Lagrange multipliers for p == P at the solution (np x 1): minus the gradient of the optimal cost with respect to p

List of plugins - ampl

  • blocksqp

  • bonmin

  • ccopt

  • fatrop

  • ipopt

  • knitro

  • madnlp

  • snopt

  • uno

  • worhp

  • feasiblesqpmethod

  • qrsqp

  • scpgen

  • sqpmethod

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Nlpsol.doc("myextraplugin")


ampl

Interface to AMPL

Authors: Joel Andersson

>List of available options

Id

Type

Description

solver

OT_STRING

AMPL solver binary


blocksqp

This is a modified version of blockSQP by Janka et al.

Authors: Dennis Janka, Joel Andersson

>List of available options

Id

Type

Description

block_hess

OT_INT

Blockwise Hessian approximation?

col_eps

OT_DOUBLE

Epsilon for COL scaling strategy

col_tau1

OT_DOUBLE

tau1 for COL scaling strategy

col_tau2

OT_DOUBLE

tau2 for COL scaling strategy

conv_strategy

OT_INT

Convexification strategy

delta

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

delta_h0

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

eps

OT_DOUBLE

Values smaller than this are regarded as numerically zero

eta

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

fallback_scaling

OT_INT

If indefinite update is used, the type of fallback strategy

fallback_update

OT_INT

If indefinite update is used, the type of fallback strategy

gamma_f

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

gamma_theta

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

globalization

OT_BOOL

Enable globalization

hess_damp

OT_INT

Activate Powell damping for BFGS

hess_damp_fac

OT_DOUBLE

Damping factor for BFGS Powell modification

hess_lim_mem

OT_INT

Full or limited memory

hess_memsize

OT_INT

Memory size for L-BFGS updates

hess_scaling

OT_INT

Scaling strategy for Hessian approximation

hess_update

OT_INT

Type of Hessian approximation

ini_hess_diag

OT_DOUBLE

Initial Hessian guess: diagonal matrix diag(iniHessDiag)

kappa_f

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

kappa_minus

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

kappa_plus

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

kappa_plus_max

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

kappa_soc

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

linsol

OT_STRING

The linear solver to be used by the QP method

max_consec_reduced_steps

OT_INT

Maximum number of consecutive reduced steps

max_consec_skipped_updates

OT_INT

Maximum number of consecutive skipped updates

max_conv_qp

OT_INT

How many additional QPs may be solved for convexification per iteration?

max_it_qp

OT_INT

Maximum number of QP iterations per SQP iteration

max_iter

OT_INT

Maximum number of SQP iterations

max_line_search

OT_INT

Maximum number of steps in line search

max_soc_iter

OT_INT

Maximum number of SOC line search iterations

max_time_qp

OT_DOUBLE

Maximum number of time in seconds per QP solve per SQP iteration

nlinfeastol

OT_DOUBLE

Nonlinear feasibility tolerance

obj_lo

OT_DOUBLE

Lower bound on objective function [-inf]

obj_up

OT_DOUBLE

Upper bound on objective function [inf]

opttol

OT_DOUBLE

Optimality tolerance

print_header

OT_BOOL

Print solver header at startup

print_iteration

OT_BOOL

Print SQP iterations

print_maxit_reached

OT_BOOL

Print error when maximum number of SQP iterations reached

qp_init

OT_BOOL

Use warmstarting

qpsol

OT_STRING

The QP solver to be used by the SQP method

qpsol_options

OT_DICT

Options to be passed to the QP solver

restore_feas

OT_BOOL

Use feasibility restoration phase

rho

OT_DOUBLE

Feasibility restoration phase parameter

s_f

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

s_theta

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

schur

OT_BOOL

Use qpOASES Schur compliment approach

skip_first_globalization

OT_BOOL

No globalization strategy in first iteration

theta_max

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

theta_min

OT_DOUBLE

Filter line search parameter, cf. IPOPT paper

warmstart

OT_BOOL

Use warmstarting

which_second_derv

OT_INT

For which block should second derivatives be provided by the user

zeta

OT_DOUBLE

Feasibility restoration phase parameter


bonmin

When in warmstart mode, output NLPSOL_LAM_X may be used as input

NOTE: Even when max_iter == 0, it is not guaranteed that input(NLPSOL_X0) == output(NLPSOL_X). Indeed if bounds on X or constraints are unmet, they will differ.

For a good tutorial on BONMIN, see https://drops.dagstuhl.de/storage/16dagstuhl-seminar-proceedings/dsp- vol09061/DagSemProc.09061.16/DagSemProc.09061.16.pdf

A good resource about the algorithms in BONMIN is: Wachter and L. T. Biegler, On the Implementation of an Interior-Point Filter Line-Search Algorithm for Large-Scale Nonlinear Programming, Mathematical Programming 106(1), pp. 25-57, 2006 (As Research Report RC 23149, IBM T. J. Watson Research Center, Yorktown, USA

Caveats:

  • with default options, multipliers for the decision variables are wrong for

equality constraints. Change the 'fixed_variable_treatment' to 'make_constraint' or 'relax_bounds' to obtain correct results. Extra doc: https://github.com/casadi/casadi/wiki/L_223

>List of available options

Id

Type

Description

bonmin

OT_DICT

Options to be passed to BONMIN

con_integer_md

OT_DICT

Integer metadata (a dictionary with lists of integers) about constraints to be passed to BONMIN

con_numeric_md

OT_DICT

Numeric metadata (a dictionary with lists of reals) about constraints to be passed to BONMIN

con_string_md

OT_DICT

String metadata (a dictionary with lists of strings) about constraints to be passed to BONMIN

grad_f

OT_FUNCTION

Function for calculating the gradient of the objective (column, autogenerated by default)

grad_f_options

OT_DICT

Options for the autogenerated gradient of the objective.

hess_lag

OT_FUNCTION

Function for calculating the Hessian of the Lagrangian (autogenerated by default)

hess_lag_options

OT_DICT

Options for the autogenerated Hessian of the Lagrangian.

jac_g

OT_FUNCTION

Function for calculating the Jacobian of the constraints (autogenerated by default)

jac_g_options

OT_DICT

Options for the autogenerated Jacobian of the constraints.

pass_nonlinear_constrai nts

OT_BOOL

Pass list of constraints entering nonlinearly to BONMIN

pass_nonlinear_variable s

OT_BOOL

Pass list of variables entering nonlinearly to BONMIN

sos1_groups

OT_INTVECTORVECTOR

Options for the autogenerated gradient of the objective.

sos1_priorities

OT_INTVECTOR

Options for the autogenerated gradient of the objective.

sos1_weights

OT_DOUBLEVECTORVECTOR

Options for the autogenerated gradient of the objective.

var_integer_md

OT_DICT

Integer metadata (a dictionary with lists of integers) about variables to be passed to BONMIN

var_numeric_md

OT_DICT

Numeric metadata (a dictionary with lists of reals) about variables to be passed to BONMIN

var_string_md

OT_DICT

String metadata (a dictionary with lists of strings) about variables to be passed to BONMIN


ccopt

>List of available options

Id

Type

Description

cc_pairs

OT_INTVECTORVECTOR

List of complementary constraints on simple bounds. Pair (i, j) encodes complementarity between the bounds on variable i and variable j.

cc_types

OT_INTVECTOR

Type of cc pairs (default: 0).

ccopt

OT_DICT

Options to be passed to ccopt relaxation algorithm

convexify_margin

OT_DOUBLE

When using a convexification strategy, make sure that the smallest eigenvalue is at least this (default: 1e-7).

convexify_strategy

OT_STRING

NONE|regularize|eigen- reflect|eigen-clip. Strategy to convexify the Lagrange Hessian before passing it to the solver.

madnlp

OT_DICT

Options to be passed to madnlp


fatrop

>List of available options

Id

Type

Description

N

OT_INT

OCP horizon

convexify_margin

OT_DOUBLE

When using a convexification strategy, make sure that the smallest eigenvalue is at least this (default: 1e-7).

convexify_strategy

OT_STRING

NONE|regularize|eigen- reflect|eigen-clip. Strategy to convexify the Lagrange Hessian before passing it to the solver.

debug

OT_BOOL

Produce debug information (default: false)

fatrop

OT_DICT

Options to be passed to fatrop

ng

OT_INTVECTOR

Number of non-dynamic constraints, length N+1

nu

OT_INTVECTOR

Number of controls, length N+1

nx

OT_INTVECTOR

Number of states, length N+1

structure_detection

OT_STRING

NONE | auto | manual

Fatrop is a solver developed at KU Leuven by Lander Vanroye and Wilm Decre. The algorithm is based on IPOPT, but the linear algebra is much more efficient.

With structure_detection = 'none' (default), it will behave as a general- purpose dense nonlinear program solver.

With structure_detection = 'manual', you can specify a block structure.

Let's say you perform multiply shooting with a system

x_k+1 = A_k x_k + B_k u_k

Suppose your constraint Jacobian looks like:

nx0  nu0  nx1  nu1  nx2  nu2
-----------------------------

nx1 |A0 B0 I0 ng1 |C0 D0 nx2 | A1 B1 I1 ng2 | C1 D1 ng3 | C2 D2

with n* capturing the number of states, inputs, and constraints in each block.

You can then specify this structure with:

N = 2 nx = [nx0 ,nx1, nx2] nu = [nu0, nu1, nu2] ng = [ng1, ng2, ng3]

With structure_detection = 'auto', the block-defining parameters nx, nu, ng, and N are automatically detected from the sparsity pattern.


ipopt

When in warmstart mode, output NLPSOL_LAM_X may be used as input

NOTE: Even when max_iter == 0, it is not guaranteed that input(NLPSOL_X0) == output(NLPSOL_X). Indeed if bounds on X or constraints are unmet, they will differ.

For a good tutorial on IPOPT, see https://drops.dagstuhl.de/storage/16dagstuhl-seminar-proceedings/dsp- vol09061/DagSemProc.09061.16/DagSemProc.09061.16.pdf

A good resource about the algorithms in IPOPT is: Wachter and L. T. Biegler, On the Implementation of an Interior-Point Filter Line-Search Algorithm for Large-Scale Nonlinear Programming, Mathematical Programming 106(1), pp. 25-57, 2006 (As Research Report RC 23149, IBM T. J. Watson Research Center, Yorktown, USA

Caveats:

  • with default options, multipliers for the decision variables are wrong for

equality constraints. Change the 'fixed_variable_treatment' to 'make_constraint' or 'relax_bounds' to obtain correct results. Extra doc: https://github.com/casadi/casadi/wiki/L_21y

>List of available options

Id

Type

Description

clip_inactive_lam

OT_BOOL

Explicitly set Lagrange multipliers to 0 when bound is deemed inactive (default: false).

con_integer_md

OT_DICT

Integer metadata (a dictionary with lists of integers) about constraints to be passed to IPOPT

con_numeric_md

OT_DICT

Numeric metadata (a dictionary with lists of reals) about constraints to be passed to IPOPT

con_string_md

OT_DICT

String metadata (a dictionary with lists of strings) about constraints to be passed to IPOPT

convexify_margin

OT_DOUBLE

When using a convexification strategy, make sure that the smallest eigenvalue is at least this (default: 1e-7).

convexify_strategy

OT_STRING

NONE|regularize|eigen- reflect|eigen-clip. Strategy to convexify the Lagrange Hessian before passing it to the solver.

grad_f

OT_FUNCTION

Function for calculating the gradient of the objective (column, autogenerated by default)

hess_lag

OT_FUNCTION

Function for calculating the Hessian of the Lagrangian (autogenerated by default)

inactive_lam_strategy

OT_STRING

Strategy to detect if a bound is inactive. RELTOL: use solver-defined constraint tolerance * inactive_lam_value|abstol: use inactive_lam_value

inactive_lam_value

OT_DOUBLE

Value used in inactive_lam_strategy (default: 10).

ipopt

OT_DICT

Options to be passed to IPOPT

jac_g

OT_FUNCTION

Function for calculating the Jacobian of the constraints (autogenerated by default)

max_iter_eig

OT_DOUBLE

Maximum number of iterations to compute an eigenvalue decomposition (default: 50).

nonlinear_variables

OT_BOOLVECTOR

Which decision variables enter nonlinearly? (detected automatically by default)

pass_nonlinear_variables

OT_BOOL

Pass list of variables entering nonlinearly to IPOPT

var_integer_md

OT_DICT

Integer metadata (a dictionary with lists of integers) about variables to be passed to IPOPT

var_numeric_md

OT_DICT

Numeric metadata (a dictionary with lists of reals) about variables to be passed to IPOPT

var_string_md

OT_DICT

String metadata (a dictionary with lists of strings) about variables to be passed to IPOPT


knitro

KNITRO interface

>List of available options

Id

Type

Description

complem_variables

OT_INTVECTORVECTOR

List of complementary constraints on simple bounds. Pair (i, j) encodes complementarity between the bounds on variable i and variable j.

contype

OT_INTVECTOR

Type of constraint

detect_linear_constraint s

OT_BOOL

Detect type of constraints

knitro

OT_DICT

Options to be passed to KNITRO

options_file

OT_STRING

Read options from file (solver specific)


madnlp

>List of available options

Id

Type

Description

convexify_margin

OT_DOUBLE

When using a convexification strategy, make sure that the smallest eigenvalue is at least this (default: 1e-7).

convexify_strategy

OT_STRING

NONE|regularize|eigen-reflect|eigen- clip. Strategy to convexify the Lagrange Hessian before passing it to the solver.

madnlp

OT_DICT

Options to be passed to madnlp


snopt

SNOPT interface

>List of available options

Id

Type

Description

snopt

OT_DICT

Options to be passed to SNOPT

start

OT_STRING

Warm-start options for Worhp: cold|warm|hot


uno

David Kiessling Uno interface

>List of available options

Id

Type

Description

uno

OT_DICT

Options to be passed to UNO


worhp

WORHP interface

Designed for Worhp 1.12

>List of available options

Id

Type

Description

worhp

OT_DICT

Options to be passed to WORHP


feasiblesqpmethod

A textbook FeasibleSQPMethod

>List of available options

Id

Type

Description

anderson_memory

OT_INT

Anderson memory. If Anderson is used default is 1, else default is 0.

contraction_acceptance_val ue

OT_DOUBLE

If the empirical contraction rate in the feasibility iterations is above this value in the heuristics the iterations are aborted.

convexify_margin

OT_DOUBLE

When using a convexification strategy, make sure that the smallest eigenvalue4 is at least this (default: 1e-7).

convexify_strategy

OT_STRING

NONE|regularize|eigen- reflect|eigen-clip. Strategy to convexify the Lagrange Hessian before passing it to the solver.

f

OT_FUNCTION

Function for calculating the objective function (autogenerated by default)

feas_tol

OT_DOUBLE

Feasibility tolerance. Below this tolerance an iterate is considered to be feasible.

g

OT_FUNCTION

Function for calculating the constraints (autogenerated by default)

grad_f

OT_FUNCTION

Function for calculating the gradient of the objective (autogenerated by default)

hess_lag

OT_FUNCTION

Function for calculating the Hessian of the Lagrangian (autogenerated by default)

hessian_approximation

OT_STRING

limited-memory|exact

init_feasible

OT_BOOL

Initialize the QP subproblems with a feasible initial value (default: false).

jac_g

OT_FUNCTION

Function for calculating the Jacobian of the constraints (autogenerated by default)

lbfgs_memory

OT_INT

Size of L-BFGS memory.

max_inner_iter

OT_DOUBLE

Maximum number of inner iterations.

max_iter

OT_INT

Maximum number of SQP iterations

max_iter_eig

OT_DOUBLE

Maximum number of iterations to compute an eigenvalue decomposition (default: 50).

merit_memory

OT_INT

Size of memory to store history of merit function values

min_iter

OT_INT

Minimum number of SQP iterations

optim_tol

OT_DOUBLE

Optimality tolerance. Below this value an iterate is considered to be optimal.

print_header

OT_BOOL

Print the header with problem statistics

print_iteration

OT_BOOL

Print the iterations

print_status

OT_BOOL

Print a status message after solving

qpsol

OT_STRING

The QP solver to be used by the SQP method [qpoases]

qpsol_options

OT_DICT

Options to be passed to the QP solver

solve_type

OT_STRING

The solver type: Either SQP or SLP. Defaults to SQP

tol_du

OT_DOUBLE

Stopping criterion for dual infeasability

tol_pr

OT_DOUBLE

Stopping criterion for primal infeasibility

tr_acceptance

OT_DOUBLE

Is the trust-region ratio above this value, the step is accepted.

tr_alpha1

OT_DOUBLE

Lower alpha in trust- region size criterion.

tr_alpha2

OT_DOUBLE

Upper alpha in trust- region size criterion.

tr_eta1

OT_DOUBLE

Lower eta in trust-region acceptance criterion.

tr_eta2

OT_DOUBLE

Upper eta in trust-region acceptance criterion.

tr_rad0

OT_DOUBLE

Initial trust-region radius.

tr_rad_max

OT_DOUBLE

Maximum trust-region radius.

tr_rad_min

OT_DOUBLE

Minimum trust-region radius.

tr_scale_vector

OT_DOUBLEVECTOR

Vector that tells where trust-region is applied.

tr_tol

OT_DOUBLE

Trust-region tolerance. Below this value another scalar is equal to the trust region radius.

use_anderson

OT_BOOL

Use Anderson Acceleration. (default false)

watchdog

OT_INT

Number of watchdog iterations in feasibility iterations. After this amount of iterations, it is checked with the contraction acceptance value, if iterations are converging.


qrsqp

A textbook SQPMethod

>List of available options

Id

Type

Description

beta

OT_DOUBLE

Line-search parameter, restoration factor of stepsize

c1

OT_DOUBLE

Armijo condition, coefficient of decrease in merit

hessian_approximation

OT_STRING

limited-memory|exact

lbfgs_memory

OT_INT

Size of L-BFGS memory.

max_iter

OT_INT

Maximum number of SQP iterations

max_iter_ls

OT_INT

Maximum number of linesearch iterations

merit_memory

OT_INT

Size of memory to store history of merit function values

min_iter

OT_INT

Minimum number of SQP iterations

min_step_size

OT_DOUBLE

The size (inf-norm) of the step size should not become smaller than this.

print_header

OT_BOOL

Print the header with problem statistics

print_iteration

OT_BOOL

Print the iterations

qpsol

OT_STRING

The QP solver to be used by the SQP method [qrqp]

qpsol_options

OT_DICT

Options to be passed to the QP solver

regularize

OT_BOOL

Automatic regularization of Lagrange Hessian.

tol_du

OT_DOUBLE

Stopping criterion for dual infeasability

tol_pr

OT_DOUBLE

Stopping criterion for primal infeasibility


scpgen

A structure-exploiting sequential quadratic programming (to be come sequential convex programming) method for nonlinear programming.

>List of available options

Id

Type

Description

beta

OT_DOUBLE

Line-search parameter, restoration factor of stepsize

c1

OT_DOUBLE

Armijo condition, coefficient of decrease in merit

codegen

OT_BOOL

C-code generation

hessian_approximation

OT_STRING

gauss-newton|exact

lbfgs_memory

OT_INT

Size of L-BFGS memory.

max_iter

OT_INT

Maximum number of SQP iterations

max_iter_ls

OT_INT

Maximum number of linesearch iterations

merit_memsize

OT_INT

Size of memory to store history of merit function values

merit_start

OT_DOUBLE

Lower bound for the merit function parameter

name_x

OT_STRINGVECTOR

Names of the variables.

print_header

OT_BOOL

Print the header with problem statistics

print_x

OT_INTVECTOR

Which variables to print.

qpsol

OT_STRING

The QP solver to be used by the SQP method

qpsol_options

OT_DICT

Options to be passed to the QP solver

reg_threshold

OT_DOUBLE

Threshold for the regularization.

regularize

OT_BOOL

Automatic regularization of Lagrange Hessian.

tol_du

OT_DOUBLE

Stopping criterion for dual infeasability

tol_pr

OT_DOUBLE

Stopping criterion for primal infeasibility

tol_pr_step

OT_DOUBLE

Stopping criterion for the step size

tol_reg

OT_DOUBLE

Stopping criterion for regularization


sqpmethod

A textbook SQPMethod

>List of available options

Id

Type

Description

beta

OT_DOUBLE

Line-search parameter, restoration factor of stepsize

c1

OT_DOUBLE

Armijo condition, coefficient of decrease in merit

convexify_margin

OT_DOUBLE

When using a convexification strategy, make sure that the smallest eigenvalue is at least this (default: 1e-7).

convexify_strategy

OT_STRING

NONE|regularize|eigen- reflect|eigen-clip. Strategy to convexify the Lagrange Hessian before passing it to the solver.

elastic_mode

OT_BOOL

Enable the elastic mode which is used when the QP is infeasible (default: false).

gamma_0

OT_DOUBLE

Starting value for the penalty parameter of elastic mode (default: 1).

gamma_1_min

OT_DOUBLE

Minimum value for gamma_1 (default: 1e-5).

gamma_max

OT_DOUBLE

Maximum value for the penalty parameter of elastic mode (default: 1e20).

hess_lag

OT_FUNCTION

Function for calculating the Hessian of the Lagrangian (autogenerated by default)

hessian_approximation

OT_STRING

limited-memory|exact

init_feasible

OT_BOOL

Initialize the QP subproblems with a feasible initial value (default: false).

jac_fg

OT_FUNCTION

Function for calculating the gradient of the objective and Jacobian of the constraints (autogenerated by default)

lbfgs_memory

OT_INT

Size of L-BFGS memory.

max_iter

OT_INT

Maximum number of SQP iterations

max_iter_eig

OT_DOUBLE

Maximum number of iterations to compute an eigenvalue decomposition (default: 50).

max_iter_ls

OT_INT

Maximum number of linesearch iterations

merit_memory

OT_INT

Size of memory to store history of merit function values

min_iter

OT_INT

Minimum number of SQP iterations

min_step_size

OT_DOUBLE

The size (inf-norm) of the step size should not become smaller than this.

print_header

OT_BOOL

Print the header with problem statistics

print_iteration

OT_BOOL

Print the iterations

print_status

OT_BOOL

Print a status message after solving

qpsol

OT_STRING

The QP solver to be used by the SQP method [qpoases]

qpsol_options

OT_DICT

Options to be passed to the QP solver

second_order_corrections

OT_BOOL

Enable second order corrections. These are used when a step is considered bad by the merit function and constraint norm (default: false).

tol_du

OT_DOUBLE

Stopping criterion for dual infeasability

tol_pr

OT_DOUBLE

Stopping criterion for primal infeasibility

Authors: Joel Andersson

Extra doc | Doc source | Implementation

QP

High-level

qpsol(...)
qpsol(str name, str solver, dict:SX qp, dict opts) -> Function
qpsol(str name, str solver, dict:MX qp, dict opts) -> Function

Low-level

conic(...)

Create a QP solver

conic(str name, str solver, dict:Sparsity qp, dict opts) -> Function

Returns a Function that solves the convex quadratic program (QP)

min          1/2 x' H x + g' x
x

subject to
LBA <= A x <= UBA
LBX <= x   <= UBX

resize(Q x, np, np) + P >= 0 (psd)

with :
H sparse (n x n) positive definite
g dense  (n x 1)
A sparse (nc x n)
Q sparse symmetric (np^2 x n)
P sparse symmetric (np x nq)

n: number of decision variables (x)
nc: number of constraints (A)
nq: shape of psd constraint matrix

Whether an indefinite H is detected depends on the plugin: some raise an error, others return a stationary point. Second-order cone constraints can be added as psd constraints through the helper function soc: || x ||_2 <= y is equivalent to soc(x, y) being psd, with soc(x, y) = [y*I x; x' y] (Schur complement). Only some plugins support psd constraints.

conic is the low-level form: the problem is given by the sparsity patterns of "h" and "a" (and optionally "q", "p"), and the numerical values are passed at every call. At least one of "h" and "a" is needed; a missing "h" means a linear objective (LP) and a missing "a" means no linear constraints. "h" must have a square, symmetric sparsity pattern. Inputs are h, g, a, lba, uba, lbx, ubx, x0, lam_x0, lam_a0, q, p (see conic_in); outputs are x, cost, lam_a, lam_x (see conic_out). Omitted inputs default to -inf (lba, lbx), +inf (uba, ubx) or 0.

qpsol is the symbolic form: a dictionary with fields "x" (dense vector), "f" (scalar), optionally "p" (parameters) and "g" (dense vector), as for nlpsol. The matrices H, g, A and the constant terms are obtained by symbolic differentiation and evaluated at every call at x0 and p; "f" must be quadratic and "g" linear in "x", this is NOT checked: other expressions are silently replaced by their second order (f) or first order (g) expansion around x0. The returned Function has the nlpsol input and output scheme (x0, p, lbx, ubx, lbg, ubg, lam_x0, lam_g0 -> x, f, g, lam_x, lam_g, lam_p); lam_p is always NaN.

Multiplier convention as for nlpsol: a multiplier is negative when the lower bound is active and positive when the upper bound is active, such that H x + g + A' lam_a + lam_x = 0.

To silence a solver, set "print_time" False plus the plugin's own options, e.g. {"print_iter": False, "print_header": False, "print_info": False} for qrqp or {"printLevel": "none"} for qpoases (its copyright notice is printed regardless).

Options common to all plugins ("error_on_fail" defaults to true for QP solvers, so a failed solve raises; with false the plugin result is returned and stats() reports "success"):

  • "discrete": list of n booleans marking integer variables; needs a plugin with integer support (e.g. cplex, gurobi, highs), otherwise an error at construction.

  • "equality": list of nc booleans hinting which linear constraints have equal bounds.

  • "print_problem": print the numerical problem data at every call (default false).

  • "print_time": print a timing table after each call (default false).

  • "expand" (qpsol only): convert an MX problem to SX (default false).

  • "sens_min_lam", "sens_linsol", "sens_linsol_options": used when differentiating the solver Function (a call embedded in an MX expression): a bound is treated as active when its multiplier exceeds "sens_min_lam" in magnitude (default 0) and the KKT system is solved with linear solver "sens_linsol" (default "qr"). The plugin options follow in the tables below.

>>> x = SX.sym("x"); y = SX.sym("y")
>>> qp = {"x": vertcat(x, y), "f": x**2 + y**2 + x*y - 3*x, "g": x + y}
>>> opts = {"print_iter": False, "print_header": False, "print_info": False}
>>> S = qpsol("S", "qrqp", qp, opts)
>>> S.name_in()
['x0', 'p', 'lbx', 'ubx', 'lbg', 'ubg', 'lam_x0', 'lam_g0']
>>> S.name_out()
['x', 'f', 'g', 'lam_x', 'lam_g', 'lam_p']
>>> sol = S(lbg=1, ubg=1, lbx=0)
>>> sol["x"], sol["f"]
(DM([1, 0]), DM(-2))
>>> sol["lam_g"], sol["lam_x"]
(DM(1), DM([0, -2]))
>>> sol["g"], sol["lam_p"].shape
(DM(1), (0, 0))
>>> S.stats()["success"], S.stats()["return_status"]
(True, 'success')
>> x = SX.sym('x'); y = SX.sym('y');
>> qp = struct('x', vertcat(x, y), 'f', x^2 + y^2 + x*y - 3*x, 'g', x + y);
>> opts = struct('print_iter', false, 'print_header', false, 'print_info', false);
>> S = qpsol('S', 'qrqp', qp, opts);
>> S.name_in()
x0
p
lbx
ubx
lbg
ubg
lam_x0
lam_g0
>> S.name_out()
x
f
g
lam_x
lam_g
lam_p
>> sol = S('lbg', 1, 'ubg', 1, 'lbx', 0);
>> sol.x, sol.f
[1, 0]
-2
>> sol.lam_g, sol.lam_x
1
[0, -2]
>> sol.g, size(sol.lam_p)
1
0 0
>> st = S.stats(); disp(st.success), disp(st.return_status)
1
success
julia> x = ca.SX.sym("x"); y = ca.SX.sym("y");
julia> qp = Dict("x" => [x; y], "f" => x^2 + y^2 + x*y - 3*x, "g" => x + y);
julia> opts = Dict("print_iter" => false, "print_header" => false, "print_info" => false);
julia> S = ca.qpsol("S", "qrqp", qp, opts);
julia> ca.name_in(S)
8-element Vector{String}:
 "x0"
 "p"
 "lbx"
 "ubx"
 "lbg"
 "ubg"
 "lam_x0"
 "lam_g0"
julia> ca.name_out(S)
6-element Vector{String}:
 "x"
 "f"
 "g"
 "lam_x"
 "lam_g"
 "lam_p"
julia> sol = S(lbg=1, ubg=1, lbx=0);
julia> sol["x"], sol["f"]
([1, 0], -2)
julia> sol["lam_g"], sol["lam_x"]
(1, [0, -2])
julia> sol["g"], size(sol["lam_p"])
(1, (0, 0))
julia> ca.stats(S)["success"], ca.stats(S)["return_status"]
(true, "success")
>>> H = DM([[2, 1], [1, 2]]); g = DM([-3, 0]); A = DM([[1, 1]])
>>> opts = {"print_iter": False, "print_header": False, "print_info": False}
>>> C = conic("C", "qrqp", {"h": H.sparsity(), "a": A.sparsity()}, opts)
>>> print(C)
C:(h[2x2],g[2],a[1x2],lba,uba,lbx[2],ubx[2],x0[2],...)->(x[2],cost,lam_a,lam_x[2]) Qrqp
>>> sol = C(h=H, g=g, a=A, lba=1, uba=1, lbx=0)
>>> sol["x"], sol["cost"]
(DM([1, 0]), DM(-2))
>>> sol["lam_a"], sol["lam_x"]
(DM(1), DM([0, -2]))
>>> LP = conic("LP", "qrqp", {"a": A.sparsity()}, opts)
>>> LP(g=g, a=A, lba=1, uba=1, lbx=0, ubx=1)["x"]
DM([1, 0])
>>> try:
...     conic("C", "qrqp", {"h": Sparsity.upper(2)}, opts)
... except RuntimeError as e:
...     print("square & symmetric" in str(e))
True
>> H = DM([2 1; 1 2]); g = DM([-3; 0]); A = DM([1 1]);
>> opts = struct('print_iter', false, 'print_header', false, 'print_info', false);
>> C = conic('C', 'qrqp', struct('h', H.sparsity(), 'a', A.sparsity()), opts); disp(C)
C:(h[2x2],g[2],a[1x2],lba,uba,lbx[2],ubx[2],x0[2],...)->(x[2],cost,lam_a,lam_x[2]) Qrqp
>> sol = C('h', H, 'g', g, 'a', A, 'lba', 1, 'uba', 1, 'lbx', 0);
>> sol.x, sol.cost
[1, 0]
-2
>> sol.lam_a, sol.lam_x
1
[0, -2]
>> LP = conic('LP', 'qrqp', struct('a', A.sparsity()), opts);
>> sol = LP('g', g, 'a', A, 'lba', 1, 'uba', 1, 'lbx', 0, 'ubx', 1); disp(sol.x)
[1, 0]
>> qp = struct('h', Sparsity.upper(2));
>> try, conic('C', 'qrqp', qp, opts); catch e, msg = e.message; end
>> contains(msg, 'square & symmetric')
1
julia> H = ca.DM([2 1; 1 2]); g = ca.DM([-3, 0]); A = ca.DM([1 1]);
julia> opts = Dict("print_iter" => false, "print_header" => false, "print_info" => false);
julia> C = ca.conic("C", "qrqp", Dict("h" => ca.sparsity(H), "a" => ca.sparsity(A)), opts);
julia> ca.class_name(C), ca.n_in(C), ca.name_out(C)
("Qrqp", 12, ["x", "cost", "lam_a", "lam_x"])
julia> sol = C(h=H, g=g, a=A, lba=1, uba=1, lbx=0);
julia> sol["x"], sol["cost"]
([1, 0], -2)
julia> sol["lam_a"], sol["lam_x"]
(1, [0, -2])
julia> LP = ca.conic("LP", "qrqp", Dict("a" => ca.sparsity(A)), opts);
julia> LP(g=g, a=A, lba=1, uba=1, lbx=0, ubx=1)["x"]
DM([1, 0])
julia> try
           ca.conic("C", "qrqp", Dict("h" => ca.Sparsity.upper(2)), opts)
       catch e
           println(occursin("square & symmetric", sprint(showerror, e)))
       end
true
>>> x = SX.sym("x")
>>> opts = {"print_iter": False, "print_header": False, "print_info": False}
>>> S = qpsol("S", "qrqp", {"x": x, "f": x**2, "g": x}, dict(opts, error_on_fail=False))
>>> sol = S(lbx=0, ubx=1, lbg=2, ubg=3)
>>> S.stats()["success"]
False
>>> S = qpsol("S", "qrqp", {"x": x, "f": x**2 - 4*x, "g": 2*x}, opts)
>>> S(ubx=1)["lam_x"], S(lbx=3)["lam_x"], S(ubg=2)["lam_g"]
(DM(2), DM(-2), DM(1))
>>> try:
...     qpsol("S", "qrqp", {"x": x, "f": x**2}, dict(opts, discrete=[True]))
... except RuntimeError as e:
...     print("integer support" in str(e))
True
>> x = SX.sym('x'); qp = struct('x', x, 'f', x^2, 'g', x);
>> opts = struct('print_iter', false, 'print_header', false, 'print_info', false);
>> S = qpsol('S', 'qrqp', qp, setfield(opts, 'error_on_fail', false));
>> sol = S('lbx', 0, 'ubx', 1, 'lbg', 2, 'ubg', 3); st = S.stats(); disp(st.success)
0
>> S = qpsol('S', 'qrqp', struct('x', x, 'f', x^2 - 4*x, 'g', 2*x), opts);
>> r1 = S('ubx', 1); r2 = S('lbx', 3); r3 = S('ubg', 2);
>> r1.lam_x, r2.lam_x, r3.lam_g
2
-2
1
>> opts.discrete = true;
>> try, qpsol('S', 'qrqp', qp, opts); catch e, msg = e.message; end
>> contains(msg, 'integer support')
1
julia> x = ca.SX.sym("x");
julia> opts = Dict("print_iter" => false, "print_header" => false, "print_info" => false);
julia> qp = Dict("x" => x, "f" => x^2, "g" => x);
julia> S = ca.qpsol("S", "qrqp", qp, merge(opts, Dict("error_on_fail" => false)));
julia> sol = S(lbx=0, ubx=1, lbg=2, ubg=3);
julia> ca.stats(S)["success"]
false
julia> S = ca.qpsol("S", "qrqp", Dict("x" => x, "f" => x^2 - 4*x, "g" => 2*x), opts);
julia> S(ubx=1)["lam_x"], S(lbx=3)["lam_x"], S(ubg=2)["lam_g"]
(2, -2, 1)
julia> try
           ca.qpsol("S", "qrqp", qp, merge(opts, Dict("discrete" => [true])))
       catch e
           println(occursin("integer support", sprint(showerror, e)))
       end
true

General information

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

discrete

OT_BOOLVECTOR

Indicates which of the variables are discrete, i.e. integer- valued

casadi::Conic

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

equality

OT_BOOLVECTOR

Indicate an upfront hint which of the constraints are equalities. Some solvers may be able to exploit this knowledge. When true, the corresponding lower and upper bounds are assumed equal. When false, the corresponding bounds may be equal or different.

casadi::Conic

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_problem

OT_BOOL

Print a numeric description of the problem

casadi::Conic

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

sens_force_equal ity

OT_BOOL

Treat constraints with equal bounds as active in parametric sensitivities, regardless of the multiplier, see issue #2545 [false].

casadi::Conic

sens_linsol

OT_STRING

Linear solver used for parametric sensitivities (default 'qr').

casadi::Conic

sens_linsol_opti ons

OT_DICT

Linear solver options used for parametric sensitivities.

casadi::Conic

sens_min_lam

OT_DOUBLE

Minimum multiplier value for a constraint to be considered active in parametric sensitivities [0].

casadi::Conic

solver_version_c heck

OT_BOOL

When the plugin loads an externally supplied solver, check that its version is compatible with the plugin [Default: true]

casadi::Conic

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

>Input scheme: casadi::ConicInput (CONIC_NUM_IN = 12)

Full name

Short

Description

CONIC_H

h

The square matrix H: sparse, (n x n). Only the lower triangular part is actually used. The matrix is assumed to be symmetrical.

CONIC_G

g

The vector g: dense, (n x 1)

CONIC_A

a

The matrix A: sparse, (nc x n) - product with x must be dense.

CONIC_LBA

lba

dense, (nc x 1), default -inf

CONIC_UBA

uba

dense, (nc x 1), default +inf

CONIC_LBX

lbx

dense, (n x 1), default -inf

CONIC_UBX

ubx

dense, (n x 1), default +inf

CONIC_X0

x0

dense, (n x 1), initial guess, default 0

CONIC_LAM_X0

lam_x0

dense, (n x 1), initial guess for the multipliers of the simple bounds, default 0

CONIC_LAM_A0

lam_a0

dense, (nc x 1), initial guess for the multipliers of the linear constraints, default 0

CONIC_Q

q

The matrix Q: sparse symmetric, (np^2 x n)

CONIC_P

p

The matrix P: sparse symmetric, (np x np)

>Output scheme: casadi::ConicOutput (CONIC_NUM_OUT = 4)

Full name

Short

Description

CONIC_X

x

The primal solution.

CONIC_COST

cost

The optimal cost.

CONIC_LAM_A

lam_a

The dual solution corresponding to linear bounds; negative for an active lower bound, positive for an active upper bound

CONIC_LAM_X

lam_x

The dual solution corresponding to simple bounds; same sign convention.

List of plugins - cbc

  • clarabel

  • clp

  • cplex

  • daqp

  • fatrop

  • gurobi

  • highs

  • hpipm

  • hpmpc

  • mosek

  • ooqp

  • osqp

  • piqp

  • proxqp

  • qpoases

  • sqic

  • superscs

  • xpress

  • ipqp

  • nlpsol

  • qrqp

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Conic.doc("myextraplugin")


cbc

Interface to Cbc solver for sparse Quadratic Programs

>List of available options

Id

Type

Description

cbc

OT_DICT

Options to be passed to CBC.Three sets of options are supported. The first can be found in OsiSolverParameters.hpp. The second can be found in CbcModel.hpp. The third are options that can be passed to CbcMain1.

hot_start

OT_BOOL

Hot start with x0 [Default false].

sos_groups

OT_INTVECTORVECTOR

Definition of SOS groups by indices.

sos_types

OT_INTVECTOR

Specify 1 or 2 for each SOS group.

sos_weights

OT_DOUBLEVECTORVECTOR

Weights corresponding to SOS entries.


clarabel

Interface to the Clarabel solver for sparse Quadratic Programs. See the Clarabel documentation (e.g. clarabel.dev) for more details.

>List of available options

Id

Type

Description

clarabel

OT_DICT

Options to be passed to Clarabel.


clp

Interface to Clp solver for sparse Quadratic Programs

>List of available options

Id

Type

Description

clp

OT_DICT

Options to be passed to CLP. A first set of options can be found in ClpParameters.hpp. eg. 'PrimalTolerance'. There are other options in additions. 'AutomaticScaling' (bool) is recognised. 'initial_solve' (default off) activates the use of Clp's initialSolve. 'initial_solve_options' takes a dictionary with following keys (see ClpSolve.hpp): SolveType (string), PresolveType (string), NumberPasses, SpecialOptions (intvectorvector), IndependentOptions (intvectorvector).


cplex

Interface to Cplex solver for sparse Quadratic Programs

>List of available options

Id

Type

Description

cplex

OT_DICT

Options to be passed to CPLEX

dep_check

OT_INT

Detect redundant constraints.

dump_filename

OT_STRING

The filename to dump to.

dump_to_file

OT_BOOL

Dumps QP to file in CPLEX format.

mip_start

OT_BOOL

Hot start integers with x0 [Default false].

qp_method

OT_INT

Determines which CPLEX algorithm to use.

sos_groups

OT_INTVECTORVECTOR

Definition of SOS groups by indices.

sos_types

OT_INTVECTOR

Specify 1 or 2 for each SOS group.

sos_weights

OT_DOUBLEVECTORVECTOR

Weights corresponding to SOS entries.

tol

OT_DOUBLE

Tolerance of solver

version_suffix

OT_STRING

Specify version of cplex to load. We will attempt to load l ibcplex<version_suffix>.[so|dll |dylib]. Default value is taken from CPLEX_VERSION env variable.

warm_start

OT_BOOL

Use warm start with simplex methods (affects only the simplex methods).


daqp

Interface to Daqp solver for sparse Quadratic Programs, see daqp.dev for more information and https://www.maths.ed.ac.uk/hall/Daqp/DaqpOptions.html for a list of options.

>List of available options

Id

Type

Description

daqp

OT_DICT

Options to be passed to Daqp.


fatrop

Interface to Fatrop Solver

In order to use this interface, you must:

  • Decision variables must only by state and control, and the variable ordering must be [x0 u0 x1 u1...]

  • The constraints must be in order: [gap0 lincon0 gap1 lincon1] gap: Ak+1 = Ak xk + Bk uk lincon: yk= Ck xk + Dk uk

A0 B0 -I
C0 D0
       A1 B1 -I
       C1 D1

where I must be a diagonal sparse matrix

  • Either supply all of N, nx, ng, nu options or rely on automatic detection

>List of available options

Id

Type

Description

N

OT_INT

OCP horizon

fatrop

OT_DICT

Options to be passed to fatrop

ng

OT_INTVECTOR

Number of non-dynamic constraints, length N+1

nu

OT_INTVECTOR

Number of controls, length N

nx

OT_INTVECTOR

Number of states, length N+1

structure_detection

OT_STRING

NONE | auto | manual


gurobi

Interface to the GUROBI Solver for quadratic programming

>List of available options

Id

Type

Description

gurobi

OT_DICT

Options to be passed to gurobi.

lazy_constraints_callba ck

OT_FUNCTION

User callback for adding LazyConstraints at MIPSOL. Input: dict with solution data. Output: dict with lazy constraints.

sos_groups

OT_INTVECTORVECTOR

Definition of SOS groups by indices.

sos_types

OT_INTVECTOR

Specify 1 or 2 for each SOS group.

sos_weights

OT_DOUBLEVECTORVECTOR

Weights corresponding to SOS entries.

vtype

OT_STRINGVECTOR

Type of variables: [CO NTINUOUS|binary|intege r|semicont|semiint]


highs

Interface to HiGHS solver for sparse Quadratic Programs, see highs.dev for more information and https://www.maths.ed.ac.uk/hall/HiGHS/HighsOptions.html for a list of options.

>List of available options

Id

Type

Description

highs

OT_DICT

Options to be passed to HiGHS.


hpipm

Interface to HPIPM Solver

In order to use this interface, you must:

  • Decision variables must only by state and control, and the variable ordering must be [x0 u0 x1 u1...]

  • The constraints must be in order: [gap0 lincon0 gap1 lincon1] gap: Ak+1 = Ak xk + Bk uk lincon: yk= Ck xk + Dk uk

A0 B0 -I
C0 D0
       A1 B1 -I
       C1 D1

where I must be a diagonal sparse matrix

  • Either supply all of N, nx, ng, nu options or rely on automatic detection

>List of available options

Id

Type

Description

N

OT_INT

OCP horizon

hpipm

OT_DICT

Options to be passed to hpipm

inf

OT_DOUBLE

Replace infinities by this amount [default: 1e8]

ng

OT_INTVECTOR

Number of non-dynamic constraints, length N+1

nu

OT_INTVECTOR

Number of controls, length N

nx

OT_INTVECTOR

Number of states, length N+1


hpmpc

Interface to HMPC Solver

In order to use this interface, you must:

  • Decision variables must only by state and control, and the variable ordering must be [x0 u0 x1 u1...]

  • The constraints must be in order: [gap0 lincon0 gap1 lincon1] gap: Ak+1 = Ak xk + Bk uk lincon: yk= Ck xk + Dk uk

A0 B0 -I
C0 D0
       A1 B1 -I
       C1 D1

where I must be a diagonal sparse matrix

  • Either supply all of N, nx, ng, nu options or rely on automatic detection

>List of available options

Id

Type

Description

N

OT_INT

OCP horizon

blasfeo_target

OT_STRING

hpmpc target

inf

OT_DOUBLE

HPMPC cannot handle infinities. Infinities will be replaced by this option's value.

max_iter

OT_INT

Max number of iterations

mu0

OT_DOUBLE

Max element in cost function as estimate of max multiplier

ng

OT_INTVECTOR

Number of non-dynamic constraints, length N+1

nu

OT_INTVECTOR

Number of controls, length N

nx

OT_INTVECTOR

Number of states, length N+1

print_level

OT_INT

Amount of diagnostic printing [Default: 1].

target

OT_STRING

hpmpc target

tol

OT_DOUBLE

Tolerance in the duality measure

warm_start

OT_BOOL

Use warm-starting


mosek

Interface to the MOSEK Optimizer for sparse Linear, Quadratic, Mixed- Integer and Second-Order Cone Programs. See https://www.mosek.com for details and the MOSEK reference manual for the list of parameters that may be passed via the mosek option dict (e.g. MSK_IPAR_LOG, MSK_DPAR_INTPNT_QO_TOL_REL_GAP).

>List of available options

Id

Type

Description

mosek

OT_DICT

Options to be passed to MOSEK. Each entry's key is the MOSEK parameter name (e.g. "MSK_IPAR_LOG", "MSK_DPAR_INTPNT_QO_TOL_REL_GAP"); the value's type must match the parameter's type (int parameters take int, dpar take double, spar take string).


ooqp

Interface to the OOQP Solver for quadratic programming The current implementation assumes that OOQP is configured with the MA27 sparse linear solver.

NOTE: when doing multiple calls to evaluate(), check if you need to reInit();

>List of available options

Id

Type

Description

artol

OT_DOUBLE

tolerance as provided with setArTol to OOQP

mutol

OT_DOUBLE

tolerance as provided with setMuTol to OOQP

print_level

OT_INT

Print level. OOQP listens to print_level 0, 10 and 100


osqp

Interface to the OSQP Solver for quadratic programming

Interface to the PROXQP Solver for quadratic programming

>List of available options

Id

Type

Description

osqp

OT_DICT

const Options to be passed to osqp.

warm_start_dual

OT_BOOL

Use lam_a0 and lam_x0 input to warmstart [Default: true].

warm_start_primal

OT_BOOL

Use x0 input to warmstart [Default: true].


piqp

Interface to the PIQP Solver for quadratic programming

>List of available options

Id

Type

Description

piqp

OT_DICT

const Options to be passed to piqp.


proxqp

>List of available options

Id

Type

Description

proxqp

OT_DICT

const proxqp options.

warm_start_dual

OT_BOOL

Use y and z input to warmstart [Default: true].

warm_start_primal

OT_BOOL

Use x input to warmstart [Default: true].


qpoases

Interface to QPOases Solver for quadratic programming

>List of available options

Id

Type

Description

CPUtime

OT_DOUBLE

The maximum allowed CPU time in seconds for the whole initialisation (and the actually required one on output). Disabled if unset.

boundRelaxation

OT_DOUBLE

Initial relaxation of bounds to start homotopy and initial value for far bounds.

boundTolerance

OT_DOUBLE

If upper and lower bounds differ less than this tolerance, they are regarded equal, i.e. as equality constraint.

enableCholeskyRefactorisation

OT_INT

Specifies the frequency of a full re-factorisation of projected Hessian matrix: 0: turns them off, 1: uses them at each iteration etc.

enableDriftCorrection

OT_INT

Specifies the frequency of drift corrections: 0: turns them off.

enableEqualities

OT_BOOL

Specifies whether equalities should be treated as always active (True) or not (False)

enableFarBounds

OT_BOOL

Enables the use of far bounds.

enableFlippingBounds

OT_BOOL

Enables the use of flipping bounds.

enableFullLITests

OT_BOOL

Enables condition-hardened (but more expensive) LI test.

enableInertiaCorrection

OT_BOOL

Should working set be repaired when negative curvature is discovered during hotstart.

enableNZCTests

OT_BOOL

Enables nonzero curvature tests.

enableRamping

OT_BOOL

Enables ramping.

enableRegularisation

OT_BOOL

Enables automatic Hessian regularisation.

epsDen

OT_DOUBLE

Denominator tolerance for ratio tests.

epsFlipping

OT_DOUBLE

Tolerance of squared Cholesky diagonal factor which triggers flipping bound.

epsIterRef

OT_DOUBLE

Early termination tolerance for iterative refinement.

epsLITests

OT_DOUBLE

Tolerance for linear independence tests.

epsNZCTests

OT_DOUBLE

Tolerance for nonzero curvature tests.

epsNum

OT_DOUBLE

Numerator tolerance for ratio tests.

epsRegularisation

OT_DOUBLE

Scaling factor of identity matrix used for Hessian regularisation.

finalRamping

OT_DOUBLE

Final value for ramping strategy.

growFarBounds

OT_DOUBLE

Factor to grow far bounds.

hessian_type

OT_STRING

Type of Hessian - see qpOASES documentation [UNKNO WN|posdef|semidef|indef|zero |identity]]

initialFarBounds

OT_DOUBLE

Initial size for far bounds.

initialRamping

OT_DOUBLE

Start value for ramping strategy.

initialStatusBounds

OT_STRING

Initial status of bounds at first iteration.

linsol_plugin

OT_STRING

Linear solver plugin

maxDualJump

OT_DOUBLE

Maximum allowed jump in dual variables in linear independence tests.

maxPrimalJump

OT_DOUBLE

Maximum allowed jump in primal variables in nonzero curvature tests.

max_schur

OT_INT

Maximal number of Schur updates [75]

nWSR

OT_INT

The maximum number of working set recalculations to be performed during the initial homotopy. Default is 5(nx + nc)

numRefinementSteps

OT_INT

Maximum number of iterative refinement steps.

numRegularisationSteps

OT_INT

Maximum number of successive regularisation steps.

printLevel

OT_STRING

Defines the amount of text output during QP solution, see Section 5.7

schur

OT_BOOL

Use Schur Complement Approach [false]

sparse

OT_BOOL

Formulate the QP using sparse matrices. [false]

terminationTolerance

OT_DOUBLE

Relative termination tolerance to stop homotopy.


sqic

Interface to the SQIC solver for quadratic programming


superscs

Interface to the SuperSCS solver for conic programming

Joris Gillis, 2019

>List of available options

Id

Type

Description

superscs

OT_DICT

Options to be passed to superscs.


xpress

Interface to FICO Xpress Optimizer for sparse Linear, Quadratic and Mixed- Integer Quadratic Programs. See https://www.fico.com/en/products/fico- xpress-optimization for more information and the Xpress reference manual for the list of controls (options) accepted under the xpress option dict.

>List of available options

Id

Type

Description

compute_iis

OT_BOOL

When the problem is infeasible, compute an IIS immediately after the solve and expose it in get_stats() as iis_rows / iis_cols. IIS computation can be expensive; set to false to skip it [Default false].

log_file

OT_STRING

Write solver log to this file path via XPRSsetlogfile. Useful for capturing output (e.g. warm-start acceptance messages) in automated tests. Empty string (default) disables file logging.

mip_start

OT_BOOL

Pass x0 as an initial integer solution hint to Xpress via XPRSaddmipsol before the MIP solve [Default false].

sos_groups

OT_INTVECTORVECTOR

Definition of SOS groups by indices.

sos_types

OT_INTVECTOR

Specify 1 or 2 for each SOS group.

sos_weights

OT_DOUBLEVECTORVECTOR

Weights corresponding to SOS entries.

xpress

OT_DICT

Options to be passed to FICO Xpress. Each entry's key is the Xpress control name (e.g. "OUTPUTLOG", "MAXTIME", "MIPRELSTOP"); the value's type must match the control's type (int / double / string).


ipqp

Solves QPs using a Mehrotra predictor-corrector interior point method

>List of available options

Id

Type

Description

constr_viol_tol

OT_DOUBLE

Constraint violation tolerance [1e-8].

dual_inf_tol

OT_DOUBLE

Dual feasibility violation tolerance [1e-8]

linear_solver

OT_STRING

A custom linear solver creator function [default: ldl]

linear_solver_options

OT_DICT

Options to be passed to the linear solver

max_iter

OT_INT

Maximum number of iterations [1000].

min_lam

OT_DOUBLE

Smallest multiplier treated as inactive for the initial active set [0].

print_header

OT_BOOL

Print header [true].

print_info

OT_BOOL

Print info [true].

print_iter

OT_BOOL

Print iterations [true].


nlpsol

Solve QPs using an Nlpsol Use the 'nlpsol' option to specify the NLP solver to use.

>List of available options

Id

Type

Description

nlpsol

OT_STRING

Name of solver.

nlpsol_options

OT_DICT

Options to be passed to solver.


qrqp

Solve QPs using an active-set method

>List of available options

Id

Type

Description

constr_viol_tol

OT_DOUBLE

Constraint violation tolerance [1e-8].

dual_inf_tol

OT_DOUBLE

Dual feasibility violation tolerance [1e-8]

max_iter

OT_INT

Maximum number of iterations [1000].

min_lam

OT_DOUBLE

Smallest multiplier treated as inactive for the initial active set [0].

print_header

OT_BOOL

Print header [true].

print_info

OT_BOOL

Print info [true].

print_iter

OT_BOOL

Print iterations [true].

print_lincomb

OT_BOOL

Print dependant linear combinations of constraints [false]. Printed numbers are 0-based indices into the vector of [simple bounds;linear bounds]

Authors: Joel Andersson

Extra doc | Doc source | Implementation

Integrator

integrator(...)
integrator(str name, str solver, dict:SX dae, dict opts) -> Function
integrator(str name, str solver, dict:MX dae, dict opts) -> Function
integrator(str name, str solver, Function dae, dict opts) -> Function
integrator(str name, str solver, dict:SX dae, float t0, [float] tout, dict opts) -> Function
integrator(str name, str solver, dict:SX dae, float t0, float tf, dict opts) -> Function
integrator(str name, str solver, dict:MX dae, float t0, [float] tout, dict opts) -> Function
integrator(str name, str solver, dict:MX dae, float t0, float tf, dict opts) -> Function
integrator(str name, str solver, Function dae, float t0, [float] tout, dict opts) -> Function
integrator(str name, str solver, Function dae, float t0, float tf, dict opts) -> Function

Create an ODE/DAE integrator Solves an initial value problem (IVP) coupled to a terminal value problem with differential equation given as an implicit ODE coupled to an algebraic equation and a set of quadratures:

Initial conditions at t=t0
x(t0)  = x0
q(t0)  = 0

Forward integration from t=t0 to t=tf
der(x) = fx(x, z, p, u, t)                  Forward ODE
0 = fz(x, z, p, u, t)                  Forward algebraic equations
der(q) = fq(x, z, p, u, t)                  Forward quadratures

Terminal conditions at t=tf
rx(tf)  = rx0
rq(tf)  = 0

Backward integration from t=tf to t=t0
der(rx) = gx(rx, rz, rp, x, z, p, t)        Backward ODE
0 = gz(rx, rz, rp, x, z, p, t)        Backward algebraic equations
der(rq) = gq(rx, rz, rp, x, z, p, t)        Backward quadratures

where we assume that both the forward and backwards integrations are index-1
(i.e. dfz/dz, dgz/drz are invertible) and furthermore that
gx, gz and gq have a linear dependency on rx, rz and rp.

The DAE is given as a dictionary with the fields "x" (differential state), "ode" (its right-hand side, same size as "x") and optionally "t" (time, scalar), "z" (algebraic variables) with "alg" (residual, same size as "z"), "p" (parameters), "u" (controls, piecewise constant on the output grid), "quad" (quadrature right-hand side) and "zero" (event indicators, experimental). Every entry must be a dense vector; row vectors are flattened to columns. Any other field name is an error, as is a symbol in an output that is not an input. The DAE can also be given as a Function with the full input scheme t, x, z, p, u and output scheme ode, alg, quad, zero (see dyn_in and dyn_out), empty where unused. The pure ODE integrators (cvodes, rk, erk, rosenbrock) reject a problem with "z".

Time grid: integrator(name, solver, dae, opts) integrates from t0 = 0 to tf = 1; integrator(name, solver, dae, t0, tf, opts) to a single output time tf; and integrator(name, solver, dae, t0, tout, opts) returns the solution at every time in the list tout. The grid must be increasing but need not contain t0; including it gives the initial state as the first output column. t0 > tf integrates backwards in time. The legacy options "t0", "tf", "grid" and "output_t0" are deprecated and emit a warning.

The returned Function has inputs x0, z0, p, u, adj_xf, adj_zf, adj_qf (see integrator_in) and outputs xf, zf, qf, adj_x0, adj_z0, adj_p, adj_u (see integrator_out). With N output times, x0, z0 and p are column vectors, u has one column per output time (the control on the interval ending at that time; a single column is broadcast), and xf, zf, qf have one column per output time. z0 is the initial guess for the algebraic variables; it must be consistent for the Sundials solvers to converge. Omitted inputs are zero. The adj_* inputs and outputs are empty unless option "nadj" is positive: then adj_xf, adj_zf and adj_qf take one adjoint seed per output time and adj_x0, adj_p and adj_u return the corresponding adjoint sensitivities, i.e. adj_x0 is the gradient of sum(adj_xf .* xf) + sum(adj_qf .* qf) with respect to x0. Option "nfwd" adds, in the same way, forward sensitivity columns to every input and output. Without these options derivatives are obtained by embedding the call in an MX expression and differentiating (sensitivity equations are created on demand).

Options common to all plugins (the plugin options follow in the tables below):

  • "nfwd", "nadj": number of forward and adjoint sensitivity directions built into the Function (default 0).

  • "expand": convert an MX DAE to SX before creating derivative functions (default false).

  • "print_stats": print integrator statistics after each call; stats() returns them.

  • "transition", "max_event_iter", "max_events", "event_tol": event handling for a DAE with "zero" indicators (experimental, see event_in and event_out).

  • "augmented_options": options passed to the integrator created for sensitivities.

  • "print_time", "verbose", "monitor", "common_options", "specific_options": diagnostics and options of the generated derivative functions, as for nlpsol.

>>> x = SX.sym("x"); p = SX.sym("p")
>>> dae = {"x": x, "p": p, "ode": -p*x, "quad": x}
>>> F = integrator("F", "cvodes", dae)
>>> print(F)
F:(x0,z0[0],p,u[0],adj_xf[],adj_zf[],adj_qf[])->(xf,zf[0],qf,adj_x0[],...,adj_u[]) ...
>>> r = F(x0=1, p=1)
>>> r["xf"], r["qf"]
(DM(0.3679), DM(0.6321))
>>> F = integrator("F", "rk", dae, 0, [1, 2, 3])
>>> F(x0=1, p=1)["xf"]
DM([[0.3679, 0.1353, 0.0498]])
>>> xf, zf, qf, adj_x0, adj_z0, adj_p, adj_u = F(1, 0, 1, 0, 0, 0, 0)
>>> xf.shape, zf.shape, adj_x0.shape
((1, 3), (0, 3), (0, 0))
>> x = SX.sym('x'); p = SX.sym('p');
>> dae = struct('x', x, 'p', p, 'ode', -p*x, 'quad', x);
>> F = integrator('F', 'cvodes', dae); disp(F)
F:(x0,z0[0],p,u[0],adj_xf[],adj_zf[],adj_qf[])->(xf,zf[0],qf,adj_x0[],...,adj_u[]) ...
>> r = F('x0', 1, 'p', 1); r.xf, r.qf
0.3679
0.6321
>> F = integrator('F', 'rk', dae, 0, [1, 2, 3]);
>> r = F('x0', 1, 'p', 1); r.xf
[[0.3679, 0.1353, 0.0498]]
>> [xf, zf, qf, adj_x0, adj_z0, adj_p, adj_u] = F(1, 0, 1, 0, 0, 0, 0);
>> size(xf), size(zf), size(adj_x0)
1 3
0 3
0 0
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> dae = Dict("x" => x, "p" => p, "ode" => -p*x, "quad" => x);
julia> F = ca.integrator("F", "cvodes", dae);
julia> ca.n_in(F), ca.n_out(F), ca.size_in(F, 4)
(7, 7, (0, 0))
julia> r = F(x0=1, p=1);
julia> r["xf"], r["qf"]
(0.3679, 0.6321)
julia> F = ca.integrator("F", "rk", dae, 0, [1, 2, 3]);
julia> F(x0=1, p=1)["xf"]
DM([[0.3679, 0.1353, 0.0498]])
julia> xf, zf, qf, adj_x0, adj_z0, adj_p, adj_u = F(1, 0, 1, 0, 0, 0, 0);
julia> size(xf), size(zf), size(adj_x0)
((1, 3), (0, 3), (0, 0))
>>> x = SX.sym("x"); z = SX.sym("z"); u = SX.sym("u")
>>> F = integrator("F", "idas", {"x": x, "z": z, "ode": -z, "alg": z**2 - x})
>>> r = F(x0=1, z0=1)
>>> r["xf"], r["zf"]
(DM(0.25), DM(0.5))
>>> F(x0=1, z0=-1)["zf"]
DM(-1.5)
>>> F = integrator("F", "rk", {"x": x, "u": u, "ode": u}, 0, [1, 2, 3])
>>> F(x0=0, u=[1, 2, 3])["xf"], F(x0=0, u=1)["xf"]
(DM([[1, 3, 6]]), DM([[1, 2, 3]]))
>>> try:
...     integrator("F", "cvodes", {"x": x, "z": z, "ode": -z, "alg": z - x})
... except RuntimeError as e:
...     print("does not support algebraic variables" in str(e))
True
>>> try:
...     integrator("F", "cvodes", {"x": x, "ode": vertcat(x, x)})
... except RuntimeError as e:
...     print("Dimension mismatch for 'ode'" in str(e))
True
>> x = SX.sym('x'); z = SX.sym('z'); u = SX.sym('u');
>> F = integrator('F', 'idas', struct('x', x, 'z', z, 'ode', -z, 'alg', z^2 - x));
>> r = F('x0', 1, 'z0', 1); r.xf, r.zf
0.25
0.5
>> r = F('x0', 1, 'z0', -1); r.zf
-1.5
>> F = integrator('F', 'rk', struct('x', x, 'u', u, 'ode', u), 0, [1, 2, 3]);
>> r = F('x0', 0, 'u', [1 2 3]); disp(r.xf)
[[1, 3, 6]]
>> r = F('x0', 0, 'u', 1); disp(r.xf)
[[1, 2, 3]]
>> dae = struct('x', x, 'z', z, 'ode', -z, 'alg', z - x);
>> try, integrator('F', 'cvodes', dae); catch e, msg = e.message; end
>> contains(msg, 'does not support algebraic variables')
1
>> dae = struct('x', x, 'ode', [x; x]);
>> try, integrator('F', 'cvodes', dae); catch e, msg = e.message; end
>> contains(msg, 'Dimension mismatch for ''ode''')
1
julia> x = ca.SX.sym("x"); z = ca.SX.sym("z"); u = ca.SX.sym("u");
julia> dae = Dict("x" => x, "z" => z, "ode" => -z, "alg" => z^2 - x);
julia> F = ca.integrator("F", "idas", dae);
julia> r = F(x0=1, z0=1);
julia> r["xf"], r["zf"]
(0.25, 0.5)
julia> F(x0=1, z0=-1)["zf"]
DM(-1.5)
julia> F = ca.integrator("F", "rk", Dict("x" => x, "u" => u, "ode" => u), 0, [1, 2, 3]);
julia> F(x0=0, u=[1 2 3])["xf"]
DM([[1, 3, 6]])
julia> F(x0=0, u=1)["xf"]
DM([[1, 2, 3]])
julia> try
           ca.integrator("F", "cvodes", Dict("x" => x, "z" => z, "ode" => -z, "alg" => z - x))
       catch e
           println(occursin("does not support algebraic variables", sprint(showerror, e)))
       end
true
julia> try
           ca.integrator("F", "cvodes", Dict("x" => x, "ode" => [x; x]))
       catch e
           println(occursin("Dimension mismatch for 'ode'", sprint(showerror, e)))
       end
true
>>> x = SX.sym("x"); p = SX.sym("p")
>>> dae = {"x": x, "p": p, "ode": -p*x, "quad": x}
>>> F = integrator("F", "cvodes", dae, {"nadj": 1})
>>> print(F)
F:(x0,z0[0],p,u[0],adj_xf,adj_zf[0],adj_qf)->(xf,zf[0],qf,adj_x0,...,adj_p,adj_u[0]) ...
>>> r = F(x0=1, p=1, adj_xf=1)
>>> r["adj_x0"], r["adj_p"]
(DM(0.3679), DM(-0.3679))
>>> F = integrator("F", "cvodes", dae)
>>> pm = MX.sym("p")
>>> J = Function("J", [pm], [jacobian(F(x0=1, p=pm)["xf"], pm)])
>>> J(1)
DM(-0.3679)
>> x = SX.sym('x'); p = SX.sym('p');
>> dae = struct('x', x, 'p', p, 'ode', -p*x, 'quad', x);
>> F = integrator('F', 'cvodes', dae, struct('nadj', 1)); disp(F)
F:(x0,z0[0],p,u[0],adj_xf,adj_zf[0],adj_qf)->(xf,zf[0],qf,adj_x0,...,adj_p,adj_u[0]) ...
>> r = F('x0', 1, 'p', 1, 'adj_xf', 1); r.adj_x0, r.adj_p
0.3679
-0.3679
>> F = integrator('F', 'cvodes', dae); pm = MX.sym('p'); r = F('x0', 1, 'p', pm);
>> J = Function('J', {pm}, {jacobian(r.xf, pm)}); J(1)
-0.3679
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> dae = Dict("x" => x, "p" => p, "ode" => -p*x, "quad" => x);
julia> F = ca.integrator("F", "cvodes", dae, Dict("nadj" => 1));
julia> ca.size_in(F, 4), ca.size_out(F, 5)
((1, 1), (1, 1))
julia> r = F(x0=1, p=1, adj_xf=1);
julia> r["adj_x0"], r["adj_p"]
(0.3679, -0.3679)
julia> F = ca.integrator("F", "cvodes", dae);
julia> pm = ca.MX.sym("p");
julia> J = ca.Function("J", [pm], [ca.jacobian(F(x0=1, p=pm)["xf"], pm)]);
julia> J(1)
DM(-0.3679)

General information

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

augmented_option s

OT_DICT

Options to be passed down to the augmented integrator, if one is constructed

casadi::Integrat or

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

common_options

OT_DICT

Options for auto-generated functions

casadi::OracleFu nction

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

event_tol

OT_DOUBLE

Termination tolerance for the event iteration

casadi::Integrat or

expand

OT_BOOL

Replace MX with SX expressions in problem formulation [false] This happens before creating derivatives unless indicated by postpone_expand

casadi::OracleFu nction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

grid

OT_DOUBLEVECTOR

[DEPRECATED] Time grid

casadi::Integrat or

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

max_event_iter

OT_INT

Maximum number of iterations to zero in on a single event

casadi::Integrat or

max_events

OT_INT

Maximum total number of events

casadi::Integrat or

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

monitor

OT_STRINGVECTOR

Set of user problem functions to be monitored

casadi::OracleFu nction

nadj

OT_INT

Number of adjoint sensitivities to be calculated [0]

casadi::Integrat or

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

nfwd

OT_INT

Number of forward sensitivities to be calculated [0]

casadi::Integrat or

number_of_finite _elements

OT_INT

Target number of finite elements. The actual number may be higher to accommodate all output times

casadi::Integrat or

output_t0

OT_BOOL

[DEPRECATED] Output the state at the initial time

casadi::Integrat or

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

postpone_expand

OT_BOOL

When expand is active, postpone it until after creation of derivatives. Default: False

casadi::OracleFu nction

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_stats

OT_BOOL

Print out statistics after integration

casadi::Integrat or

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

rootfinder

OT_STRING

An implicit function solver

casadi::Integrat or

rootfinder_optio ns

OT_DICT

Options to be passed to the NLP Solver

casadi::Integrat or

show_eval_warnin gs

OT_BOOL

Show warnings generated from function evaluations [true]

casadi::OracleFu nction

simplify

OT_BOOL

Implement as MX Function (codege neratable/serial izable) default: false

casadi::Integrat or

simplify_options

OT_DICT

Any options to pass to simplified form Function constructor

casadi::Integrat or

specific_options

OT_DICT

Options for specific auto- generated functions, overwriting the defaults from common_options. Nested dictionary.

casadi::OracleFu nction

t0

OT_DOUBLE

[DEPRECATED] Beginning of the time horizon

casadi::Integrat or

tf

OT_DOUBLE

[DEPRECATED] End of the time horizon

casadi::Integrat or

transition

OT_FUNCTION

Function to be called a zero- crossing events

casadi::Integrat or

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

>Input scheme: casadi::IntegratorInput (INTEGRATOR_NUM_IN = 7)

Full name

Short

Description

INTEGRATOR_X0

x0

Differential state at the initial time.

INTEGRATOR_Z0

z0

Initial guess for the algebraic variable at the initial time.

INTEGRATOR_P

p

Parameters.

INTEGRATOR_U

u

Piecewise constant control, a new control interval starts at each output time.

INTEGRATOR_ADJ_XF

adj_xf

Adjoint seeds corresponding to the states at the output times.

INTEGRATOR_ADJ_ZF

adj_zf

Adjoint seeds corresponding to the algebraic variables at the output times.

INTEGRATOR_ADJ_QF

adj_qf

Adjoint seeds corresponding to the quadratures at the output times.

>Output scheme: casadi::IntegratorOutput (INTEGRATOR_NUM_OUT = 7)

Full name

Short

Description

INTEGRATOR_XF

xf

Differential state at all output times.

INTEGRATOR_ZF

zf

Algebraic variable at all output times.

INTEGRATOR_QF

qf

Quadrature state at all output times.

INTEGRATOR_ADJ_X0

adj_x0

Adjoint sensitivities corresponding to the initial state.

INTEGRATOR_ADJ_Z0

adj_z0

Adjoint sensitivities corresponding to the algebraic variable guess.

INTEGRATOR_ADJ_P

adj_p

Adjoint sensitivities corresponding to the parameter vector.

INTEGRATOR_ADJ_U

adj_u

Adjoint sensitivities corresponding to the control vector.

List of plugins - cvodes

  • idas

  • collocation

  • erk

  • rosenbrock

  • rk

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Integrator.doc("myextraplugin")


cvodes

Interface to CVodes from the Sundials suite.

A call to evaluate will integrate to the end.

You can retrieve the entire state trajectory as follows, after the evaluate call: Call reset. Then call integrate(t_i) and getOuput for a series of times t_i.

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Absolute tolerence for the IVP solution

always_recalculate_jacobian

OT_BOOL

Recalculate Jacobian before factorizations, even if Jacobian is current [default: true]

disable_internal_warnings

OT_BOOL

Disable SUNDIALS internal warning messages

fsens_all_at_once

OT_BOOL

Calculate all right hand sides of the sensitivity equations at once

fsens_err_con

OT_BOOL

include the forward sensitivities in all error controls

interpolation_type

OT_STRING

Type of interpolation for the adjoint sensitivities

linear_multistep_method

OT_STRING

Integrator scheme: BDF|adams

linear_solver

OT_STRING

A custom linear solver creator function [default: qr]

linear_solver_options

OT_DICT

Options to be passed to the linear solver

max_krylov

OT_INT

Maximum Krylov subspace size

max_multistep_order

OT_INT

Maximum order for the (variable-order) multistep method

max_num_steps

OT_INT

Maximum number of integrator steps

max_order

OT_DOUBLE

Maximum order

max_step_size

OT_DOUBLE

Max step size [default: 0/inf]

min_step_size

OT_DOUBLE

Min step size [default: 0/0.0]

newton_scheme

OT_STRING

Linear solver scheme in the Newton method: DIRECT|gmres|bcgstab|tfqmr

nonlin_conv_coeff

OT_DOUBLE

Coefficient in the nonlinear convergence test

nonlinear_solver_iteration

OT_STRING

Nonlinear solver type: NEWTON|functional

quad_err_con

OT_BOOL

Should the quadratures affect the step size control

reltol

OT_DOUBLE

Relative tolerence for the IVP solution

scale_abstol

OT_BOOL

Scale absolute tolerance by nominal value

second_order_correction

OT_BOOL

Second order correction in the augmented system Jacobian [true]

sensitivity_method

OT_STRING

Sensitivity method: SIMULTANEOUS|staggered

step0

OT_DOUBLE

initial step size [default: 0/estimated]

steps_per_checkpoint

OT_INT

Number of steps between two consecutive checkpoints

stop_at_end

OT_BOOL

[DEPRECATED] Stop the integrator at the end of the interval

use_preconditioner

OT_BOOL

Precondition the iterative solver [default: true]


idas

Interface to IDAS from the Sundials suite.

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Absolute tolerence for the IVP solution

abstolv

OT_DOUBLEVECTOR

Absolute tolerarance for each component

calc_ic

OT_BOOL

Use IDACalcIC to get consistent initial conditions.

calc_icB

OT_BOOL

Use IDACalcIC to get consistent initial conditions for backwards system [default: equal to calc_ic].

cj_scaling

OT_BOOL

IDAS scaling on cj for the user-defined linear solver module

constraints

OT_INTVECTOR

Constrain the solution y=[x,z]. 0 (default): no constraint on yi, 1: yi >= 0.0, -1: yi <= 0.0, 2: yi > 0.0, -2: yi < 0.0.

disable_internal_warnings

OT_BOOL

Disable SUNDIALS internal warning messages

first_time

OT_DOUBLE

First requested time as a fraction of the time interval

fsens_err_con

OT_BOOL

include the forward sensitivities in all error controls

init_xdot

OT_DOUBLEVECTOR

Initial values for the state derivatives

interpolation_type

OT_STRING

Type of interpolation for the adjoint sensitivities

linear_solver

OT_STRING

A custom linear solver creator function [default: qr]

linear_solver_options

OT_DICT

Options to be passed to the linear solver

max_krylov

OT_INT

Maximum Krylov subspace size

max_multistep_order

OT_INT

Maximum order for the (variable-order) multistep method

max_num_steps

OT_INT

Maximum number of integrator steps

max_order

OT_DOUBLE

Maximum order

max_step_size

OT_DOUBLE

Maximim step size

newton_scheme

OT_STRING

Linear solver scheme in the Newton method: DIRECT|gmres|bcgstab|tfqmr

nonlin_conv_coeff

OT_DOUBLE

Coefficient in the nonlinear convergence test

quad_err_con

OT_BOOL

Should the quadratures affect the step size control

reltol

OT_DOUBLE

Relative tolerence for the IVP solution

scale_abstol

OT_BOOL

Scale absolute tolerance by nominal value

second_order_correction

OT_BOOL

Second order correction in the augmented system Jacobian [true]

sensitivity_method

OT_STRING

Sensitivity method: SIMULTANEOUS|staggered

step0

OT_DOUBLE

initial step size [default: 0/estimated]

steps_per_checkpoint

OT_INT

Number of steps between two consecutive checkpoints

stop_at_end

OT_BOOL

[DEPRECATED] Stop the integrator at the end of the interval

suppress_algebraic

OT_BOOL

Suppress algebraic variables in the error testing

use_preconditioner

OT_BOOL

Precondition the iterative solver [default: true]


collocation

Fixed-step implicit Runge-Kutta integrator ODE/DAE integrator based on collocation schemes

The method is still under development

>List of available options

Id

Type

Description

collocation_scheme

OT_STRING

Collocation scheme: radau|legendre

interpolation_order

OT_INT

Order of the interpolating polynomials

number_of_finite_elements

OT_INT

Target number of finite elements. The actual number may be higher to accommodate all output times

rootfinder

OT_STRING

An implicit function solver

rootfinder_options

OT_DICT

Options to be passed to the NLP Solver

simplify

OT_BOOL

Implement as MX Function (codegeneratable/serializable) default: false

simplify_options

OT_DICT

Any options to pass to simplified form Function constructor


erk

Explicit Runge-Kutta integrator for ODEs: a pair of order 5(4) with adaptive or fixed steps, or the classical method of order 4 with fixed steps.

Steps are independent of the output times. Adaptive steps are chosen by error control on the nominal states; with fixed steps, each run of steps over a control group (or up to the end) is divided into equal steps of at most step_size. Outputs inside a step come from a dense output (order 4 and 3 respectively) at no extra cost. Forward sensitivities are the exact derivatives of the discrete solution and adjoint sensitivities are the exact discrete adjoint of the taped steps. With fixed steps the tape has a known bound, so adjoints can be code-generated; with adaptive steps, set max_tape_steps.

Zero-crossing events (DAE output zero, option transition) are located on the dense output of the step in which a function becomes negative; integration restarts from the state after the transition. Sensitivities, forward, adjoint and forward-over-adjoint, include those of the event times.

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Absolute tolerance [1e-8]

control_group_size

OT_INTVECTOR

Number of output intervals in each control group, over which the controls, one column each, are constant: a run of steps [default: 1 for each output interval]

max_num_steps

OT_INT

Adaptive steps: maximum number of steps per output interval [10000]

max_step_size

OT_DOUBLE

Adaptive steps: maximum step size [default: unbounded]

max_tape_steps

OT_INT

Adaptive steps: capacity, in steps, of a tape in the work vector, for adjoint sensitivities; needed for code generation [0: tape of unbounded size]. With fixed steps, the tape is sized exactly.

method

OT_STRING

Runge-Kutta method: 'rk45' (pair of order 5(4), adaptive unless step_size is set) or 'rk4' (classical, order 4, fixed steps only; default step_size (tf - t0)/20) [rk45]

min_step_size

OT_DOUBLE

Adaptive steps: minimum step size [1e-14]

quad_err_con

OT_BOOL

Adaptive steps: include the quadratures in the error control [true]

reltol

OT_DOUBLE

Relative tolerance [1e-6]

step0

OT_DOUBLE

Adaptive steps: initial step size [default: estimated]

step_size

OT_DOUBLE

Fixed steps: each run of steps, over a control group or up to the end without controls, is divided into equal steps of at most step_size [0: adaptive steps]


rosenbrock

Rosenbrock-Wanner integrator for stiff ODEs and semi-explicit index-1 DAEs, with adaptive or fixed steps.

An 8-stage, stiffly accurate, L-stable method of order 5 with an embedded method of order 4. Each step needs one Jacobian and one sparse QR factorization; the method is linearly implicit, without Newton iterations. Steps cross the output times within a control group, which are interpolated by a dense output of order 4. Step sizes are chosen from the nominal solution only, so forward sensitivities are the exact derivatives of the discrete solution (internal numerical differentiation) and adjoint sensitivities are the exact discrete adjoint of the taped steps. With step_size, each run of steps over a control group is divided into equal steps instead, and the tape has a known bound.

Zero-crossing events (DAE output zero, option transition) are located on the dense output of the step in which a function becomes negative; integration restarts from the state after the transition. Sensitivities, forward, adjoint and forward-over-adjoint, include those of the event times.

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Absolute tolerance [1e-8]

control_group_size

OT_INTVECTOR

Number of output intervals in each control group, over which the controls, one column each, are constant: a run of steps [default: 1 for each output interval]

init_max_iter

OT_INT

Maximum number of Newton iterations for consistent algebraic states [20]

init_tol

OT_DOUBLE

Tolerance on the scaled Newton step when making the algebraic states consistent [1e-3]

max_num_steps

OT_INT

Adaptive steps: maximum number of steps per output interval [10000]

max_step_size

OT_DOUBLE

Adaptive steps: maximum step size [default: unbounded]

max_tape_steps

OT_INT

Adaptive steps: capacity, in steps, of a tape in the work vector, for adjoint sensitivities; needed for code generation [0: tape of unbounded size]. With fixed steps, the tape is sized exactly.

min_step_size

OT_DOUBLE

Adaptive steps: minimum step size [1e-14]

quad_err_con

OT_BOOL

Adaptive steps: include the quadratures in the error control [true]

reltol

OT_DOUBLE

Relative tolerance [1e-6]

step0

OT_DOUBLE

Adaptive steps: initial step size [default: estimated]

step_size

OT_DOUBLE

Fixed steps: each run of steps, over a control group or up to the end without controls, is divided into equal steps of at most step_size [0: adaptive steps]


rk --

Fixed-step explicit Runge-Kutta integrator for ODEs Currently implements RK4.

The method is still under development

Authors: Joel Andersson

Extra doc | Doc source | Implementation

Rootfinding

rootfinder(...)
rootfinder(str name, str solver, dict:SX rfp, dict opts) -> Function
rootfinder(str name, str solver, dict:MX rfp, dict opts) -> Function
rootfinder(str name, str solver, Function f, dict opts) -> Function

Create a solver for rootfinding problems

Returns a Function that solves a system of nonlinear equations g(x, p) = 0 for x, given the parameters p and an initial guess for x. The problem is given as a dictionary with fields "x" (unknowns, dense column vector), "g" (residual, dense column vector of the same size) and optionally "p" (parameters); any other field name is an error. The returned Function has inputs x0 (the guess) and p, and output x (see rootfinder_in and rootfinder_out). Omitted inputs are zero.

More generally, the problem is given as a Function [y0, y1, ..., yi, ..., yn] = F(x0, x1, ..., xj, ..., xm) where input xj is unknown and output yi is the residual that must be zero. The result is [y0, y1, ..., xj, ..., yn] = G(x0, x1, ..., xj_guess, ..., xm): the unknown input is replaced by a guess (its name gets a "0" suffix) and the residual output is replaced by the solution (named like the unknown input); the other inputs and outputs are passed through. By default j = 0 and i = 0; options "implicit_input" and "implicit_output" select other indices. xj and yi must be dense column vectors of the same size and d(yi)/d(xj) must be structurally and numerically invertible: a structurally rank-deficient Jacobian is an error at construction, a singular one makes the plugin fail.

The call can be embedded in an MX expression and differentiated: derivatives follow from the implicit function theorem, using the linear solver chosen with "linear_solver". "error_on_fail" defaults to true: a solve that does not converge raises; with false the last iterate is returned and stats() reports "success" and "return_status".

Options common to all plugins (the plugin options follow in the tables below):

  • "implicit_input", "implicit_output": indices j and i above (default 0).

  • "linear_solver", "linear_solver_options": Linsol plugin for the Newton steps and the sensitivities (default "qr").

  • "jacobian_function": user-supplied Function for d(yi)/d(xj) (generated by default).

  • "constraints": list with one entry per unknown, 0 (default) for no constraint, 1 for >= 0, -1 for <= 0, 2 for > 0, -2 for < 0; only honored by plugins that support it (e.g. kinsol), ignored by newton.

  • "expand", "print_time", "verbose", "common_options", "specific_options": as for nlpsol.

>>> x = SX.sym("x"); p = SX.sym("p")
>>> G = rootfinder("G", "newton", {"x": x, "p": p, "g": x**2 - p})
>>> G
Function(G:(x0,p)->(x) Newton)
>>> G(x0=1, p=2)["x"], G(1, 2)
(DM(1.4142), DM(1.4142))
>>> G.stats()["success"], G.stats()["return_status"]
(True, 'success')
>>> pm = MX.sym("p")
>>> dxdp = Function("dxdp", [pm], [jacobian(G(x0=1, p=pm)["x"], pm)])
>>> dxdp(4)
DM(0.25)
>>> f = Function("f", [x, p], [x**2 - p, 3*x], ["x", "p"], ["g", "h"])
>>> G = rootfinder("G", "newton", f)
>>> G
Function(G:(x0,p)->(x,h) Newton)
>>> G(x0=1, p=4)
{'h': DM(6), 'x': DM(2)}
>>> f = Function("f", [p, x], [3*x, x**2 - p], ["p", "x"], ["h", "g"])
>>> G = rootfinder("G", "newton", f, {"implicit_input": 1, "implicit_output": 1})
>>> G
Function(G:(p,x0)->(h,x) Newton)
>> x = SX.sym('x'); p = SX.sym('p');
>> G = rootfinder('G', 'newton', struct('x', x, 'p', p, 'g', x^2 - p)); disp(G)
G:(x0,p)->(x) Newton
>> r = G('x0', 1, 'p', 2); r.x, G(1, 2)
1.4142
1.4142
>> st = G.stats(); disp(st.success), disp(st.return_status)
1
success
>> pm = MX.sym('p'); r = G('x0', 1, 'p', pm);
>> dxdp = Function('dxdp', {pm}, {jacobian(r.x, pm)}); disp(dxdp(4))
0.25
>> f = Function('f', {x, p}, {x^2 - p, 3*x}, {'x', 'p'}, {'g', 'h'});
>> G = rootfinder('G', 'newton', f); disp(G)
G:(x0,p)->(x,h) Newton
>> r = G('x0', 1, 'p', 4); disp(r.x), disp(r.h)
2
6
>> f = Function('f', {p, x}, {3*x, x^2 - p}, {'p', 'x'}, {'h', 'g'});
>> G = rootfinder('G', 'newton', f, struct('implicit_input', 1, 'implicit_output', 1)); disp(G)
G:(p,x0)->(h,x) Newton
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> G = ca.rootfinder("G", "newton", Dict("x" => x, "p" => p, "g" => x^2 - p))
Function(G:(x0,p)->(x) Newton)
julia> G(x0=1, p=2)["x"], G(1, 2)
(1.4142, 1.4142)
julia> ca.stats(G)["success"], ca.stats(G)["return_status"]
(true, "success")
julia> pm = ca.MX.sym("p");
julia> dxdp = ca.Function("dxdp", [pm], [ca.jacobian(G(x0=1, p=pm)["x"], pm)]);
julia> dxdp(4)
DM(0.25)
julia> f = ca.Function("f", [x, p], [x^2 - p, 3*x], ["x", "p"], ["g", "h"]);
julia> G = ca.rootfinder("G", "newton", f)
Function(G:(x0,p)->(x,h) Newton)
julia> G(x0=1, p=4)
Dict{String, DM} with 2 entries:
  "h" => 6
  "x" => 2
julia> f = ca.Function("f", [p, x], [3*x, x^2 - p], ["p", "x"], ["h", "g"]);
julia> opts = Dict("implicit_input" => 1, "implicit_output" => 1);
julia> G = ca.rootfinder("G", "newton", f, opts)
Function(G:(p,x0)->(h,x) Newton)
>>> x = SX.sym("x"); p = SX.sym("p")
>>> G = rootfinder("G", "newton", {"x": x, "p": p, "g": x**2 - p}, {"max_iter": 2})
>>> try:
...     G(x0=1, p=2)
... except RuntimeError as e:
...     print("rootfinder process failed" in str(e))
True
>>> opts = {"max_iter": 2, "error_on_fail": False, "print_iteration": False}
>>> G = rootfinder("G", "newton", {"x": x, "p": p, "g": x**2 - p}, opts)
>>> G(x0=1, p=2)["x"], G.stats()["return_status"]
(DM(1.4167), 'max_iteration_reached')
>>> X = SX.sym("x", 2)
>>> try:
...     rootfinder("G", "newton", {"x": X, "g": vertcat(X[0] - 1, 1)})
... except RuntimeError as e:
...     print("structurally rank-deficient" in str(e))
True
>>> try:
...     rootfinder("G", "newton", {"x": X, "g": X[0]})
... except RuntimeError as e:
...     print("Dimension mismatch" in str(e))
True
>> x = SX.sym('x'); p = SX.sym('p'); rfp = struct('x', x, 'p', p, 'g', x^2 - p);
>> G = rootfinder('G', 'newton', rfp, struct('max_iter', 2));
>> try, G('x0', 1, 'p', 2); catch e, msg = e.message; end
>> contains(msg, 'rootfinder process failed')
1
>> opts = struct('max_iter', 2, 'error_on_fail', false, 'print_iteration', false);
>> G = rootfinder('G', 'newton', rfp, opts);
>> r = G('x0', 1, 'p', 2); st = G.stats(); r.x, st.return_status
1.4167
max_iteration_reached
>> X = SX.sym('x', 2);
>> rfp = struct('x', X, 'g', [X(1) - 1; 1]);
>> try, rootfinder('G', 'newton', rfp); catch e, msg = e.message; end
>> contains(msg, 'structurally rank-deficient')
1
>> try, rootfinder('G', 'newton', struct('x', X, 'g', X(1))); catch e, msg = e.message; end
>> contains(msg, 'Dimension mismatch')
1
julia> x = ca.SX.sym("x"); p = ca.SX.sym("p");
julia> rfp = Dict("x" => x, "p" => p, "g" => x^2 - p);
julia> G = ca.rootfinder("G", "newton", rfp, Dict("max_iter" => 2));
julia> try
           G(x0=1, p=2)
       catch e
           println(occursin("rootfinder process failed", sprint(showerror, e)))
       end
true
julia> opts = Dict("max_iter" => 2, "error_on_fail" => false, "print_iteration" => false);
julia> G = ca.rootfinder("G", "newton", rfp, opts);
julia> G(x0=1, p=2)["x"], ca.stats(G)["return_status"]
(1.4167, "max_iteration_reached")
julia> X = ca.SX.sym("x", 2);
julia> try
           ca.rootfinder("G", "newton", Dict("x" => X, "g" => [X[1] - 1; 1]))
       catch e
           println(occursin("structurally rank-deficient", sprint(showerror, e)))
       end
true
julia> try
           ca.rootfinder("G", "newton", Dict("x" => X, "g" => X[1]))
       catch e
           println(occursin("Dimension mismatch", sprint(showerror, e)))
       end
true

General information

>List of available options

Id

Type

Description

Used in

ad_weight

OT_DOUBLE

Weighting factor for derivative calculation.When there is an option of either using forward or reverse mode directional derivatives, the condition ad_wei ght*nf<=(1- ad_weight)*na is used where nf and na are estimates of the number of forward/reverse mode directional derivatives needed. By default, ad_weight is calculated automatically, but this can be overridden by setting this option. In particular, 0 means forcing forward mode and 1 forcing reverse mode. Leave unset for (class specific) heuristics.

casadi::Function Internal

ad_weight_sp

OT_DOUBLE

Weighting factor for sparsity pattern calculation calc ulation.Override s default behavior. Set to 0 and 1 to force forward and reverse mode respectively. Cf. option "ad_weight". When set to -1, sparsity is completely ignored and dense matrices are used.

casadi::Function Internal

always_inline

OT_BOOL

Force inlining.

casadi::Function Internal

cache

OT_DICT

Prepopulate the function cache. Default: empty

casadi::Function Internal

codegen_options

OT_DICT

Options to be passed to the code generator of jit, e.g. {"stats": true} to record statistics inside the compiled code. Default: none

casadi::Function Internal

common_options

OT_DICT

Options for auto-generated functions

casadi::OracleFu nction

compiler

OT_STRING

Just-in-time compiler plugin to be used.

casadi::Function Internal

constraints

OT_INTVECTOR

Constrain the unknowns. 0 (default): no constraint on ui, 1: ui >= 0.0, -1: ui <= 0.0, 2: ui > 0.0, -2: ui < 0.0.

casadi::Rootfind er

custom_jacobian

OT_FUNCTION

Override CasADi's AD. Use together with 'jac_penalty': 0. Note: Highly experimental. Syntax may break often.

casadi::Function Internal

der_options

OT_DICT

Default options to be used to populate forward_options, reverse_options, and jacobian_options before those options are merged in.

casadi::Function Internal

derivative_of

OT_FUNCTION

The function is a derivative of another function. The type of derivative (directional derivative, Jacobian) is inferred from the function name.

casadi::Function Internal

dump

OT_BOOL

Dump function to file upon first evaluation. [false]

casadi::Function Internal

dump_dir

OT_STRING

Directory to dump inputs/outputs and traces to. Make sure the directory exists [.]

casadi::Function Internal

dump_format

OT_STRING

Choose file format to dump matrices. See DM.from_file [mtx]

casadi::Function Internal

dump_in

OT_BOOL

Dump numerical values of inputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

dump_out

OT_BOOL

Dump numerical values of outputs to file (readable with DM.from_file) [default: false] A counter is used to generate unique names. The counter may be reset using r eset_dump_count.

casadi::Function Internal

enable_fd

OT_BOOL

Enable derivative calculation by finite differencing. [default: false]]

casadi::Function Internal

enable_forward

OT_BOOL

Enable derivative calculation using generated functions for Jacobian-times- vector products - typically using forward mode AD - if available. [default: true]

casadi::Function Internal

enable_jacobian

OT_BOOL

Enable derivative calculation using generated functions for Jacobians of all differentiable outputs with respect to all differentiable inputs - if available. [default: true]

casadi::Function Internal

enable_reverse

OT_BOOL

Enable derivative calculation using generated functions for transposed Jacobian-times- vector products - typically using reverse mode AD - if available. [default: true]

casadi::Function Internal

error_on_fail

OT_BOOL

Throw exceptions when function evaluation fails (default true).

casadi::ProtoFun ction

expand

OT_BOOL

Replace MX with SX expressions in problem formulation [false] This happens before creating derivatives unless indicated by postpone_expand

casadi::OracleFu nction

external_transfo rm

OT_VECTORVECTOR

List of external _transform instruction arguments. Default: empty

casadi::Function Internal

fd_method

OT_STRING

Method for finite differencing [default 'central']

casadi::Function Internal

fd_options

OT_DICT

Options to be passed to the finite difference instance

casadi::Function Internal

forward_options

OT_DICT

Options to be passed to a forward mode constructor

casadi::Function Internal

gather_stats

OT_BOOL

Deprecated option (ignored): Statistics are now always collected.

casadi::Function Internal

implicit_input

OT_INT

Index of the input that corresponds to the actual root- finding

casadi::Rootfind er

implicit_output

OT_INT

Index of the output that corresponds to the actual root- finding

casadi::Rootfind er

inputs_check

OT_BOOL

Throw exceptions when the numerical values of the inputs don't make sense

casadi::Function Internal

is_diff_in

OT_BOOLVECTOR

Indicate for each input if it should be differentiable.

casadi::Function Internal

is_diff_out

OT_BOOLVECTOR

Indicate for each output if it should be differentiable.

casadi::Function Internal

jac_penalty

OT_DOUBLE

When requested for a number of forward/reverse directions, it may be cheaper to compute first the full jacobian and then multiply with seeds, rather than obtain the requested directions in a straightforward manner. Casadi uses a heuristic to decide which is cheaper. A high value of 'jac_penalty' makes it less likely for the heurstic to chose the full Jacobian strategy. The special value -1 indicates never to use the full Jacobian strategy

casadi::Function Internal

jacobian_functio n

OT_FUNCTION

Function object for calculating the Jacobian (autogenerated by default)

casadi::Rootfind er

jacobian_options

OT_DICT

Options to be passed to a Jacobian constructor

casadi::Function Internal

jit

OT_BOOL

Use just-in-time compiler to speed up the evaluation

casadi::Function Internal

jit_cleanup

OT_BOOL

Cleanup up the temporary source file that jit creates. Default: true

casadi::Function Internal

jit_name

OT_STRING

The file name used to write out code. The actual file names used depend on 'jit_t emp_suffix' and include extensions. Default: 'jit_tmp'

casadi::Function Internal

jit_options

OT_DICT

Options to be passed to the jit compiler.

casadi::Function Internal

jit_serialize

OT_STRING

Specify behaviour when serializing a jitted function: SOURCE|link|embe d.

casadi::Function Internal

jit_temp_suffix

OT_BOOL

Use a temporary (seemingly random) filename suffix for generated code and libraries. This is desired for thread- safety. This behaviour may defeat caching compiler wrappers. Default: true

casadi::Function Internal

linear_solver

OT_STRING

User-defined linear solver class. Needed for sensitivities.

casadi::Rootfind er

linear_solver_op tions

OT_DICT

Options to be passed to the linear solver.

casadi::Rootfind er

max_io

OT_INT

Acceptable number of inputs and outputs. Warn if exceeded.

casadi::Function Internal

max_num_dir

OT_INT

Specify the maximum number of directions for derivative functions. Overrules the builtin optimize d_num_dir.

casadi::Function Internal

monitor

OT_STRINGVECTOR

Set of user problem functions to be monitored

casadi::OracleFu nction

never_inline

OT_BOOL

Forbid inlining.

casadi::Function Internal

post_expand

OT_BOOL

After construction, expand this Function. Default: False

casadi::Function Internal

post_expand_opti ons

OT_DICT

Options to be passed to post- construction expansion. Default: empty

casadi::Function Internal

postpone_expand

OT_BOOL

When expand is active, postpone it until after creation of derivatives. Default: False

casadi::OracleFu nction

print_canonical

OT_BOOL

When printing numerical matrices, use a format that is exact and reproducible in generated C code.

casadi::Function Internal

print_in

OT_BOOL

Print numerical values of inputs [default: false]

casadi::Function Internal

print_out

OT_BOOL

Print numerical values of outputs [default: false]

casadi::Function Internal

print_time

OT_BOOL

print information about execution time. Implies record_time.

casadi::ProtoFun ction

record_time

OT_BOOL

record information about execution time, for retrieval with stats().

casadi::ProtoFun ction

regularity_check

OT_BOOL

Throw exceptions when NaN or Inf appears during evaluation

casadi::ProtoFun ction

reverse_options

OT_DICT

Options to be passed to a reverse mode constructor

casadi::Function Internal

show_eval_warnin gs

OT_BOOL

Show warnings generated from function evaluations [true]

casadi::OracleFu nction

specific_options

OT_DICT

Options for specific auto- generated functions, overwriting the defaults from common_options. Nested dictionary.

casadi::OracleFu nction

user_data

OT_VOIDPTR

A user-defined field that can be used to identify the function or pass additional information

casadi::Function Internal

verbose

OT_BOOL

Verbose evaluation for debugging

casadi::ProtoFun ction

>Input scheme: casadi::RootfinderInput (ROOTFINDER_NUM_IN = 2)

Full name

Short

Description

ROOTFINDER_X0

x0

Initial guess for the solution.

ROOTFINDER_P

p

Parameters.

>Output scheme: casadi::RootfinderOutput (ROOTFINDER_NUM_OUT = 1)

Full name

Short

Description

ROOTFINDER_X

x

Solution to the system of equations.

List of plugins - kinsol

  • fast_newton

  • nlpsol

  • newton

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Rootfinder.doc("myextraplugin")


kinsol

KINSOL interface from the Sundials suite

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Stopping criterion tolerance

disable_internal_warnings

OT_BOOL

Disable KINSOL internal warning messages

exact_jacobian

OT_BOOL

Use exact Jacobian information

f_scale

OT_DOUBLEVECTOR

Equation scaling factors

iterative_solver

OT_STRING

gmres|bcgstab|tfqmr

linear_solver_type

OT_STRING

dense|banded|iterative|use r_defined

lower_bandwidth

OT_INT

Lower bandwidth for banded linear solvers

max_iter

OT_INT

Maximum number of Newton iterations. Putting 0 sets the default value of KinSol.

max_krylov

OT_INT

Maximum Krylov space dimension

pretype

OT_STRING

Type of preconditioner

print_level

OT_INT

Verbosity level

strategy

OT_STRING

Globalization strategy

u_scale

OT_DOUBLEVECTOR

Variable scaling factors

upper_bandwidth

OT_INT

Upper bandwidth for banded linear solvers

use_preconditioner

OT_BOOL

Precondition an iterative solver


fast_newton

Implements simple newton iterations to solve an implicit function.

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Stopping criterion tolerance on ||g||__inf)

abstolStep

OT_DOUBLE

Stopping criterion tolerance on step size

max_iter

OT_INT

Maximum number of Newton iterations to perform before returning.


nlpsol


newton

Implements simple newton iterations to solve an implicit function.

>List of available options

Id

Type

Description

abstol

OT_DOUBLE

Stopping criterion tolerance on max(|F|)

abstolStep

OT_DOUBLE

Stopping criterion tolerance on step size

line_search

OT_BOOL

Enable line-search (default: true)

max_iter

OT_INT

Maximum number of Newton iterations to perform before returning.

print_iteration

OT_BOOL

Print information about each iteration

Authors: Joel Andersson

Extra doc | Doc source | Implementation

Linear systems

class Linsol(...)

Linear solver.

Solves the square linear system A*X = B or A'*X = B for X with a sparse direct solver plugin. A Linsol is created for a fixed sparsity pattern of A; the numerical values are given at every call. A matrix with another sparsity pattern is projected onto the fixed one (entries outside it are dropped). The solve is split in a symbolic factorization (sfact, pivot selection from the pattern), a numeric factorization (nfact) and the triangular solves (solve); solve(A, B) performs all three. A numerically singular matrix makes nfact (or solve) raise an error for most plugins; for a symbolic (MX) A, solve returns an expression node that is differentiable with respect to A and B.

Available plugins include "qr" and "ldl" (sparse direct QR and LDL, codegen support), "symbolicqr" (QR as a symbolic expression), "csparse", "csparsecholesky", "lapacklu", "lapackqr", "ma27", "mumps". neig and rank are only implemented by "ldl", det by "qr" and "csparse". The constructor raises an error for a non-square pattern only when the plugin checks it; otherwise the solve fails.

>>> A = DM([[3, 1], [1, 2]]); b = DM([4, 3])
>>> L = Linsol("L", "qr", A.sparsity())
>>> L.plugin_name(), L.sparsity()
('qr', Sparsity(2x2))
>>> L.solve(A, b), L.solve(DM([[1, 2], [0, 1]]), DM([1, 1]), True)
(DM([1, 1]), DM([1, -1]))
>>> L.solve(A, DM([[4, 1], [3, 0]]))
DM(
[[1, 0.4],
 [1, -0.2]])
>>> L.det(A)
5.0
>>> try:
...     L.solve(DM([[1, 1], [1, 1]]), b)
... except RuntimeError as e:
...     print("'nfact' failed" in str(e))
True
>>> Am = MX.sym("A", A.sparsity()); bm = MX.sym("b", 2)
>>> f = Function("f", [Am, bm], [L.solve(Am, bm), L.det(Am)])
>>> f(A, b)
(DM([1, 1]), DM(5))
>> A = DM([3 1; 1 2]); b = DM([4; 3]);
>> L = Linsol('L', 'qr', A.sparsity());
>> L.plugin_name(), L.sparsity()
qr
2x2
>> L.solve(A, b), L.solve(DM([1 2; 0 1]), DM([1; 1]), true)
[1, 1]
[1, -1]
>> L.solve(A, DM([4 1; 3 0]))
[[1, 0.4],
[1, -0.2]]
>> L.det(A)
5
>> try, L.solve(DM([1 1; 1 1]), b); catch e, msg = e.message; end
>> contains(msg, '''nfact'' failed')
1
>> Am = MX.sym('A', A.sparsity()); bm = MX.sym('b', 2);
>> f = Function('f', {Am, bm}, {L.solve(Am, bm), L.det(Am)});
>> [xs, d] = f(A, b); disp(xs), disp(d)
[1, 1]
5
julia> A = ca.DM([3 1; 1 2]); b = ca.DM([4, 3]);
julia> L = ca.Linsol("L", "qr", ca.sparsity(A));
julia> ca.plugin_name(L), ca.sparsity(L)
("qr", 2x2)
julia> ca.solve(L, A, b)
DM([1, 1])
julia> ca.solve(L, ca.DM([1 2; 0 1]), ca.DM([1, 1]), true)
DM([1, -1])
julia> ca.solve(L, A, ca.DM([4 1; 3 0]))
DM(
[[1, 0.4],
 [1, -0.2]])
julia> L.det(A)
5.0
julia> try
           ca.solve(L, ca.DM([1 1; 1 1]), b, false)
       catch e
           println(occursin("'nfact' failed", sprint(showerror, e)))
       end
true
julia> Am = ca.MX.sym("A", ca.sparsity(A)); bm = ca.MX.sym("b", 2);
julia> f = ca.Function("f", [Am, bm], [ca.solve(L, Am, bm), L.det(Am)]);
julia> f(A, b)
([1, 1], 5)

General informationList of plugins - csparsecholesky

  • csparse

  • ma27

  • lapacklu

  • lapackqr

  • mumps

  • ldl

  • qr

  • tridiag

  • symbolicqr

Note: some of the plugins in this list might not be available on your system. Also, there might be extra plugins available to you that are not listed here. You can obtain their documentation with Linsol.doc("myextraplugin")


csparsecholesky

Linsol with CSparseCholesky Interface


csparse

Linsol with CSparse Interface


ma27

Interface to the sparse direct linear solver MA27 Works for symmetric indefinite systems Partly adopted from qpOASES 3.2

Authors: Joel Andersson


lapacklu

This class solves the linear system A.x=b by making an LU factorization of A: A = L.U, with L lower and U upper triangular

>List of available options

Id

Type

Description

allow_equilibration_failure

OT_BOOL

Non-fatal error when equilibration fails

equilibration

OT_BOOL

Equilibrate the matrix


lapackqr

This class solves the linear system A.x=b by making an QR factorization of A: A = Q.R, with Q orthogonal and R upper triangular

>List of available options

Id

Type

Description

max_nrhs

OT_INT

Maximum number of right-hand-sides that get processed in a single pass [default:10].


mumps

Interface to the sparse direct linear solver MUMPS Works for symmetric indefinite systems

Authors: Joel Andersson

>List of available options

Id

Type

Description

posdef

OT_BOOL

Positive definite

symmetric

OT_BOOL

Symmetric matrix


ldl

Linear solver using sparse direct LDL factorization

>List of available options

Id

Type

Description

incomplete

OT_BOOL

Incomplete factorization, without any fill-in

preordering

OT_BOOL

Approximate minimal degree (AMD) preordering


qr --

Linear solver using sparse direct QR factorization

>List of available options

Id

Type

Description

cache

OT_DOUBLE

Amount of factorisations to remember (thread-local) [0]

eps

OT_DOUBLE

Minimum R entry before singularity is declared [1e-12]


tridiag

Linear solver for tridiagonal matrices


symbolicqr

Linear solver for sparse least-squares problems Inspired from https://github.com/scipy/scipy/blob/v0.14.0/scipy/sparse/linalg/isolve/lsqr.py#L96

Linsol based on QR factorization with sparsity pattern based reordering without partial pivoting

>List of available options

Id

Type

Description

fopts

OT_DICT

Options to be passed to generated function objects

Authors: Joel Andersson

Extra doc

class_name(...)

Get class name.

class_name(self) -> str

Extra doc | Doc source | Implementation

debug_repr(...)
debug_repr(self) -> str
det(...)

Matrix determinant as an MX graph node.

det(self, DM A) -> float
det(self, MX A) -> MX

Matrix determinant.

Not available for all solvers ("qr" and "csparse"); factorizes A first.

>>> A = DM([[3, 1], [1, 2]])
>>> Linsol("L", "qr", A.sparsity()).det(A)
5.0
>>> try:
...     Linsol("L", "ldl", A.sparsity()).det(A)
... except RuntimeError as e:
...     print("'det' not defined" in str(e))
True
>> A = DM([3 1; 1 2]); L = Linsol('L', 'qr', A.sparsity()); disp(L.det(A))
5
>> L = Linsol('L', 'ldl', A.sparsity());
>> try, L.det(A); catch e, disp(contains(e.message, '''det'' not defined')); end
1
julia> A = ca.DM([3 1; 1 2]);
julia> ca.Linsol("L", "qr", ca.sparsity(A)).det(A)
5.0
julia> try
           ca.Linsol("L", "ldl", ca.sparsity(A)).det(A)
       catch e
           println(occursin("'det' not defined", sprint(showerror, e)))
       end
true

Doc source | Implementation | Extra doc

disp(...)

Print a description of the object.

disp(self, bool more)

Doc source | Implementation

static doc(...)

Get solver specific documentation.

doc(str name) -> str

Same as doc_linsol.

>>> "LDL" in Linsol.doc("ldl")
True
>> contains(Linsol.doc('ldl'), 'LDL')
1
julia> occursin("LDL", ca.Linsol.doc("ldl"))
true

Extra doc | Doc source | Implementation

static has_plugin(...)

Check if a plugin is available.

has_plugin(str name) -> bool

Same as has_linsol.

>>> Linsol.has_plugin("qr"), Linsol.has_plugin("no_such_plugin")
(True, False)
>> Linsol.has_plugin('qr'), Linsol.has_plugin('no_such_plugin')
1
0
julia> ca.Linsol.has_plugin("qr"), ca.Linsol.has_plugin("no_such_plugin")
(true, false)

Extra doc | Doc source | Implementation

is_null(...)
is_null(self) -> bool
static load_plugin(...)

Explicitly load a plugin dynamically.

load_plugin(str name)

Same as load_linsol; raises an error when the plugin cannot be found.

>>> try:
...     Linsol.load_plugin("no_such_plugin")
... except RuntimeError as e:
...     print("no_such_plugin" in str(e))
True
>> try, Linsol.load_plugin('no_such_plugin'); catch e, msg = e.message; end
>> contains(msg, 'no_such_plugin')
1
julia> try
           ca.Linsol.load_plugin("no_such_plugin")
       catch e
           println(occursin("no_such_plugin", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

neig(...)

Number of negative eigenvalues.

neig(self, DM A) -> int

Not available for all solvers (only "ldl"); uses the factorization of the most recent nfact call, which must have been made with the same matrix.

>>> A = DM([[-2, 0], [0, 1]])
>>> L = Linsol("L", "ldl", A.sparsity())
>>> L.nfact(A)
>>> L.neig(A)
1
>>> try:
...     Linsol("L", "qr", A.sparsity()).neig(A)
... except RuntimeError as e:
...     print("'neig' not defined" in str(e))
True
>> A = DM([-2 0; 0 1]); L = Linsol('L', 'ldl', A.sparsity());
>> L.nfact(A); disp(L.neig(A))
1
>> L = Linsol('L', 'qr', A.sparsity());
>> try, L.neig(A); catch e, disp(contains(e.message, '''neig'' not defined')); end
1
julia> A = ca.DM([-2 0; 0 1]);
julia> L = ca.Linsol("L", "ldl", ca.sparsity(A));
julia> ca.nfact(L, A)
julia> ca.neig(L, A)
1
julia> try
           ca.neig(ca.Linsol("L", "qr", ca.sparsity(A)), A)
       catch e
           println(occursin("'neig' not defined", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

nfact(...)

Numeric factorization of the linear system.

nfact(self, DM A)

Factorizes the values of A (after sfact if not done yet), so that neig, rank and the low-level solve can use the factorization. Raises an error when the factorization fails with option "regularity_check" set; otherwise a failure is only reported by solve.

>>> A = DM([[3, 1], [1, 2]])
>>> L = Linsol("L", "ldl", A.sparsity())
>>> L.nfact(A)
>>> L.neig(A), L.rank(A)
(0, 2)
>>> L.nfact(DM([[-1, 0], [0, 1]]))
>>> L.neig(DM([[-1, 0], [0, 1]]))
1
>> A = DM([3 1; 1 2]); L = Linsol('L', 'ldl', A.sparsity());
>> L.nfact(A); fprintf('%d %d\n', L.neig(A), L.rank(A))
0 2
>> B = DM([-1 0; 0 1]); L.nfact(B); disp(L.neig(B))
1
julia> A = ca.DM([3 1; 1 2]);
julia> L = ca.Linsol("L", "ldl", ca.sparsity(A));
julia> ca.nfact(L, A)
julia> ca.neig(L, A), ca.rank(L, A)
(0, 2)
julia> ca.nfact(L, ca.DM([-1 0; 0 1]))
julia> ca.neig(L, ca.DM([-1 0; 0 1]))
1

Extra doc | Doc source | Implementation

plugin_name(...)

Query plugin name.

plugin_name(self) -> str

Doc source | Implementation

print_ptr(...)
print_ptr(self)
rank(...)

Matrix rank.

rank(self, DM A) -> int

Not available for all solvers (only "ldl"); uses the factorization of the most recent nfact call, which must have been made with the same matrix.

A rank-deficient matrix also triggers a warning in nfact.

>>> A = DM([[2, 1], [1, 3]])
>>> L = Linsol("L", "ldl", A.sparsity())
>>> L.nfact(A)
>>> L.rank(A)
2
>> A = DM([2 1; 1 3]); L = Linsol('L', 'ldl', A.sparsity());
>> L.nfact(A); disp(L.rank(A))
2
julia> A = ca.DM([2 1; 1 3]);
julia> L = ca.Linsol("L", "ldl", ca.sparsity(A));
julia> ca.nfact(L, A)
julia> ca.rank(L, A)
2

Extra doc | Doc source | Implementation

sfact(...)

Symbolic factorization of the linear system, e.g. selecting pivots.

sfact(self, DM A)

Only uses the sparsity pattern of A. Called automatically by nfact and solve when needed; raises an error when the plugin fails.

Extra doc | Doc source | Implementation

solve(...)
solve(self, DM A, DM B, bool tr) -> DM
solve(self, MX A, MX B, bool tr) -> MX

Solve the linear system A*X = B (or A'*X = B with tr true)

For DM arguments, factorizes A and solves for all columns of B at once; the result is dense. For MX arguments, returns an expression node that is differentiable. The row count of A and B must match.

Parameters:
  • A -- Square matrix with the sparsity pattern given at construction (projected onto it otherwise)

  • B -- Right-hand side, one column per system to solve

  • tr -- Solve with the transpose of A instead

Returns:

X with the shape of B

>>> L = Linsol("L", "qr", Sparsity.dense(2, 2))
>>> L.solve(DM([[3, 1], [1, 2]]), DM([4, 3]))
DM([1, 1])
>>> try:
...     L.solve(DM([[3, 1], [1, 2]]), DM([1, 2, 3]))
... except RuntimeError as e:
...     print("matching row count" in str(e))
True
>> L = Linsol('L', 'qr', Sparsity.dense(2, 2));
>> L.solve(DM([3 1; 1 2]), DM([4; 3]))
[1, 1]
>> try, L.solve(DM([3 1; 1 2]), DM([1; 2; 3])); catch e, msg = e.message; end
>> contains(msg, 'matching row count')
1
julia> L = ca.Linsol("L", "qr", ca.Sparsity.dense(2, 2));
julia> ca.solve(L, ca.DM([3 1; 1 2]), ca.DM([4, 3]))
DM([1, 1])
julia> try
           ca.solve(L, ca.DM([3 1; 1 2]), ca.DM([1, 2, 3]))
       catch e
           println(occursin("matching row count", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

sparsity(...)

Get the sparsity pattern of A fixed at construction.

sparsity(self) -> Sparsity

Doc source | Implementation

stats(...)

Get all statistics obtained at the end of the last evaluate call.

stats(self, int mem) -> dict

Plugin-specific; empty for most plugins. Raises an error before the first solve. With the option "record_time" set, it holds call counts and timings (n_call_*, t_proc_*, t_wall_*) of sfact, nfact and solve.

>>> L = Linsol("L", "qr", Sparsity.dense(1, 1))
>>> try:
...     L.stats()
... except RuntimeError as e:
...     print("did not solve a problem yet" in str(e))
True
>>> L.solve(DM(2), DM(4)), L.stats()
(DM(2), {})
>>> L = Linsol("L", "qr", Sparsity.dense(1, 1), {"record_time": True})
>>> L.solve(DM(2), DM(4)); L.stats()["n_call_solve"]
DM(2)
1
>> L = Linsol('L', 'qr', Sparsity.dense(1, 1));
>> try, L.stats(); catch e, disp(contains(e.message, 'did not solve a problem yet')); end
1
>> L.solve(DM(2), DM(4)), isempty(fieldnames(L.stats()))
2
1
julia> L = ca.Linsol("L", "qr", ca.Sparsity.dense(1, 1));
julia> try
           ca.stats(L)
       catch e
           println(occursin("did not solve a problem yet", sprint(showerror, e)))
       end
true
julia> ca.solve(L, ca.DM(2), ca.DM(4)), ca.stats(L)
(2, Dict{String, Any}())
julia> L = ca.Linsol("L", "qr", ca.Sparsity.dense(1, 1), Dict("record_time" => true));
julia> ca.solve(L, ca.DM(2), ca.DM(4)); ca.stats(L)["n_call_solve"]
1

Extra doc | Doc source | Implementation

str(...)

Get string representation.

str(self, bool more) -> str

Doc source | Implementation

static type_name(...)

Get type name.

type_name() -> str

Extra doc | Doc source | Implementation

Opti stack

class Opti(...)

A simplified interface for NLP modeling/solving.

Opti collects decision variables, parameters, an objective and constraints written in natural syntax, builds an nlpsol (or qpsol) instance from them and gives numerical access to the solution. The bookkeeping of flattening variables into one vector and constraints into bounds is hidden.

Workflow:

  • Declare symbols with variable() and parameter(); they are plain MX symbols.

  • State the problem with minimize() and subject_to().

  • Pick a numerical back-end with solver().

  • Give parameters a value with set_value(), optionally a guess with set_initial().

  • Call solve(); it returns an OptiSol snapshot whose value() evaluates expressions.

Opti is stateful: every call above mutates the instance, and the problem is rebuilt lazily at the next solve(). An OptiSol is a copy taken at the time of solve(), so later changes to the Opti do not affect it. Only symbols created by this instance may appear in its expressions; raw MX.sym symbols or symbols of another Opti raise an error.

The constructor argument selects the problem class: "nlp" (default, solved with nlpsol) or "conic" (quadratic programs and SOCPs, solved with qpsol).

An iteration callback can be registered with opti.callback(fh); fh is called with the iteration number after every solver iteration, and opti.debug.value() inside it returns the current iterate. Calling opti.callback() without argument removes it.

>>> opti = Opti()
>>> x = opti.variable()
>>> y = opti.variable()
>>> opti.minimize((y-x**2)**2)
>>> opti.subject_to(x**2+y**2==1)
>>> opti.subject_to(x+y>=1)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> sol.value(x), sol.value(y)
(0.7862, 0.6180)
>>> sol.value(opti.f)
0
>> opti = Opti();
>> x = opti.variable(); y = opti.variable();
>> opti.minimize((y-x^2)^2);
>> opti.subject_to(x^2+y^2==1);
>> opti.subject_to(x+y>=1);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> sol.value(x), sol.value(y)
0.7862
0.6180
>> sol.value(opti.f)
0
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> y = ca.variable(opti);
julia> ca.minimize(opti, (y - x^2)^2)
julia> ca.subject_to(opti, x^2 + y^2 == 1)
julia> ca.subject_to(opti, x + y >= 1)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.value(sol, x), ca.value(sol, y)
(0.7862, 0.6180)
julia> ca.value(sol, ca.f(opti))
0

Parametric problems are re-solved by changing parameter values:

>>> opti = Opti()
>>> x = opti.variable(2)
>>> p = opti.parameter()
>>> opti.minimize(sumsqr(x-p))
>>> opti.subject_to(1 <= (sum1(x) <= 2))
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> opti.set_value(p, 3)
>>> sol = opti.solve()
>>> sol.value(sum1(x))
2.0
>>> opti.set_value(p, 0)
>>> sol = opti.solve()
>>> sol.value(sum1(x))
1.0
>> opti = Opti();
>> x = opti.variable(2); p = opti.parameter();
>> opti.minimize(sumsqr(x-p));
>> opti.subject_to(1 <= sum1(x) <= 2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> opti.set_value(p, 3); sol = opti.solve();
>> sol.value(sum1(x))
2
>> opti.set_value(p, 0); sol = opti.solve();
>> sol.value(sum1(x))
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> p = ca.parameter(opti);
julia> ca.minimize(opti, ca.sumsqr(x - p))
julia> ca.subject_to(opti, 1 <= (sum(x) <= 2))
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> ca.set_value(opti, p, 3)
julia> sol = ca.solve(opti);
julia> ca.value(sol, sum(x))
2.0
julia> ca.set_value(opti, p, 0)
julia> sol = ca.solve(opti);
julia> ca.value(sol, sum(x))
1.0

An iteration callback:

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-1)**2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> history = []
>>> opti.callback(lambda i: history.append((i, opti.debug.value(x))))
>>> sol = opti.solve()
>>> history
[(0, 0.0), (1, 1.0)]
>>> opti.callback()
>>> sol = opti.solve()
>>> len(history)
2
>> opti = Opti(); x = opti.variable(); opti.minimize((x-1)^2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> opti.callback(@(i) fprintf('%d %.3f\n', i, opti.debug.value(x)));
>> sol = opti.solve();
0 0.000
1 1.000
>> opti.callback();
>> sol = opti.solve();
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 1)^2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> history = Tuple{Int,Float64}[];
julia> ca.callback(opti, i -> push!(history, (i, ca.value(ca.debug(opti), x))))
julia> sol = ca.solve(opti);
julia> history
2-element Vector{Tuple{Int64, Float64}}:
 (0, 0.0)
 (1, 1.0)
julia> ca.callback(opti)
julia> sol = ca.solve(opti);
julia> length(history)
2

See also: OptiSol, OptiAdvanced, nlpsol, qpsol

Authors: Joris Gillis, Erik Lambrechts, Joel Andersson

Extra doc

static bounded(...)

Construct a double inequality.

bounded(MX lb, MX expr, MX ub) -> MX

Returns the expression (lb <= expr) <= ub, which subject_to() recognizes as a double-bounded constraint lb <= expr <= ub when lb and ub are free of decision variables. Identical to writing lb <= (expr <= ub) by hand; provided because Python's chained comparison lb <= expr <= ub raises an error for MX. A static method; the instance is not needed.

>>> opti = Opti()
>>> x = opti.variable(2)
>>> opti.subject_to(opti.bounded(-1, x, 1))
>>> opti.subject_to(Opti.bounded(0, x[0] + x[1], 1))
>>> opti.ng, opti.lbg, opti.ubg
(3, MX(vertcat(all_-1(2x1), 0)), MX(ones(3x1)))
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> ca.subject_to(opti, ca.bounded(-1, x, 1))
julia> ca.subject_to(opti, ca.Opti.bounded(0, x[1] + x[2], 1))
julia> ca.ng(opti), ca.lbg(opti), ca.ubg(opti)
(3, vertcat(all_-1(2x1), 0), ones(3x1))

Extra doc | Doc source | Implementation

callback_class(...)
callback_class(self)
callback_class(self, OptiCallback callback)

Helper methods for callback()

Do not use directly; use opti.callback(fh) in Python/MATLAB, which wraps a callable in an OptiCallback and registers it here. The no-argument form removes the callback.

Extra doc | Doc source | Implementation

class_name(...)

Get class name.

class_name(self) -> str

Extra doc | Doc source | Implementation

copy(...)

Get a deep copy of the Opti instance.

copy(self) -> Opti

The copy shares the symbols (so expressions in them stay valid for both) but has its own constraints, values, initial guesses and solver state. Updating the copy does not update the original.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize(x**2)
>>> opti2 = opti.copy()
>>> opti2.subject_to(x >= 2)
>>> opti.ng, opti2.ng
(0, 1)
>> opti = Opti(); x = opti.variable(); opti.minimize(x^2);
>> opti2 = opti.copy(); opti2.subject_to(x >= 2); fprintf('%d %d\n', opti.ng, opti2.ng)
0 1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, x^2)
julia> opti2 = opti.copy();
julia> ca.subject_to(opti2, x >= 2)
julia> ca.ng(opti), ca.ng(opti2)
(0, 1)

Extra doc | Doc source | Implementation

debug_repr(...)
debug_repr(self) -> str
disp(...)

Print a summary of the instance.

disp(self, bool more)

Shows the instance number, the number of variables, parameters and constraints that appear in the problem, whether the solver is up to date and the last return status.

>>> opti = Opti()
>>> x = opti.variable(2)
>>> opti.minimize(sumsqr(x))
>>> opti.subject_to(x[0] >= 1)
>>> print(opti)
Opti {
  instance #...
  #variables: 1 (nx = 2)
  #parameters: 0 (np = 0)
  #constraints: 1 (ng = 1)
  CasADi solver needs updating.
}
>> opti = Opti(); x = opti.variable(2);
>> opti.minimize(sumsqr(x)); opti.subject_to(x(1) >= 1); disp(opti)
Opti {
instance #...
#variables: 1 (nx = 2)
#parameters: 0 (np = 0)
#constraints: 1 (ng = 1)
CasADi solver needs updating.
}
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> ca.minimize(opti, ca.sumsqr(x))
julia> ca.subject_to(opti, x[1] >= 1)
julia> opti
Opti(Opti {
  instance #45
  #variables: 1 (nx = 2)
  #parameters: 0 (np = 0)
  #constraints: 1 (ng = 1)
  CasADi solver needs updating.
})

Extra doc | Doc source | Implementation

dual(...)

Get the dual variable (Lagrange multiplier) of a constraint.

dual(self, MX m) -> MX

m must be the exact expression object that was passed to subject_to(). The result is symbolic; evaluate it with value(). For inequality constraints the dual is nonnegative (the sign of lam_g is removed); for equality constraints it equals the corresponding entries of lam_g. Keep a reference to the constraint expression when you need its dual later.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-3)**2)
>>> con = x <= 1
>>> opti.subject_to(con)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> sol.value(opti.dual(con)), sol.value(opti.lam_g)
(4.0, 4.0)
>>> opti.subject_to()
>>> con = x >= 4
>>> opti.subject_to(con)
>>> sol = opti.solve()
>>> sol.value(opti.dual(con)), sol.value(opti.lam_g)
(2.0, -2.0)
>>> try:
...   opti.dual(x >= 4)
... except Exception as e:
...   print(str(e).splitlines()[-1])
Constraint not present in Opti stack.
>> opti = Opti(); x = opti.variable(); opti.minimize((x-3)^2);
>> con = x <= 1; opti.subject_to(con);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> sol.value(opti.dual(con)), sol.value(opti.lam_g)
4
4
>> opti.subject_to(); con = x >= 4; opti.subject_to(con); sol = opti.solve();
>> sol.value(opti.dual(con)), sol.value(opti.lam_g)
2
-2
>> try, opti.dual(x >= 4); catch e, disp(contains(e.message, 'Constraint not present')); end
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 3)^2)
julia> con = x <= 1;
julia> ca.subject_to(opti, con)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.value(sol, ca.dual(opti, con))
4.0
julia> ca.value(sol, ca.lam_g(opti))
4.0
julia> ca.subject_to(opti)
julia> con = x >= 4;
julia> ca.subject_to(opti, con)
julia> sol = ca.solve(opti);
julia> ca.value(sol, ca.dual(opti, con))
2.0
julia> ca.value(sol, ca.lam_g(opti))
-2.0
julia> try
           ca.dual(opti, x >= 4)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Constraint not present in Opti stack.

See also: lam_g

Extra doc | Doc source | Implementation

initial(...)

Get assignment expressions for the initial guesses.

initial(self) -> [MX]

One expression value==var per variable and dual variable, holding the current initial guess. Pass the list to value() to evaluate an expression at the initial guess, or to set_initial() of another Opti instance with the same symbols.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.set_initial(x, 2)
>>> opti.minimize(x**2)
>>> print(opti.initial())
[MX((2==opti..._x_1))]
>>> opti.value(x**2+1, opti.initial())
5.0
>> opti = Opti(); x = opti.variable(); opti.set_initial(x, 2); opti.minimize(x^2);
>> ini = opti.initial(); disp(ini{1})
(2==opti..._x_1)
>> opti.value(x^2+1, opti.initial())
5
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.set_initial(opti, x, 2)
julia> ca.minimize(opti, x^2)
julia> print(ca.initial(opti))
MX[(2==opti..._x_1)]
julia> opti.value(x^2 + 1, ca.initial(opti))
5.0

Extra doc | Doc source | Implementation

is_null(...)
is_null(self) -> bool
minimize(...)

Set the objective.

minimize(self, MX f, float linear_scale)

The objective must be a scalar expression in the variables and parameters of this instance; a non-scalar raises an error. The default objective is 0. Each call replaces the previous objective. Dual variables (opti.dual, opti.lam_g) may not appear in it.

Parameters:
  • f -- Scalar MX expression to minimize

  • linear_scale -- The solver sees f divided by this factor (default 1)

>>> opti = Opti()
>>> x = opti.variable(2)
>>> opti.minimize(sumsqr(x))
>>> opti.minimize(x[0]**2, 2)
>>> print(opti.f, opti.f_linear_scale)
sq(opti..._x_1[0]) 2.0
>>> try:
...   opti.minimize(x)
... except Exception as e:
...   print(str(e).splitlines()[-1])
Objective must be scalar, got 2x1.
>> opti = Opti(); x = opti.variable(2);
>> opti.minimize(sumsqr(x)); opti.minimize(x(1)^2, 2);
>> opti.f, opti.f_linear_scale
sq(opti..._x_1[0])
2
>> try, opti.minimize(x); catch e, disp(contains(e.message, 'Objective must be scalar')); end
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> ca.minimize(opti, ca.sumsqr(x))
julia> opti.minimize(x[1]^2, 2)
julia> print(ca.f(opti), " ", ca.f_linear_scale(opti))
sq(opti..._x_1[0]) 2.0
julia> try
           ca.minimize(opti, x)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Objective must be scalar, got 2x1.

Extra doc | Doc source | Implementation

print_ptr(...)
print_ptr(self)
return_status(...)

Get the return status of the last solve.

return_status(self) -> str

The plugin's "return_status" string (e.g. "Solve_Succeeded" or "Infeasible_Problem_Detected" for Ipopt), or "unknown" when no solve has happened. No stability is guaranteed for the strings.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize(x**2)
>>> opti.return_status()
'unknown'
>>> opti.subject_to(x >= 1)
>>> opti.subject_to(x <= -1)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> try:
...   opti.solve()
... except Exception as e:
...   print(opti.return_status())
Infeasible_Problem_Detected
>> opti = Opti(); x = opti.variable(); opti.minimize(x^2);
>> opti.return_status()
unknown
>> opti.subject_to(x >= 1); opti.subject_to(x <= -1);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> try, opti.solve(); catch e, disp(opti.return_status()); end
Infeasible_Problem_Detected
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, x^2)
julia> ca.return_status(opti)
"unknown"
julia> ca.subject_to(opti, x >= 1)
julia> ca.subject_to(opti, x <= -1)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> try
           ca.solve(opti)
       catch e
           println(ca.return_status(opti))
       end
Infeasible_Problem_Detected

Extra doc | Doc source | Implementation

scale_helper(...)

Scale a helper function constructed via opti.x, opti.g, ...

scale_helper(self, Function h) -> Function

Wraps a user-written derivative function so that it operates in the scaled space the solver sees (set_linear_scale(), minimize()/subject_to() scales). h must be named "nlp_jac_g" (inputs x, p; outputs g, jac_g_x) or "nlp_hess_l" (inputs x, p, lam_f, lam_g; output the Lagrangian Hessian); other names raise an error. The result can be handed to a solver that accepts custom derivative functions.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.set_linear_scale(x, 2, 1)
>>> opti.minimize((x-p)**2)
>>> opti.subject_to(x >= 0)
>>> h = Function("nlp_jac_g", [opti.x, opti.p], [opti.g, jacobian(opti.g, opti.x)],
...              ["x", "p"], ["g", "jac_g_x"])
>>> hs = opti.scale_helper(h)
>>> hs(x=3, p=0)
{'g': DM(7), 'jac_g_x': DM(2)}
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.set_linear_scale(x, 2, 1); opti.minimize((x-p)^2); opti.subject_to(x >= 0);
>> J = jacobian(opti.g, opti.x);
>> h = Function('nlp_jac_g', {opti.x, opti.p}, {opti.g, J}, {'x', 'p'}, {'g', 'jac_g_x'});
>> hs = opti.scale_helper(h); r = hs('x', 3, 'p', 0); disp(r.g), disp(r.jac_g_x)
7
2
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.set_linear_scale(opti, x, 2, 1)
julia> ca.minimize(opti, (x - p)^2)
julia> ca.subject_to(opti, x >= 0)
julia> g, X = ca.g(opti), ca.x(opti);
julia> h = ca.Function("nlp_jac_g", [X, ca.p(opti)], [g, ca.jacobian(g, X)],
                       ["x", "p"], ["g", "jac_g_x"]);
julia> hs = ca.scale_helper(opti, h);
julia> hs(x=3, p=0)
Dict{String, DM} with 2 entries:
  "g" => 7
  "jac_g_x" => 2

Extra doc | Doc source | Implementation

set_domain(...)

Set the domain of a decision variable.

set_domain(self, MX x, str domain)

Marks all scalars of x as integer or real (default). The information is passed to the solver as the nlpsol/qpsol option "discrete"; a solver without integer support raises an error at solve().

Parameters:
  • x -- A decision variable (pure symbol, not an expression)

  • domain -- "real" or "integer"; anything else raises an error

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.set_domain(x, "integer")
>>> opti.minimize((x-1.4)**2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> try:
...   opti.solve()
... except Exception as e:
...   print(str(e).splitlines()[-1])
Discrete variables require a solver with integer support
>>> try:
...   opti.set_domain(x, "binary")
... except Exception as e:
...   print("Unknown domain 'binary'. Known values are 'real', 'integer'." in str(e))
True
>> opti = Opti(); x = opti.variable(); opti.set_domain(x, 'integer');
>> opti.minimize((x-1.4)^2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> try, opti.solve(); catch e, disp(contains(e.message, 'solver with integer support')); end
1
>> try, opti.set_domain(x, 'binary'); catch e, disp(contains(e.message, 'Unknown')); end
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.set_domain(opti, x, "integer")
julia> ca.minimize(opti, (x - 1.4)^2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> try
           ca.solve(opti)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Discrete variables require a solver with integer support
julia> try
           ca.set_domain(opti, x, "binary")
       catch e
           msg = "Unknown domain 'binary'. Known values are 'real', 'integer'."
           println(occursin(msg, sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

set_initial(...)
set_initial(self, [MX] assignments)
set_initial(self, MX x, DM v)

Set the initial guess of decision variables or dual variables.

The guess is used as x0 (and lam_g0 for opti.lam_g or opti.dual(con)) at the next solve(); the default is 0. x may be a variable, a slice of one, or a linear mapping of variables such as 10*x[0]; a nonlinear expression raises an error. Parameters are refused with a hint to use set_value(). The list form takes assignment expressions var==value, as returned by value_variables() or initial(), which makes warm starting a one-liner. Calling this method invalidates value() until the next solve().

Parameters:
  • x -- Variable (or linear mapping of variables) to initialize

  • v -- Numerical value; scalars are broadcast to the shape of x

>>> opti = Opti()
>>> x = opti.variable(2)
>>> p = opti.parameter()
>>> opti.set_initial(x, 1)
>>> opti.set_initial(10*x[0], 2)
>>> print(opti.initial())
[MX(([0.2, 1]==opti..._x_1))]
>>> try:
...   opti.set_initial(p, 1)
... except Exception as e:
...   print(str(e).splitlines()[-1])
You cannot set an initial value for a parameter. Did you mean 'set_value'?
>>> try:
...   opti.set_initial(x[0]*x[1], 1)
... except Exception as e:
...   print("Use symbols or simple mappings of symbols" in str(e))
True
>> opti = Opti(); x = opti.variable(2); p = opti.parameter();
>> opti.set_initial(x, 1); opti.set_initial(10*x(1), 2);
>> ini = opti.initial(); disp(ini{1})
([0.2, 1]==opti..._x_1)
>> try, opti.set_initial(p, 1); catch e, disp(contains(e.message, 'mean ''set_value''')); end
1
>> try, opti.set_initial(x(1)*x(2), 1); catch e, disp(contains(e.message, 'simple')); end
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> p = ca.parameter(opti);
julia> ca.set_initial(opti, x, 1)
julia> ca.set_initial(opti, 10*x[1], 2)
julia> print(ca.initial(opti))
MX[([0.2, 1]==opti..._x_1)]
julia> try
           ca.set_initial(opti, p, 1)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
You cannot set an initial value for a parameter. Did you mean 'set_value'?
julia> try
           ca.set_initial(opti, x[1]*x[2], 1)
       catch e
           msg = "Use symbols or simple mappings of symbols"
           println(occursin(msg, sprint(showerror, e)))
       end
true

Warm start from a previous solution:

>>> opti = Opti()
>>> x = opti.variable()
>>> y = opti.variable()
>>> opti.minimize((y-x**2)**2)
>>> opti.subject_to(x**2+y**2==1)
>>> opti.subject_to(x+y>=1)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> opti.set_initial(sol.value_variables())
>>> opti.set_initial(opti.lam_g, sol.value(opti.lam_g))
>>> opti.solve().stats()["iter_count"] < sol.stats()["iter_count"]
True
>> opti = Opti(); x = opti.variable(); y = opti.variable();
>> opti.minimize((y-x^2)^2); opti.subject_to(x^2+y^2==1); opti.subject_to(x+y>=1);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> opti.set_initial(sol.value_variables());
>> opti.set_initial(opti.lam_g, sol.value(opti.lam_g));
>> sol2 = opti.solve(); s1 = sol.stats(); s2 = sol2.stats();
>> s2.iter_count < s1.iter_count
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> y = ca.variable(opti);
julia> ca.minimize(opti, (y - x^2)^2)
julia> ca.subject_to(opti, x^2 + y^2 == 1)
julia> ca.subject_to(opti, x + y >= 1)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> opti.set_initial(ca.value_variables(sol))
julia> ca.set_initial(opti, ca.lam_g(opti), ca.value(sol, ca.lam_g(opti)))
julia> ca.stats(ca.solve(opti))["iter_count"] < ca.stats(sol)["iter_count"]
true

See also: set_value, initial, value_variables

Extra doc | Doc source | Implementation

set_linear_scale(...)

Set the linear scaling of a decision variable.

set_linear_scale(self, MX x, DM scale, DM offset)

The solver works with (x-offset)/scale instead of x; all user-facing values (value(), initial guesses, duals) stay in the original units. Useful when variables differ by orders of magnitude.

Parameters:
  • x -- Decision variable or linear mapping of variables

  • scale -- Scalar or matrix of the shape of x (default 1)

  • offset -- Scalar or matrix of the shape of x (default 0)

>>> opti = Opti()
>>> T = opti.variable()
>>> opti.set_linear_scale(T, 20, 273.15)
>>> opti.minimize((T-300)**2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> sol.value(T), opti.x_linear_scale, opti.x_linear_scale_offset
(300.0, DM(20), DM(273.15))
>>> opti.debug.arg()["x0"]
DM(-13.6575)
>> opti = Opti(); T = opti.variable();
>> opti.set_linear_scale(T, 20, 273.15); opti.minimize((T-300)^2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> sol.value(T), opti.x_linear_scale, opti.x_linear_scale_offset
300
20
273.15
>> a = opti.debug.arg(); disp(a.x0)
-13.6575
julia> opti = ca.Opti();
julia> T = ca.variable(opti);
julia> ca.set_linear_scale(opti, T, 20, 273.15)
julia> ca.minimize(opti, (T - 300)^2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.value(sol, T)
300.0
julia> ca.x_linear_scale(opti), ca.x_linear_scale_offset(opti)
(20, 273.15)

See also: x_linear_scale, x_linear_scale_offset, scale_helper

Extra doc | Doc source | Implementation

set_value(...)
set_value(self, [MX] assignments)
set_value(self, MX x, DM v)

Set the value of a parameter.

Every parameter that appears in the problem must have a value before solve(); the value stays until changed, so re-solving with new data only needs set_value() and solve(). x may be a parameter, a slice, or a linear mapping of parameters. Decision variables are refused with a hint to use set_initial(). The list form accepts assignment expressions par==value, as returned by value_parameters(). Calling this method invalidates value() of variables until the next solve().

Parameters:
  • x -- Parameter (or linear mapping of parameters)

  • v -- Numerical value; scalars are broadcast

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter(2)
>>> opti.set_value(p, [1, 2])
>>> opti.set_value(p[1], 5)
>>> opti.value(p)
array([1., 5.])
>>> try:
...   opti.set_value(x, 1)
... except Exception as e:
...   print(str(e).splitlines()[-1])
You cannot set a value for a variable. Did you mean 'set_initial'?
>>> opti.set_value([p==7])
>>> opti.value(p)
array([7., 7.])
>> opti = Opti(); x = opti.variable(); p = opti.parameter(2);
>> opti.set_value(p, [1; 2]); opti.set_value(p(2), 5); disp(opti.value(p)')
1 5
>> try, opti.set_value(x, 1); catch e, disp(contains(e.message, 'mean ''set_initial''')); end
1
>> opti.set_value({p==7}); disp(opti.value(p)')
7 7
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti, 2);
julia> ca.set_value(opti, p, [1, 2])
julia> ca.set_value(opti, p[2], 5)
julia> ca.value(opti, p)
2-element Vector{Float64}:
 1.0
 5.0
julia> try
           ca.set_value(opti, x, 1)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
You cannot set a value for a variable. Did you mean 'set_initial'?
julia> ca.set_value(opti, [p == 7])
julia> ca.value(opti, p)
2-element Vector{Float64}:
 7.0
 7.0

See also: set_initial, value_parameters

Extra doc | Doc source | Implementation

solve(...)

Solve the problem.

solve(self) -> OptiSol

Builds (or reuses) the solver, evaluates the bounds for the current parameter values, runs the solver from the current initial guess and returns an OptiSol snapshot. Raises an error when the solver does not report success (including iteration or time limits, see solve_limited()); the latest iterate then remains available through opti.debug.value() and opti.value(). Calling solve() again without changing anything repeats the same solve from the same initial guess.

Returns:

OptiSol copy of the problem and its solution

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-1)**6)
>>> opti.solver("ipopt", {"print_time": False},
...             {"print_level": 0, "max_iter": 2, "sb": "yes"})
>>> try:
...   opti.solve()
... except Exception as e:
...   print("Solver failed" in str(e), "'Maximum_Iterations_Exceeded'" in str(e))
True True
>>> opti.debug.value(x), opti.return_status()
(0.36, 'Maximum_Iterations_Exceeded')
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> sol.value(x), sol.stats()["success"]
(1.0, True)
>> opti = Opti(); x = opti.variable(); opti.minimize((x-1)^6);
>> ipopt = struct('print_level', 0, 'max_iter', 2, 'sb', 'yes');
>> opti.solver('ipopt', struct('print_time', false), ipopt);
>> try, opti.solve(); catch e, disp(contains(e.message, 'Maximum_Iterations_Exceeded')); end
1
>> opti.debug.value(x), opti.return_status()
0.36
Maximum_Iterations_Exceeded
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve(); s = sol.stats(); disp(sol.value(x)), disp(s.success)
1.0
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 1)^6)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "max_iter" => 2, "sb" => "yes"))
julia> try
           ca.solve(opti)
       catch e
           msg = sprint(showerror, e)
           println(occursin("Solver failed", msg), " ",
                   occursin("'Maximum_Iterations_Exceeded'", msg))
       end
true true
julia> ca.value(ca.debug(opti), x), ca.return_status(opti)
(0.36, "Maximum_Iterations_Exceeded")
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.value(sol, x), ca.stats(sol)["success"]
(1.0, true)

See also: solve_limited, OptiSol, stats, return_status

Extra doc | Doc source | Implementation

solve_limited(...)

Solve the problem, accepting a limit as outcome.

solve_limited(self) -> OptiSol

Same as solve(), but does not raise when the solver stopped because of an iteration or time limit (unified_return_status "SOLVER_RET_LIMITED"); other failures such as infeasibility still raise.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-1)**6)
>>> opti.solver("ipopt", {"print_time": False},
...             {"print_level": 0, "max_iter": 2, "sb": "yes"})
>>> sol = opti.solve_limited()
>>> sol.stats()["unified_return_status"], sol.value(x)
('SOLVER_RET_LIMITED', 0.36)
>> opti = Opti(); x = opti.variable(); opti.minimize((x-1)^6);
>> ipopt = struct('print_level', 0, 'max_iter', 2, 'sb', 'yes');
>> opti.solver('ipopt', struct('print_time', false), ipopt);
>> sol = opti.solve_limited(); s = sol.stats();
>> s.unified_return_status, sol.value(x)
SOLVER_RET_LIMITED
0.36
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 1)^6)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "max_iter" => 2, "sb" => "yes"))
julia> sol = ca.solve_limited(opti);
julia> ca.stats(sol)["unified_return_status"], ca.value(sol, x)
("SOLVER_RET_LIMITED", 0.36)

Extra doc | Doc source | Implementation

solver(...)

Select the numerical solver and its options.

solver(self, str solver, dict plugin_options, dict solver_options)

Must be called before solve(). The solver is (re)constructed lazily at the next solve() when this method or the problem structure changed.

Parameters:
  • solver -- Name of an nlpsol plugin ("ipopt", "sqpmethod", "bonmin",...) or, for a "conic" Opti, of a qpsol plugin ("qrqp", "qpoases", "osqp",...)

  • plugin_options -- Dict passed as-is to nlpsol/qpsol: CasADi-level options such as "print_time", "expand", "detect_simple_bounds", "error_on_fail", "iteration_callback", and plugin options that are registered as CasADi options (e.g. "qpsol" and "print_iteration" of sqpmethod, "print_iter" of qrqp)

  • solver_options -- Dict of the back-end's native options; it is nested under the key solver, so {"max_iter": 50} here equals {"ipopt": {"max_iter": 50}} in plugin_options. Opti also sets the nlpsol options "equality" and "discrete" unless given explicitly.

No stability is guaranteed for option names; they belong to the plugins.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-2)**2)
>>> try:
...   opti.solve()
... except Exception as e:
...   print("You must call 'solver' on the Opti stack" in str(e))
True
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> opti.solve().value(x)
2.0
>>> opti.solver("sqpmethod", {"print_time": False, "print_header": False,
...   "print_iteration": False, "print_status": False, "qpsol": "qrqp",
...   "qpsol_options": {"print_iter": False, "print_header": False, "print_info": False}})
>>> opti.solve().value(x)
2.0
>> opti = Opti(); x = opti.variable(); opti.minimize((x-2)^2);
>> try, opti.solve(); catch e, disp(contains(e.message, 'You must call ''solver''')); end
1
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve(); disp(sol.value(x))
2
>> qp = struct('print_iter', false, 'print_header', false, 'print_info', false);
>> opts = struct('print_time', false, 'print_header', false, 'print_iteration', false);
>> opts.print_status = false; opts.qpsol = 'qrqp'; opts.qpsol_options = qp;
>> opti.solver('sqpmethod', opts); sol = opti.solve(); disp(sol.value(x))
2
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 2)^2)
julia> try
           ca.solve(opti)
       catch e
           println(occursin("You must call 'solver' on the Opti stack", sprint(showerror, e)))
       end
true
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> ca.value(ca.solve(opti), x)
2.0
julia> qp_opts = Dict("print_iter" => false, "print_header" => false, "print_info" => false);
julia> ca.solver(opti, "sqpmethod", Dict("print_time" => false, "print_header" => false,
           "print_iteration" => false, "print_status" => false, "qpsol" => "qrqp",
           "qpsol_options" => qp_opts))
julia> ca.value(ca.solve(opti), x)
2.0

See also: nlpsol, qpsol, solve

Extra doc | Doc source | Implementation

stats(...)

Get the statistics of the last solve.

stats(self) -> dict

The dict returned by the nlpsol/qpsol plugin, passed as-is: always "success", "return_status" and "unified_return_status", plus plugin- specific entries such as "iter_count". Raises an error before the first solve(). No stability is guaranteed for the plugin-specific entries.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-1)**2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> s = sol.stats()
>>> s["success"], s["return_status"], s["unified_return_status"], s["iter_count"]
(True, 'Solve_Succeeded', 'SOLVER_RET_SUCCESS', 1)
>> opti = Opti(); x = opti.variable(); opti.minimize((x-1)^2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve(); s = sol.stats();
>> s.success, s.return_status, s.unified_return_status, s.iter_count
1
Solve_Succeeded
SOLVER_RET_SUCCESS
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 1)^2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> s = ca.stats(sol);
julia> s["success"], s["return_status"], s["unified_return_status"], s["iter_count"]
(true, "Solve_Succeeded", "SOLVER_RET_SUCCESS", 1)

Extra doc | Doc source | Implementation

str(...)

Get string representation.

str(self, bool more) -> str

Doc source | Implementation

to_function(...)

Same, with inputs and outputs picked by name from a dict of expressions.

to_function(self, str name, [MX] args, [MX] res, dict opts) -> Function
to_function(self, str name, dict:MX dict, [str] name_in, [str] name_out, dict opts) -> Function
to_function(self, str name, [MX] args, [MX] res, [str] name_in, [str] name_out, dict opts) -> Function

Create a CasADi Function from the Opti solver.

Packs bounds evaluation, the solver call and the evaluation of res into one Function, which is much cheaper to call repeatedly than set_value/solve/value. Inputs corresponding to parameters supply their values; inputs corresponding to variables or dual variables supply the initial guess; anything not listed keeps the value stored in the Opti at the time of the call. Outputs are evaluated at the solution.

A solver failure does not raise by default: the last iterate is returned and the Function's stats() report success False. Pass "error_on_fail": True in the plugin_options of solver() to raise instead. Function options in opts are applied to the result; the entry "helper_options" is applied to the internal evaluation function.

Parameters:
  • name -- Name of the resulting Function

  • args -- List of parameters, decision variables and dual variables (or vertcat of them); each must be purely symbolic and independent, else an error is raised

  • res -- List of expressions evaluated at the solution

  • name_in -- Optional input names (same length as args)

  • name_out -- Optional output names (same length as res)

  • opts -- Function options

>>> opti = Opti()
>>> x = opti.variable()
>>> y = opti.variable()
>>> p = opti.parameter()
>>> opti.minimize((x-p)**2 + (y-x)**2)
>>> opti.subject_to(x >= 0)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> F = opti.to_function("F", [p, x], [vertcat(x, y), opti.lam_g],
...                      ["p", "x0"], ["xy", "lam"])
>>> F
Function(F:(p,x0)->(xy[2],lam) MXFunction)
>>> r = F(p=2, x0=1)
>>> r["xy"], r["lam"]
(DM([2, 2]), DM(0.0000))
>>> F.stats()["success"]
True
>>> F = opti.to_function("F", {"p": p, "x": x}, ["p"], ["x"])
>>> F(3)
DM(3)
>>> try:
...   opti.to_function("F", [p+1], [x])
... except Exception as e:
...   print(str(e).splitlines()[-1])
Argument 0 is not purely symbolic.
>> opti = Opti(); x = opti.variable(); y = opti.variable(); p = opti.parameter();
>> opti.minimize((x-p)^2 + (y-x)^2); opti.subject_to(x >= 0);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> F = opti.to_function('F', {p, x}, {vertcat(x, y), opti.lam_g}, {'p', 'x0'}, {'xy', 'lam'});
>> F
F:(p,x0)->(xy[2],lam) MXFunction
>> r = F('p', 2, 'x0', 1); disp(r.xy), disp(r.lam)
[2, 2]
0.0000
>> s = F.stats(); disp(s.success)
1
>> F = opti.to_function('F', struct('p', p, 'x', x), {'p'}, {'x'}); disp(F(3))
3
>> try, opti.to_function('F', {p+1}, {x}); catch e, disp(contains(e.message, 'symbolic')); end
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> y = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.minimize(opti, (x - p)^2 + (y - x)^2)
julia> ca.subject_to(opti, x >= 0)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> F = ca.to_function(opti, "F", [p, x], [[x; y], ca.lam_g(opti)],
                          ["p", "x0"], ["xy", "lam"])
Function(F:(p,x0)->(xy[2],lam) MXFunction)
julia> r = F(p=2, x0=1);
julia> r["xy"], r["lam"]
([2, 2], 0.0000)
julia> ca.stats(F)["success"]
true
julia> F = ca.to_function(opti, "F", Dict("p" => p, "x" => x), ["p"], ["x"]);
julia> F(3)
DM(3)
julia> try
           ca.to_function(opti, "F", [p + 1], [x])
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Argument 0 is not purely symbolic.

See also: nlpsol

Doc source | Implementation | Extra doc

type_name(...)

Readable name of the class.

type_name(self) -> str

Doc source | Implementation

update_user_dict(...)
update_user_dict(self, MX m, dict meta)
update_user_dict(self, [MX] m, dict meta)

Add user data to a symbol or constraint.

Merges meta into the dict attached to a variable, parameter, dual variable (or every symbol of an expression) or to a constraint expression passed to subject_to(). Opti itself stores a "stacktrace" entry there in Python and MATLAB, which is what describe()/x_describe() print as "called from".

Parameters:
  • m -- Symbol, expression of symbols, or constraint expression

  • meta -- Dict entries to add (existing keys are overwritten)

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.update_user_dict(x, {"name": "speed", "unit": "m/s"})
>>> d = opti.user_dict(x)
>>> d["name"], d["unit"], "stacktrace" in d
('speed', 'm/s', True)
>>> con = x >= 0
>>> opti.subject_to(con)
>>> opti.update_user_dict(con, {"name": "nonneg"})
>>> opti.user_dict(con)["name"]
'nonneg'
>> opti = Opti(); x = opti.variable();
>> opti.update_user_dict(x, struct('name', 'speed', 'unit', 'm/s'));
>> d = opti.user_dict(x); fprintf('%s %s %d\n', d.name, d.unit, isfield(d, 'stacktrace'))
speed m/s 1
>> con = x >= 0; opti.subject_to(con); opti.update_user_dict(con, struct('name', 'nonneg'));
>> d = opti.user_dict(con); disp(d.name)
nonneg
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.update_user_dict(opti, x, Dict("name" => "speed", "unit" => "m/s"))
julia> d = ca.user_dict(opti, x);
julia> d["name"], d["unit"], haskey(d, "stacktrace")
("speed", "m/s", true)
julia> con = x >= 0;
julia> ca.subject_to(opti, con)
julia> ca.update_user_dict(opti, con, Dict("name" => "nonneg"))
julia> ca.user_dict(opti, con)["name"]
"nonneg"

Extra doc | Doc source | Implementation

user_dict(...)

Get the user data of a symbol or constraint.

user_dict(self, MX m) -> dict
Parameters:

m -- A single symbol or a constraint expression; other expressions raise an error

>>> opti = Opti()
>>> x = opti.variable()
>>> sorted(opti.user_dict(x).keys())
['stacktrace']
>>> try:
...   opti.user_dict(x+1)
... except Exception as e:
...   print(str(e).splitlines()[-1])
Symbol expected, got expression.
>> opti = Opti(); x = opti.variable(); disp(fieldnames(opti.user_dict(x)))
{'stacktrace'}
>> try, opti.user_dict(x+1); catch e, disp(contains(e.message, 'Symbol expected')); end
1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> sort(collect(keys(ca.user_dict(opti, x))))
1-element Vector{String}:
 "stacktrace"
julia> try
           ca.user_dict(opti, x + 1)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Symbol expected, got expression.

Extra doc | Doc source | Implementation

value(...)
value(self, DM x, [MX] values) -> double
value(self, SX x, [MX] values) -> double
value(self, MX x, [MX] values) -> double

Evaluate an expression at the current values.

Variables take the latest solver result, parameters their set_value(), dual variables the latest multipliers. Before the first solve(), or after set_initial()/set_value() changed the state, an expression involving variables raises an error unless every variable in it is overruled through values; parameter-only expressions always work. After a failed solve() the latest iterate is returned (the same holds for opti.debug.value()). A variable that does not appear in the problem raises an error.

Parameters:
  • x -- Expression in the symbols of this instance (an MX). A DM is returned as is. SX expressions are not supported: a NaN matrix of the same sparsity is returned.

  • values -- Optional list of assignments var==value (e.g. opti.initial()) that overrule the stored values for this evaluation only

Returns:

The numerical value

A scalar becomes a float, a dense matrix a numpy array and a sparse matrix a scipy sparse matrix.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.minimize((x-p)**2)
>>> opti.set_value(p, 3)
>>> opti.value(2*p)
6.0
>>> try:
...   opti.value(x)
... except Exception as e:
...   print(str(e).splitlines()[-1])
This action is forbidden since you have not solved the Opti stack yet (with calling 'solve').
>>> opti.value(x+p, [x==1]), opti.value(x**2, opti.initial())
(4.0, 0.0)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> opti.value(x), sol.value(x), sol.value(x+p, [p==10])
(3.0, 3.0, 13.0)
>>> type(sol.value(vertcat(x, p))).__name__, sol.value(DM([1, 2]))
('ndarray', array([1., 2.]))

The value is a double matrix, sparse when the expression is sparse.

>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.minimize((x-p)^2); opti.set_value(p, 3);
>> opti.value(2*p)
6
>> try, opti.value(x); catch e, disp(contains(e.message, 'not solved the Opti stack')); end
1
>> opti.value(x+p, {x==1}), opti.value(x^2, opti.initial())
4
0
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> opti.value(x), sol.value(x), sol.value(x+p, {p==10})
3
3
13
>> v = sol.value(vertcat(x, p)); disp(class(v)), disp(size(v)), disp(sol.value(DM([1; 2]))')
double
2 1
1 2

A scalar becomes a Float64, any other value a dense Matrix{Float64}.

julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.minimize(opti, (x - p)^2)
julia> ca.set_value(opti, p, 3)
julia> ca.value(opti, 2*p)
6.0
julia> try
           ca.value(opti, x)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
This action is forbidden since you have not solved the Opti stack yet (with calling 'solve').
julia> opti.value(x + p, [x == 1]), opti.value(x^2, ca.initial(opti))
(4.0, 0.0)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.value(opti, x), ca.value(sol, x)
(3.0, 3.0)
julia> sol.value(x + p, [p == 10])
13.0
julia> ca.value(sol, [x; p]), ca.value(sol, ca.DM([1, 2]))
([3.0, 3.0], [1.0, 2.0])

See also: initial, value_variables, OptiSol.value

Extra doc | Doc source | Implementation

value_parameters(...)
value_parameters(self) -> [MX]
value_variables(...)

Get assignment expressions for the latest values.

value_variables(self) -> [MX]

value_variables() gives value==var for every variable with its latest solver result; value_parameters() gives value==par for every parameter with its set value. Both feed set_initial()/set_value() to transfer a solution to the next solve or to another Opti.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.minimize((x-p)**2)
>>> opti.set_value(p, 2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> print(opti.value_variables(), opti.value_parameters())
[MX((2==opti..._x_1))] [MX((2==opti..._p_1))]
>>> opti.set_initial(sol.value_variables())
>>> opti.value(x, opti.initial())
2.0
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.minimize((x-p)^2); opti.set_value(p, 2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> vv = opti.value_variables(); vp = opti.value_parameters(); disp(vv{1}), disp(vp{1})
(2==opti..._x_1)
(2==opti..._p_1)
>> opti.set_initial(sol.value_variables()); disp(opti.value(x, opti.initial()))
2
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.minimize(opti, (x - p)^2)
julia> ca.set_value(opti, p, 2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> print(ca.value_variables(opti), " ", ca.value_parameters(opti))
MX[(2==opti..._x_1)] MX[(2==opti..._p_1)]
julia> opti.set_initial(ca.value_variables(sol))
julia> opti.value(x, ca.initial(opti))
2.0

Extra doc | Doc source | Implementation

class OptiSol(...)

Snapshot of an Opti problem and its solution.

Returned by Opti::solve and Opti::solve_limited. It is a deep copy made at that moment: later set_value/set_initial/subject_to calls on the Opti do not change what value() returns, so several OptiSol objects can be kept and compared. The API is guaranteed to be stable.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.minimize((x-p)**2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> opti.set_value(p, 1)
>>> sol1 = opti.solve()
>>> opti.set_value(p, 2)
>>> sol2 = opti.solve()
>>> sol1.value(x), sol2.value(x)
(1.0, 2.0)
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.minimize((x-p)^2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> opti.set_value(p, 1); sol1 = opti.solve();
>> opti.set_value(p, 2); sol2 = opti.solve();
>> sol1.value(x), sol2.value(x)
1
2
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.minimize(opti, (x - p)^2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> ca.set_value(opti, p, 1)
julia> sol1 = ca.solve(opti);
julia> ca.set_value(opti, p, 2)
julia> sol2 = ca.solve(opti);
julia> ca.value(sol1, x), ca.value(sol2, x)
(1.0, 2.0)

Authors: Joris Gillis, Erik Lambrechts

Extra doc

disp(...)
disp(self, bool more)
stats(...)

Get the solver statistics of this solve.

stats(self) -> dict

The dict returned by the nlpsol/qpsol plugin, passed as-is ("success", "return_status", "iter_count", ...). No stability is guaranteed for the entries.

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize((x-1)**2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> sol.stats()["success"], sol.stats()["return_status"]
(True, 'Solve_Succeeded')
>> opti = Opti(); x = opti.variable(); opti.minimize((x-1)^2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve(); s = sol.stats(); disp(s.success), disp(s.return_status)
1
Solve_Succeeded
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, (x - 1)^2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.stats(sol)["success"], ca.stats(sol)["return_status"]
(true, "Solve_Succeeded")

Extra doc | Doc source | Implementation

str(...)
str(self, bool more) -> str
type_name(...)
type_name(self) -> str
value(...)
value(self, DM x, [MX] values) -> double
value(self, SX x, [MX] values) -> double
value(self, MX x, [MX] values) -> double

Evaluate an expression at the solution.

Same as Opti::value on the snapshot: variables take their optimal values, parameters the values used for the solve, dual variables the multipliers. values overrules individual symbols for this evaluation only, e.g. opti.initial() to evaluate at the initial guess.

Parameters:
  • x -- Expression (MX) in the symbols of the Opti; a DM is returned as is

  • values -- Optional list of assignments var==value

A scalar becomes a float, a dense matrix a numpy array and a sparse matrix a scipy sparse matrix.

>>> opti = Opti()
>>> x = opti.variable()
>>> y = opti.variable()
>>> opti.minimize((y-x**2)**2)
>>> opti.subject_to(x**2+y**2==1)
>>> opti.subject_to(x+y>=1)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> sol.value(x), sol.value(vertcat(x, y)).shape
(0.7862, (2,))
>>> sol.value(opti.f, [y==2])
1.9098
>>> sol.value(x**2+y, opti.initial())
0.0
>>> sol.value(jacobian(opti.g, opti.x)).shape
(2, 2)

The value is a double matrix, sparse when the expression is sparse.

>> opti = Opti(); x = opti.variable(); y = opti.variable();
>> opti.minimize((y-x^2)^2); opti.subject_to(x^2+y^2==1); opti.subject_to(x+y>=1);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> sol.value(x), size(sol.value(vertcat(x, y)))
0.7862
2 1
>> sol.value(opti.f, {y==2})
1.9098
>> sol.value(x^2+y, opti.initial())
0
>> size(sol.value(jacobian(opti.g, opti.x)))
2 2

A scalar becomes a Float64, any other value a dense Matrix{Float64}.

julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> y = ca.variable(opti);
julia> ca.minimize(opti, (y - x^2)^2)
julia> ca.subject_to(opti, x^2 + y^2 == 1)
julia> ca.subject_to(opti, x + y >= 1)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> ca.value(sol, x), size(ca.value(sol, [x; y]))
(0.7862, (2,))
julia> sol.value(ca.f(opti), [y == 2])
1.9098
julia> sol.value(x^2 + y, ca.initial(opti))
0.0
julia> size(ca.value(sol, ca.jacobian(ca.g(opti), ca.x(opti))))
(2, 2)

Extra doc | Doc source | Implementation

value_parameters(...)
value_parameters(self) -> [MX]
value_variables(...)

Get assignment expressions for the optimal solution.

value_variables(self) -> [MX]

value_variables() gives value==var for every variable, value_parameters() value==par for every parameter. Pass them to Opti::set_initial / Opti::set_value to warm start the next solve.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.minimize((x-p)**2)
>>> opti.set_value(p, 2)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> print(sol.value_variables(), sol.value_parameters())
[MX((2==opti..._x_1))] [MX((2==opti..._p_1))]
>>> opti.set_initial(sol.value_variables())
>>> opti.solve().stats()["iter_count"]
0
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.minimize((x-p)^2); opti.set_value(p, 2);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve();
>> vv = sol.value_variables(); vp = sol.value_parameters(); disp(vv{1}), disp(vp{1})
(2==opti..._x_1)
(2==opti..._p_1)
>> opti.set_initial(sol.value_variables()); sol2 = opti.solve();
>> s = sol2.stats(); disp(s.iter_count)
0
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.minimize(opti, (x - p)^2)
julia> ca.set_value(opti, p, 2)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> sol = ca.solve(opti);
julia> print(ca.value_variables(sol), " ", ca.value_parameters(sol))
MX[(2==opti..._x_1)] MX[(2==opti..._p_1)]
julia> opti.set_initial(ca.value_variables(sol))
julia> ca.stats(ca.solve(opti))["iter_count"]
0

Extra doc | Doc source | Implementation

class OptiAdvanced(...)

Opti with debugging and low-level access.

Obtained through Opti::debug or Opti::advanced; it is a deep copy of the Opti instance with the methods below added. No API stability is guaranteed for these methods. Most of them bake the problem (flatten variables and constraints) on the fly, so they also work on a copy that has not been solved.

Extra doc

active_symvar(...)

Get the symbols of a given type that appear in the problem.

active_symvar(self, casadi::VariableType type) -> [MX]

Empty before the problem has been baked (solve, or any method that bakes).

>>> opti = Opti()
>>> x = opti.variable()
>>> y = opti.variable()
>>> opti.minimize(x**2)
>>> d = opti.debug
>>> d.active_symvar(OPTI_VAR)
[]
>>> d.bake()
>>> print(d.active_symvar(OPTI_VAR), d.active_values(OPTI_VAR))
[MX(opti..._x_1)] [DM(0)]
>> opti = Opti(); x = opti.variable(); y = opti.variable(); opti.minimize(x^2);
>> d = opti.debug; disp(isempty(d.active_symvar(OPTI_VAR)))
1
>> d.bake(); a = d.active_symvar(OPTI_VAR); v = d.active_values(OPTI_VAR);
>> a{1}, v{1}
opti..._x_1
0
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> y = ca.variable(opti);
julia> ca.minimize(opti, x^2)
julia> d = ca.debug(opti);
julia> ca.active_symvar(d, ca.OPTI_VAR)
MX[]
julia> ca.bake(d)
julia> print(ca.active_symvar(d, ca.OPTI_VAR), " ", ca.active_values(d, ca.OPTI_VAR))
MX[opti..._x_1] DM[0]

Extra doc | Doc source | Implementation

active_values(...)

Initial guesses (or parameter values) of the symbols returned by

active_values(self, casadi::VariableType type) -> [DM]

active_symvar.

Doc source | Implementation

arg(...)

Solver arguments prepared by solve_prepare (x0, p, lam_g0, lbg, ubg)

arg(self) -> dict:DM

Doc source | Implementation

assert_active_symbol(...)

Raise an error unless m is a symbol of this instance that appears in the

assert_active_symbol(self, MX m)

problem.

Doc source | Implementation

assert_baked(...)

Raise an error when the problem is dirty.

assert_baked(self)

Doc source | Implementation

assert_empty(...)

Raise an error if an objective or constraints are present.

assert_empty(self)

Doc source | Implementation

assert_solved(...)

Raise an error unless solved()

assert_solved(self)

Doc source | Implementation

bake(...)

Fix the structure of the optimization problem.

bake(self)

Flattens the active variables, parameters and constraints into the x, p, g, lbg and ubg vectors and builds the bounds function. Called automatically by solve() and the accessors; raises an error when neither an objective nor a constraint is set.

Extra doc | Doc source | Implementation

baked_copy(...)

Copy of the instance with the problem baked (see bake)

baked_copy(self) -> OptiAdvanced

Doc source | Implementation

canon_expr(...)

Classify a constraint expression (for internal use only)

canon_expr(self, MX expr) -> MetaCon

Returns the MetaCon that subject_to() would store: the constraint type, canonical expression and bounds.

>>> opti = Opti()
>>> x = opti.variable()
>>> c = opti.debug.canon_expr(0 <= (x <= 1))
>>> print(c.type == OPTI_DOUBLE_INEQUALITY, c.lb, c.ub, c.canon)
True 0 1 opti..._x_1
>>> opti.debug.canon_expr(x + 1).type == OPTI_UNKNOWN
True
>> opti = Opti(); x = opti.variable();
>> c = opti.debug.canon_expr(0 <= x <= 1);
>> c.type == OPTI_DOUBLE_INEQUALITY, c.lb, c.ub, c.canon
1
0
1
opti..._x_1
>> c = opti.debug.canon_expr(x + 1); disp(c.type == OPTI_UNKNOWN)
1
julia> opti = ca.Opti();
julia> x = opti.variable();
julia> c = ca.canon_expr(opti.debug, 0 <= (x <= 1));
julia> println(c.type == ca.OPTI_DOUBLE_INEQUALITY, " ", c.lb, " ", c.ub, " ", c.canon)
true 0 1 opti..._x_1
julia> ca.canon_expr(opti.debug, x + 1).type == ca.OPTI_UNKNOWN
true

Extra doc | Doc source | Implementation

constraints(...)

Get the constraint expressions as passed to subject_to.

constraints(self) -> [MX]
>>> opti = Opti()
>>> x = opti.variable()
>>> opti.subject_to(x >= 0)
>>> opti.subject_to(1 <= (x**2 <= 4))
>>> print(opti.debug.constraints())
[MX((0<=opti..._x_1)), MX((1<=(sq(opti..._x_1)<=4)))]
>> opti = Opti(); x = opti.variable();
>> opti.subject_to(x >= 0); opti.subject_to(1 <= x^2 <= 4);
>> c = opti.debug.constraints(); disp(c{1}), disp(c{2})
(0<=opti..._x_1)
((1<=sq(opti..._x_1))<=4)
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.subject_to(opti, x >= 0)
julia> ca.subject_to(opti, 1 <= (x^2 <= 4))
julia> print(ca.constraints(ca.debug(opti)))
MX[(0<=opti..._x_1), (1<=(sq(opti..._x_1)<=4))]

Extra doc | Doc source | Implementation

describe(...)

Describe an expression in terms of this instance.

describe(self, MX x, int indent, dict opts) -> str

For a symbol: its kind, name, shape and origin, or a note that it belongs to another Opti instance or was declared outside of Opti. For a constraint: its shape and origin. For another expression: the symbols it depends on.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.debug.describe(MX.sym("w"))
"MX symbol 'w' of shape 1x1, declared outside of Opti."
>>> print(opti.debug.describe(x*p))
General expression, dependent on 2 symbols:
  Opti decision variable 'opti..._x_1' of shape 1x1, called from ...
  Opti parameter 'opti..._p_1' of shape 1x1, called from ...
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.debug.describe(MX.sym('w'))
MX symbol 'w' of shape 1x1, declared outside of Opti.
>> opti.debug.describe(x*p)
General expression, dependent on 2 symbols:
Opti decision variable 'opti..._x_1' of shape 1x1, called from ...
Opti parameter 'opti..._p_1' of shape 1x1, called from ...
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> ca.describe(ca.debug(opti), ca.MX.sym("w"))
"MX symbol 'w' of shape 1x1, declared outside of Opti."
julia> print(ca.describe(ca.debug(opti), x*p))
General expression, dependent on 2 symbols:
  Opti decision variable 'opti..._x_1' of shape 1x1, called from ...
  Opti parameter 'opti..._p_1' of shape 1x1, called from ...

Extra doc | Doc source | Implementation

g_describe(...)

Describe row i of the constraint vector g.

g_describe(self, int i, dict opts) -> str
>>> opti = Opti()
>>> x = opti.variable(3)
>>> opti.subject_to(x >= 0)
>>> print(opti.debug.g_describe(1))
Opti constraint of shape 3x1, called from ...
At nonzero 1, part 0.
>> opti = Opti(); x = opti.variable(3); opti.subject_to(x >= 0);
>> opti.debug.g_describe(2)
Opti constraint of shape 3x1, called from ...
At nonzero 2, part 0.
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 3);
julia> ca.subject_to(opti, x >= 0)
julia> print(ca.g_describe(ca.debug(opti), 1))
Opti constraint of shape 3x1, called from ...
At nonzero 1, part 0.

Extra doc | Doc source | Implementation

g_index_reduce_g(...)

Row of the reduced g for row i of g when "detect_simple_bounds" is active

g_index_reduce_g(self, int i) -> int

(-1 if moved)

Doc source | Implementation

g_index_reduce_x(...)

Index into x when row i of g was reduced to a simple bound (-1 otherwise)

g_index_reduce_x(self, int i) -> int

Doc source | Implementation

g_index_unreduce_g(...)

Row of g for row i of the reduced g.

g_index_unreduce_g(self, int i) -> int

Doc source | Implementation

g_lookup(...)

Get the constraint expression that owns row i of g.

g_lookup(self, int i) -> MX
>>> opti = Opti()
>>> x = opti.variable(2)
>>> opti.subject_to(x >= 0)
>>> opti.subject_to(x[0] + x[1] == 1)
>>> print(opti.debug.g_lookup(2))
(1==(opti..._x_1[0]+opti..._x_1[1]))
>> opti = Opti(); x = opti.variable(2);
>> opti.subject_to(x >= 0); opti.subject_to(x(1) + x(2) == 1);
>> opti.debug.g_lookup(3)
(1==(opti..._x_1[0]+opti..._x_1[1]))
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> ca.subject_to(opti, x >= 0)
julia> ca.subject_to(opti, x[1] + x[2] == 1)
julia> ca.g_lookup(ca.debug(opti), 2)
MX((1==(opti52_x_1[0]+opti52_x_1[1])))

Extra doc | Doc source | Implementation

get_meta(...)

Get meta-data of symbol (for internal use only)

get_meta(self, MX m) -> MetaVar

Doc source | Implementation

get_meta_con(...)

Get meta-data of symbol (for internal use only)

get_meta_con(self, MX m) -> MetaCon

Doc source | Implementation

instance_number(...)

Sequence number of this Opti instance in the process; prefixes the symbol

instance_number(self) -> int

names.

Doc source | Implementation

is_parametric(...)

Check whether an expression depends on parameters only.

is_parametric(self, MX expr) -> bool

True when no decision variable of this instance appears in expr (constants count as parametric).

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.debug.is_parametric(2*p), opti.debug.is_parametric(x*p)
(True, False)
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> fprintf('%d %d\n', opti.debug.is_parametric(2*p), opti.debug.is_parametric(x*p))
1 0
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> d = ca.debug(opti);
julia> ca.is_parametric(d, 2*p), ca.is_parametric(d, x*p)
(true, false)

Extra doc | Doc source | Implementation

mark_problem_dirty(...)

Flag that the problem structure changed since the last bake.

mark_problem_dirty(self, bool flag)

Doc source | Implementation

mark_solved(...)

Set or clear the solved state.

mark_solved(self, bool flag)

Doc source | Implementation

mark_solver_dirty(...)

Flag that the solver must be reconstructed (solver() was called)

mark_solver_dirty(self, bool flag)

Doc source | Implementation

objective(...)

Objective expression; same as f()

objective(self) -> MX

Doc source | Implementation

problem_dirty(...)

True when the problem must be baked again before solving.

problem_dirty(self) -> bool

Doc source | Implementation

property problem_dirty_
problem_dirty_(self) -> bool
res(...)

Result dict of the latest solve (x, f, g, lam_x, lam_g, lam_p)

res(self) -> dict:DM
res(self, dict:DM res)

Store a solver result dict as the latest values (marks the instance solved)

Doc source | Implementation

set_meta(...)

Set meta-data of an expression.

set_meta(self, MX m, MetaVar meta)

Doc source | Implementation

set_meta_con(...)

Set meta-data of an expression.

set_meta_con(self, MX m, MetaCon meta)

Doc source | Implementation

show_infeasibilities(...)

Print the constraints violated at the latest iterate.

show_infeasibilities(self, float tol, dict opts)

For every row of g whose violation max(g-ubg, lbg-g) is at least tol, prints the bounds, the value, the violation and the description of the constraint (also in scaled units when scaling is active). Requires a solve; typically called after an infeasible solve through opti.debug.

Parameters:
  • tol -- Violation threshold (default 0, which also lists rounding-level violations)

  • opts -- Passed to g_describe

>>> opti = Opti()
>>> x = opti.variable()
>>> opti.minimize(x**2)
>>> opti.subject_to(x >= 1)
>>> opti.subject_to(x <= -1)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> try:
...   opti.solve()
... except Exception as e:
...   pass
>>> opti.debug.show_infeasibilities(1e-6)
Violated constraints (tol 1e-06), in order of declaration:
------- i = 0/2 ------
1 <= ... <= inf (viol ...)
Opti constraint of shape 1x1, called from ...
------- i = 1/2 ------
-inf <= ... <= -1 (viol ...)
Opti constraint of shape 1x1, called from ...
>> opti = Opti(); x = opti.variable(); opti.minimize(x^2);
>> opti.subject_to(x >= 1); opti.subject_to(x <= -1);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> try, opti.solve(); catch e, end
>> opti.debug.show_infeasibilities(1e-6)
Violated constraints (tol 1e-06), in order of declaration:
------- i = 1/2 ------
1 <= ... <= inf (viol ...)
Opti constraint of shape 1x1, called from ...
------- i = 2/2 ------
-inf <= ... <= -1 (viol ...)
Opti constraint of shape 1x1, called from ...
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> ca.minimize(opti, x^2)
julia> ca.subject_to(opti, x >= 1)
julia> ca.subject_to(opti, x <= -1)
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> try
           ca.solve(opti)
       catch e
       end
julia> ca.show_infeasibilities(ca.debug(opti), 1e-6)
Violated constraints (tol 1e-06), in order of declaration:
------- i = 0/2 ------
1 <= ... <= inf (viol ...)
Opti constraint of shape 1x1, called from ...
------- i = 1/2 ------
-inf <= ... <= -1 (viol ...)
Opti constraint of shape 1x1, called from ...

Extra doc | Doc source | Implementation

solve_actual(...)

Run the solver on an argument dict (see solve_prepare)

solve_actual(self, dict:DM args) -> dict:DM

Doc source | Implementation

solve_prepare(...)

Prepare the solver arguments (first half of solve)

solve_prepare(self)

Checks the constraints and parameter values and fills arg() with x0, p, lam_g0, lbg and ubg. solve_actual() then runs the solver on such a dict, and res() stores its result so that value() works. Together they allow custom solver invocations.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> opti.minimize((x-p)**2)
>>> opti.subject_to(x <= 1)
>>> opti.set_value(p, 3)
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> sol = opti.solve()
>>> d = opti.debug
>>> d.solve_prepare()
>>> d.arg()
{'lam_g0': DM(0), 'lbg': DM(-inf), 'p': DM(3), 'ubg': DM(1), 'x0': DM(0)}
>>> r = d.solve_actual(d.arg())
>>> d.res(r)
>>> d.value(x), sorted(d.res().keys())
(1.0, ['f', 'g', 'lam_g', 'lam_p', 'lam_x', 'x'])
>> opti = Opti(); x = opti.variable(); p = opti.parameter();
>> opti.minimize((x-p)^2); opti.subject_to(x <= 1); opti.set_value(p, 3);
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve(); d = opti.debug; d.solve_prepare();
>> a = d.arg(); disp(fieldnames(a)'), disp(a.lbg), disp(a.ubg), disp(a.x0)
{'lam_g0'} {'lbg'} {'p'} {'ubg'} {'x0'}
-inf
1
0
>> r = d.solve_actual(d.arg()); d.res(r);
>> d.value(x), sort(fieldnames(d.res()))'
1
{'f'} {'g'} {'lam_g'} {'lam_p'} {'lam_x'} {'x'}
julia> opti = ca.Opti();
julia> x = opti.variable();
julia> p = opti.parameter();
julia> opti.minimize((x - p)^2)
julia> opti.subject_to(x <= 1)
julia> opti.set_value(p, 3)
julia> opti.solver("ipopt", Dict("print_time" => false), Dict("print_level" => 0, "sb" => "yes"))
julia> sol = opti.solve();
julia> d = opti.debug;
julia> ca.solve_prepare(d)
julia> sort(collect(ca.arg(d)), by=first)
5-element Vector{Pair{String, DM}}:
 "lam_g0" => 0
    "lbg" => -inf
      "p" => 3
    "ubg" => 1
     "x0" => 0
julia> r = ca.solve_actual(d, ca.arg(d));
julia> ca.res(d, r)
julia> ca.value(d, x), sort(collect(keys(ca.res(d))))
(1.0, ["f", "g", "lam_g", "lam_p", "lam_x", "x"])

Extra doc | Doc source | Implementation

solved(...)

True when a solver result is available for value()

solved(self) -> bool

Doc source | Implementation

property solved_
solved_(self) -> bool
solver_dirty(...)

True when the solver must be reconstructed.

solver_dirty(self) -> bool

Doc source | Implementation

property solver_dirty_
solver_dirty_(self) -> bool
symvar(...)
symvar(self) -> [MX]
symvar(self, MX expr) -> [MX]
symvar(self, MX expr, casadi::VariableType type) -> [MX]

Get the symbols of this instance.

Without argument: every symbol created so far (variables, parameters and the dual variables of constraints), whether or not it appears in the problem. With expr: the symbols of this instance that expr depends on, optionally filtered by type. The result is ordered by creation.

>>> opti = Opti()
>>> x = opti.variable()
>>> p = opti.parameter()
>>> y = opti.variable()
>>> print(opti.debug.symvar())
[MX(opti..._x_1), MX(opti..._p_1), MX(opti..._x_2)]
>>> print(opti.debug.symvar(y*p + 1), opti.debug.symvar(y*p, OPTI_PAR))
[MX(opti..._p_1), MX(opti..._x_2)] [MX(opti..._p_1)]
>> opti = Opti(); x = opti.variable(); p = opti.parameter(); y = opti.variable();
>> sv = opti.debug.symvar(); disp(numel(sv)), disp(sv{2})
3
opti..._p_1
>> sv = opti.debug.symvar(y*p + 1); disp(sv{1}), disp(sv{2})
opti..._p_1
opti..._x_2
>> sv = opti.debug.symvar(y*p, OPTI_PAR); disp(numel(sv)), disp(sv{1})
1
opti..._p_1
julia> opti = ca.Opti();
julia> x = ca.variable(opti);
julia> p = ca.parameter(opti);
julia> y = ca.variable(opti);
julia> d = ca.debug(opti);
julia> print(ca.symvar(d))
MX[opti..._x_1, opti..._p_1, opti..._x_2]
julia> print(ca.symvar(d, y*p + 1), " ", ca.symvar(d, y*p, ca.OPTI_PAR))
MX[opti..._p_1, opti..._x_2] MX[opti..._p_1]

Extra doc | Doc source | Implementation

x_describe(...)

Describe entry i of the flattened x vector.

x_describe(self, int i, dict opts) -> str

Human-readable description of the variable owning xi , plus the position inside the variable. Use it to trace NaN/Inf reports of a solver back to the source.

Parameters:

opts -- "max_stacktrace_depth" (default 1)

>>> opti = Opti()
>>> x = opti.variable(3)
>>> opti.minimize(sumsqr(x))
>>> print(opti.debug.x_describe(2))
Opti decision variable 'opti..._x_1' of shape 3x1, called from ...
At nonzero 2.
>> opti = Opti(); x = opti.variable(3); opti.minimize(sumsqr(x));
>> opti.debug.x_describe(3)
Opti decision variable 'opti..._x_1' of shape 3x1, called from ...
At nonzero 3.
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 3);
julia> ca.minimize(opti, ca.sumsqr(x))
julia> print(ca.x_describe(ca.debug(opti), 2))
Opti decision variable 'opti..._x_1' of shape 3x1, called from ...
At nonzero 2.

Extra doc | Doc source | Implementation

x_lookup(...)

Get the variable that owns entry i of the flattened x vector.

x_lookup(self, int i) -> MX
>>> opti = Opti()
>>> x = opti.variable(2)
>>> y = opti.variable()
>>> opti.minimize(sumsqr(x) + y**2)
>>> print(opti.debug.x_lookup(1), opti.debug.x_lookup(2))
opti..._x_1 opti..._x_2
>> opti = Opti(); x = opti.variable(2); y = opti.variable();
>> opti.minimize(sumsqr(x) + y^2);
>> opti.debug.x_lookup(2), opti.debug.x_lookup(3)
opti..._x_1
opti..._x_2
julia> opti = ca.Opti();
julia> x = ca.variable(opti, 2);
julia> y = ca.variable(opti);
julia> ca.minimize(opti, ca.sumsqr(x) + y^2)
julia> d = ca.debug(opti);
julia> print(ca.x_lookup(d, 1), " ", ca.x_lookup(d, 2))
opti..._x_1 opti..._x_2

Extra doc | Doc source | Implementation

Advanced

DaeBuilder

class DaeBuilder(...)

A symbolic representation of a differential-algebraic equations model.

A DaeBuilder holds a list of uniquely named model variables with FMI-style meta data (causality, variability, type, start value, bounds, unit, ...) together with the model equations. The model is either built symbolically with add, eq, when and friends, or imported from an FMU / modelDescription.xml (constructor with a path, load_fmi_description). Numerical evaluation goes through the function factory create, which returns differentiable Function objects.

Every variable belongs to at most one CasADi category, derived from its causality, variability and defining equation:

Variables:

t:      independent variable (usually time)
c:      constants
p:      parameters
d:      dependent parameters (time independent)
u:      controls
w:      dependent variables  (time dependent)
x:      differential states
z:      algebraic variables
q:      quadrature states
y:      outputs

Equations:

differential equations: \dot{x} ==  ode(...)
algebraic equations:          0 ==  alg(...)
quadrature equations:   \dot{q} == quad(...)
dependent parameters:         d == ddef(d_prev,p)
dependent variables:          w == wdef(w_prev,x,z,u,p,t)
output equations:             y == ydef(...)
initial equations:     init_lhs == init_rhs(...)
events:      when when_cond < 0: when_lhs := when_rhs

The category names ("x", "ode", ...) are the strings accepted by all, inputs, outputs, create and the other category-based members. Internal helper variables (named der(x), __alg__0, __assign__.., __when__0, ...) are created as equations are added; they show up in all().

>>> dae = DaeBuilder("rocket")
>>> a = dae.add("a", "parameter", "tunable")
>>> u = dae.add("u", "input")
>>> h = dae.add("h", dict(start=0))
>>> v = dae.add("v", dict(start=0, unit="m/s"))
>>> m = dae.add("m", dict(start=1))
>>> dae.eq(dae.der(h), v)
>>> dae.eq(dae.der(v), (u - a*v**2)/m - 9.81)
>>> dae.eq(dae.der(m), -u**2)
>>> dae.x(), dae.u(), dae.p()
(['h', 'v', 'm'], ['u'], ['a'])
>>> f = dae.create("f", ["x", "u", "p"], ["ode"])
>>> f
Function(f:(x[3],u,p)->(ode[3]) MXFunction)
>>> f([0, 0, 1], 1, 0.5)
DM([0, -8.81, -1])
>> dae = DaeBuilder('rocket');
>> a = dae.add('a', 'parameter', 'tunable'); u = dae.add('u', 'input');
>> h = dae.add('h', struct('start', 0)); v = dae.add('v', struct('start', 0, 'unit', 'm/s'));
>> m = dae.add('m', struct('start', 1));
>> dae.eq(dae.der(h), v); dae.eq(dae.der(v), (u - a*v^2)/m - 9.81); dae.eq(dae.der(m), -u^2);
>> dae.x()
h
v
m
>> dae.u(), dae.p()
u
a
>> f = dae.create('f', {'x', 'u', 'p'}, {'ode'}); disp(f)
f:(x[3],u,p)->(ode[3]) MXFunction
>> f([0; 0; 1], 1, 0.5)
[0, -8.81, -1]
julia> dae = ca.DaeBuilder("rocket");
julia> a = ca.add(dae, "a", "parameter", "tunable");
julia> u = ca.add(dae, "u", "input");
julia> h = ca.add(dae, "h", Dict("start" => 0));
julia> v = ca.add(dae, "v", Dict("start" => 0, "unit" => "m/s"));
julia> m = ca.add(dae, "m", Dict("start" => 1));
julia> ca.eq(dae, ca.der(dae, h), v)
julia> ca.eq(dae, ca.der(dae, v), (u - a*v^2)/m - 9.81)
julia> ca.eq(dae, ca.der(dae, m), -u^2)
julia> ca.x(dae), ca.u(dae), ca.p(dae)
(["h", "v", "m"], ["u"], ["a"])
julia> f = ca.create(dae, "f", ["x", "u", "p"], ["ode"])
Function(f:(x[3],u,p)->(ode[3]) MXFunction)
julia> f([0, 0, 1], 1, 0.5)
DM([0, -8.81, -1])

Authors: Joel Andersson

Extra doc

add(...)

Add a new model variable, symbolic expression already available.

add(self, str name, dict opts) -> MX
add(self, str name, str causality, dict opts) -> MX
add(self, str name, str causality, str variability, dict opts) -> MX
add(self, str name, str causality, str variability, MX expr, dict opts)

Registers an existing symbolic primitive instead of creating a new one. expr must be a pure symbol (is_symbolic()) whose name equals name; anything else is an error. The dimension attribute is not taken from the expression.

Overload: add(self, str name, dict opts)

Add a new model variable, default variability and causality.

The causality defaults to "local"; the variability follows from the type as above, so a plain add(name) gives a continuous local variable of category z.

Overload: add(self, str name, str causality, dict opts)

Add a new model variable, default variability.

The variability follows the FMI 3.0 default: "fixed" for parameters and calculated parameters, "continuous" for floating-point variables and "discrete" for any other type (see the "type" option).

Overload: add(self, str name, str causality, str variability, dict opts)

Add a new model variable.

Creates a variable with FMI 3.0 causality and variability and returns its symbolic expression, a dense column vector with numel elements (the product of the dimensions). The category follows from causality and variability and may change later when equations are added:

  • "parameter": "tunable" gives p (c for non-floating-point types), "fixed" gives c; other variabilities are an error

  • "calculatedParameter": d; requires "fixed" or "tunable"

  • "input": u; requires "continuous" or "discrete"

  • "output" and "local": "constant" gives c, "discrete" gives a state x with zero derivative, "continuous" gives z until an equation defines the variable (w) or its derivative (x); "local" also accepts "fixed" and "tunable" (d)

  • "independent": t; requires "continuous", at most one per model

Variables with causality "output" are additionally listed in y(). Unless the first variable is the independent one, a hidden variable "time" is created first.

Parameters:
  • name -- Unique variable name; reusing a name is an error

  • causality -- "parameter", "calculatedParameter", "input", "output", "local" or "independent"

  • variability -- "constant", "fixed", "tunable", "discrete" or "continuous"

  • opts -- Attributes (any other key is an error): "dimension" (list of int, [1]): shape; all entries must be positive "type" (string, "Float64"): FMI 3 type, e.g. "Float32", "Int32", "Boolean", "String" "start" (double or list): start value, scalar is broadcast; also sets the current value, see get "min", "max", "nominal" (double): bounds and scaling "initial" (string): "exact", "approx", "calculated" or "na"; default per FMI from causality and variability "description", "unit", "display_unit" (string): meta data "dimension" (list of int, [1]): shape; all entries must be positive "type" (string, "Float64"): FMI 3 type, e.g. "Float32", "Int32", "Boolean", "String" "start" (double or list): start value, scalar is broadcast; also sets the current value, see get "min", "max", "nominal" (double): bounds and scaling "initial" (string): "exact", "approx", "calculated" or "na"; default per FMI from causality and variability "description", "unit", "display_unit" (string): meta data

Returns:

Symbolic expression of the new variable, named like the variable

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> x, x.shape, dae.category("x"), dae.causality("x"), dae.variability("x")
(MX(x), (1, 1), 'z', 'local', 'continuous')
>>> p = dae.add("p", "parameter", "tunable")
>>> dae.category("p"), dae.variability("p")
('p', 'tunable')
>>> b = dae.add("b", "input", dict(type="Boolean", start=False))
>>> dae.category("b"), dae.variability("b"), dae.type("b")
('u', 'discrete', 'Boolean')
>>> r = dae.add("r", dict(dimension=[3], start=[1, 2, 3], min=0, unit="m"))
>>> r.shape, dae.start("r"), dae.min("r"), dae.unit("r")
((3, 1), [1.0, 2.0, 3.0], 0.0, 'm')
>>> try:
...   dae.add("x")
... except Exception as e:
...   print("already exists" in str(e))
True
>>> try:
...   dae.add("q", "parameter", "continuous")
... except Exception as e:
...   print("requires 'fixed' or 'tunable'" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x');
>> x, size(x), dae.category('x'), dae.causality('x')
x
1 1
z
local
>> dae.variability('x')
continuous
>> p = dae.add('p', 'parameter', 'tunable');
>> dae.category('p'), dae.variability('p')
p
tunable
>> b = dae.add('b', 'input', struct('type', 'Boolean', 'start', false));
>> dae.category('b'), dae.variability('b'), dae.type('b')
u
discrete
Boolean
>> r = dae.add('r', struct('dimension', 3, 'start', [1 2 3], 'min', 0, 'unit', 'm'));
>> size(r), dae.start('r'), dae.unit('r')
3 1
1 2 3
m
>> try, dae.add('x'); catch e, disp(contains(e.message, 'already exists')); end
1
>> try, dae.add('q', 'parameter', 'continuous'); catch e, msg = e.message; end
>> contains(msg, 'requires ''fixed'' or ''tunable''')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> x, size(x), ca.category(dae, "x"), ca.causality(dae, "x"), ca.variability(dae, "x")
(x, (1, 1), "z", "local", "continuous")
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> ca.category(dae, "p"), ca.variability(dae, "p")
("p", "tunable")
julia> b = ca.add(dae, "b", "input", Dict("type" => "Boolean", "start" => false));
julia> ca.category(dae, "b"), ca.variability(dae, "b"), ca.type(dae, "b")
("u", "discrete", "Boolean")
julia> opts = Dict("dimension" => [3], "start" => [1, 2, 3], "min" => 0, "unit" => "m");
julia> r = ca.add(dae, "r", opts);
julia> size(r), ca.start(dae, "r"), dae.min("r"), ca.unit(dae, "r")
((3, 1), [1.0, 2.0, 3.0], 0.0, "m")
julia> try
           ca.add(dae, "x")
       catch e
           println(occursin("already exists", sprint(showerror, e)))
       end
true
julia> try
           ca.add(dae, "q", "parameter", "continuous")
       catch e
           println(occursin("requires 'fixed' or 'tunable'", sprint(showerror, e)))
       end
true

See also: eq, der, var, category, set_category

Extra doc | Doc source | Implementation

add_fun(...)

Add an external function.

add_fun(self, Function f) -> Function
add_fun(self, str name, Importer compiler, dict opts) -> Function
add_fun(self, str name, [str] arg, [str] res, dict opts) -> Function

Loads the function name from the compiled sources or shared library behind compiler (see external) and stores it.

Overload: add_fun(self, Function f)

Add an already existing function.

Stores f under its own name; a stored function with the same name is an error.

>>> a = MX.sym("a")
>>> F = Function("F", [a], [a**2])
>>> dae = DaeBuilder("m")
>>> dae.add_fun(F)
Function(F:(i0)->(o0) MXFunction)
>>> [g.name() for g in dae.fun()]
['F']
>> a = MX.sym('a'); F = Function('F', {a}, {a^2});
>> dae = DaeBuilder('m');
>> dae.add_fun(F)
F:(i0)->(o0) MXFunction
>> cellfun(@(g) disp(g.name()), dae.fun())
F
julia> a = ca.MX.sym("a");
julia> F = ca.Function("F", [a], [a^2]);
julia> dae = ca.DaeBuilder("m");
julia> ca.add_fun(dae, F)
Function(F:(i0)->(o0) MXFunction)
julia> [ca.name(g) for g in ca.fun(dae)]
1-element Vector{String}:
 "F"

Overload: add_fun(self, str name, [str] arg, [str] res, dict opts)

Add a function from loaded expressions.

Creates a Function mapping the model variables arg to the binding expressions of the dependent variables res and stores it in the instance. Stored functions are listed by disp and retrieved with fun.

Parameters:
  • name -- Function name; must not exist yet

  • arg -- Names of model variables used as inputs

  • res -- Names of dependent variables w, whose definitions become the outputs; any other name is an error

  • opts -- Function options

Returns:

The created function

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w = dae.add("w")
>>> dae.eq(w, sin(x))
>>> dae.eq(dae.der(x), -w)
>>> f = dae.add_fun("wfun", ["x"], ["w"])
>>> f
Function(wfun:(x)->(w) MXFunction)
>>> dae.has_fun("wfun"), dae.has_fun("nope")
(True, False)
>>> try:
...   dae.add_fun("bad", ["x"], ["x"])
... except Exception as e:
...   print("Cannot find dependent" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); w = dae.add('w');
>> dae.eq(w, sin(x)); dae.eq(dae.der(x), -w);
>> f = dae.add_fun('wfun', {'x'}, {'w'}); disp(f)
wfun:(x)->(w) MXFunction
>> dae.has_fun('wfun'), dae.has_fun('nope')
1
0
>> try, dae.add_fun('bad', {'x'}, {'x'}); catch e, msg = e.message; end
>> contains(msg, 'Cannot find dependent')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w = ca.add(dae, "w");
julia> ca.eq(dae, w, sin(x))
julia> f = ca.add_fun(dae, "wfun", ["x"], ["w"])
Function(wfun:(x)->(w) MXFunction)
julia> ca.has_fun(dae, "wfun"), ca.has_fun(dae, "nope")
(true, false)
julia> try
           ca.add_fun(dae, "bad", ["x"], ["x"])
       catch e
           println(occursin("Cannot find dependent", sprint(showerror, e)))
       end
true

See also: fun, has_fun, gather_fun

Extra doc | Doc source | Implementation

add_lc(...)

Add a named linear combination of output expressions.

add_lc(self, str name, [str] f_out)

Declares the name of a linear combination of output categories, so that create can produce its Hessian blocks hess_<name>_<in1>_<in2> with the multipliers lam_<out> as extra inputs.

Parameters:
  • name -- Alphanumeric name

  • f_out -- Output categories in the combination, e.g. ["ode", "alg"]; must be non-empty without duplicates

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> z = dae.add("z")
>>> dae.eq(dae.der(x), -x*z)
>>> dae.eq(0, z - x**2)
>>> dae.add_lc("gamma", ["ode", "alg"])
>>> H = dae.create("H", ["x", "z", "lam_ode", "lam_alg"],
...                ["hess_gamma_x_x", "hess_gamma_x_z"])
>>> H
Function(H:(x,z,lam_ode,lam_alg)->(hess_gamma_x_x,hess_gamma_x_z) MXFunction)
>>> H(1, 2, 1, 1)
(DM(2), DM(-1))
>> dae = DaeBuilder('m'); x = dae.add('x'); z = dae.add('z');
>> dae.eq(dae.der(x), -x*z); dae.eq(0, z - x^2);
>> dae.add_lc('gamma', {'ode', 'alg'});
>> out = {'hess_gamma_x_x', 'hess_gamma_x_z'};
>> H = dae.create('H', {'x', 'z', 'lam_ode', 'lam_alg'}, out); disp(H)
H:(x,z,lam_ode,lam_alg)->(hess_gamma_x_x,hess_gamma_x_z) MXFunction
>> [Hxx, Hxz] = H(1, 2, 1, 1); disp(Hxx), disp(Hxz)
2
-1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> z = ca.add(dae, "z");
julia> ca.eq(dae, ca.der(dae, x), -x*z)
julia> ca.eq(dae, 0, z - x^2)
julia> ca.add_lc(dae, "gamma", ["ode", "alg"])
julia> H = ca.create(dae, "H", ["x", "z", "lam_ode", "lam_alg"],
                     ["hess_gamma_x_x", "hess_gamma_x_z"])
Function(H:(x,z,lam_ode,lam_alg)->(hess_gamma_x_x,hess_gamma_x_z) MXFunction)
julia> H(1, 2, 1, 1)
(2, -1)

See also: create

Extra doc | Doc source | Implementation

alg(...)

[DEPRECATED] Replaced with outputs("alg")

alg(self) -> [MX]

Doc source | Implementation

all(...)

Get a list of all variables of a particular category.

all(self) -> [str]
all(self, str cat) -> [str]

Names of the members of a category in category order; empty for an empty category, an unknown category name is an error. x(), z(), u() etc. are shorthands.

Get a list of all variables.

Names of all variables in creation order, including the hidden "time" variable and the internal helper variables created by eq, when, assign and reinit.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> dae.eq(dae.der(x), -x)
>>> dae.all()
['time', 'x', 'der(x)', '__assign__der(x)__']
>>> dae.all("x"), dae.all("w"), dae.all("calculated")
(['x'], ['der(x)'], ['__assign__der(x)__'])
>> dae = DaeBuilder('m'); x = dae.add('x'); dae.eq(dae.der(x), -x);
>> dae.all()
time
x
der(x)
__assign__der(x)__
>> dae.all('x'), dae.all('w'), dae.all('calculated')
x
der(x)
__assign__der(x)__
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> ca.eq(dae, ca.der(dae, x), -x)
julia> ca.all(dae)
4-element Vector{String}:
 "time"
 "x"
 "der(x)"
 "__assign__der(x)__"
julia> ca.all(dae, "x"), ca.all(dae, "w"), ca.all(dae, "calculated")
(["x"], ["der(x)"], ["__assign__der(x)__"])

See also: has, x, w

Extra doc | Doc source | Implementation

assign(...)

Assignment inside a when-equation or if-else equation.

assign(self, str name, MX val) -> str

Creates a helper variable holding the expression val assigned to the variable name when the event fires, and returns the helper's name for use in when. Intended for discrete-valued variables; reinit is the counterpart for continuous states.

Parameters:
  • name -- Model variable that receives the value

  • val -- Expression in model variables

Returns:

Name of the created assignment variable, e.g. __assign__b__

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(start=0))
>>> b = dae.add("b", dict(type="Boolean", start=False))
>>> dae.eq(dae.der(x), 1)
>>> dae.assign("b", True)
'__assign__b__'
>>> dae.when(x > 1, [dae.assign("b", True)])
>>> dae.disp(True)
nt = 0, nx = 2, nz = 0, nq = 0, ny = 0, np = 0, nc = 0, nd = 0, nw = 1, nu = 0
Model variables:
  x = [x, b]
  w = [der(x)]
List of dependent variables (w):
  der(x) := 1
Time derivatives of differential states (x):
  x: der(x)
  b: 0
When equations:
  when (1-x) < 0 :
    b := 1
>> dae = DaeBuilder('m'); x = dae.add('x', struct('start', 0));
>> b = dae.add('b', struct('type', 'Boolean', 'start', false));
>> dae.eq(dae.der(x), 1);
>> dae.assign('b', true)
__assign__b__
>> dae.when(x > 1, {dae.assign('b', true)});
>> dae.disp(true)
nt = 0, nx = 2, nz = 0, nq = 0, ny = 0, np = 0, nc = 0, nd = 0, nw = 1, nu = 0
Model variables:
x = [x, b]
w = [der(x)]
List of dependent variables (w):
der(x) := 1
Time derivatives of differential states (x):
x: der(x)
b: 0
When equations:
when (1-x) < 0 :
b := 1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("start" => 0));
julia> b = ca.add(dae, "b", Dict("type" => "Boolean", "start" => false));
julia> ca.eq(dae, ca.der(dae, x), 1)
julia> ca.assign(dae, "b", true)
"__assign__b__"
julia> ca.when(dae, x > 1, [ca.assign(dae, "b", true)])
julia> ca.disp(dae, true)
nt = 0, nx = 2, nz = 0, nq = 0, ny = 0, np = 0, nc = 0, nd = 0, nw = 1, nu = 0
Model variables:
  x = [x, b]
  w = [der(x)]
List of dependent variables (w):
  der(x) := 1
Time derivatives of differential states (x):
  x: der(x)
  b: 0
When equations:
  when (1-x) < 0 :
    b := 1

See also: when, reinit

Extra doc | Doc source | Implementation

attribute(...)

Get an attribute for several variables, concatenated

attribute(self, str a, [str] name) -> [float]
attribute(self, str a, str name) -> float

("start"/"value" per element)

Get an attribute, single variable.

Numerical attribute of a scalar variable, selected by name: "min", "max", "nominal", "start" or "value" (the current value, see get). Any other attribute name, or a non-scalar variable, is an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(start=1, min=-2, nominal=10))
>>> v = dae.add("v", dict(dimension=[2], start=[1, 2]))
>>> dae.attribute("start", "x"), dae.attribute("min", "x")
(1.0, -2.0)
>>> dae.attribute("start", ["x", "v"]), dae.attribute("nominal", ["x"])
([1.0, 1.0, 2.0], [10.0])
>>> dae.set_attribute("min", "x", -1)
>>> dae.set_attribute("start", ["x", "v"], [9, 8, 7])
>>> dae.min("x"), dae.start("v")
(-1.0, [8.0, 7.0])
>>> try:
...   dae.attribute("unit", "x")
... except Exception as e:
...   print("No such enum" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x', struct('start', 1, 'min', -2, 'nominal', 10));
>> v = dae.add('v', struct('dimension', 2, 'start', [1 2]));
>> dae.attribute('start', 'x'), dae.attribute('min', 'x')
1
-2
>> dae.attribute('start', {'x', 'v'}), dae.attribute('nominal', {'x'})
1 1 2
10
>> dae.set_attribute('min', 'x', -1); dae.set_attribute('start', {'x', 'v'}, [9 8 7]);
>> dae.min('x'), dae.start('v')
-1
8 7
>> try, dae.attribute('unit', 'x'); catch e, disp(contains(e.message, 'No such enum')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("start" => 1, "min" => -2, "nominal" => 10));
julia> v = ca.add(dae, "v", Dict("dimension" => [2], "start" => [1, 2]));
julia> ca.attribute(dae, "start", "x"), ca.attribute(dae, "min", "x")
(1.0, -2.0)
julia> ca.attribute(dae, "start", ["x", "v"]), ca.attribute(dae, "nominal", ["x"])
([1.0, 1.0, 2.0], [10.0])
julia> ca.set_attribute(dae, "min", "x", -1)
julia> ca.set_attribute(dae, "start", ["x", "v"], [9, 8, 7])
julia> dae.min("x"), ca.start(dae, "v")
(-1.0, [8.0, 7.0])
julia> try
           ca.attribute(dae, "unit", "x")
       catch e
           println(occursin("No such enum", sprint(showerror, e)))
       end
true

See also: min, max, nominal, start, get

Doc source | Implementation | Extra doc

beq(...)

Get the binding equation for a variable.

beq(self, str name) -> MX

The right-hand side of the explicit equation defining the variable; a variable without binding equation is an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w = dae.add("w")
>>> dae.eq(w, sin(x))
>>> dae.eq(dae.der(x), -w)
>>> dae.beq("w"), dae.beq("der(x)")
(MX(sin(x)), MX((-w)))
>> dae = DaeBuilder('m'); x = dae.add('x'); w = dae.add('w');
>> dae.eq(w, sin(x)); dae.eq(dae.der(x), -w);
>> dae.beq('w'), dae.beq('der(x)')
sin(x)
(-w)
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w = ca.add(dae, "w");
julia> ca.eq(dae, w, sin(x))
julia> ca.beq(dae, "w")
MX(sin(x))

See also: has_beq, wdef

Extra doc | Doc source | Implementation

c(...)

Named constants.

c(self) -> [str]

Names of the variables of category c (fixed parameters and constants), in category order. Equivalent to all("c"). Constants are never function inputs: create substitutes their current value, see set.

See also: p, cdef, set, nc

Extra doc | Doc source | Implementation

categories(...)

Which categories are possible for a variable?

categories(self, str name) -> [str]

The categories set_category accepts for the variable given its current category and usage; an empty string stands for "no category". Controls, parameters and constants can be exchanged freely; states not used in any right-hand side can become quadrature states or lose their category.

>>> dae = DaeBuilder("m")
>>> u = dae.add("u", "input")
>>> x = dae.add("x")
>>> q = dae.add("q")
>>> dae.eq(dae.der(x), -x)
>>> dae.eq(dae.der(q), x**2)
>>> dae.categories("u"), dae.categories("x"), dae.categories("q")
(['p', 'u', 'c'], ['x'], ['x', 'q', ''])
>> dae = DaeBuilder('m'); u = dae.add('u', 'input'); x = dae.add('x'); q = dae.add('q');
>> dae.eq(dae.der(x), -x); dae.eq(dae.der(q), x^2);
>> dae.categories('u'), dae.categories('x')
p
u
c
x
>> strjoin(cellstr(dae.categories('q')), ',')
x,q,
julia> dae = ca.DaeBuilder("m");
julia> u = ca.add(dae, "u", "input");
julia> x = ca.add(dae, "x");
julia> q = ca.add(dae, "q");
julia> ca.eq(dae, ca.der(dae, x), -x)
julia> ca.eq(dae, ca.der(dae, q), x^2)
julia> ca.categories(dae, "u"), ca.categories(dae, "x"), ca.categories(dae, "q")
(["p", "u", "c"], ["x"], ["x", "q", ""])

See also: category, set_category

Extra doc | Doc source | Implementation

category(...)

Get the variable category.

category(self, str name) -> str

One of "t", "c", "p", "d", "w", "u", "x", "z", "q", "calculated" (internal helper variables), or an empty string for no category.

See also: categories, set_category, causality, variability

Extra doc | Doc source | Implementation

causality(...)

Get the causality.

causality(self, str name) -> str

One of "parameter", "calculatedParameter", "input", "output", "local", "independent".

>>> dae = DaeBuilder("m")
>>> t = dae.add("t", "independent")
>>> u = dae.add("u", "input")
>>> x = dae.add("x")
>>> dae.causality("t"), dae.causality("u"), dae.causality("x")
('independent', 'input', 'local')
>> dae = DaeBuilder('m'); t = dae.add('t', 'independent'); u = dae.add('u', 'input');
>> x = dae.add('x');
>> dae.causality('t'), dae.causality('u'), dae.causality('x')
independent
input
local
julia> dae = ca.DaeBuilder("m");
julia> t = ca.add(dae, "t", "independent");
julia> u = ca.add(dae, "u", "input");
julia> x = ca.add(dae, "x");
julia> ca.causality(dae, "t"), ca.causality(dae, "u"), ca.causality(dae, "x")
("independent", "input", "local")

See also: set_causality, variability, category

Extra doc | Doc source | Implementation

cdef(...)

Definitions of named constants.

cdef(self) -> [MX]

The binding expressions of the constants c, one per entry of c(). Only constants that have a binding equation (imported from a symbolic model description) are supported; a constant without one raises an error.

See also: c, ddef, wdef

Extra doc | Doc source | Implementation

class_name(...)

Get class name.

class_name(self) -> str

Extra doc | Doc source | Implementation

compile_fmu(...)

Compile the sources produced by export_fmu.

compile_fmu(self, dict files, dict opts) -> dict

Compiles all .c entries of files (through one amalgamation translation unit) into a shared library <name>.<ext> in the current directory using an Importer plugin, and returns the map extended with the binary at its FMI 3 archive location binaries/<platform>/. The FMI 3 headers must be on the include path.

Parameters:
  • files -- the {local_file -> archive path} map returned by export_fmu

  • opts -- compile options: "compiler" (Importer plugin, default "shell"), "compiler_options" (options for that plugin), "include_dirs" (list of directories)

Returns:

the file map augmented with the amalgamation source and compiled binary

See also: export_fmu, pack_fmu

Extra doc | Doc source | Implementation

create(...)

Create a function with standard integrator DAE signature, default naming.

create(self) -> Function
create(self, str fname, dict opts) -> Function
create(self, str name, [str] name_in, [str] name_out, dict opts) -> Function
create(self, str fname, [str] name_in, [str] name_out, bool sx, bool lifted_calls) -> Function

The function is named <name>_dae.

Overload: create(self, str fname, dict opts)

Create a function with standard integrator DAE signature.

Shorthand for create(fname, ["t", "x", "z", "p", "u"], ["ode", "alg", "quad", "zero"], opts): a function that can be passed directly to integrator. Empty categories give empty inputs or outputs.

Parameters:
  • name -- Name assigned to the resulting function object

  • opts -- Optional settings

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> u = dae.add("u", "input")
>>> dae.eq(dae.der(x), -x + u)
>>> f = dae.create("mydae")
>>> f
Function(mydae:(t[0],x,z[0],p[0],u)->(ode,alg[0],quad[0],zero[0]) MXFunction)
>>> f(0, 1, [], [], 3)
(DM(2), DM(0x1), DM(0x1), DM(0x1))
>> dae = DaeBuilder('m'); x = dae.add('x'); u = dae.add('u', 'input');
>> dae.eq(dae.der(x), -x + u);
>> f = dae.create('mydae'); disp(f)
mydae:(t[0],x,z[0],p[0],u)->(ode,alg[0],quad[0],zero[0]) MXFunction
>> [ode, alg, quad, zero] = f(0, 1, [], [], 3); disp(ode), disp(alg), disp(quad), disp(zero)
2
0x1
0x1
0x1
>> res = f('t', 0, 'x', 1, 'u', 3); disp(res.ode)
2
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> u = ca.add(dae, "u", "input");
julia> ca.eq(dae, ca.der(dae, x), -x + u)
julia> f = ca.create(dae, "mydae")
Function(mydae:(t[0],x,z[0],p[0],u)->(ode,alg[0],quad[0],zero[0]) MXFunction)
julia> f(0, 1, [], [], 3)
(2, 0x1, 0x1, 0x1)
julia> f(t=0, x=1, u=3)["ode"]
DM(2)

See also: transition

Overload: create(self, str name, [str] name_in, [str] name_out, dict opts)

Construct a function object, names provided.

The function factory: builds a Function whose inputs are variable categories and whose outputs are equation categories or derivatives of them. Inputs are any of t, p, d, u, x, z, q, w; constants c are never inputs, their current values (see set) are substituted. Outputs are ode, alg, quad, zero, ddef, wdef, y. Dependent variables w and parameters d not given as inputs are substituted out. Derivative outputs use the Function factory naming with underscores: jac_ode_x (Jacobian block) or hess_<lc>_x_x for a linear combination declared with add_lc, with the multipliers lam_ode, lam_alg, ... as inputs. The created function is a snapshot: later changes to the instance do not affect it. For an imported FMU the function evaluates the FMU binary.

Parameters:
  • name -- Name assigned to the resulting function object

  • name_in -- Names of all the inputs

  • name_out -- Names of all the outputs

  • opts -- Optional settings: Function options for a symbolic model; for an FMU also "aux" (names of variables reported in stats() after evaluation), "enable_ad", "parallelization" and the other FmuFunction options

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> z = dae.add("z")
>>> u = dae.add("u", "input")
>>> p = dae.add("p", "parameter", "tunable")
>>> c = dae.add("c", "parameter", "fixed", dict(start=3))
>>> w = dae.add("w")
>>> y = dae.add("y", "output")
>>> dae.eq(dae.der(x), -c*x + z*u)
>>> dae.eq(0, x - p*z**2)
>>> dae.eq(w, x + z)
>>> dae.eq(y, w**2)
>>> f = dae.create("f", ["x", "z", "u", "p"], ["ode", "alg", "y"])
>>> f
Function(f:(x,z,u,p)->(ode,alg,y) MXFunction)
>>> f(1, 2, 3, 4)
(DM(3), DM(15), DM(9))
>>> J = dae.create("J", ["x", "z", "u", "p"], ["jac_ode_x", "jac_alg_z"])
>>> J(1, 2, 3, 4)
(DM(-3), DM(16))
>>> dae.create("g", ["x", "z", "w"], ["ode", "wdef"])
Function(g:(x,z,w[3])->(ode,wdef[3]) MXFunction)
>>> dae.create("s", ["x", "z", "u", "p"], ["ode"], True)
Function(s:(x,z,u,p)->(ode) SXFunction)
>>> try:
...   dae.create("f", ["x", "z", "c"], ["ode"])
... except Exception as e:
...   print('Cannot process "c" as input' in str(e))
True
>>> try:
...   dae.create("f", ["x", "z"], ["w"])
... except Exception as e:
...   print('Cannot process "w" as output' in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); z = dae.add('z'); u = dae.add('u', 'input');
>> p = dae.add('p', 'parameter', 'tunable');
>> c = dae.add('c', 'parameter', 'fixed', struct('start', 3));
>> w = dae.add('w'); y = dae.add('y', 'output');
>> dae.eq(dae.der(x), -c*x + z*u); dae.eq(0, x - p*z^2);
>> dae.eq(w, x + z); dae.eq(y, w^2);
>> f = dae.create('f', {'x', 'z', 'u', 'p'}, {'ode', 'alg', 'y'}); disp(f)
f:(x,z,u,p)->(ode,alg,y) MXFunction
>> [ode, alg, yval] = f(1, 2, 3, 4); disp(ode), disp(alg), disp(yval)
3
15
9
>> J = dae.create('J', {'x', 'z', 'u', 'p'}, {'jac_ode_x', 'jac_alg_z'});
>> [J_ode_x, J_alg_z] = J(1, 2, 3, 4); disp(J_ode_x), disp(J_alg_z)
-3
16
>> dae.create('g', {'x', 'z', 'w'}, {'ode', 'wdef'})
g:(x,z,w[3])->(ode,wdef[3]) MXFunction
>> dae.create('s', {'x', 'z', 'u', 'p'}, {'ode'}, true)
s:(x,z,u,p)->(ode) SXFunction
>> try, dae.create('f', {'x', 'z', 'c'}, {'ode'}); catch e, msg = e.message; end
>> contains(msg, 'Cannot process "c" as input')
1
>> try, dae.create('f', {'x', 'z'}, {'w'}); catch e, msg = e.message; end
>> contains(msg, 'Cannot process "w" as output')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> z = ca.add(dae, "z");
julia> u = ca.add(dae, "u", "input");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> c = ca.add(dae, "c", "parameter", "fixed", Dict("start" => 3));
julia> w = ca.add(dae, "w");
julia> y = ca.add(dae, "y", "output");
julia> ca.eq(dae, ca.der(dae, x), -c*x + z*u)
julia> ca.eq(dae, 0, x - p*z^2)
julia> ca.eq(dae, w, x + z)
julia> ca.eq(dae, y, w^2)
julia> f = ca.create(dae, "f", ["x", "z", "u", "p"], ["ode", "alg", "y"])
Function(f:(x,z,u,p)->(ode,alg,y) MXFunction)
julia> f(1, 2, 3, 4)
(3, 15, 9)
julia> J = ca.create(dae, "J", ["x", "z", "u", "p"], ["jac_ode_x", "jac_alg_z"]);
julia> J(1, 2, 3, 4)
(-3, 16)
julia> ca.create(dae, "g", ["x", "z", "w"], ["ode", "wdef"])
Function(g:(x,z,w[3])->(ode,wdef[3]) MXFunction)
julia> ca.create(dae, "s", ["x", "z", "u", "p"], ["ode"], true)
Function(s:(x,z,u,p)->(ode) SXFunction)
julia> try
           ca.create(dae, "f", ["x", "z", "c"], ["ode"])
       catch e
           println(occursin("Cannot process \"c\" as input", sprint(showerror, e)))
       end
true
julia> try
           ca.create(dae, "f", ["x", "z"], ["w"])
       catch e
           println(occursin("Cannot process \"w\" as output", sprint(showerror, e)))
       end
true

See also: oracle, add_lc, dependent_fun, transition

Overload: create(self, str fname, [str] name_in, [str] name_out, bool sx, bool lifted_calls)

Construct a function object, legacy syntax.

Same as the overload with options, but with the flags sx (expand to an SX function) and lifted_calls (account for function calls lifted into w, see lift) instead; neither is available for an imported FMU.

Extra doc | Doc source | Implementation

d(...)

Dependent parameters.

d(self) -> [str]

Names of the variables of category d (causality "calculatedParameter", or "local" with "fixed"/"tunable" variability), in category order. Equivalent to all("d"). They are defined by binding equations and are calculated by dependent_fun.

See also: ddef, dependent_fun, nd

Extra doc | Doc source | Implementation

ddef(...)

Definitions of dependent parameters.

ddef(self) -> [MX]

The binding expressions of the dependent parameters, one per entry of d(). Interdependencies are allowed but must be non-cyclic (see sort). Equivalent to outputs("ddef"). A dependent parameter without a binding equation raises an error.

See also: d, wdef, sort, eliminate

Extra doc | Doc source | Implementation

debug_repr(...)
debug_repr(self) -> str
dependent_fun(...)

Construct a function for evaluating dependent parameters.

dependent_fun(self, str fname, [str] s_in, [str] s_out) -> Function

Builds a Function that calculates the dependent parameters d and/or dependent variables w from their binding equations, substituting the interdependencies out, with the given categories as inputs.

Parameters:
  • fname -- Function name

  • s_in -- Input categories; a category that is also an output is an error, and every variable the definitions depend on must be covered

  • s_out -- "d", "w" or both; anything else is an error

Returns:

Function with one (concatenated) output per entry of s_out

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w1 = dae.add("w1")
>>> w2 = dae.add("w2")
>>> p = dae.add("p", "parameter", "tunable")
>>> dae.eq(w1, 2*x)
>>> dae.eq(w2, w1**2 + p)
>>> dae.eq(dae.der(x), -w2)
>>> f = dae.dependent_fun("f", ["x", "p"], ["w"])
>>> f
Function(f:(x,p)->(w[3]) MXFunction)
>>> f(1, 3)
DM([2, 7, -7])
>>> try:
...   dae.dependent_fun("f", ["x", "w"], ["w"])
... except Exception as e:
...   print("cannot be both input and output" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); w1 = dae.add('w1'); w2 = dae.add('w2');
>> p = dae.add('p', 'parameter', 'tunable');
>> dae.eq(w1, 2*x); dae.eq(w2, w1^2 + p); dae.eq(dae.der(x), -w2);
>> f = dae.dependent_fun('f', {'x', 'p'}, {'w'}); disp(f)
f:(x,p)->(w[3]) MXFunction
>> f(1, 3)
[2, 7, -7]
>> try, dae.dependent_fun('f', {'x', 'w'}, {'w'}); catch e, msg = e.message; end
>> contains(msg, 'cannot be both input and output')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w1 = ca.add(dae, "w1");
julia> w2 = ca.add(dae, "w2");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> ca.eq(dae, w1, 2*x)
julia> ca.eq(dae, w2, w1^2 + p)
julia> ca.eq(dae, ca.der(dae, x), -w2)
julia> f = ca.dependent_fun(dae, "f", ["x", "p"], ["w"])
Function(f:(x,p)->(w[3]) MXFunction)
julia> f(1, 3)
DM([2, 7, -7])
julia> try
           ca.dependent_fun(dae, "f", ["x", "w"], ["w"])
       catch e
           println(occursin("cannot be both input and output", sprint(showerror, e)))
       end
true

See also: w, d, create, eliminate

Extra doc | Doc source | Implementation

der(...)

Get the time derivative of model variables, single variable.

der(self) -> [str]
der(self, [str] name) -> [str]
der(self, MX v) -> MX
der(self, MX v) -> MX
der(self, str name) -> str

The name of the derivative variable of a single variable, e.g. der(x) for x.

Overload: der(self)

Model structure: All time derivatives.

Names of all derivative variables, in creation order: the der(x) variables created by der for a symbolic model, or the variables marked as derivatives in an imported model structure.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> dae.der()
[]
>>> dae.eq(dae.der(x), -y)
>>> dae.eq(dae.der(y), x)
>>> dae.der()
['der(x)', 'der(y)']
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> isempty(dae.der())
1
>> dae.eq(dae.der(x), -y); dae.eq(dae.der(y), x);
>> dae.der()
der(x)
der(y)
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> ca.der(dae)
String[]
julia> ca.eq(dae, ca.der(dae, x), -y)
julia> ca.eq(dae, ca.der(dae, y), x)
julia> ca.der(dae)
2-element Vector{String}:
 "der(x)"
 "der(y)"

Overload: der(self, [str] name)

Get the time derivative of model variables.

The names of the derivative variables of the given variables; a variable without a derivative variable is an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> p = dae.add("p", "parameter", "tunable")
>>> dae.eq(dae.der(x), -y)
>>> dae.eq(dae.der(y), x)
>>> dae.der("x"), dae.der(["x", "y"])
('der(x)', ['der(x)', 'der(y)'])
>>> try:
...   dae.der("p")
... except Exception as e:
...   print("No derivative expression" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> p = dae.add('p', 'parameter', 'tunable');
>> dae.eq(dae.der(x), -y); dae.eq(dae.der(y), x);
>> dae.der('x'), dae.der({'x', 'y'})
der(x)
der(x)
der(y)
>> try, dae.der('p'); catch e, disp(contains(e.message, 'No derivative expression')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> ca.eq(dae, ca.der(dae, x), -y)
julia> ca.eq(dae, ca.der(dae, y), x)
julia> ca.der(dae, "x"), ca.der(dae, ["x", "y"])
("der(x)", ["der(x)", "der(y)"])
julia> try
           ca.der(dae, "p")
       catch e
           println(occursin("No derivative expression", sprint(showerror, e)))
       end
true

Overload: der(self, MX v)

Differentiate an expression with respect to time.

For a model variable x the derivative variable der(x) is returned, created on first use (as an algebraic variable until eq gives it a defining equation). For a concatenation of variables the derivatives are concatenated; for a general expression the chain rule is applied through the derivatives of the variables it depends on. The derivative of the independent variable is 1 and that of parameters, constants, inputs and discrete variables is 0. The expression must be a column vector in model variables.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> p = dae.add("p", "parameter", "tunable")
>>> dae.der(x)
MX(der(x))
>>> dae.der(vertcat(x, y))
MX(vertcat(der(x), der(y)))
>>> dae.der(x*y + p)
MX(((y*der(x))+(x*der(y))))
>>> dae.der(p)
MX(0)
>>> dae.z()
['x', 'y', 'der(x)', 'der(y)']
>>> try:
...   dae.der(vertcat(x, y).T)
... except Exception as e:
...   print("must be a vector" in str(e))
True
>>> try:
...   dae.der(MX.sym("foo"))
... except Exception as e:
...   print("No such variable" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> p = dae.add('p', 'parameter', 'tunable');
>> dae.der(x)
der(x)
>> dae.der([x; y])
vertcat(der(x), der(y))
>> dae.der(x*y + p)
((y*der(x))+(x*der(y)))
>> dae.der(p)
0
>> dae.z()
x
y
der(x)
der(y)
>> try, dae.der([x; y]'); catch e, disp(contains(e.message, 'must be a vector')); end
1
>> try, dae.der(MX.sym('foo')); catch e, disp(contains(e.message, 'No such variable')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> ca.der(dae, x)
MX(der(x))
julia> ca.der(dae, [x; y])
MX(vertcat(der(x), der(y)))
julia> ca.der(dae, x*y + p)
MX(((y*der(x))+(x*der(y))))
julia> ca.der(dae, p)
MX(0)
julia> ca.z(dae)
4-element Vector{String}:
 "x"
 "y"
 "der(x)"
 "der(y)"
julia> try
           ca.der(dae, [x; y]')
       catch e
           println(occursin("must be a vector", sprint(showerror, e)))
       end
true
julia> try
           ca.der(dae, ca.MX.sym("foo"))
       catch e
           println(occursin("No such variable", sprint(showerror, e)))
       end
true

See also: eq, der, var

Extra doc | Doc source | Implementation

derivatives(...)

[DEPRECATED] Renamed "der"

derivatives(self) -> [str]

Doc source | Implementation

description(...)

Get/set description.

description(self, str name) -> str

Free-text description of a variable, also settable with the "description" option of add.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(description="position"))
>>> dae.description("x")
'position'
>>> dae.set_description("x", "height")
>>> dae.description("x")
'height'
>> dae = DaeBuilder('m'); x = dae.add('x', struct('description', 'position'));
>> dae.description('x')
position
>> dae.set_description('x', 'height');
>> dae.description('x')
height
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("description" => "position"));
julia> ca.description(dae, "x")
"position"
julia> ca.set_description(dae, "x", "height")
julia> ca.description(dae, "x")
"height"

Extra doc | Doc source | Implementation

dimension(...)

Get the dimensions of a variable.

dimension(self, str name) -> [int]

The "dimension" list given to add (default [1]). The expression is always flattened to a column vector.

See also: numel

Extra doc | Doc source | Implementation

disp(...)

Print a description of the object.

disp(self, bool more)

Doc source | Implementation

display_unit(...)

Get/set the display unit.

display_unit(self, str name) -> str

Display unit string of a variable; empty by default. Also settable with the "display_unit" option of add.

Extra doc | Doc source | Implementation

eliminate(...)

Eliminate all dependent parameters.

eliminate(self, str cat)

Substitutes the variables of an acyclic category out of all model expressions: "c", "d" or "w" (sorted first with sort). The variables keep existing but become calculated and the category is left empty. For "q" the quadrature states are turned into regular states x instead. Any other category is an error.

Parameters:

cat -- "c", "d", "w" or "q"

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w1 = dae.add("w1")
>>> w2 = dae.add("w2")
>>> dae.eq(w2, w1**2)
>>> dae.eq(w1, 2*x)
>>> dae.eq(dae.der(x), -w2)
>>> dae.eliminate("w")
>>> dae.w(), dae.outputs("ode"), dae.category("w1")
([], [MX((-sq((2.*x))))], 'calculated')
>>> try:
...   dae.eliminate("x")
... except Exception as e:
...   print("Elimination not supported" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); w1 = dae.add('w1'); w2 = dae.add('w2');
>> dae.eq(w2, w1^2); dae.eq(w1, 2*x); dae.eq(dae.der(x), -w2);
>> dae.eliminate('w');
>> disp(isempty(dae.w())), cellfun(@disp, dae.outputs('ode')), disp(dae.category('w1'))
1
(-sq((2.*x)))
calculated
>> try, dae.eliminate('x'); catch e, msg = e.message; end
>> contains(msg, 'Elimination not supported')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w1 = ca.add(dae, "w1");
julia> w2 = ca.add(dae, "w2");
julia> ca.eq(dae, w2, w1^2)
julia> ca.eq(dae, w1, 2*x)
julia> ca.eq(dae, ca.der(dae, x), -w2)
julia> ca.eliminate(dae, "w")
julia> ca.w(dae), ca.outputs(dae, "ode"), ca.category(dae, "w1")
(String[], MX[(-sq((2.*x)))], "calculated")
julia> try
           ca.eliminate(dae, "x")
       catch e
           println(occursin("Elimination not supported", sprint(showerror, e)))
       end
true

See also: sort, dependent_fun, lift

Extra doc | Doc source | Implementation

eq(...)

Add a simple equation.

eq(self, MX lhs, MX rhs, dict opts)

Adds the equation lhs == rhs and reclassifies variables accordingly:

  • lhs is the derivative of a state (der(x)): the equation becomes the ODE of x, which moves from z to x; der(x) becomes a dependent variable w

  • lhs is a variable of category z: the equation is its binding equation and the variable moves to w; it must not have a binding equation already

  • lhs is a concatenation of such variables: split into one equation per component

  • lhs is anything else, typically 0: an implicit (algebraic) equation 0 == lhs - rhs is added to outputs("alg"); a second equation for a variable that already has a binding equation is treated this way too

A derivative der(x) that appears in rhs before it was defined is replaced by a new algebraic variable der_x with the trivial ODE der(x) == der_x, keeping the DAE semi-explicit. Scalar sides are broadcast to the length of the other side; sparse sides are densified. Variables appearing in rhs are marked as used, so a quadrature state q referenced there becomes a regular state x.

Parameters:
  • lhs -- Column vector expression; a parameter, constant or state as left-hand side is an error

  • rhs -- Column vector expression in model variables only; dimensions must match after broadcasting

  • opts -- Must be empty

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> z = dae.add("z")
>>> w = dae.add("w")
>>> dae.x(), dae.z(), dae.w()
([], ['x', 'y', 'z', 'w'], [])
>>> dae.eq(dae.der(x), -x + z)
>>> dae.x(), dae.z(), dae.w()
(['x'], ['y', 'z', 'w'], ['der(x)'])
>>> dae.eq(0, x - 2*z)
>>> dae.z(), dae.outputs("alg")
(['y', 'z', 'w'], [MX((-(x-(2.*z))))])
>>> dae.eq(w, x*z)
>>> dae.w(), dae.wdef()
(['der(x)', 'w'], [MX((z-x)), MX((x*z))])
>>> dae.eq(vertcat(dae.der(y), w), vertcat(w, 1))
>>> dae.x(), dae.outputs("ode"), dae.outputs("alg")
(['x', 'y'], [MX((z-x)), MX(w)], [MX((-(x-(2.*z)))), MX((-(w-1)))])
>>> try:
...   dae.eq(x, 1)
... except Exception as e:
...   print("Cannot handle left-hand-side" in str(e))
True
>>> try:
...   dae.eq(vertcat(dae.der(x), dae.der(y)), vertcat(1, 2, 3))
... except Exception as e:
...   print("Mismatched dimensions" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> z = dae.add('z'); w = dae.add('w');
>> isempty(dae.x()), dae.z(), isempty(dae.w())
1
x
y
z
w
1
>> dae.eq(dae.der(x), -x + z);
>> dae.x(), dae.z(), dae.w()
x
y
z
w
der(x)
>> dae.eq(0, x - 2*z);
>> disp(dae.z()), cellfun(@disp, dae.outputs('alg'))
y
z
w
(-(x-(2.*z)))
>> dae.eq(w, x*z);
>> disp(dae.w()), cellfun(@disp, dae.wdef())
der(x)
w
(z-x)
(x*z)
>> dae.eq([dae.der(y); w], [w; 1]);
>> disp(dae.x()), cellfun(@disp, dae.outputs('ode')), cellfun(@disp, dae.outputs('alg'))
x
y
(z-x)
w
(-(x-(2.*z)))
(-(w-1))
>> try, dae.eq(x, 1); catch e, disp(contains(e.message, 'Cannot handle left-hand-side')); end
1
>> try, dae.eq([dae.der(x); dae.der(y)], [1; 2; 3]); catch e, msg = e.message; end
>> contains(msg, 'Mismatched dimensions')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> z = ca.add(dae, "z");
julia> w = ca.add(dae, "w");
julia> ca.x(dae), ca.z(dae), ca.w(dae)
(String[], ["x", "y", "z", "w"], String[])
julia> ca.eq(dae, ca.der(dae, x), -x + z)
julia> ca.x(dae), ca.z(dae), ca.w(dae)
(["x"], ["y", "z", "w"], ["der(x)"])
julia> ca.eq(dae, 0, x - 2*z)
julia> ca.z(dae), ca.outputs(dae, "alg")
(["y", "z", "w"], MX[(-(x-(2.*z)))])
julia> ca.eq(dae, w, x*z)
julia> ca.w(dae), ca.wdef(dae)
(["der(x)", "w"], MX[(z-x), (x*z)])
julia> ca.eq(dae, [ca.der(dae, y); w], [w; 1])
julia> ca.x(dae), ca.outputs(dae, "ode"), ca.outputs(dae, "alg")
(["x", "y"], MX[(z-x), w], MX[(-(x-(2.*z))), (-(w-1))])
julia> try
           ca.eq(dae, x, 1)
       catch e
           println(occursin("Cannot handle left-hand-side", sprint(showerror, e)))
       end
true
julia> try
           ca.eq(dae, [ca.der(dae, x); ca.der(dae, y)], [1, 2, 3])
       catch e
           println(occursin("Mismatched dimensions", sprint(showerror, e)))
       end
true

See also: der, when, set_init, add

Extra doc | Doc source | Implementation

export_fmu(...)

Export instance into an FMU.

export_fmu(self, dict opts) -> dict

Generates the files of an FMI 3.0 model exchange FMU in the current directory: C code for the model equations and their derivatives (<name>.c, <name>.h), the FMI wrapper <name>_wrap.c, buildDescription.xml, modelDescription.xml and, with serialization, the oracle as oracle.casadi plus a layered-standard manifest. Quadrature states are not supported. The result maps each local file name to its path inside the FMU archive, ready for compile_fmu and pack_fmu.

Parameters:

opts -- Options (any other key is an error): "no_warning" (bool, false): suppress the "experimental" warning "with_serialization" (bool, true): include the serialized oracle "no_warning" (bool, false): suppress the "experimental" warning "with_serialization" (bool, true): include the serialized oracle

Returns:

Map local file name to archive path

See also: compile_fmu, pack_fmu, oracle

Extra doc | Doc source | Implementation

fun(...)

Get all functions.

fun(self) -> [Function]
fun(self, str name) -> Function

Get function by name.

Returns the stored function with this name; an unknown name is an error.

>>> a = MX.sym("a")
>>> dae = DaeBuilder("m")
>>> f = dae.add_fun(Function("F", [a], [a**2]))
>>> dae.fun("F")
Function(F:(i0)->(o0) MXFunction)
>>> try:
...   dae.fun("nope")
... except Exception as e:
...   print("No such function" in str(e))
True
>> a = MX.sym('a'); dae = DaeBuilder('m');
>> f = dae.add_fun(Function('F', {a}, {a^2}));
>> dae.fun('F')
F:(i0)->(o0) MXFunction
>> try, dae.fun('nope'); catch e, disp(contains(e.message, 'No such function')); end
1
julia> a = ca.MX.sym("a");
julia> dae = ca.DaeBuilder("m");
julia> f = ca.add_fun(dae, ca.Function("F", [a], [a^2]));
julia> ca.fun(dae, "F")
Function(F:(i0)->(o0) MXFunction)
julia> try
           ca.fun(dae, "nope")
       catch e
           println(occursin("No such function", sprint(showerror, e)))
       end
true

See also: has_fun, add_fun

Doc source | Implementation | Extra doc

gather_fun(...)

Collect embedded functions from the expression graph.

gather_fun(self, int max_depth)

Finds the Function objects called inside the model equations and stores them, so that they are listed by fun(). Functions whose name is already stored are skipped with a warning.

Parameters:

max_depth -- How deep to look into nested function calls; -1 for unlimited

>>> a = MX.sym("a")
>>> F = Function("F", [a], [a**2])
>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> dae.eq(dae.der(x), F(x))
>>> [g.name() for g in dae.fun()]
[]
>>> dae.gather_fun()
>>> [g.name() for g in dae.fun()]
['F']
>> a = MX.sym('a'); F = Function('F', {a}, {a^2});
>> dae = DaeBuilder('m'); x = dae.add('x');
>> dae.eq(dae.der(x), F(x));
>> numel(dae.fun())
0
>> dae.gather_fun();
>> cellfun(@(g) disp(g.name()), dae.fun())
F
julia> a = ca.MX.sym("a");
julia> F = ca.Function("F", [a], [a^2]);
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> ca.eq(dae, ca.der(dae, x), F(x))
julia> [ca.name(g) for g in ca.fun(dae)]
String[]
julia> ca.gather_fun(dae)
julia> [ca.name(g) for g in ca.fun(dae)]
1-element Vector{String}:
 "F"

See also: fun, add_fun

Extra doc | Doc source | Implementation

get(...)

Evaluate the values for a set of variables at the initial time, one entry

get(self, [str] name) -> [GenericType]
get(self, str name) -> GenericType

per name.

Evaluate the values for a set of variables at the initial time, single value.

For a symbolic model the current value (see set): a number for a scalar, a list for a vector-valued variable, a string for a string variable; nan when unset. For an imported FMU the value is obtained by evaluating the FMU.

See also: set, start

Doc source | Implementation | Extra doc

has(...)

Check if a particular variable exists.

has(self, str name) -> bool
>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> dae.has("x"), dae.has("der(x)"), dae.has("time")
(True, False, True)
>>> dae.der(x), dae.has("der(x)")
(MX(der(x)), True)
>> dae = DaeBuilder('m'); x = dae.add('x');
>> dae.has('x'), dae.has('der(x)'), dae.has('time')
1
0
1
>> dae.der(x), dae.has('der(x)')
der(x)
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> ca.has(dae, "x"), ca.has(dae, "der(x)"), ca.has(dae, "time")
(true, false, true)
julia> ca.der(dae, x), ca.has(dae, "der(x)")
(der(x), true)

See also: all, var

Extra doc | Doc source | Implementation

has_beq(...)

Does a variable have a binding equation?

has_beq(self, str name) -> bool

A binding equation is the right-hand side of an explicit equation eq(v, expr) (or an imported one); dependent variables, dependent parameters and defined derivatives have one.

See also: beq, eq

Extra doc | Doc source | Implementation

has_fun(...)

Does a particular function already exist?

has_fun(self, str name) -> bool

True when a function with this name has been stored with add_fun or gather_fun.

See also: fun, add_fun

Extra doc | Doc source | Implementation

has_t(...)

Is there a time variable?

has_t(self) -> bool

True when an independent variable has been declared explicitly (or imported), i.e. when t_new() is non-empty.

See also: time, t_new

Extra doc | Doc source | Implementation

init_lhs(...)

Initial conditions, left-hand-side.

init_lhs(self) -> [MX]

The variable expressions that have an initial equation, in the order the equations were set with set_init; init_rhs() holds the matching right-hand sides.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> p = dae.add("p", "parameter", "tunable")
>>> dae.eq(dae.der(x), -x)
>>> dae.set_init("x", 2*p)
>>> dae.init_lhs(), dae.init_rhs()
([MX(x)], [MX((2.*p))])
>> dae = DaeBuilder('m'); x = dae.add('x'); p = dae.add('p', 'parameter', 'tunable');
>> dae.eq(dae.der(x), -x); dae.set_init('x', 2*p);
>> cellfun(@disp, dae.init_lhs()), cellfun(@disp, dae.init_rhs())
x
(2.*p)
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> ca.set_init(dae, "x", 2*p)
julia> ca.init_lhs(dae), ca.init_rhs(dae)
(MX[x], MX[(2.*p)])

See also: init_rhs, set_init

Extra doc | Doc source | Implementation

init_rhs(...)

Initial conditions, right-hand-side.

init_rhs(self) -> [MX]

The right-hand sides of the initial equations, matching init_lhs().

See also: init_lhs, set_init

Extra doc | Doc source | Implementation

initial(...)

Get/set the initial property.

initial(self, str name) -> str

The FMI initial attribute: "exact", "approx", "calculated" or "na". The default follows from causality and variability per the FMI specification; it can be given with the "initial" option of add. Other values are an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(initial="approx"))
>>> p = dae.add("p", "parameter", "tunable")
>>> u = dae.add("u", "input")
>>> dae.initial("x"), dae.initial("p"), dae.initial("u")
('approx', 'exact', 'na')
>>> dae.set_initial("x", "exact")
>>> dae.initial("x")
'exact'
>> dae = DaeBuilder('m'); x = dae.add('x', struct('initial', 'approx'));
>> p = dae.add('p', 'parameter', 'tunable'); u = dae.add('u', 'input');
>> dae.initial('x'), dae.initial('p'), dae.initial('u')
approx
exact
na
>> dae.set_initial('x', 'exact');
>> dae.initial('x')
exact
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("initial" => "approx"));
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> u = ca.add(dae, "u", "input");
julia> ca.initial(dae, "x"), ca.initial(dae, "p"), ca.initial(dae, "u")
("approx", "exact", "na")
julia> dae.set_initial("x", "exact")
julia> ca.initial(dae, "x")
"exact"

Extra doc | Doc source | Implementation

initial_unknowns(...)

Model structure: initial unknowns.

initial_unknowns(self) -> [str]

Names of the variables listed under InitialUnknowns in the model structure of an imported model description. Empty for a symbolically constructed model.

See also: load_fmi_description, der

Extra doc | Doc source | Implementation

inputs(...)

Input expressions for a specific category.

inputs(self, str cat) -> [MX]

The symbolic expressions of the variables of an input category, in category order.

Parameters:

cat -- One of "t", "c", "p", "d", "w", "u", "x", "z", "q"; an output category such as "ode" is an error

Returns:

List of (column vector) expressions, one per variable; empty when the category is empty

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> z = dae.add("z")
>>> u = dae.add("u", "input")
>>> dae.eq(dae.der(x), -x + z*u)
>>> dae.eq(0, x - 2*z)
>>> dae.inputs("x"), dae.inputs("z"), dae.inputs("u"), dae.inputs("p")
([MX(x)], [MX(z)], [MX(u)], [])
>>> try:
...   dae.inputs("ode")
... except Exception as e:
...   print("not an input category" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); z = dae.add('z'); u = dae.add('u', 'input');
>> dae.eq(dae.der(x), -x + z*u); dae.eq(0, x - 2*z);
>> cellfun(@disp, dae.inputs('x')), cellfun(@disp, dae.inputs('z'))
x
z
>> cellfun(@disp, dae.inputs('u')), disp(numel(dae.inputs('p')))
u
0
>> try, dae.inputs('ode'); catch e, disp(contains(e.message, 'not an input category')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> z = ca.add(dae, "z");
julia> u = ca.add(dae, "u", "input");
julia> ca.eq(dae, ca.der(dae, x), -x + z*u)
julia> ca.eq(dae, 0, x - 2*z)
julia> ca.inputs(dae, "x"), ca.inputs(dae, "z"), ca.inputs(dae, "u"), ca.inputs(dae, "p")
(MX[x], MX[z], MX[u], MX[])
julia> try
           ca.inputs(dae, "ode")
       catch e
           println(occursin("not an input category", sprint(showerror, e)))
       end
true

See also: outputs, var, all

Extra doc | Doc source | Implementation

is_null(...)
is_null(self) -> bool
jac_sparsity(...)

Get Jacobian sparsity.

jac_sparsity(self, [str] onames, [str] inames) -> Sparsity

Structural dependency pattern of the variables onames with respect to inames, one row per output name and one column per input name, taken from the dependency information of the model structure. This information comes from an imported model description or is computed by export_fmu; for a symbolically constructed model it is otherwise absent and the pattern has no nonzeros.

Parameters:
  • onames -- Names of (derivative or output) variables

  • inames -- Names of variables to differentiate with respect to

Returns:

Sparsity pattern of size len(onames) by len(inames)

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> u = dae.add("u", "input")
>>> dae.eq(dae.der(x), -x*u)
>>> dae.jac_sparsity(["der(x)"], ["x", "u"])
Sparsity(1x2,0nz)
>> dae = DaeBuilder('m'); x = dae.add('x'); u = dae.add('u', 'input');
>> dae.eq(dae.der(x), -x*u);
>> dae.jac_sparsity({'der(x)'}, {'x', 'u'})
1x2,0nz
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> u = ca.add(dae, "u", "input");
julia> ca.eq(dae, ca.der(dae, x), -x*u)
julia> ca.jac_sparsity(dae, ["der(x)"], ["x", "u"])
Sparsity(1x2,0nz)

See also: load_fmi_description, export_fmu

Extra doc | Doc source | Implementation

lift(...)

Lift problem formulation by extracting shared subexpressions.

lift(self, bool lift_shared, bool lift_calls)

Scans the right-hand sides of the ODEs, quadratures and algebraic equations and replaces shared subexpressions and/or embedded function calls by new dependent variables named w_<k>, appended to w with their definitions. The lifted definitions become part of wdef; create with "w" as input then exposes them, and create with lifted_calls accounts for the calls in jac_wdef_w and Hessians. A warning is issued when w is non-empty already, which is the case as soon as a state has an ODE.

Parameters:
  • lift_shared -- Lift subexpressions that are used more than once

  • lift_calls -- Lift calls to embedded Function objects, including their arguments

>>> a = MX.sym("a")
>>> F = Function("F", [a], [sin(a) + a**2])
>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> dae.eq(0, x - F(y))
>>> dae.eq(0, y - F(x)**2 - F(y))
>>> dae.lift()
>>> dae.w()
['w_0', 'w_1', 'w_2', 'w_3', 'w_4']
>>> dae.wdef()
[MX(x), MX(y), MX(F(w_1){0}), MX(F(w_0){0}), MX(F(w_1){0})]
>>> dae.outputs("alg")
[MX((-(w_0-w_2))), MX((-((w_1-sq(w_3))-w_4)))]
>>> dae.create("f", ["z", "w"], ["alg", "wdef"])
Function(f:(z[2],w[5])->(alg[2],wdef[5]) MXFunction)
>> a = MX.sym('a'); F = Function('F', {a}, {sin(a) + a^2});
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> dae.eq(0, x - F(y)); dae.eq(0, y - F(x)^2 - F(y));
>> dae.lift();
>> dae.w()
w_0
w_1
w_2
w_3
w_4
>> cellfun(@disp, dae.wdef())
x
y
F(w_1){0}
F(w_0){0}
F(w_1){0}
>> cellfun(@disp, dae.outputs('alg'))
(-(w_0-w_2))
(-((w_1-sq(w_3))-w_4))
>> dae.create('f', {'z', 'w'}, {'alg', 'wdef'})
f:(z[2],w[5])->(alg[2],wdef[5]) MXFunction
julia> a = ca.MX.sym("a");
julia> F = ca.Function("F", [a], [sin(a) + a^2]);
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> ca.eq(dae, 0, x - F(y))
julia> ca.eq(dae, 0, y - F(x)^2 - F(y))
julia> ca.lift(dae)
julia> ca.w(dae)
5-element Vector{String}:
 "w_0"
 "w_1"
 "w_2"
 "w_3"
 "w_4"
julia> ca.wdef(dae)
5-element Vector{MX}:
 MX(x)
 MX(y)
 MX(F(w_1){0})
 MX(F(w_0){0})
 MX(F(w_1){0})
julia> ca.outputs(dae, "alg")
2-element Vector{MX}:
 MX((-(w_0-w_2)))
 MX((-((w_1-sq(w_3))-w_4)))
julia> ca.create(dae, "f", ["z", "w"], ["alg", "wdef"])
Function(f:(z[2],w[5])->(alg[2],wdef[5]) MXFunction)

See also: eliminate, w, wdef

Extra doc | Doc source | Implementation

load_fmi_description(...)

Import problem description from FMI or XML.

load_fmi_description(self, str filename)

Reads a modelDescription.xml (FMI 1.0, 2.0 or 3.0) into an empty instance: model variables with their attributes, the default experiment (start_time etc.), the model structure (der, initial_unknowns, dependencies used by jac_sparsity) and, for symbolic model descriptions, the equations. A standard FMU results in a non-symbolic instance whose functions call the FMU binary found in the FMU directory. The constructor with a path calls this for <path>/modelDescription.xml. An instance that already has variables, or a missing file, is an error.

Parameters:

filename -- Path to the XML file

See also: DaeBuilder, symbolic, provides_directional_derivatives

Extra doc | Doc source | Implementation

max(...)

Get the upper bound for several (scalar) variables.

max(self, [str] name) -> [float]
max(self, str name) -> float

Get the upper bound, single variable (inf by default)

Doc source | Implementation

min(...)

Get the lower bound for several (scalar) variables.

min(self, [str] name) -> [float]
min(self, str name) -> float

Get the lower bound, single variable.

The "min" attribute; -inf by default. Only scalar variables are supported.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(min=-2, max=2, nominal=10))
>>> dae.min("x"), dae.max("x"), dae.nominal("x")
(-2.0, 2.0, 10.0)
>>> dae.set_min("x", 0)
>>> dae.set_max(["x"], [5])
>>> dae.set_nominal("x", 2)
>>> dae.min(["x"]), dae.max("x"), dae.nominal(["x"])
([0.0], 5.0, [2.0])
>> dae = DaeBuilder('m'); x = dae.add('x', struct('min', -2, 'max', 2, 'nominal', 10));
>> dae.min('x'), dae.max('x'), dae.nominal('x')
-2
2
10
>> dae.set_min('x', 0); dae.set_max({'x'}, 5); dae.set_nominal('x', 2);
>> dae.min({'x'}), dae.max('x'), dae.nominal({'x'})
0
5
2
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("min" => -2, "max" => 2, "nominal" => 10));
julia> dae.min("x"), dae.max("x"), ca.nominal(dae, "x")
(-2.0, 2.0, 10.0)
julia> ca.set_min(dae, "x", 0)
julia> ca.set_max(dae, ["x"], [5])
julia> ca.set_nominal(dae, "x", 2)
julia> dae.min(["x"]), dae.max("x"), ca.nominal(dae, ["x"])
([0.0], 5.0, [2.0])

See also: set_min, max, nominal

Doc source | Implementation | Extra doc

name(...)

Name of instance.

name(self) -> str
>>> dae = DaeBuilder("rocket")
>>> dae.name()
'rocket'
>>> dae.create()
Function(rocket_dae:(t[0],x[0],z[0],p[0],u[0])->(ode[0],alg[0],quad[0],zero[0]) MXFunction)
>> dae = DaeBuilder('rocket');
>> dae.name()
rocket
>> dae.create()
rocket_dae:(t[0],x[0],z[0],p[0],u[0])->(ode[0],alg[0],quad[0],zero[0]) MXFunction
julia> dae = ca.DaeBuilder("rocket");
julia> ca.name(dae)
"rocket"
julia> ca.create(dae)
Function(rocket_dae:(t[0],x[0],z[0],p[0],u[0])->(ode[0],alg[0],quad[0],zero[0]) MXFunction)

Extra doc | Doc source | Implementation

nc(...)

Named constants.

nc(self) -> int

Number of variables of category c, i.e. the length of c().

See also: c

Extra doc | Doc source | Implementation

nd(...)

Dependent parameters.

nd(self) -> int

Number of variables of category d, i.e. the length of d().

See also: d

Extra doc | Doc source | Implementation

nominal(...)

Get the nominal value for several (scalar) variables.

nominal(self, [str] name) -> [float]
nominal(self, str name) -> float

Get the nominal value, single variable (1 by default)

Doc source | Implementation

np(...)

Parameters.

np(self) -> int

Number of variables of category p, i.e. the length of p().

See also: p

Extra doc | Doc source | Implementation

nq(...)

Quadrature states.

nq(self) -> int

Number of variables of category q, i.e. the length of q().

See also: q

Extra doc | Doc source | Implementation

nu(...)

Free controls.

nu(self) -> int

Number of variables of category u, i.e. the length of u().

See also: u

Extra doc | Doc source | Implementation

numel(...)

Get the number of elements of a variable.

numel(self, str name) -> int

Product of the dimensions, i.e. the length of the variable's column vector expression.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> m = dae.add("m", dict(dimension=[2, 3]))
>>> dae.numel("x"), dae.numel("m"), dae.dimension("m"), dae.var("m").shape
(1, 6, [2, 3], (6, 1))
>> dae = DaeBuilder('m'); x = dae.add('x'); m = dae.add('m', struct('dimension', [2 3]));
>> dae.numel('x'), dae.numel('m')
1
6
>> dae.dimension('m'), size(dae.var('m'))
2 3
6 1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> m = ca.add(dae, "m", Dict("dimension" => [2, 3]));
julia> ca.numel(dae, "x"), ca.numel(dae, "m"), ca.dimension(dae, "m"), size(ca.var(dae, "m"))
(1, 6, [2, 3], (6, 1))

See also: dimension, var

Extra doc | Doc source | Implementation

nw(...)

Dependent variables.

nw(self) -> int

Number of variables of category w, i.e. the length of w().

See also: w

Extra doc | Doc source | Implementation

nx(...)

Differential states.

nx(self) -> int

Number of variables of category x, i.e. the length of x(). Vector- valued variables count once.

>>> dae = DaeBuilder("m")
>>> pos = dae.add("pos", dict(dimension=[3]))
>>> dae.eq(dae.der(pos), -pos)
>>> dae.nx(), dae.create()
(1, Function(m_dae:(t[0],x[3],z[0],p[0],u[0])->(ode[3],alg[0],quad[0],zero[0]) MXFunction))
>> dae = DaeBuilder('m'); pos = dae.add('pos', struct('dimension', 3));
>> dae.eq(dae.der(pos), -pos);
>> dae.nx(), dae.create()
1
m_dae:(t[0],x[3],z[0],p[0],u[0])->(ode[3],alg[0],quad[0],zero[0]) MXFunction
julia> dae = ca.DaeBuilder("m");
julia> pos = ca.add(dae, "pos", Dict("dimension" => [3]));
julia> ca.eq(dae, ca.der(dae, pos), -pos)
julia> ca.nx(dae), ca.create(dae)
(1, m_dae:(t[0],x[3],z[0],p[0],u[0])->(ode[3],alg[0],quad[0],zero[0]) MXFunction)

See also: x

Extra doc | Doc source | Implementation

ny(...)

Output variables.

ny(self) -> int

Number of output variables, i.e. the length of y().

See also: y

Extra doc | Doc source | Implementation

nz(...)

Algebraic variables.

nz(self) -> int

Number of variables of category z, i.e. the length of z().

See also: z

Extra doc | Doc source | Implementation

nzero(...)

Zero-crossing functions.

nzero(self) -> int

Number of event indicators, one per when equation; the length of outputs("zero").

See also: when, transition

Extra doc | Doc source | Implementation

ode(...)

[DEPRECATED] Replaced with outputs("ode")

ode(self) -> [MX]

Doc source | Implementation

oracle(...)

Get the (cached) oracle, SX or MX.

oracle(self, bool sx, bool elim_w, bool lifted_calls) -> Function

The Function behind create for a symbolic model: inputs are all input categories except c (whose current values are substituted), outputs are all output categories, each as one concatenated vector (empty vectors for empty categories). The oracle is cached and rebuilt when variables or equations change. Not available for an imported FMU.

Parameters:
  • sx -- Return the SX expansion of the oracle instead of the MX graph

  • elim_w -- Substitute the dependent variables w out and drop them as input

  • lifted_calls -- Replace embedded function calls in wdef by zeros, for use with create with lifted_calls; incompatible with elim_w

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w = dae.add("w")
>>> dae.eq(w, sin(x))
>>> dae.eq(dae.der(x), -w)
>>> f = dae.oracle()
>>> f.name(), f.name_in()
('mx_oracle', ['t', 'p', 'd', 'w', 'u', 'x', 'z', 'q'])
>>> f.name_out()
['ode', 'alg', 'quad', 'zero', 'ddef', 'wdef', 'y']
>>> f.size1_in("w"), f.size1_in("p")
(2, 0)
>>> dae.oracle(True).class_name(), dae.oracle(False, True).name_in()
('SXFunction', ['t', 'p', 'd', 'u', 'x', 'z', 'q'])
>> dae = DaeBuilder('m'); x = dae.add('x'); w = dae.add('w');
>> dae.eq(w, sin(x)); dae.eq(dae.der(x), -w);
>> f = dae.oracle();
>> f.name(), strjoin(cellstr(f.name_in()), ' ')
mx_oracle
t p d w u x z q
>> strjoin(cellstr(f.name_out()), ' ')
ode alg quad zero ddef wdef y
>> f.size1_in('w'), f.size1_in('p')
2
0
>> g = dae.oracle(true); disp(g.class_name())
SXFunction
>> g = dae.oracle(false, true); disp(strjoin(cellstr(g.name_in()), ' '))
t p d u x z q
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w = ca.add(dae, "w");
julia> ca.eq(dae, w, sin(x))
julia> ca.eq(dae, ca.der(dae, x), -w)
julia> f = ca.oracle(dae);
julia> ca.name(f), ca.name_in(f)
("mx_oracle", ["t", "p", "d", "w", "u", "x", "z", "q"])
julia> ca.name_out(f)
7-element Vector{String}:
 "ode"
 "alg"
 "quad"
 "zero"
 "ddef"
 "wdef"
 "y"
julia> ca.size1_in(f, "w"), ca.size1_in(f, "p")
(2, 0)
julia> ca.class_name(ca.oracle(dae, true)), ca.name_in(ca.oracle(dae, false, true))
("SXFunction", ["t", "p", "d", "u", "x", "z", "q"])

See also: create, symbolic

Extra doc | Doc source | Implementation

outputs(...)

[DEPRECATED] Renamed "y"

outputs(self) -> [str]
outputs(self, str cat) -> [MX]

Output expressions for a specific category.

The defining expressions of an equation category, in the order of the corresponding input category: "ode" (right-hand sides of the states x), "alg" (residuals), "quad" (right-hand sides of q), "zero" (zero-crossing functions of the when equations), "ddef" and "wdef" (binding expressions of d and w), "y" (expressions of the outputs).

Parameters:

cat -- One of the output categories above; an input category is an error

Returns:

List of expressions, empty when the category is empty

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> z = dae.add("z")
>>> u = dae.add("u", "input")
>>> dae.eq(dae.der(x), -x + z*u)
>>> dae.eq(0, x - 2*z)
>>> dae.outputs("ode"), dae.outputs("alg"), dae.outputs("y")
([MX(((z*u)-x))], [MX((-(x-(2.*z))))], [])
>>> try:
...   dae.outputs("x")
... except Exception as e:
...   print("No input category" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); z = dae.add('z'); u = dae.add('u', 'input');
>> dae.eq(dae.der(x), -x + z*u); dae.eq(0, x - 2*z);
>> cellfun(@disp, dae.outputs('ode')), cellfun(@disp, dae.outputs('alg'))
((z*u)-x)
(-(x-(2.*z)))
>> numel(dae.outputs('y'))
0
>> try, dae.outputs('x'); catch e, disp(contains(e.message, 'No input category')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> z = ca.add(dae, "z");
julia> u = ca.add(dae, "u", "input");
julia> ca.eq(dae, ca.der(dae, x), -x + z*u)
julia> ca.eq(dae, 0, x - 2*z)
julia> ca.outputs(dae, "ode"), ca.outputs(dae, "alg"), ca.outputs(dae, "y")
(MX[((z*u)-x)], MX[(-(x-(2.*z)))], MX[])
julia> try
           ca.outputs(dae, "x")
       catch e
           println(occursin("No input category", sprint(showerror, e)))
       end
true

See also: inputs, wdef, ddef, create

Doc source | Implementation | Extra doc

p(...)

Parameters.

p(self) -> [str]

Names of the variables of category p (causality "parameter", variability "tunable", floating-point type), in category order. Equivalent to all("p").

>>> dae = DaeBuilder("m")
>>> p = dae.add("p", "parameter", "tunable")
>>> c = dae.add("c", "parameter", "fixed")
>>> u = dae.add("u", "input")
>>> dae.p(), dae.c(), dae.u()
(['p'], ['c'], ['u'])
>> dae = DaeBuilder('m'); p = dae.add('p', 'parameter', 'tunable');
>> c = dae.add('c', 'parameter', 'fixed'); u = dae.add('u', 'input');
>> dae.p(), dae.c(), dae.u()
p
c
u
julia> dae = ca.DaeBuilder("m");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> c = ca.add(dae, "c", "parameter", "fixed");
julia> u = ca.add(dae, "u", "input");
julia> ca.p(dae), ca.c(dae), ca.u(dae)
(["p"], ["c"], ["u"])

See also: c, u, np, set_variability

Extra doc | Doc source | Implementation

pack_fmu(...)

Pack files from export_fmu / compile_fmu into a single .fmu archive.

pack_fmu(self, dict files, dict opts) -> str

Zips the entries of files at their archive paths and removes the local files afterwards. Requires a build with WITH_LIBZIP=ON.

Parameters:
  • files -- the {local_file -> archive path} map to pack

  • opts -- packaging options: path (default '<name>.fmu')

Returns:

Path of the created archive

See also: export_fmu, compile_fmu

Extra doc | Doc source | Implementation

parse_fmi(...)

Import existing problem from FMI/XML, alias of load_fmi_description

parse_fmi(self, str filename)

Doc source | Implementation

pre(...)

Get the pre-variables of model variables, single variable (not implemented)

pre(self, [str] name) -> [str]
pre(self, MX v) -> MX
pre(self, str name) -> str

Overload: pre(self, [str] name)

Get the pre-variables of model variables.

Not implemented: returns the names unchanged, with a warning the first time.

See also: reinit

Overload: pre(self, MX v)

Get the pre-expression given variable expression.

Not implemented: returns the expression unchanged, with a warning the first time. Meant for the value of a variable just before an event, as in reinit("v", -0.8*pre(v)).

See also: reinit, when

Doc source | Implementation | Extra doc

print_ptr(...)
print_ptr(self)
provides_directional_derivative(...)

Does the FMU provide support for analytic derivatives (FMI 2 naming)

provides_directional_derivative(self) -> bool

Doc source | Implementation

provides_directional_derivatives(...)

Does the FMU provide support for analytic derivatives.

provides_directional_derivatives(self) -> bool

Reads the providesDirectionalDerivatives flag of an imported FMU. Calling it on a symbolic instance is an error.

See also: symbolic, load_fmi_description

Extra doc | Doc source | Implementation

prune(...)

Prune unused controls.

prune(self, bool prune_p, bool prune_u)

Intended to drop the parameters p and/or controls u that do not appear in any model equation from their categories (the variables themselves remain).

Parameters:
  • prune_p -- Consider the parameters p

  • prune_u -- Consider the controls u

See also: p, u

Extra doc | Doc source | Implementation

q(...)

Quadrature states.

q(self) -> [str]

Names of the variables of category q: differential states that do not appear in any right-hand side. Equivalent to all("q"). A state is only placed here by set_category(name, "q") or automatically with the constructor option "detect_quad".

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> q = dae.add("q")
>>> dae.eq(dae.der(x), -x)
>>> dae.eq(dae.der(q), x**2)
>>> dae.x(), dae.q()
(['x', 'q'], [])
>>> dae.set_category("q", "q")
>>> dae.x(), dae.q(), dae.outputs("quad")
(['x'], ['q'], [MX(sq(x))])
>> dae = DaeBuilder('m'); x = dae.add('x'); q = dae.add('q');
>> dae.eq(dae.der(x), -x); dae.eq(dae.der(q), x^2);
>> dae.x(), isempty(dae.q())
x
q
1
>> dae.set_category('q', 'q');
>> disp(dae.x()), disp(dae.q()), cellfun(@disp, dae.outputs('quad'))
x
q
sq(x)
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> q = ca.add(dae, "q");
julia> ca.eq(dae, ca.der(dae, x), -x)
julia> ca.eq(dae, ca.der(dae, q), x^2)
julia> ca.x(dae), ca.q(dae)
(["x", "q"], String[])
julia> ca.set_category(dae, "q", "q")
julia> ca.x(dae), ca.q(dae), ca.outputs(dae, "quad")
(["x"], ["q"], MX[sq(x)])

See also: set_category, x, nq

Extra doc | Doc source | Implementation

quad(...)

[DEPRECATED] Replaced with outputs("quad")

quad(self) -> [MX]

Doc source | Implementation

reinit(...)

Reinitialize a state inside when-equations.

reinit(self, str name, MX val) -> str

Creates a helper variable holding the new value val of the state name after the event, and returns the helper's name for use in when. Use pre(v) for the value before the event (currently an identity mapping).

Parameters:
  • name -- Model variable that is reinitialized

  • val -- Expression in model variables

Returns:

Name of the created variable, e.g. __reinit__v__0

>>> dae = DaeBuilder("ball")
>>> h = dae.add("h", dict(start=5))
>>> v = dae.add("v", dict(start=0))
>>> dae.eq(dae.der(h), v)
>>> dae.eq(dae.der(v), -9.81)
>>> r = dae.reinit("v", -0.8*v)
>>> r, dae.category(r)
('__reinit__v__0', 'calculated')
>>> dae.when(h < 0, [r])
>>> dae.nzero()
1
>> dae = DaeBuilder('ball');
>> h = dae.add('h', struct('start', 5)); v = dae.add('v', struct('start', 0));
>> dae.eq(dae.der(h), v); dae.eq(dae.der(v), -9.81);
>> r = dae.reinit('v', -0.8*v); disp(r), disp(dae.category(r))
__reinit__v__0
calculated
>> dae.when(h < 0, {r}); disp(dae.nzero())
1
julia> dae = ca.DaeBuilder("ball");
julia> h = ca.add(dae, "h", Dict("start" => 5));
julia> v = ca.add(dae, "v", Dict("start" => 0));
julia> ca.eq(dae, ca.der(dae, h), v)
julia> ca.eq(dae, ca.der(dae, v), -9.81)
julia> r = ca.reinit(dae, "v", -0.8*v);
julia> r, ca.category(dae, r)
("__reinit__v__0", "calculated")
julia> ca.when(dae, h < 0, [r])
julia> ca.nzero(dae)
1

See also: when, assign, pre

Extra doc | Doc source | Implementation

reorder(...)

Reorder variables in a category.

reorder(self, str cat, [str] v)

Replaces the ordering of a category by v, which must be a permutation of the current members: a missing or extra name is an error. The ordering determines the order of the entries in the vectors used by create (e.g. of x and ode).

Parameters:
  • cat -- Category name, e.g. "x"

  • v -- All current members of the category, in the new order

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> dae.eq(dae.der(x), -y)
>>> dae.eq(dae.der(y), x)
>>> dae.x(), dae.outputs("ode")
(['x', 'y'], [MX((-y)), MX(x)])
>>> dae.reorder("x", ["y", "x"])
>>> dae.x(), dae.outputs("ode")
(['y', 'x'], [MX(x), MX((-y))])
>>> try:
...   dae.reorder("x", ["y"])
... except Exception as e:
...   print("1 elements provided for 2 components" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> dae.eq(dae.der(x), -y); dae.eq(dae.der(y), x);
>> disp(dae.x()), cellfun(@disp, dae.outputs('ode'))
x
y
(-y)
x
>> dae.reorder('x', {'y', 'x'});
>> disp(dae.x()), cellfun(@disp, dae.outputs('ode'))
y
x
x
(-y)
>> try, dae.reorder('x', {'y'}); catch e, msg = e.message; end
>> contains(msg, '1 elements provided for 2 components')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> ca.eq(dae, ca.der(dae, x), -y)
julia> ca.eq(dae, ca.der(dae, y), x)
julia> ca.x(dae), ca.outputs(dae, "ode")
(["x", "y"], MX[(-y), x])
julia> ca.reorder(dae, "x", ["y", "x"])
julia> ca.x(dae), ca.outputs(dae, "ode")
(["y", "x"], MX[x, (-y)])
julia> try
           ca.reorder(dae, "x", ["y"])
       catch e
           println(occursin("1 elements provided for 2 components", sprint(showerror, e)))
       end
true

See also: set_all, all

Extra doc | Doc source | Implementation

reset(...)

Clear all set values.

reset(self)

Resets the current value of every variable to nan (empty for string variables); the start attributes are kept.

See also: set, get

Extra doc | Doc source | Implementation

sanity_check(...)

Check if dimensions match.

sanity_check(self)

Raises an error if there is more than one independent variable or if it is not scalar. Called by disp with more set and by add_lc.

>>> dae = DaeBuilder("m")
>>> dae.sanity_check()
>> dae = DaeBuilder('m');
>> dae.sanity_check()
julia> dae = ca.DaeBuilder("m");
julia> ca.sanity_check(dae)

Extra doc | Doc source | Implementation

set(...)

Set the current value (string) for several string variables.

set(self, [str] name, [float] val)
set(self, [str] name, [str] val)
set(self, str name, float val)
set(self, str name, str val)

Overload: set(self, [str] name, [float] val)

Set the current value for several variables (one per variable or one per element)

Overload: set(self, str name, float val)

Set the current value, single value.

The current value is what get returns and what create substitutes for the constants c; set it before creating functions. A variable's current value is initialized from its "start" option and is nan when unset. A vector-valued variable gets all elements set.

>>> dae = DaeBuilder("m")
>>> c = dae.add("c", "parameter", "fixed")
>>> x = dae.add("x", dict(start=1))
>>> v = dae.add("v", dict(dimension=[2]))
>>> s = dae.add("s", dict(type="String"))
>>> dae.get("c"), dae.get("x"), dae.get("v"), repr(dae.get("s"))
(nan, 1.0, [nan, nan], "''")
>>> dae.set("c", 2.5)
>>> dae.set("v", 1)
>>> dae.set("s", "hello")
>>> dae.get(["c", "v", "s"])
[2.5, [1.0, 1.0], 'hello']
>>> dae.set(["c", "x"], [3, 4])
>>> dae.set(["v"], [5, 6])
>>> dae.get(["c", "x", "v"])
[3.0, 4.0, [5.0, 6.0]]
>>> dae.reset()
>>> dae.get(["c", "x"])
[nan, nan]
>> dae = DaeBuilder('m'); c = dae.add('c', 'parameter', 'fixed');
>> x = dae.add('x', struct('start', 1)); v = dae.add('v', struct('dimension', 2));
>> s = dae.add('s', struct('type', 'String'));
>> val = dae.get({'c', 'x', 'v', 's'});
>> val{1}, val{2}, val{3}, isempty(val{4})
NaN
1
NaN NaN
1
>> dae.set('c', 2.5); dae.set('v', 1); dae.set('s', 'hello');
>> val = dae.get({'c', 'v', 's'}); disp(val{1}), disp(val{2}), disp(val{3})
2.5000
1 1
hello
>> dae.set({'c', 'x'}, [3 4]); dae.set({'v'}, [5 6]);
>> val = dae.get({'c', 'x', 'v'}); disp(val{1}), disp(val{2}), disp(val{3})
3
4
5 6
julia> dae = ca.DaeBuilder("m");
julia> c = ca.add(dae, "c", "parameter", "fixed");
julia> x = ca.add(dae, "x", Dict("start" => 1));
julia> v = ca.add(dae, "v", Dict("dimension" => [2]));
julia> s = ca.add(dae, "s", Dict("type" => "String"));
julia> ca.get(dae, "c"), ca.get(dae, "x"), ca.get(dae, "v"), ca.get(dae, "s")
(NaN, 1.0, [NaN, NaN], "")
julia> ca.set(dae, "c", 2.5)
julia> ca.set(dae, "v", 1)
julia> ca.set(dae, "s", "hello")
julia> ca.get(dae, ["c", "v", "s"])
3-element Vector{Any}:
 2.5
  [1.0, 1.0]
  "hello"
julia> ca.set(dae, ["c", "x"], [3, 4])
julia> ca.set(dae, ["v"], [5, 6])
julia> ca.get(dae, ["c", "x", "v"])
3-element Vector{Any}:
 3.0
 4.0
  [5.0, 6.0]
julia> ca.reset(dae)
julia> ca.get(dae, ["c", "x"])
2-element Vector{Any}:
 NaN
 NaN

The value of a constant is baked into the functions created afterwards:

>>> dae = DaeBuilder("m")
>>> c = dae.add("c", "parameter", "fixed")
>>> x = dae.add("x")
>>> dae.eq(dae.der(x), -c*x)
>>> dae.set("c", 3)
>>> dae.create("f", ["x"], ["ode"])(2)
DM(-6)
>> dae = DaeBuilder('m'); c = dae.add('c', 'parameter', 'fixed'); x = dae.add('x');
>> dae.eq(dae.der(x), -c*x);
>> dae.set('c', 3);
>> f = dae.create('f', {'x'}, {'ode'}); disp(f(2))
-6
julia> dae = ca.DaeBuilder("m");
julia> c = ca.add(dae, "c", "parameter", "fixed");
julia> x = ca.add(dae, "x");
julia> ca.eq(dae, ca.der(dae, x), -c*x)
julia> ca.set(dae, "c", 3)
julia> ca.create(dae, "f", ["x"], ["ode"])(2)
DM(-6)

See also: get, reset, start, c

Overload: set(self, str name, str val)

Set the current value, single value (string), for variables of type "String"

Doc source | Implementation | Extra doc

set_all(...)

Set all variables within a a category.

set_all(self, str v, [str] name)

Makes name the complete, ordered content of category v, moving variables in and out as needed:

  • "y": the listed variables get causality "output", all other outputs become "local"

  • "u", "p", "c": the listed variables are moved into the category with set_category; members not listed become constants c (for "u" and "p")

  • "x", "q": the listed states are moved in; members not listed lose their category (they must not appear in any right-hand side)

Other categories and duplicate names are an error. Names not permitted in the category raise the error of set_category.

Parameters:
  • v -- Category name

  • name -- Variables that should form the category, in order

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> u1 = dae.add("u1", "input")
>>> p1 = dae.add("p1", "parameter", "tunable")
>>> dae.eq(dae.der(x), -x + u1*p1)
>>> dae.set_all("u", ["p1", "u1"])
>>> dae.u(), dae.p(), dae.c()
(['p1', 'u1'], [], [])
>>> dae.set_all("p", ["u1"])
>>> dae.u(), dae.p(), dae.c()
(['p1'], ['u1'], [])
>>> dae.set_all("y", ["x"])
>>> dae.y(), dae.causality("x")
(['x'], 'output')
>>> try:
...   dae.set_all("x", ["x", "x"])
... except Exception as e:
...   print("Duplicate names" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); u1 = dae.add('u1', 'input');
>> p1 = dae.add('p1', 'parameter', 'tunable');
>> dae.eq(dae.der(x), -x + u1*p1);
>> dae.set_all('u', {'p1', 'u1'});
>> dae.u(), isempty(dae.p()), isempty(dae.c())
p1
u1
1
1
>> dae.set_all('p', {'u1'});
>> dae.u(), dae.p()
p1
u1
>> dae.set_all('y', {'x'});
>> dae.y(), dae.causality('x')
x
output
>> try, dae.set_all('x', {'x', 'x'}); catch e, msg = e.message; end
>> contains(msg, 'Duplicate names')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> u1 = ca.add(dae, "u1", "input");
julia> p1 = ca.add(dae, "p1", "parameter", "tunable");
julia> ca.set_all(dae, "u", ["p1", "u1"])
julia> ca.u(dae), ca.p(dae), ca.c(dae)
(["p1", "u1"], String[], String[])
julia> ca.set_all(dae, "p", ["u1"])
julia> ca.u(dae), ca.p(dae), ca.c(dae)
(["p1"], ["u1"], String[])
julia> ca.set_all(dae, "y", ["x"])
julia> ca.y(dae), ca.causality(dae, "x")
(["x"], "output")
julia> try
           ca.set_all(dae, "x", ["x", "x"])
       catch e
           println(occursin("Duplicate names", sprint(showerror, e)))
       end
true

See also: reorder, set_category, set_causality

Extra doc | Doc source | Implementation

set_attribute(...)

Set an attribute, one value per variable or one value per element.

set_attribute(self, str a, [str] name, [float] val)
set_attribute(self, str a, str name, float val)

Set an attribute, single variable (vector-valued variables get all elements set)

Doc source | Implementation

set_category(...)

Set the variable category, if permitted.

set_category(self, str name, str val)

The following changes are permitted:

  • Controls u can be changed to/from tunable parameters p or fixed parameters c

  • Differential states that do not appear in the right-hand-sides can be changed between regular states x, quadrature states q and no category (empty string)

  • A state can be made the independent variable t, replacing the current one

Other changes are not permitted. Causality and variability is updated accordingly.

>>> dae = DaeBuilder("m")
>>> u = dae.add("u", "input")
>>> x = dae.add("x")
>>> q = dae.add("q")
>>> dae.eq(dae.der(x), -x)
>>> dae.eq(dae.der(q), x**2)
>>> dae.set_category("q", "q")
>>> dae.x(), dae.q()
(['x'], ['q'])
>>> dae.set_category("q", "")
>>> dae.x(), dae.q(), dae.category("q")
(['x'], [], '')
>>> dae.set_category("u", "p")
>>> dae.u(), dae.p(), dae.causality("u"), dae.variability("u")
([], ['u'], 'parameter', 'tunable')
>>> try:
...   dae.set_category("x", "q")
... except Exception as e:
...   print("Cannot change category of x from 'x' to 'q'" in str(e))
True
>> dae = DaeBuilder('m'); u = dae.add('u', 'input'); x = dae.add('x'); q = dae.add('q');
>> dae.eq(dae.der(x), -x); dae.eq(dae.der(q), x^2);
>> dae.set_category('q', 'q');
>> dae.x(), dae.q()
x
q
>> dae.set_category('q', '');
>> dae.x(), isempty(dae.q()), isempty(dae.category('q'))
x
1
1
>> dae.set_category('u', 'p');
>> isempty(dae.u()), dae.p()
1
u
>> dae.causality('u'), dae.variability('u')
parameter
tunable
>> try, dae.set_category('x', 'q'); catch e, msg = e.message; end
>> contains(msg, 'Cannot change category of x from ''x'' to ''q''')
1
julia> dae = ca.DaeBuilder("m");
julia> u = ca.add(dae, "u", "input");
julia> x = ca.add(dae, "x");
julia> q = ca.add(dae, "q");
julia> ca.eq(dae, ca.der(dae, x), -x)
julia> ca.eq(dae, ca.der(dae, q), x^2)
julia> ca.set_category(dae, "q", "q")
julia> ca.x(dae), ca.q(dae)
(["x"], ["q"])
julia> ca.set_category(dae, "q", "")
julia> ca.x(dae), ca.q(dae), ca.category(dae, "q")
(["x"], String[], "")
julia> ca.set_category(dae, "u", "p")
julia> ca.u(dae), ca.p(dae), ca.causality(dae, "u"), ca.variability(dae, "u")
(String[], ["u"], "parameter", "tunable")
julia> try
           ca.set_category(dae, "x", "q")
       catch e
           println(occursin("Cannot change category of x from 'x' to 'q'", sprint(showerror, e)))
       end
true

See also: category, categories, set_all

Extra doc | Doc source | Implementation

set_causality(...)

Set the causality, if permitted.

set_causality(self, str name, str val)

The following changes are permitted:

  • For controls u (variability "continuous", causality "input"), free parameters p (variability "tunable", causality "parameter") and fixed parameters c (variability "fixed", causality "parameter"), causality can only be changed indirectly, by updating the variability

  • Add or remove an output y by setting the causality to "output" or "local", respectively

No other changes are permitted.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y", "output")
>>> dae.eq(dae.der(x), -x)
>>> dae.eq(y, 2*x)
>>> dae.set_causality("y", "local")
>>> dae.set_causality("x", "output")
>>> dae.y(), dae.causality("y")
(['x'], 'local')
>>> try:
...   dae.set_causality("x", "input")
... except Exception as e:
...   print("Cannot change causality" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y', 'output');
>> dae.eq(dae.der(x), -x); dae.eq(y, 2*x);
>> dae.set_causality('y', 'local'); dae.set_causality('x', 'output');
>> dae.y(), dae.causality('y')
x
local
>> try, dae.set_causality('x', 'input'); catch e, msg = e.message; end
>> contains(msg, 'Cannot change causality')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y", "output");
julia> ca.eq(dae, y, 2*x)
julia> ca.set_causality(dae, "y", "local")
julia> ca.set_causality(dae, "x", "output")
julia> ca.y(dae), ca.causality(dae, "y")
(["x"], "local")
julia> try
           ca.set_causality(dae, "x", "input")
       catch e
           println(occursin("Cannot change causality", sprint(showerror, e)))
       end
true

See also: causality, set_variability, set_category, set_all

Extra doc | Doc source | Implementation

set_description(...)

Get/set description.

set_description(self, str name, str val)

Free-text description of a variable, also settable with the "description" option of add.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(description="position"))
>>> dae.description("x")
'position'
>>> dae.set_description("x", "height")
>>> dae.description("x")
'height'
>> dae = DaeBuilder('m'); x = dae.add('x', struct('description', 'position'));
>> dae.description('x')
position
>> dae.set_description('x', 'height');
>> dae.description('x')
height
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("description" => "position"));
julia> ca.description(dae, "x")
"position"
julia> ca.set_description(dae, "x", "height")
julia> ca.description(dae, "x")
"height"

Extra doc | Doc source | Implementation

set_display_unit(...)

Get/set the display unit.

set_display_unit(self, str name, str val)

Display unit string of a variable; empty by default. Also settable with the "display_unit" option of add.

Extra doc | Doc source | Implementation

set_init(...)

Specify the initial equation for a variable.

set_init(self, str name, MX init_rhs)

Sets name == init_rhs as initial equation, replacing any previous one for the same variable. An empty init_rhs removes the initial equation.

Parameters:
  • name -- Model variable

  • init_rhs -- Expression in model variables, or an empty expression to remove

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> p = dae.add("p", "parameter", "tunable")
>>> dae.eq(dae.der(x), -x)
>>> dae.init_lhs(), dae.init_rhs()
([], [])
>>> dae.set_init("x", 2*p)
>>> dae.init_lhs(), dae.init_rhs()
([MX(x)], [MX((2.*p))])
>>> dae.set_init("x", MX())
>>> dae.init_lhs(), dae.init_rhs()
([], [])
>> dae = DaeBuilder('m'); x = dae.add('x'); p = dae.add('p', 'parameter', 'tunable');
>> dae.eq(dae.der(x), -x);
>> numel(dae.init_lhs()), numel(dae.init_rhs())
0
0
>> dae.set_init('x', 2*p);
>> cellfun(@disp, dae.init_lhs()), cellfun(@disp, dae.init_rhs())
x
(2.*p)
>> dae.set_init('x', MX());
>> numel(dae.init_lhs()), numel(dae.init_rhs())
0
0
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> ca.init_lhs(dae), ca.init_rhs(dae)
(MX[], MX[])
julia> ca.set_init(dae, "x", 2*p)
julia> ca.init_lhs(dae), ca.init_rhs(dae)
(MX[x], MX[(2.*p)])
julia> ca.set_init(dae, "x", ca.MX())
julia> ca.init_lhs(dae), ca.init_rhs(dae)
(MX[], MX[])

See also: init_lhs, init_rhs

Extra doc | Doc source | Implementation

set_initial(...)

Get/set the initial property.

set_initial(self, str name, str val)

The FMI initial attribute: "exact", "approx", "calculated" or "na". The default follows from causality and variability per the FMI specification; it can be given with the "initial" option of add. Other values are an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(initial="approx"))
>>> p = dae.add("p", "parameter", "tunable")
>>> u = dae.add("u", "input")
>>> dae.initial("x"), dae.initial("p"), dae.initial("u")
('approx', 'exact', 'na')
>>> dae.set_initial("x", "exact")
>>> dae.initial("x")
'exact'
>> dae = DaeBuilder('m'); x = dae.add('x', struct('initial', 'approx'));
>> p = dae.add('p', 'parameter', 'tunable'); u = dae.add('u', 'input');
>> dae.initial('x'), dae.initial('p'), dae.initial('u')
approx
exact
na
>> dae.set_initial('x', 'exact');
>> dae.initial('x')
exact
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("initial" => "approx"));
julia> p = ca.add(dae, "p", "parameter", "tunable");
julia> u = ca.add(dae, "u", "input");
julia> ca.initial(dae, "x"), ca.initial(dae, "p"), ca.initial(dae, "u")
("approx", "exact", "na")
julia> dae.set_initial("x", "exact")
julia> ca.initial(dae, "x")
"exact"

Extra doc | Doc source | Implementation

set_max(...)

Set the upper bound for several variables.

set_max(self, [str] name, [float] val)
set_max(self, str name, float val)

Set the upper bound, single variable.

Doc source | Implementation

set_min(...)

Set the lower bound for several variables.

set_min(self, [str] name, [float] val)
set_min(self, str name, float val)

Set the lower bound, single variable.

Doc source | Implementation

set_nominal(...)

Set the nominal value for several variables.

set_nominal(self, [str] name, [float] val)
set_nominal(self, str name, float val)

Set the nominal value, single variable.

Doc source | Implementation

set_start(...)

Set the start attribute for several variables.

set_start(self, [str] name, [float] val)
set_start(self, str name, [float] val)
set_start(self, str name, float val)

val holds either one value per variable (broadcast over the elements) or one value per element of all variables concatenated; any other length is an error.

Overload: set_start(self, str name, [float] val)

Set the start attribute, vector argument (length numel, or 1 to broadcast)

Overload: set_start(self, str name, float val)

Set the start attribute, single variable (all elements for a vector- valued variable)

Extra doc | Doc source | Implementation

set_start_time(...)

Set the start time of the default experiment.

set_start_time(self, float val)

Doc source | Implementation

set_step_size(...)

Set the step size of the default experiment.

set_step_size(self, float val)

Doc source | Implementation

set_stop_time(...)

Set the stop time of the default experiment.

set_stop_time(self, float val)

Doc source | Implementation

set_tolerance(...)

Set the tolerance of the default experiment.

set_tolerance(self, float val)

Doc source | Implementation

set_type(...)

Get/set the type.

set_type(self, str name, str val)

The variable type in FMI 3 naming ("Float64", "Float32", "Int32", "Boolean", "String", ...) or, with fmi_version 2, in FMI 2 naming ("real", "integer", "boolean", "string", "enum"). Setting accepts FMI 3 names; other versions or names are an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> n = dae.add("n", dict(type="Int32"))
>>> dae.type("x"), dae.type("x", 2), dae.type("n"), dae.type("n", 2)
('Float64', 'real', 'Int32', 'integer')
>>> dae.set_type("x", "Float32")
>>> dae.type("x")
'Float32'
>>> try:
...   dae.set_type("x", "bogus")
... except Exception as e:
...   print("No such enum" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); n = dae.add('n', struct('type', 'Int32'));
>> dae.type('x'), dae.type('x', 2), dae.type('n'), dae.type('n', 2)
Float64
real
Int32
integer
>> dae.set_type('x', 'Float32');
>> dae.type('x')
Float32
>> try, dae.set_type('x', 'bogus'); catch e, disp(contains(e.message, 'No such enum')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> n = ca.add(dae, "n", Dict("type" => "Int32"));
julia> ca.type(dae, "x"), ca.type(dae, "x", 2), ca.type(dae, "n"), ca.type(dae, "n", 2)
("Float64", "real", "Int32", "integer")
julia> ca.set_type(dae, "x", "Float32")
julia> ca.type(dae, "x")
"Float32"
julia> try
           ca.set_type(dae, "x", "bogus")
       catch e
           println(occursin("No such enum", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

set_unit(...)

Get/set the unit.

set_unit(self, str name, str val)

Unit string of a variable, e.g. "m/s"; empty by default. Also settable with the "unit" option of add.

>>> dae = DaeBuilder("m")
>>> v = dae.add("v", dict(unit="m/s"))
>>> dae.unit("v")
'm/s'
>>> dae.set_unit("v", "km/h")
>>> dae.unit("v")
'km/h'
>> dae = DaeBuilder('m'); v = dae.add('v', struct('unit', 'm/s'));
>> dae.unit('v')
m/s
>> dae.set_unit('v', 'km/h');
>> dae.unit('v')
km/h
julia> dae = ca.DaeBuilder("m");
julia> v = ca.add(dae, "v", Dict("unit" => "m/s"));
julia> ca.unit(dae, "v")
"m/s"
julia> ca.set_unit(dae, "v", "km/h")
julia> ca.unit(dae, "v")
"km/h"

Extra doc | Doc source | Implementation

set_value_reference(...)

Get/set value reference.

set_value_reference(self, str name, int val)

The FMI value reference of a variable: imported from the model description, or by default the index of the variable in the instance.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> dae.value_reference("x"), dae.value_reference("y")
(1, 2)
>>> dae.set_value_reference("x", 100)
>>> dae.value_reference("x")
100
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> dae.value_reference('x'), dae.value_reference('y')
1
2
>> dae.set_value_reference('x', 100);
>> dae.value_reference('x')
100
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> ca.value_reference(dae, "x"), ca.value_reference(dae, "y")
(1, 2)
julia> ca.set_value_reference(dae, "x", 100)
julia> ca.value_reference(dae, "x")
100

Extra doc | Doc source | Implementation

set_variability(...)

Set the variability, if permitted.

set_variability(self, str name, str val)

For controls u (variability "continuous", causality "input"), free parameters p (variability "tunable", causality "parameter") and fixed parameters c (variability "fixed", causality "parameter"), update variability in order to change the category. Causality is updated accordingly.

Other changes are not permitted.

>>> dae = DaeBuilder("m")
>>> u = dae.add("u", "input")
>>> x = dae.add("x")
>>> dae.eq(dae.der(x), -u*x)
>>> dae.set_variability("u", "fixed")
>>> dae.u(), dae.c(), dae.causality("u")
([], ['u'], 'parameter')
>>> dae.set_variability("u", "tunable")
>>> dae.p(), dae.causality("u")
(['u'], 'parameter')
>>> dae.set_variability("u", "continuous")
>>> dae.u(), dae.causality("u")
(['u'], 'input')
>>> try:
...   dae.set_variability("x", "discrete")
... except Exception as e:
...   print("Cannot change variability" in str(e))
True
>> dae = DaeBuilder('m'); u = dae.add('u', 'input'); x = dae.add('x');
>> dae.eq(dae.der(x), -u*x);
>> dae.set_variability('u', 'fixed');
>> isempty(dae.u()), dae.c(), dae.causality('u')
1
u
parameter
>> dae.set_variability('u', 'tunable');
>> dae.p(), dae.causality('u')
u
parameter
>> dae.set_variability('u', 'continuous');
>> dae.u(), dae.causality('u')
u
input
>> try, dae.set_variability('x', 'discrete'); catch e, msg = e.message; end
>> contains(msg, 'Cannot change variability')
1
julia> dae = ca.DaeBuilder("m");
julia> u = ca.add(dae, "u", "input");
julia> x = ca.add(dae, "x");
julia> ca.set_variability(dae, "u", "fixed")
julia> ca.u(dae), ca.c(dae), ca.causality(dae, "u")
(String[], ["u"], "parameter")
julia> ca.set_variability(dae, "u", "tunable")
julia> ca.p(dae), ca.causality(dae, "u")
(["u"], "parameter")
julia> ca.set_variability(dae, "u", "continuous")
julia> ca.u(dae), ca.causality(dae, "u")
(["u"], "input")
julia> try
           ca.set_variability(dae, "x", "discrete")
       catch e
           println(occursin("Cannot change variability", sprint(showerror, e)))
       end
true

See also: variability, set_causality, set_category

Extra doc | Doc source | Implementation

set_y(...)

[DEPRECATED] Replaced with set_all("y", name)

set_y(self, [str] name)

Doc source | Implementation

sort(...)

Sort dependent parameters.

sort(self, str cat)

Reorders an acyclic category ("c", "d" or "w") so that every variable comes after the ones it depends on, using a block triangular (Dulmage-Mendelsohn) decomposition of the dependency pattern. Vector-valued variables are treated as a unit. Other categories are an error.

Parameters:

cat -- "c", "d" or "w"

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w1 = dae.add("w1")
>>> w2 = dae.add("w2")
>>> dae.eq(w2, w1**2)
>>> dae.eq(w1, 2*x)
>>> dae.eq(dae.der(x), -w2)
>>> dae.w(), dae.wdef()
(['w2', 'w1', 'der(x)'], [MX(sq(w1)), MX((2.*x)), MX((-w2))])
>>> dae.sort("w")
>>> dae.w(), dae.wdef()
(['w1', 'w2', 'der(x)'], [MX((2.*x)), MX(sq(w1)), MX((-w2))])
>> dae = DaeBuilder('m'); x = dae.add('x'); w1 = dae.add('w1'); w2 = dae.add('w2');
>> dae.eq(w2, w1^2); dae.eq(w1, 2*x); dae.eq(dae.der(x), -w2);
>> disp(dae.w()), cellfun(@disp, dae.wdef())
w2
w1
der(x)
sq(w1)
(2.*x)
(-w2)
>> dae.sort('w');
>> disp(dae.w()), cellfun(@disp, dae.wdef())
w1
w2
der(x)
(2.*x)
sq(w1)
(-w2)
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w1 = ca.add(dae, "w1");
julia> w2 = ca.add(dae, "w2");
julia> ca.eq(dae, w2, w1^2)
julia> ca.eq(dae, w1, 2*x)
julia> ca.eq(dae, ca.der(dae, x), -w2)
julia> ca.w(dae), ca.wdef(dae)
(["w2", "w1", "der(x)"], MX[sq(w1), (2.*x), (-w2)])
julia> ca.sort(dae, "w")
julia> ca.w(dae), ca.wdef(dae)
(["w1", "w2", "der(x)"], MX[(2.*x), sq(w1), (-w2)])

See also: eliminate, reorder

Extra doc | Doc source | Implementation

start(...)

Get the start attribute for several variables, concatenated.

start(self, [str] name) -> [float]
start(self, str name) -> [float]

Get the start attribute, single variable.

The start values of a variable as a list with numel entries, also for scalars.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(start=1))
>>> v = dae.add("v", dict(dimension=[2]))
>>> dae.start("x"), dae.start("v"), dae.start(["x", "v"])
([1.0], [0.0, 0.0], [1.0, 0.0, 0.0])
>>> dae.set_start("v", [3, 4])
>>> dae.set_start(["x", "v"], [0, 1])
>>> dae.start(["x", "v"])
[0.0, 1.0, 1.0]
>>> dae.set_start(["x", "v"], [1, 2, 3])
>>> dae.start(["x", "v"])
[1.0, 2.0, 3.0]
>>> try:
...   dae.set_start("v", [1, 2, 3])
... except Exception as e:
...   print("expected number of elements (2) or number of variables (1)" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x', struct('start', 1));
>> v = dae.add('v', struct('dimension', 2));
>> dae.start('x'), dae.start('v'), dae.start({'x', 'v'})
1
0 0
1 0 0
>> dae.set_start('v', [3 4]); dae.set_start({'x', 'v'}, [0 1]);
>> dae.start({'x', 'v'})
0 1 1
>> dae.set_start({'x', 'v'}, [1 2 3]);
>> dae.start({'x', 'v'})
1 2 3
>> try, dae.set_start('v', [1 2 3]); catch e, msg = e.message; end
>> contains(msg, 'expected number of elements (2) or number of variables (1)')
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("start" => 1));
julia> v = ca.add(dae, "v", Dict("dimension" => [2]));
julia> ca.start(dae, "x"), ca.start(dae, "v"), ca.start(dae, ["x", "v"])
([1.0], [0.0, 0.0], [1.0, 0.0, 0.0])
julia> ca.set_start(dae, "v", [3, 4])
julia> ca.set_start(dae, ["x", "v"], [0, 1])
julia> ca.start(dae, ["x", "v"])
3-element Vector{Float64}:
 0.0
 1.0
 1.0
julia> ca.set_start(dae, ["x", "v"], [1, 2, 3])
julia> ca.start(dae, ["x", "v"])
3-element Vector{Float64}:
 1.0
 2.0
 3.0
julia> try
           ca.set_start(dae, "v", [1, 2, 3])
       catch e
           msg = "expected number of elements (2) or number of variables (1)"
           println(occursin(msg, sprint(showerror, e)))
       end
true

See also: set_start, get

Doc source | Implementation | Extra doc

start_time(...)

Get the start time.

start_time(self) -> float

Start time of the default experiment: imported from the model description or set with set_start_time; nan when unknown.

>>> dae = DaeBuilder("m")
>>> dae.start_time(), dae.stop_time(), dae.tolerance(), dae.step_size()
(nan, nan, nan, nan)
>>> dae.set_start_time(0)
>>> dae.set_stop_time(10)
>>> dae.set_tolerance(1e-6)
>>> dae.set_step_size(0.01)
>>> dae.start_time(), dae.stop_time(), dae.tolerance(), dae.step_size()
(0.0, 10.0, 1e-06, 0.01)
>> dae = DaeBuilder('m');
>> fprintf('%g %g %g %g\n', dae.start_time, dae.stop_time, dae.tolerance, dae.step_size)
NaN NaN NaN NaN
>> dae.set_start_time(0); dae.set_stop_time(10);
>> dae.set_tolerance(1e-6); dae.set_step_size(0.01);
>> fprintf('%g %g %g %g\n', dae.start_time, dae.stop_time, dae.tolerance, dae.step_size)
0 10 1e-06 0.01
julia> dae = ca.DaeBuilder("m");
julia> ca.start_time(dae), ca.stop_time(dae), ca.tolerance(dae), ca.step_size(dae)
(NaN, NaN, NaN, NaN)
julia> ca.set_start_time(dae, 0)
julia> ca.set_stop_time(dae, 10)
julia> ca.set_tolerance(dae, 1e-6)
julia> ca.set_step_size(dae, 0.01)
julia> ca.start_time(dae), ca.stop_time(dae), ca.tolerance(dae), ca.step_size(dae)
(0.0, 10.0, 1.0e-6, 0.01)

See also: set_start_time, stop_time

Extra doc | Doc source | Implementation

step_size(...)

Get the step size of the default experiment, nan when unknown.

step_size(self) -> float

Doc source | Implementation

stop_time(...)

Get the stop time of the default experiment, nan when unknown.

stop_time(self) -> float

Doc source | Implementation

str(...)

Get string representation.

str(self, bool more) -> str

Doc source | Implementation

symbolic(...)

Symbolic DAE instance?

symbolic(self) -> bool

True for a symbolically constructed model (or a symbolic model description), false for an imported standard FMU whose equations live in a binary.

>>> DaeBuilder("m").symbolic()
True
julia> ca.symbolic(ca.DaeBuilder("m"))
true

See also: load_fmi_description, oracle

Extra doc | Doc source | Implementation

t_new(...)

Independent variable (usually time)

t_new(self) -> [str]

Name of the independent variable as a list: empty when none has been declared, otherwise a single name. Equivalent to all("t").

See also: time, has_t

Extra doc | Doc source | Implementation

tear(...)

Identify iteration variables and residual equations using naming convention.

tear(self)

Variables named res__<iv> are interpreted as residual equations with iteration variable <iv> (optionally followed by __<hold> markers). The iteration variables are removed from z and u and appended to z, so that z and alg match up. Hold markers are not implemented and only produce a warning.

See also: z, sort

Extra doc | Doc source | Implementation

time(...)

Expression for independent variable (usually time)

time(self) -> MX

Only available when an independent variable has been declared explicitly with add(name, "independent") or imported from the model description; otherwise an error is raised. Without an explicit declaration a hidden variable named "time" exists in all() but is not categorized as t.

>>> dae = DaeBuilder("m")
>>> t = dae.add("t", "independent")
>>> x = dae.add("x")
>>> dae.time(), dae.has_t(), dae.t_new()
(MX(t), True, ['t'])
>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> dae.all(), dae.has_t(), dae.t_new()
(['time', 'x'], False, [])
>>> try:
...   dae.time()
... except Exception as e:
...   print("No explicit time variable" in str(e))
True
>> dae = DaeBuilder('m'); t = dae.add('t', 'independent'); x = dae.add('x');
>> dae.time(), dae.has_t(), dae.t_new()
t
1
t
>> dae = DaeBuilder('m'); x = dae.add('x');
>> dae.all(), dae.has_t(), isempty(dae.t_new())
time
x
0
1
>> try, dae.time(); catch e, disp(contains(e.message, 'No explicit time variable')); end
1
julia> dae = ca.DaeBuilder("m");
julia> t = ca.add(dae, "t", "independent");
julia> x = ca.add(dae, "x");
julia> dae.time(), ca.has_t(dae), ca.t_new(dae)
(t, true, ["t"])
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> ca.all(dae), ca.has_t(dae), ca.t_new(dae)
(["time", "x"], false, String[])
julia> try
           dae.time()
       catch e
           println(occursin("No explicit time variable", sprint(showerror, e)))
       end
true

See also: has_t, t_new

Extra doc | Doc source | Implementation

tolerance(...)

Get the tolerance of the default experiment, nan when unknown.

tolerance(self) -> float

Doc source | Implementation

transition(...)

Construct an event transition function, default naming.

transition(self) -> Function
transition(self, str fname) -> Function
transition(self, str fname, int index) -> Function

The function is named <name>_transition.

Overload: transition(self, str fname)

Construct a function describing transition at any events.

Builds the event function expected by the "transition" option of integrator, with an event index as first input: for a single event the function of transition(fname, 0) with a dummy index input, for several events a switch over the per-event functions. Without when equations a null Function is returned.

>>> dae = DaeBuilder("ball")
>>> h = dae.add("h", dict(start=5))
>>> v = dae.add("v", dict(start=0))
>>> dae.eq(dae.der(h), v)
>>> dae.eq(dae.der(v), -9.81)
>>> dae.transition().is_null()
True
>>> dae.when(h < 0, [dae.reinit("v", -0.8*v)])
>>> dae.transition("tr")
Function(tr:(index[],t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction)
>> dae = DaeBuilder('ball');
>> h = dae.add('h', struct('start', 5)); v = dae.add('v', struct('start', 0));
>> dae.eq(dae.der(h), v); dae.eq(dae.der(v), -9.81);
>> dae.transition().is_null()
1
>> dae.when(h < 0, {dae.reinit('v', -0.8*v)});
>> dae.transition('tr')
tr:(index[],t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction
julia> dae = ca.DaeBuilder("ball");
julia> h = ca.add(dae, "h", Dict("start" => 5));
julia> v = ca.add(dae, "v", Dict("start" => 0));
julia> ca.eq(dae, ca.der(dae, h), v)
julia> ca.eq(dae, ca.der(dae, v), -9.81)
julia> ca.is_null(ca.transition(dae))
true
julia> ca.when(dae, h < 0, [ca.reinit(dae, "v", -0.8*v)])
julia> ca.transition(dae, "tr")
Function(tr:(index[],t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction)

See also: when, create

Overload: transition(self, str fname, int index)

Construct a function describing transition at a specific events.

Builds a Function with inputs t, x, z, p, u and outputs post_x, post_z: the states after the event with index index (0-based, in the order the when equations were added). Dependent variables are substituted out.

Parameters:
  • fname -- Function name

  • index -- Event index; out of range is an error

>>> dae = DaeBuilder("ball")
>>> h = dae.add("h", dict(start=5))
>>> v = dae.add("v", dict(start=0))
>>> dae.eq(dae.der(h), v)
>>> dae.eq(dae.der(v), -9.81)
>>> dae.when(h < 0, [dae.reinit("v", -0.8*v)])
>>> T = dae.transition("tr", 0)
>>> T
Function(tr:(t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction)
>>> T(0, [-0.1, -3], [], [], [])
(DM([-0.1, 2.4]), DM(0x1))
>>> try:
...   dae.transition("tr", 1)
... except Exception as e:
...   print("Illegal event index" in str(e))
True
>> dae = DaeBuilder('ball');
>> h = dae.add('h', struct('start', 5)); v = dae.add('v', struct('start', 0));
>> dae.eq(dae.der(h), v); dae.eq(dae.der(v), -9.81);
>> dae.when(h < 0, {dae.reinit('v', -0.8*v)});
>> T = dae.transition('tr', 0); disp(T)
tr:(t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction
>> [post_x, post_z] = T(0, [-0.1; -3], [], [], []); disp(post_x), disp(post_z)
[-0.1, 2.4]
0x1
>> try, dae.transition('tr', 1); catch e, msg = e.message; end
>> contains(msg, 'Illegal event index')
1
julia> dae = ca.DaeBuilder("ball");
julia> h = ca.add(dae, "h", Dict("start" => 5));
julia> v = ca.add(dae, "v", Dict("start" => 0));
julia> ca.eq(dae, ca.der(dae, h), v)
julia> ca.eq(dae, ca.der(dae, v), -9.81)
julia> ca.when(dae, h < 0, [ca.reinit(dae, "v", -0.8*v)])
julia> T = ca.transition(dae, "tr", 0)
Function(tr:(t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction)
julia> T(0, [-0.1, -3], [], [], [])
([-0.1, 2.4], 0x1)
julia> try
           ca.transition(dae, "tr", 1)
       catch e
           println(occursin("Illegal event index", sprint(showerror, e)))
       end
true

See also: when, create

Extra doc | Doc source | Implementation

type(...)

Get/set the type.

type(self, str name, int fmi_version) -> str

The variable type in FMI 3 naming ("Float64", "Float32", "Int32", "Boolean", "String", ...) or, with fmi_version 2, in FMI 2 naming ("real", "integer", "boolean", "string", "enum"). Setting accepts FMI 3 names; other versions or names are an error.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> n = dae.add("n", dict(type="Int32"))
>>> dae.type("x"), dae.type("x", 2), dae.type("n"), dae.type("n", 2)
('Float64', 'real', 'Int32', 'integer')
>>> dae.set_type("x", "Float32")
>>> dae.type("x")
'Float32'
>>> try:
...   dae.set_type("x", "bogus")
... except Exception as e:
...   print("No such enum" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x'); n = dae.add('n', struct('type', 'Int32'));
>> dae.type('x'), dae.type('x', 2), dae.type('n'), dae.type('n', 2)
Float64
real
Int32
integer
>> dae.set_type('x', 'Float32');
>> dae.type('x')
Float32
>> try, dae.set_type('x', 'bogus'); catch e, disp(contains(e.message, 'No such enum')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> n = ca.add(dae, "n", Dict("type" => "Int32"));
julia> ca.type(dae, "x"), ca.type(dae, "x", 2), ca.type(dae, "n"), ca.type(dae, "n", 2)
("Float64", "real", "Int32", "integer")
julia> ca.set_type(dae, "x", "Float32")
julia> ca.type(dae, "x")
"Float32"
julia> try
           ca.set_type(dae, "x", "bogus")
       catch e
           println(occursin("No such enum", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

type_name(...)

Readable name of the class.

type_name(self) -> str

Doc source | Implementation

u(...)

Free controls.

u(self) -> [str]

Names of the variables of category u (causality "input"), in category order. Equivalent to all("u").

See also: p, nu, set_category

Extra doc | Doc source | Implementation

unit(...)

Get/set the unit.

unit(self, str name) -> str

Unit string of a variable, e.g. "m/s"; empty by default. Also settable with the "unit" option of add.

>>> dae = DaeBuilder("m")
>>> v = dae.add("v", dict(unit="m/s"))
>>> dae.unit("v")
'm/s'
>>> dae.set_unit("v", "km/h")
>>> dae.unit("v")
'km/h'
>> dae = DaeBuilder('m'); v = dae.add('v', struct('unit', 'm/s'));
>> dae.unit('v')
m/s
>> dae.set_unit('v', 'km/h');
>> dae.unit('v')
km/h
julia> dae = ca.DaeBuilder("m");
julia> v = ca.add(dae, "v", Dict("unit" => "m/s"));
julia> ca.unit(dae, "v")
"m/s"
julia> ca.set_unit(dae, "v", "km/h")
julia> ca.unit(dae, "v")
"km/h"

Extra doc | Doc source | Implementation

value_reference(...)

Get/set value reference.

value_reference(self, str name) -> int

The FMI value reference of a variable: imported from the model description, or by default the index of the variable in the instance.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> dae.value_reference("x"), dae.value_reference("y")
(1, 2)
>>> dae.set_value_reference("x", 100)
>>> dae.value_reference("x")
100
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> dae.value_reference('x'), dae.value_reference('y')
1
2
>> dae.set_value_reference('x', 100);
>> dae.value_reference('x')
100
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> ca.value_reference(dae, "x"), ca.value_reference(dae, "y")
(1, 2)
julia> ca.set_value_reference(dae, "x", 100)
julia> ca.value_reference(dae, "x")
100

Extra doc | Doc source | Implementation

var(...)

Get variable expression by name.

var(self, str name) -> MX

The symbolic expression of a model variable: a dense column vector with numel entries, named after the variable. An unknown name is an error. Also available via the call operator.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", dict(dimension=[2]))
>>> dae.var("x"), dae.var("x").shape
(MX(x), (2, 1))
>>> dae.has("x"), dae.has("y")
(True, False)
>>> try:
...   dae.var("y")
... except Exception as e:
...   print("No such variable" in str(e))
True
>> dae = DaeBuilder('m'); x = dae.add('x', struct('dimension', 2));
>> dae.var('x'), size(dae.var('x'))
x
2 1
>> dae.has('x'), dae.has('y')
1
0
>> try, dae.var('y'); catch e, disp(contains(e.message, 'No such variable')); end
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", Dict("dimension" => [2]));
julia> ca.var(dae, "x"), size(ca.var(dae, "x"))
(x, (2, 1))
julia> ca.has(dae, "x"), ca.has(dae, "y")
(true, false)
julia> try
           ca.var(dae, "y")
       catch e
           println(occursin("No such variable", sprint(showerror, e)))
       end
true

See also: has, all, inputs

Extra doc | Doc source | Implementation

variability(...)

Get the variability.

variability(self, str name) -> str

One of "constant", "fixed", "tunable", "discrete", "continuous".

See also: set_variability, causality

Extra doc | Doc source | Implementation

w(...)

Dependent variables.

w(self) -> [str]

Names of the variables of category w, in category order. Equivalent to all("w"). A variable becomes dependent when it is the left-hand side of an explicit equation eq(v, expr); the derivative variables der(x) of the states are dependent variables too.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> w = dae.add("w")
>>> dae.eq(w, sin(x))
>>> dae.eq(dae.der(x), -w)
>>> dae.w()
['w', 'der(x)']
>>> dae.wdef()
[MX(sin(x)), MX((-w))]
>> dae = DaeBuilder('m'); x = dae.add('x'); w = dae.add('w');
>> dae.eq(w, sin(x)); dae.eq(dae.der(x), -w);
>> dae.w()
w
der(x)
>> cellfun(@disp, dae.wdef())
sin(x)
(-w)
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> w = ca.add(dae, "w");
julia> ca.eq(dae, w, sin(x))
julia> ca.eq(dae, ca.der(dae, x), -w)
julia> ca.w(dae)
2-element Vector{String}:
 "w"
 "der(x)"
julia> ca.wdef(dae)
2-element Vector{MX}:
 MX(sin(x))
 MX((-w))

See also: wdef, dependent_fun, eliminate, nw

Extra doc | Doc source | Implementation

wdef(...)

Dependent variables and corresponding definitions.

wdef(self) -> [MX]

The binding expressions of the dependent variables, one per entry of w(). Interdependencies are allowed but must be non-cyclic (see sort). Equivalent to outputs("wdef").

See also: w, ddef, sort, eliminate

Extra doc | Doc source | Implementation

when(...)

Add when equations.

when(self, MX cond, [str] eqs, dict opts)

Adds an event: whenever the zero-crossing function of cond becomes negative, the assignments in eqs are executed. The condition must be a strict inequality a < b (or a > b); it is stored as the zero- crossing function a - b in outputs("zero"). The event transition can be obtained with transition.

Parameters:
  • cond -- Strict inequality between model expressions; <= or any other expression is an error

  • eqs -- Names returned by reinit or assign; may be empty

  • opts -- Must be empty

>>> dae = DaeBuilder("ball")
>>> h = dae.add("h", dict(start=5))
>>> v = dae.add("v", dict(start=0))
>>> dae.eq(dae.der(h), v)
>>> dae.eq(dae.der(v), -9.81)
>>> dae.when(h < 0, [dae.reinit("v", -0.8*v)])
>>> dae.nzero(), dae.outputs("zero")
(1, [MX(h)])
>>> T = dae.transition()
>>> T
Function(ball_transition:(index[],t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction)
>>> T(0, 0, [-0.1, -3], [], [], [])
(DM([-0.1, 2.4]), DM(0x1))
>>> try:
...   dae.when(h <= 0, [])
... except Exception as e:
...   print("Only strict inequality" in str(e))
True
>> dae = DaeBuilder('ball');
>> h = dae.add('h', struct('start', 5)); v = dae.add('v', struct('start', 0));
>> dae.eq(dae.der(h), v); dae.eq(dae.der(v), -9.81);
>> dae.when(h < 0, {dae.reinit('v', -0.8*v)});
>> disp(dae.nzero()), cellfun(@disp, dae.outputs('zero'))
1
h
>> T = dae.transition(); disp(T)
ball_transition:(index[],t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction
>> [post_x, post_z] = T(0, 0, [-0.1; -3], [], [], []); disp(post_x), disp(post_z)
[-0.1, 2.4]
0x1
>> try, dae.when(h <= 0, {}); catch e, msg = e.message; end
>> contains(msg, 'Only strict inequality')
1
julia> dae = ca.DaeBuilder("ball");
julia> h = ca.add(dae, "h", Dict("start" => 5));
julia> v = ca.add(dae, "v", Dict("start" => 0));
julia> ca.eq(dae, ca.der(dae, h), v)
julia> ca.eq(dae, ca.der(dae, v), -9.81)
julia> ca.when(dae, h < 0, [ca.reinit(dae, "v", -0.8*v)])
julia> ca.nzero(dae), ca.outputs(dae, "zero")
(1, MX[h])
julia> T = ca.transition(dae)
Function(ball_transition:(index[],t[0],x[2],z[0],p[0],u[0])->(post_x[2],post_z[0]) MXFunction)
julia> T(0, 0, [-0.1, -3], [], [], [])
([-0.1, 2.4], 0x1)
julia> try
           ca.when(dae, h <= 0, String[])
       catch e
           println(occursin("Only strict inequality", sprint(showerror, e)))
       end
true

See also: reinit, assign, transition, nzero

Extra doc | Doc source | Implementation

x(...)

Differential states.

x(self) -> [str]

Names of the variables of category x, in category order. Equivalent to all("x"). A continuous variable becomes a differential state once its time derivative is given a defining equation with eq; it is an algebraic variable z before that.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x")
>>> y = dae.add("y")
>>> dae.x(), dae.z()
([], ['x', 'y'])
>>> dae.eq(dae.der(x), -y)
>>> dae.x(), dae.z(), dae.nx()
(['x'], ['y'], 1)
>> dae = DaeBuilder('m'); x = dae.add('x'); y = dae.add('y');
>> isempty(dae.x()), dae.z()
1
x
y
>> dae.eq(dae.der(x), -y);
>> dae.x(), dae.z(), dae.nx()
x
y
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x");
julia> y = ca.add(dae, "y");
julia> ca.x(dae), ca.z(dae)
(String[], ["x", "y"])
julia> ca.eq(dae, ca.der(dae, x), -y)
julia> ca.x(dae), ca.z(dae), ca.nx(dae)
(["x"], ["y"], 1)

See also: z, q, nx, all, inputs

Extra doc | Doc source | Implementation

y(...)

Outputs.

y(self) -> [str]

Names of the variables with causality "output", in category order. Equivalent to all("y"). Outputs are also members of another category (x, w, z, ...); outputs("y") gives their expressions.

>>> dae = DaeBuilder("m")
>>> x = dae.add("x", "output")
>>> y = dae.add("y", "output")
>>> w = dae.add("w")
>>> dae.eq(dae.der(x), -w)
>>> dae.eq(w, x**2)
>>> dae.eq(y, 2*x)
>>> dae.y(), dae.x(), dae.w()
(['x', 'y'], ['x'], ['der(x)', 'w', 'y'])
>>> dae.outputs("y")
[MX(x), MX(y)]
>>> dae.set_causality("y", "local")
>>> dae.y(), dae.ny()
(['x'], 1)
>> dae = DaeBuilder('m'); x = dae.add('x', 'output'); y = dae.add('y', 'output');
>> w = dae.add('w');
>> dae.eq(dae.der(x), -w); dae.eq(w, x^2); dae.eq(y, 2*x);
>> dae.y()
x
y
>> dae.x(), dae.w()
x
der(x)
w
y
>> cellfun(@disp, dae.outputs('y'))
x
y
>> dae.set_causality('y', 'local');
>> dae.y(), dae.ny()
x
1
julia> dae = ca.DaeBuilder("m");
julia> x = ca.add(dae, "x", "output");
julia> y = ca.add(dae, "y", "output");
julia> w = ca.add(dae, "w");
julia> ca.eq(dae, ca.der(dae, x), -w)
julia> ca.eq(dae, w, x^2)
julia> ca.eq(dae, y, 2*x)
julia> ca.y(dae), ca.x(dae), ca.w(dae)
(["x", "y"], ["x"], ["der(x)", "w", "y"])
julia> ca.outputs(dae, "y")
2-element Vector{MX}:
 MX(x)
 MX(y)
julia> ca.set_causality(dae, "y", "local")
julia> ca.y(dae), ca.ny(dae)
(["x"], 1)

See also: set_causality, set_all, ny, outputs

Extra doc | Doc source | Implementation

ydef(...)

[DEPRECATED] Replaced with outputs("y")

ydef(self) -> [MX]

Doc source | Implementation

z(...)

Algebraic variables.

z(self) -> [str]

Names of the variables of category z, in category order. Equivalent to all("z"). Every continuous local or output variable starts in this category and leaves it when it gets a defining equation (w) or an equation for its derivative (x).

See also: x, w, nz, eq

Extra doc | Doc source | Implementation

zero(...)

[DEPRECATED] Replaced with outputs("zero")

zero(self) -> [MX]

Doc source | Implementation

Callback

class Callback(...)

User-defined Function implemented by subclassing.

A Callback is a Function whose numerical evaluation (and optionally its derivatives) is written by the user in Python, MATLAB or C++ by overriding virtual methods. It can be called like any Function, embedded in MX graphs, mapped, and used inside NLPs and integrators.

A subclass must call the base constructor and then construct(name, opts) from its own constructor; construct() queries the virtual methods below (get_n_in, get_n_out, get_sparsity_in/out, get_name_in/out) and calls init() and finalize(), so all data those methods need must be set before construct() runs. Only eval() is mandatory. Defaults: one scalar input "i0" and one scalar output "o0".

Object lifetime: the Function side holds a raw pointer to the user object and does not own it. The user must keep the Callback object alive (in Python: keep a reference) for as long as any Function, expression or solver that uses it exists; otherwise evaluation fails with "Callback object has been deleted". The same holds for objects returned from get_jacobian/get_forward/get_reverse. Callback objects cannot be copied.

Derivatives: by default a Callback is not differentiable, so jacobian(), forward/reverse sweeps and NLP solvers that need gradients fail with "Derivatives cannot be calculated". Either override has_jacobian/get_jacobian, has_forward/get_forward or has_reverse/get_reverse, or pass the option "enable_fd": True to construct() to use finite differences ("fd_method": "central" (default), "forward", "backward" or "smoothing"; "fd_options" such as {"h": 1e-6} tune the step). A user-provided Jacobian is itself differentiated with finite differences only when it is a Callback with "enable_fd"; a Function built from SX/MX gives exact second derivatives.

>>> class MyCallback(Callback):
...   def __init__(self, name, d, opts={}):
...     Callback.__init__(self)
...     self.d = d
...     self.construct(name, opts)
...   def get_n_in(self): return 1
...   def get_n_out(self): return 1
...   def eval(self, arg):
...     return [sin(self.d*arg[0])]
>>> f = MyCallback("f", 0.5)
>>> f
Callback(f:(i0)->(o0) CallbackInternal)
>>> f(2)
DM(0.8415)
>>> x = MX.sym("x")
>>> f(x)
MX(f(x){0})
>>> try:
...   jacobian(f(x), x)
... except Exception as e:
...   print("Derivatives cannot be calculated for f" in str(e))
True
>>> f = MyCallback("f", 0.5, {"enable_fd": True})
>>> J = Function("J", [x], [jacobian(f(x), x)])
>>> J(2)
DM(0.2702)
>> c = {'classdef MyCallback < casadi.Callback', 'properties', 'd', 'end', 'methods'};
>> c = [c, {'function self = MyCallback(name, d, varargin)'}];
>> c = [c, {'self@casadi.Callback(); self.d = d; construct(self, name, varargin{:});'}];
>> c = [c, {'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {sin(self.d*arg{1})};'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'MyCallback.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = MyCallback('f', 0.5); disp(f)
f:(i0)->(o0) CallbackInternal
>> f(2)
0.8415
>> x = MX.sym('x'); disp(f(x))
f(x){0}
>> try, jacobian(f(x), x); catch e, disp(contains(e.message, 'Derivatives cannot be')); end
1
>> f = MyCallback('f', 0.5, struct('enable_fd', true));
>> J = Function('J', {x}, {jacobian(f(x), x)}); J(2)
0.2702
>> rmpath(d); rmdir(d, 's');
julia> struct MyCallback <: ca.Callback
           d::Float64
       end
julia> ca.get_n_in(::MyCallback) = 1
julia> ca.get_n_out(::MyCallback) = 1
julia> ca.eval_(cb::MyCallback, arg) = [sin(cb.d * arg[1])]
julia> f = ca.callback(MyCallback(0.5), "f");
julia> ca.Function(f)
Function(f:(i0)->(o0) CallbackInternal)
julia> f(2)
DM(0.8415)
julia> x = ca.MX.sym("x");
julia> f(x)
MX(f(x){0})
julia> try
           ca.jacobian(f(x), x)
       catch e
           println(occursin("Derivatives cannot be calculated for f", sprint(showerror, e)))
       end
true
julia> f = ca.callback(MyCallback(0.5), "f", Dict("enable_fd" => true));
julia> J = ca.Function("J", [x], [ca.jacobian(f(x), x)]);
julia> J(2)
DM(0.2702)

The callback object must outlive every use of the Function:

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
>>> x = MX.sym("x")
>>> f = Sq("f")
>>> F = Function("F", [x], [f(x)])
>>> F(3)
DM(9)
>>> del f
>>> try:
...   F(3)
... except Exception as e:
...   print(str(e).splitlines()[-1])
Callback object has been deleted
>> c = {'classdef SqCb < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqCb(name)', 'self@casadi.Callback(); construct(self, name);'}];
>> c = [c, {'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqCb.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> x = MX.sym('x'); f = SqCb('f'); F = Function('F', {x}, {f(x)}); disp(F(3))
9
>> delete(f)
>> try, F(3); catch e, disp(contains(e.message, 'Callback object has been deleted')); end
...
1
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> x = ca.MX.sym("x");
julia> f = ca.callback(Sq(), "f");
julia> F = ca.Function("F", [x], [f(x)]);
julia> F(3)
DM(9)
julia> f = nothing; GC.gc()
julia> try
           F(3)
       catch e
           println(last(split(sprint(showerror, e), "\n")))
       end
Callback object has been deleted

Use in an NLP with finite differences:

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
>>> f = Sq("f", {"enable_fd": True})
>>> opti = Opti()
>>> v = opti.variable()
>>> opti.minimize(f(v-1))
>>> opti.solver("ipopt", {"print_time": False}, {"print_level": 0, "sb": "yes"})
>>> opti.solve().value(v)
1.0
>> c = {'classdef SqFd < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqFd(name, opts)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name, opts);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqFd.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqFd('f', struct('enable_fd', true));
>> opti = Opti(); v = opti.variable(); opti.minimize(f(v-1));
>> opti.solver('ipopt', struct('print_time', false), struct('print_level', 0, 'sb', 'yes'));
>> sol = opti.solve(); disp(sol.value(v))
1.0000
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> f = ca.callback(Sq(), "f", Dict("enable_fd" => true));
julia> opti = ca.Opti();
julia> v = ca.variable(opti);
julia> ca.minimize(opti, f(v - 1))
julia> ca.solver(opti, "ipopt", Dict("print_time" => false),
                  Dict("print_level" => 0, "sb" => "yes"))
julia> ca.value(ca.solve(opti), v)
1.0

See also: Function, external

Authors: Joris Gillis, Joel Andersson

Extra doc

construct(...)

Construct the internal Function object.

construct(self, str name, dict opts)

The class constructor only creates a null pointer; this call creates the Function. It must be called once from the subclass constructor, after all data needed by get_n_in/get_n_out/get_sparsity_in/get_sparsity_out/get_name_in/get_name_out is set, because those methods are evaluated here. init() and finalize() are called at the end. Calling it twice raises an error.

Parameters:
  • name -- Name of the Function

  • opts -- Function options, e.g. "enable_fd", "fd_method", "fd_options", "enable_forward", "enable_reverse", "enable_jacobian"

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
>>> f = Sq("f", {"enable_fd": True, "fd_method": "forward"})
>>> f.name(), f.n_in(), f.n_out()
('f', 1, 1)
>>> try:
...   f.construct("g")
... except Exception as e:
...   print("Internal class already created" in str(e))
True
>> c = {'classdef SqOpts < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqOpts(name, opts)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name, opts);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqOpts.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqOpts('f', struct('enable_fd', true, 'fd_method', 'forward'));
>> fprintf('%s %d %d\n', f.name(), f.n_in(), f.n_out())
f 1 1
>> try, f.construct('g'); catch e, disp(contains(e.message, 'already created')); end
1
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> f = ca.callback(Sq(), "f", Dict("enable_fd" => true, "fd_method" => "forward"));
julia> ca.name(f), ca.n_in(f), ca.n_out(f)
("f", 1, 1)
julia> try
           ca.construct(f, "g")
       catch e
           println(occursin("Internal class already created", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

eval(...)

Evaluate numerically.

eval(self, [DM] arg) -> [DM]

The method a subclass must implement. Receives one DM per input (with the sparsity of get_sparsity_in) and must return a list with one entry per output; each entry is converted to a DM and must match the shape of get_sparsity_out, otherwise the call raises an error. Exceptions raised inside propagate to the caller. The default implementation raises an error.

This signature is not thread-safe. For guaranteed thread-safety, use eval_buffer.

Parameters:

arg -- Input values

Returns:

Output values

>>> class Scale(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_n_in(self): return 2
...   def get_sparsity_in(self, i):
...     return Sparsity.dense(2, 1) if i == 0 else Sparsity.dense(1, 1)
...   def get_sparsity_out(self, i): return Sparsity.dense(2, 1)
...   def eval(self, arg):
...     return [arg[0]*arg[1]]
>>> f = Scale("f")
>>> f([1, 2], 3)
DM([3, 6])
>>> class Bad(Scale):
...   def eval(self, arg):
...     return [arg[1]]
>>> try:
...   Bad("b")([1, 2], 3)
... except Exception as e:
...   print("Shape mismatch" in str(e))
True
>> c = {'classdef Scale < casadi.Callback', 'methods'};
>> c = [c, {'function self = Scale(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function n = get_n_in(self)', 'n = 2;', 'end'}];
>> c = [c, {'function sp = get_sparsity_in(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(1, 1);'}];
>> c = [c, {'if i == 0, sp = casadi.Sparsity.dense(2, 1); end', 'end'}];
>> c = [c, {'function sp = get_sparsity_out(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(2, 1);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}*arg{2}};'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'Scale.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = Scale('f'); disp(f([1; 2], 3))
[3, 6]
>> c = {'classdef BadScale < Scale', 'methods', 'function self = BadScale(name)'};
>> c = [c, {'self@Scale(name);', 'end', 'function r = eval(self, arg)', 'r = {arg{2}};'}];
>> c = [c, {'end', 'end', 'end'}]; fid = fopen(fullfile(d, 'BadScale.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid); g = BadScale('b');
>> try, g([1; 2], 3); catch e, disp(contains(e.message, 'Shape mismatch')); end
1
>> rmpath(d); rmdir(d, 's');
julia> abstract type AbstractScale <: ca.Callback end
julia> struct Scale <: AbstractScale end
julia> ca.get_n_in(::AbstractScale) = 2
julia> ca.get_sparsity_in(::AbstractScale, i) = ca.Sparsity.dense(i == 0 ? 2 : 1, 1)
julia> ca.get_sparsity_out(::AbstractScale, i) = ca.Sparsity.dense(2, 1)
julia> ca.eval_(::Scale, arg) = [arg[1] * arg[2]]
julia> f = ca.callback(Scale(), "f");
julia> f([1, 2], 3)
DM([3, 6])
julia> struct Bad <: AbstractScale end
julia> ca.eval_(::Bad, arg) = [arg[2]]
julia> try
           ca.callback(Bad(), "b")([1, 2], 3)
       catch e
           println(occursin("Shape mismatch", sprint(showerror, e)))
       end
true

Extra doc | Doc source | Implementation

eval_buffer(...)

A copy-free low level interface.

eval_buffer(self, double const ** arg, [int] sizes_arg, double ** res, [int] sizes_res) -> int

Alternative to eval() that works on the raw nonzero buffers, avoiding DM allocation. Override has_eval_buffer() to return true to activate it. In Python the method receives two tuples of memoryview objects (inputs and outputs), each holding only the structural nonzeros of the corresponding input or output in column-major order; write the result into the output buffers and return 0.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_sparsity_in(self, i): return Sparsity.dense(3, 1)
...   def get_sparsity_out(self, i): return Sparsity.dense(3, 1)
...   def has_eval_buffer(self): return True
...   def eval_buffer(self, arg, res):
...     a = np.frombuffer(arg[0], dtype=np.float64)
...     r = np.frombuffer(res[0], dtype=np.float64)
...     r[:] = a**2
...     return 0
>>> f = Sq("f")
>>> f([1, 2, 3])
DM([1, 4, 9])
julia> struct Sq <: ca.Callback end
julia> ca.get_sparsity_in(::Sq, i) = ca.Sparsity.dense(3, 1)
julia> ca.get_sparsity_out(::Sq, i) = ca.Sparsity.dense(3, 1)
julia> ca.has_eval_buffer(::Sq) = true
julia> ca.eval_buffer(::Sq, arg, res) = (res[1] .= arg[1] .^ 2; 0)
julia> f = ca.callback(Sq(), "f");
julia> f([1, 2, 3])
DM([1, 4, 9])

Extra doc | Doc source | Implementation

finalize(...)

Finalize the object.

finalize(self)

Called from construct() after init(), as the last step before the Function can be evaluated. The default does nothing.

Extra doc | Doc source | Implementation

get_factory(...)

Customize calls to the function factory.

get_factory(self, str name, [str] s_in, [str] s_out, dict:[str] aux, dict opts) -> Function

Called when a derived function is requested by name through Function::factory; the default delegates to the standard factory.

Extra doc | Doc source | Implementation

get_forward(...)

Return function that calculates forward derivatives.

get_forward(self, int nfwd, str name, [str] inames, [str] onames, dict opts) -> Function

Override has_forward(nfwd) to return true for the numbers of directions you support (nfwd==1 is enough; CasADi then loops) and get_forward() to return a Function with inputs [nominal inputs, nominal outputs, one forward seed per input] and one forward sensitivity per output. For nfwd>1 the seeds and sensitivities are horizontally stacked (n-by-nfwd*m). forward(nfwd) on the Function caches the result.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_forward(self, nfwd): return nfwd == 1
...   def get_forward(self, nfwd, name, inames, onames, opts):
...     print(nfwd, name, inames, onames)
...     x, y, xd = SX.sym("x"), SX.sym("y", Sparsity(1, 1)), SX.sym("xd")
...     return Function(name, [x, y, xd], [2*x*xd], inames, onames, opts)
>>> f = Sq("f")
>>> x = MX.sym("x")
>>> J = Function("J", [x], [jacobian(f(x), x)])
1 fwd1_f ['i0', 'out_o0', 'fwd_i0'] ['fwd_o0']
>>> J(3)
DM(6)
>> c = {'classdef SqFwd < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqFwd(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end'}];
>> c = [c, {'function b = has_forward(self, nfwd)', 'b = nfwd == 1;', 'end'}];
>> c = [c, {'function F = get_forward(self, nfwd, name, inames, onames, opts)'}];
>> c = [c, {'disp(nfwd); disp(name); disp(inames); disp(onames);'}];
>> c = [c, {'x = casadi.SX.sym(''x''); y = casadi.SX.sym(''y'', casadi.Sparsity(1, 1));'}];
>> c = [c, {'xd = casadi.SX.sym(''xd'');'}];
>> c = [c, {'F = casadi.Function(name, {x, y, xd}, {2*x*xd}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqFwd.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqFwd('f'); x = MX.sym('x'); J = Function('J', {x}, {jacobian(f(x), x)});
1
fwd1_f
i0
out_o0
fwd_i0
fwd_o0
>> J(3)
6
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> ca.has_forward(::Sq, nfwd) = nfwd == 1
julia> function ca.get_forward(::Sq, nfwd, name, inames, onames, opts)
           println(nfwd, " ", name, " ", inames, " ", onames)
           x = ca.SX.sym("x"); y = ca.SX.sym("y", ca.Sparsity(1, 1)); xd = ca.SX.sym("xd")
           ca.Function(name, [x, y, xd], [2x*xd], inames, onames, opts)
       end
julia> f = ca.callback(Sq(), "f");
julia> x = ca.MX.sym("x");
julia> J = ca.Function("J", [x], [ca.jacobian(f(x), x)]);
1 fwd1_f ["i0", "out_o0", "fwd_i0"] ["fwd_o0"]
julia> J(3)
DM(6)

Extra doc | Doc source | Implementation

get_jac_sparsity(...)

Return sparsity of Jacobian of all input elements.

get_jac_sparsity(self, int oind, int iind, bool symmetric) -> Sparsity

with respect to all output elements. Override has_jac_sparsity(oind, iind) to return true and get_jac_sparsity() to return the pattern of the Jacobian block of output oind with respect to input iind. Without it the block is assumed dense. Finite differencing exploits the pattern (fewer evaluations) and the result of jacobian() carries it.

>>> class Diag(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_sparsity_in(self, i): return Sparsity.dense(3, 1)
...   def get_sparsity_out(self, i): return Sparsity.dense(3, 1)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_jac_sparsity(self, oind, iind): return True
...   def get_jac_sparsity(self, oind, iind, symmetric): return Sparsity.diag(3)
>>> f = Diag("f", {"enable_fd": True})
>>> x = MX.sym("x", 3)
>>> J = jacobian(f(x), x)
>>> J.sparsity()
Sparsity(3x3,3nz)
>>> Function("J", [x], [J])([1, 2, 3])
DM(
[[2, 00, 00],
 [00, 4, 00],
 [00, 00, 6]])
>> c = {'classdef DiagCb < casadi.Callback', 'methods'};
>> c = [c, {'function self = DiagCb(name, opts)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name, opts);', 'end'}];
>> c = [c, {'function sp = get_sparsity_in(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(3, 1);', 'end'}];
>> c = [c, {'function sp = get_sparsity_out(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(3, 1);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}.^2};', 'end'}];
>> c = [c, {'function b = has_jac_sparsity(self, oind, iind)', 'b = true;', 'end'}];
>> c = [c, {'function sp = get_jac_sparsity(self, oind, iind, symmetric)'}];
>> c = [c, {'sp = casadi.Sparsity.diag(3);', 'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'DiagCb.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = DiagCb('f', struct('enable_fd', true)); x = MX.sym('x', 3); J = jacobian(f(x), x);
>> J.sparsity()
3x3,3nz
>> JF = Function('J', {x}, {J}); disp(JF([1; 2; 3]))
[[2, 00, 00],
[00, 4, 00],
[00, 00, 6]]
>> rmpath(d); rmdir(d, 's');
julia> struct Diag <: ca.Callback end
julia> ca.get_sparsity_in(::Diag, i) = ca.Sparsity.dense(3, 1)
julia> ca.get_sparsity_out(::Diag, i) = ca.Sparsity.dense(3, 1)
julia> ca.eval_(::Diag, arg) = [arg[1] .^ 2]
julia> ca.has_jac_sparsity(::Diag, oind, iind) = true
julia> ca.get_jac_sparsity(::Diag, oind, iind, symmetric) = ca.Sparsity.diag(3)
julia> f = ca.callback(Diag(), "f", Dict("enable_fd" => true));
julia> x = ca.MX.sym("x", 3);
julia> J = ca.jacobian(f(x), x);
julia> ca.sparsity(J)
Sparsity(3x3,3nz)
julia> ca.Function("J", [x], [J])([1, 2, 3])
DM(
[[2, 00, 00],
 [00, 4, 00],
 [00, 00, 6]])

Extra doc | Doc source | Implementation

get_jacobian(...)

Return Jacobian of all input elements with respect to all output elements.

get_jacobian(self, str name, [str] inames, [str] onames, dict opts) -> Function

Override has_jacobian() to return true and get_jacobian() to return a Function with inputs [all nominal inputs, all nominal outputs] and one output per (output, input) pair, each the dense or sparse Jacobian block of that output with respect to that input (row-major over the pairs). Use the inames, onames and opts passed in: they carry the expected names and the "derivative_of" option. The returned Function may be an SX/MX Function (then higher derivatives are exact) or another Callback (keep a reference to it).

>>> class F43(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_sparsity_in(self, i): return Sparsity.dense(4, 1)
...   def get_sparsity_out(self, i): return Sparsity.dense(3, 1)
...   def eval(self, arg):
...     a, b, c, d = vertsplit(arg[0])
...     return [vertcat(sin(c)*d+d**2, 2*a+c, b**2+5*c)]
...   def has_jacobian(self): return True
...   def get_jacobian(self, name, inames, onames, opts):
...     print(name, inames, onames)
...     x = SX.sym("x", 4)
...     y = SX.sym("y", Sparsity(3, 1))
...     a, b, c, d = vertsplit(x)
...     J = blockcat([[0, 0, d*cos(c), sin(c)+2*d], [2, 0, 1, 0], [0, 2*b, 5, 0]])
...     return Function(name, [x, y], [J], inames, onames, opts)
>>> f = F43("f")
>>> x = MX.sym("x", 4)
>>> J = Function("J", [x], [jacobian(f(x), x)])
jac_f ['i0', 'out_o0'] ['jac_o0_i0']
>>> J([1, 2, 0, 3])
DM(
[[0, 0, 3, 6],
 [2, 0, 1, 0],
 [0, 4, 5, 0]])
>> c = {'classdef F43 < casadi.Callback', 'methods'};
>> c = [c, {'function self = F43(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function sp = get_sparsity_in(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(4, 1);', 'end'}];
>> c = [c, {'function sp = get_sparsity_out(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(3, 1);', 'end'}];
>> c = [c, {'function r = eval(self, arg)'}];
>> c = [c, {'v = arg{1}; a = v(1); b = v(2); c = v(3); d = v(4);'}];
>> c = [c, {'r = {[sin(c)*d+d^2; 2*a+c; b^2+5*c]};', 'end'}];
>> c = [c, {'function b = has_jacobian(self)', 'b = true;', 'end'}];
>> c = [c, {'function J = get_jacobian(self, name, inames, onames, opts)'}];
>> c = [c, {'disp(name); disp(inames); disp(onames);'}];
>> c = [c, {'x = casadi.SX.sym(''x'', 4); a = x(1); b = x(2); c = x(3); d = x(4);'}];
>> c = [c, {'y = casadi.SX.sym(''y'', casadi.Sparsity(3, 1));'}];
>> c = [c, {'Jm = [0, 0, d*cos(c), sin(c)+2*d; 2, 0, 1, 0; 0, 2*b, 5, 0];'}];
>> c = [c, {'J = casadi.Function(name, {x, y}, {Jm}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'F43.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = F43('f'); x = MX.sym('x', 4); J = Function('J', {x}, {jacobian(f(x), x)});
jac_f
i0
out_o0
jac_o0_i0
>> J([1; 2; 0; 3])
[[0, 0, 3, 6],
[2, 0, 1, 0],
[0, 4, 5, 0]]
>> rmpath(d); rmdir(d, 's');
julia> struct F43 <: ca.Callback end
julia> ca.get_sparsity_in(::F43, i) = ca.Sparsity.dense(4, 1)
julia> ca.get_sparsity_out(::F43, i) = ca.Sparsity.dense(3, 1)
julia> function ca.eval_(::F43, arg)
           a, b, c, d = arg[1][1], arg[1][2], arg[1][3], arg[1][4]
           [[sin(c)*d + d^2; 2a + c; b^2 + 5c]]
       end
julia> ca.has_jacobian(::F43) = true
julia> function ca.get_jacobian(::F43, name, inames, onames, opts)
           println(name, " ", inames, " ", onames)
           x = ca.SX.sym("x", 4); y = ca.SX.sym("y", ca.Sparsity(3, 1))
           a, b, c, d = x[1], x[2], x[3], x[4]
           J = [0 0 d*cos(c) sin(c)+2d; 2 0 1 0; 0 2b 5 0]
           ca.Function(name, [x, y], [J], inames, onames, opts)
       end
julia> f = ca.callback(F43(), "f");
julia> x = ca.MX.sym("x", 4);
julia> J = ca.Function("J", [x], [ca.jacobian(f(x), x)]);
jac_f ["i0", "out_o0"] ["jac_o0_i0"]
julia> J([1, 2, 0, 3])
DM(
[[0, 0, 3, 6],
 [2, 0, 1, 0],
 [0, 4, 5, 0]])

Extra doc | Doc source | Implementation

get_n_in(...)

Get the number of inputs.

get_n_in(self) -> int

Called during construct(). Default: 1.

Extra doc | Doc source | Implementation

get_n_out(...)

Get the number of outputs.

get_n_out(self) -> int

Called during construct(). Default: 1.

>>> class Split(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_n_in(self): return 1
...   def get_n_out(self): return 2
...   def eval(self, arg):
...     return [arg[0]**2, -arg[0]]
>>> f = Split("f")
>>> f(3)
(DM(9), DM(-3))
>> c = {'classdef SplitCb < casadi.Callback', 'methods'};
>> c = [c, {'function self = SplitCb(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function n = get_n_out(self)', 'n = 2;', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2, -arg{1}};'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SplitCb.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SplitCb('f'); [a, b] = f(3); disp(a), disp(b)
9
-3
>> rmpath(d); rmdir(d, 's');
julia> struct Split <: ca.Callback end
julia> ca.get_n_in(::Split) = 1
julia> ca.get_n_out(::Split) = 2
julia> ca.eval_(::Split, arg) = [arg[1]^2, -arg[1]]
julia> f = ca.callback(Split(), "f");
julia> f(3)
(9, -3)

Extra doc | Doc source | Implementation

get_name_in(...)

Get the name of an input.

get_name_in(self, int i) -> str

Called during construct(). Default: "i0", "i1", ... Names allow calling the Function with keyword arguments.

>>> class Lin(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_n_in(self): return 2
...   def get_name_in(self, i): return ["x", "a"][i]
...   def get_name_out(self, i): return "y"
...   def eval(self, arg):
...     return [arg[1]*arg[0]]
>>> f = Lin("f")
>>> f
Callback(f:(x,a)->(y) CallbackInternal)
>>> f(x=2, a=3)
{'y': DM(6)}
>> c = {'classdef Lin < casadi.Callback', 'methods'};
>> c = [c, {'function self = Lin(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function n = get_n_in(self)', 'n = 2;', 'end'}];
>> c = [c, {'function s = get_name_in(self, i)'}];
>> c = [c, {'names = {''x'', ''a''}; s = names{i+1};', 'end'}];
>> c = [c, {'function s = get_name_out(self, i)', 's = ''y'';', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{2}*arg{1}};'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'Lin.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = Lin('f'); disp(f)
f:(x,a)->(y) CallbackInternal
>> r = f('x', 2, 'a', 3); disp(r.y)
6
>> rmpath(d); rmdir(d, 's');
julia> struct Lin <: ca.Callback end
julia> ca.get_n_in(::Lin) = 2
julia> ca.get_name_in(::Lin, i) = ["x", "a"][i + 1]
julia> ca.get_name_out(::Lin, i) = "y"
julia> ca.eval_(::Lin, arg) = [arg[2] * arg[1]]
julia> f = ca.callback(Lin(), "f");
julia> ca.Function(f)
Function(f:(x,a)->(y) CallbackInternal)
julia> f(x=2, a=3)
Dict{String, DM} with 1 entry:
  "y" => 6

Extra doc | Doc source | Implementation

get_name_out(...)

Get the name of an output.

get_name_out(self, int i) -> str

Called during construct(). Default: "o0", "o1", ...

Extra doc | Doc source | Implementation

get_reverse(...)

Return function that calculates adjoint derivatives.

get_reverse(self, int nadj, str name, [str] inames, [str] onames, dict opts) -> Function

Override has_reverse(nadj) to return true for the numbers of directions you support and get_reverse() to return a Function with inputs [nominal inputs, nominal outputs, one adjoint seed per output] and one adjoint sensitivity per input. For nadj>1 the seeds and sensitivities are horizontally stacked. Reverse mode is what gradient-based NLP solvers use for the objective gradient. reverse(nadj) caches the result.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_reverse(self, nadj): return nadj == 1
...   def get_reverse(self, nadj, name, inames, onames, opts):
...     print(nadj, name, inames, onames)
...     x, y, yb = SX.sym("x"), SX.sym("y", Sparsity(1, 1)), SX.sym("yb")
...     return Function(name, [x, y, yb], [2*x*yb], inames, onames, opts)
>>> f = Sq("f")
>>> x = MX.sym("x")
>>> G = Function("G", [x], [gradient(f(x), x)])
1 adj1_f ['i0', 'out_o0', 'adj_o0'] ['adj_i0']
>>> G(3)
DM(6)
>> c = {'classdef SqAdj < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqAdj(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end'}];
>> c = [c, {'function b = has_reverse(self, nadj)', 'b = nadj == 1;', 'end'}];
>> c = [c, {'function F = get_reverse(self, nadj, name, inames, onames, opts)'}];
>> c = [c, {'disp(nadj); disp(name); disp(inames); disp(onames);'}];
>> c = [c, {'x = casadi.SX.sym(''x''); y = casadi.SX.sym(''y'', casadi.Sparsity(1, 1));'}];
>> c = [c, {'yb = casadi.SX.sym(''yb'');'}];
>> c = [c, {'F = casadi.Function(name, {x, y, yb}, {2*x*yb}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqAdj.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqAdj('f'); x = MX.sym('x'); G = Function('G', {x}, {gradient(f(x), x)});
1
adj1_f
i0
out_o0
adj_o0
adj_i0
>> G(3)
6
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> ca.has_reverse(::Sq, nadj) = nadj == 1
julia> function ca.get_reverse(::Sq, nadj, name, inames, onames, opts)
           println(nadj, " ", name, " ", inames, " ", onames)
           x = ca.SX.sym("x"); y = ca.SX.sym("y", ca.Sparsity(1, 1)); yb = ca.SX.sym("yb")
           ca.Function(name, [x, y, yb], [2x*yb], inames, onames, opts)
       end
julia> f = ca.callback(Sq(), "f");
julia> x = ca.MX.sym("x");
julia> G = ca.Function("G", [x], [ca.gradient(f(x), x)]);
1 adj1_f ["i0", "out_o0", "adj_o0"] ["adj_i0"]
julia> G(3)
DM(6)

Extra doc | Doc source | Implementation

get_sparsity_in(...)

Get the sparsity of an input.

get_sparsity_in(self, int i) -> Sparsity

Called during construct() for i in 0..n_in-1. Default: scalar (1-by-1 dense). Inputs are padded or projected to this pattern when the Function is called.

>>> class Trace(Callback):
...   def __init__(self, name, n, opts={}):
...     Callback.__init__(self)
...     self.n = n
...     self.construct(name, opts)
...   def get_sparsity_in(self, i): return Sparsity.diag(self.n)
...   def eval(self, arg):
...     return [sum1(diag(arg[0]))]
>>> f = Trace("f", 3)
>>> f.sparsity_in(0), f(DM.ones(3, 3))
(Sparsity(3x3,3nz), DM(3))
>> c = {'classdef TraceCb < casadi.Callback', 'properties', 'n', 'end', 'methods'};
>> c = [c, {'function self = TraceCb(name, n)'}];
>> c = [c, {'self@casadi.Callback(); self.n = n; construct(self, name);', 'end'}];
>> c = [c, {'function sp = get_sparsity_in(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.diag(self.n);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {sum1(diag(arg{1}))};'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'TraceCb.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = TraceCb('f', 3); disp(f.sparsity_in(0)), disp(f(DM.ones(3, 3)))
3x3,3nz
3
>> rmpath(d); rmdir(d, 's');
julia> struct Trace <: ca.Callback
           n::Int
       end
julia> ca.get_sparsity_in(cb::Trace, i) = ca.Sparsity.diag(cb.n)
julia> ca.eval_(::Trace, arg) = [ca.sum1(ca.diag(arg[1]))]
julia> f = ca.callback(Trace(3), "f");
julia> ca.sparsity_in(f, 0), f(ca.DM.ones(3, 3))
(3x3,3nz, 3)

Extra doc | Doc source | Implementation

get_sparsity_out(...)

Get the sparsity of an output.

get_sparsity_out(self, int i) -> Sparsity

Called during construct() for i in 0..n_out-1. Default: scalar (1-by-1 dense). The value returned by eval() for output i must have this shape.

Extra doc | Doc source | Implementation

has_eval_buffer(...)

Does the Callback class support a copy-free low level interface ?

has_eval_buffer(self) -> bool

Return true to have eval_buffer() called instead of eval(). Default: false.

Extra doc | Doc source | Implementation

has_forward(...)

Return function that calculates forward derivatives.

has_forward(self, int nfwd) -> bool

Override has_forward(nfwd) to return true for the numbers of directions you support (nfwd==1 is enough; CasADi then loops) and get_forward() to return a Function with inputs [nominal inputs, nominal outputs, one forward seed per input] and one forward sensitivity per output. For nfwd>1 the seeds and sensitivities are horizontally stacked (n-by-nfwd*m). forward(nfwd) on the Function caches the result.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_forward(self, nfwd): return nfwd == 1
...   def get_forward(self, nfwd, name, inames, onames, opts):
...     print(nfwd, name, inames, onames)
...     x, y, xd = SX.sym("x"), SX.sym("y", Sparsity(1, 1)), SX.sym("xd")
...     return Function(name, [x, y, xd], [2*x*xd], inames, onames, opts)
>>> f = Sq("f")
>>> x = MX.sym("x")
>>> J = Function("J", [x], [jacobian(f(x), x)])
1 fwd1_f ['i0', 'out_o0', 'fwd_i0'] ['fwd_o0']
>>> J(3)
DM(6)
>> c = {'classdef SqFwd < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqFwd(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end'}];
>> c = [c, {'function b = has_forward(self, nfwd)', 'b = nfwd == 1;', 'end'}];
>> c = [c, {'function F = get_forward(self, nfwd, name, inames, onames, opts)'}];
>> c = [c, {'disp(nfwd); disp(name); disp(inames); disp(onames);'}];
>> c = [c, {'x = casadi.SX.sym(''x''); y = casadi.SX.sym(''y'', casadi.Sparsity(1, 1));'}];
>> c = [c, {'xd = casadi.SX.sym(''xd'');'}];
>> c = [c, {'F = casadi.Function(name, {x, y, xd}, {2*x*xd}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqFwd.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqFwd('f'); x = MX.sym('x'); J = Function('J', {x}, {jacobian(f(x), x)});
1
fwd1_f
i0
out_o0
fwd_i0
fwd_o0
>> J(3)
6
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> ca.has_forward(::Sq, nfwd) = nfwd == 1
julia> function ca.get_forward(::Sq, nfwd, name, inames, onames, opts)
           println(nfwd, " ", name, " ", inames, " ", onames)
           x = ca.SX.sym("x"); y = ca.SX.sym("y", ca.Sparsity(1, 1)); xd = ca.SX.sym("xd")
           ca.Function(name, [x, y, xd], [2x*xd], inames, onames, opts)
       end
julia> f = ca.callback(Sq(), "f");
julia> x = ca.MX.sym("x");
julia> J = ca.Function("J", [x], [ca.jacobian(f(x), x)]);
1 fwd1_f ["i0", "out_o0", "fwd_i0"] ["fwd_o0"]
julia> J(3)
DM(6)

Extra doc | Doc source | Implementation

has_jac_sparsity(...)

Return sparsity of Jacobian of all input elements.

has_jac_sparsity(self, int oind, int iind) -> bool

with respect to all output elements. Override has_jac_sparsity(oind, iind) to return true and get_jac_sparsity() to return the pattern of the Jacobian block of output oind with respect to input iind. Without it the block is assumed dense. Finite differencing exploits the pattern (fewer evaluations) and the result of jacobian() carries it.

>>> class Diag(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_sparsity_in(self, i): return Sparsity.dense(3, 1)
...   def get_sparsity_out(self, i): return Sparsity.dense(3, 1)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_jac_sparsity(self, oind, iind): return True
...   def get_jac_sparsity(self, oind, iind, symmetric): return Sparsity.diag(3)
>>> f = Diag("f", {"enable_fd": True})
>>> x = MX.sym("x", 3)
>>> J = jacobian(f(x), x)
>>> J.sparsity()
Sparsity(3x3,3nz)
>>> Function("J", [x], [J])([1, 2, 3])
DM(
[[2, 00, 00],
 [00, 4, 00],
 [00, 00, 6]])
>> c = {'classdef DiagCb < casadi.Callback', 'methods'};
>> c = [c, {'function self = DiagCb(name, opts)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name, opts);', 'end'}];
>> c = [c, {'function sp = get_sparsity_in(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(3, 1);', 'end'}];
>> c = [c, {'function sp = get_sparsity_out(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(3, 1);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}.^2};', 'end'}];
>> c = [c, {'function b = has_jac_sparsity(self, oind, iind)', 'b = true;', 'end'}];
>> c = [c, {'function sp = get_jac_sparsity(self, oind, iind, symmetric)'}];
>> c = [c, {'sp = casadi.Sparsity.diag(3);', 'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'DiagCb.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = DiagCb('f', struct('enable_fd', true)); x = MX.sym('x', 3); J = jacobian(f(x), x);
>> J.sparsity()
3x3,3nz
>> JF = Function('J', {x}, {J}); disp(JF([1; 2; 3]))
[[2, 00, 00],
[00, 4, 00],
[00, 00, 6]]
>> rmpath(d); rmdir(d, 's');
julia> struct Diag <: ca.Callback end
julia> ca.get_sparsity_in(::Diag, i) = ca.Sparsity.dense(3, 1)
julia> ca.get_sparsity_out(::Diag, i) = ca.Sparsity.dense(3, 1)
julia> ca.eval_(::Diag, arg) = [arg[1] .^ 2]
julia> ca.has_jac_sparsity(::Diag, oind, iind) = true
julia> ca.get_jac_sparsity(::Diag, oind, iind, symmetric) = ca.Sparsity.diag(3)
julia> f = ca.callback(Diag(), "f", Dict("enable_fd" => true));
julia> x = ca.MX.sym("x", 3);
julia> J = ca.jacobian(f(x), x);
julia> ca.sparsity(J)
Sparsity(3x3,3nz)
julia> ca.Function("J", [x], [J])([1, 2, 3])
DM(
[[2, 00, 00],
 [00, 4, 00],
 [00, 00, 6]])

Extra doc | Doc source | Implementation

has_jacobian(...)

Return Jacobian of all input elements with respect to all output elements.

has_jacobian(self) -> bool

Override has_jacobian() to return true and get_jacobian() to return a Function with inputs [all nominal inputs, all nominal outputs] and one output per (output, input) pair, each the dense or sparse Jacobian block of that output with respect to that input (row-major over the pairs). Use the inames, onames and opts passed in: they carry the expected names and the "derivative_of" option. The returned Function may be an SX/MX Function (then higher derivatives are exact) or another Callback (keep a reference to it).

>>> class F43(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def get_sparsity_in(self, i): return Sparsity.dense(4, 1)
...   def get_sparsity_out(self, i): return Sparsity.dense(3, 1)
...   def eval(self, arg):
...     a, b, c, d = vertsplit(arg[0])
...     return [vertcat(sin(c)*d+d**2, 2*a+c, b**2+5*c)]
...   def has_jacobian(self): return True
...   def get_jacobian(self, name, inames, onames, opts):
...     print(name, inames, onames)
...     x = SX.sym("x", 4)
...     y = SX.sym("y", Sparsity(3, 1))
...     a, b, c, d = vertsplit(x)
...     J = blockcat([[0, 0, d*cos(c), sin(c)+2*d], [2, 0, 1, 0], [0, 2*b, 5, 0]])
...     return Function(name, [x, y], [J], inames, onames, opts)
>>> f = F43("f")
>>> x = MX.sym("x", 4)
>>> J = Function("J", [x], [jacobian(f(x), x)])
jac_f ['i0', 'out_o0'] ['jac_o0_i0']
>>> J([1, 2, 0, 3])
DM(
[[0, 0, 3, 6],
 [2, 0, 1, 0],
 [0, 4, 5, 0]])
>> c = {'classdef F43 < casadi.Callback', 'methods'};
>> c = [c, {'function self = F43(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function sp = get_sparsity_in(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(4, 1);', 'end'}];
>> c = [c, {'function sp = get_sparsity_out(self, i)'}];
>> c = [c, {'sp = casadi.Sparsity.dense(3, 1);', 'end'}];
>> c = [c, {'function r = eval(self, arg)'}];
>> c = [c, {'v = arg{1}; a = v(1); b = v(2); c = v(3); d = v(4);'}];
>> c = [c, {'r = {[sin(c)*d+d^2; 2*a+c; b^2+5*c]};', 'end'}];
>> c = [c, {'function b = has_jacobian(self)', 'b = true;', 'end'}];
>> c = [c, {'function J = get_jacobian(self, name, inames, onames, opts)'}];
>> c = [c, {'disp(name); disp(inames); disp(onames);'}];
>> c = [c, {'x = casadi.SX.sym(''x'', 4); a = x(1); b = x(2); c = x(3); d = x(4);'}];
>> c = [c, {'y = casadi.SX.sym(''y'', casadi.Sparsity(3, 1));'}];
>> c = [c, {'Jm = [0, 0, d*cos(c), sin(c)+2*d; 2, 0, 1, 0; 0, 2*b, 5, 0];'}];
>> c = [c, {'J = casadi.Function(name, {x, y}, {Jm}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'F43.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = F43('f'); x = MX.sym('x', 4); J = Function('J', {x}, {jacobian(f(x), x)});
jac_f
i0
out_o0
jac_o0_i0
>> J([1; 2; 0; 3])
[[0, 0, 3, 6],
[2, 0, 1, 0],
[0, 4, 5, 0]]
>> rmpath(d); rmdir(d, 's');
julia> struct F43 <: ca.Callback end
julia> ca.get_sparsity_in(::F43, i) = ca.Sparsity.dense(4, 1)
julia> ca.get_sparsity_out(::F43, i) = ca.Sparsity.dense(3, 1)
julia> function ca.eval_(::F43, arg)
           a, b, c, d = arg[1][1], arg[1][2], arg[1][3], arg[1][4]
           [[sin(c)*d + d^2; 2a + c; b^2 + 5c]]
       end
julia> ca.has_jacobian(::F43) = true
julia> function ca.get_jacobian(::F43, name, inames, onames, opts)
           println(name, " ", inames, " ", onames)
           x = ca.SX.sym("x", 4); y = ca.SX.sym("y", ca.Sparsity(3, 1))
           a, b, c, d = x[1], x[2], x[3], x[4]
           J = [0 0 d*cos(c) sin(c)+2d; 2 0 1 0; 0 2b 5 0]
           ca.Function(name, [x, y], [J], inames, onames, opts)
       end
julia> f = ca.callback(F43(), "f");
julia> x = ca.MX.sym("x", 4);
julia> J = ca.Function("J", [x], [ca.jacobian(f(x), x)]);
jac_f ["i0", "out_o0"] ["jac_o0_i0"]
julia> J([1, 2, 0, 3])
DM(
[[0, 0, 3, 6],
 [2, 0, 1, 0],
 [0, 4, 5, 0]])

Extra doc | Doc source | Implementation

has_reverse(...)

Return function that calculates adjoint derivatives.

has_reverse(self, int nadj) -> bool

Override has_reverse(nadj) to return true for the numbers of directions you support and get_reverse() to return a Function with inputs [nominal inputs, nominal outputs, one adjoint seed per output] and one adjoint sensitivity per input. For nadj>1 the seeds and sensitivities are horizontally stacked. Reverse mode is what gradient-based NLP solvers use for the objective gradient. reverse(nadj) caches the result.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_reverse(self, nadj): return nadj == 1
...   def get_reverse(self, nadj, name, inames, onames, opts):
...     print(nadj, name, inames, onames)
...     x, y, yb = SX.sym("x"), SX.sym("y", Sparsity(1, 1)), SX.sym("yb")
...     return Function(name, [x, y, yb], [2*x*yb], inames, onames, opts)
>>> f = Sq("f")
>>> x = MX.sym("x")
>>> G = Function("G", [x], [gradient(f(x), x)])
1 adj1_f ['i0', 'out_o0', 'adj_o0'] ['adj_i0']
>>> G(3)
DM(6)
>> c = {'classdef SqAdj < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqAdj(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end'}];
>> c = [c, {'function b = has_reverse(self, nadj)', 'b = nadj == 1;', 'end'}];
>> c = [c, {'function F = get_reverse(self, nadj, name, inames, onames, opts)'}];
>> c = [c, {'disp(nadj); disp(name); disp(inames); disp(onames);'}];
>> c = [c, {'x = casadi.SX.sym(''x''); y = casadi.SX.sym(''y'', casadi.Sparsity(1, 1));'}];
>> c = [c, {'yb = casadi.SX.sym(''yb'');'}];
>> c = [c, {'F = casadi.Function(name, {x, y, yb}, {2*x*yb}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqAdj.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqAdj('f'); x = MX.sym('x'); G = Function('G', {x}, {gradient(f(x), x)});
1
adj1_f
i0
out_o0
adj_o0
adj_i0
>> G(3)
6
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> ca.has_reverse(::Sq, nadj) = nadj == 1
julia> function ca.get_reverse(::Sq, nadj, name, inames, onames, opts)
           println(nadj, " ", name, " ", inames, " ", onames)
           x = ca.SX.sym("x"); y = ca.SX.sym("y", ca.Sparsity(1, 1)); yb = ca.SX.sym("yb")
           ca.Function(name, [x, y, yb], [2x*yb], inames, onames, opts)
       end
julia> f = ca.callback(Sq(), "f");
julia> x = ca.MX.sym("x");
julia> G = ca.Function("G", [x], [ca.gradient(f(x), x)]);
1 adj1_f ["i0", "out_o0", "adj_o0"] ["adj_i0"]
julia> G(3)
DM(6)

Extra doc | Doc source | Implementation

init(...)

Initialize the object.

init(self)

Called from construct() after the inputs and outputs are known and the options are processed, before finalize(). Override to allocate data; the default does nothing.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     print("before construct")
...     self.construct(name, opts)
...     print("after construct")
...   def init(self): print("init", self.n_in())
...   def finalize(self): print("finalize")
...   def eval(self, arg):
...     return [arg[0]**2]
>>> f = Sq("f")
before construct
init 1
finalize
after construct
>> c = {'classdef SqInit < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqInit(name)'}];
>> c = [c, {'self@casadi.Callback(); disp(''before construct'');'}];
>> c = [c, {'construct(self, name); disp(''after construct'');', 'end'}];
>> c = [c, {'function init(self)', 'fprintf(''init %d\n'', self.n_in());', 'end'}];
>> c = [c, {'function finalize(self)', 'disp(''finalize'');', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqInit.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqInit('f');
before construct
init 1
finalize
after construct
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.init(::Sq) = println("init")
julia> ca.finalize(::Sq) = println("finalize")
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> begin
           println("before construct")
           f = ca.callback(Sq(), "f")
           println("after construct")
       end
before construct
init
finalize
after construct

Extra doc | Doc source | Implementation

static type_name(...)

Get type name.

type_name() -> str

Extra doc | Doc source | Implementation

uses_output(...)

Do the derivative functions need nondifferentiated outputs?

uses_output(self) -> bool

Derivative functions obtained from get_jacobian/get_forward/get_reverse receive the nominal outputs as extra inputs. When this returns false (default) those inputs are passed as empty (all-zero sparsity) placeholders; return true to receive the actual output values, e.g. to reuse them in the derivative computation.

>>> class Sq(Callback):
...   def __init__(self, name, opts={}):
...     Callback.__init__(self)
...     self.construct(name, opts)
...   def eval(self, arg):
...     return [arg[0]**2]
...   def has_jacobian(self): return True
...   def get_jacobian(self, name, inames, onames, opts):
...     x = SX.sym("x")
...     y = SX.sym("y", self.sparsity_out(0) if self.uses_output() else Sparsity(1, 1))
...     return Function(name, [x, y], [2*x], inames, onames, opts)
>>> class SqU(Sq):
...   def uses_output(self): return True
>>> Sq("f").jacobian().sparsity_in(1), SqU("f").jacobian().sparsity_in(1)
(Sparsity(1x1,0nz), Sparsity(1x1))
>> c = {'classdef SqJac < casadi.Callback', 'methods'};
>> c = [c, {'function self = SqJac(name)'}];
>> c = [c, {'self@casadi.Callback(); construct(self, name);', 'end'}];
>> c = [c, {'function r = eval(self, arg)', 'r = {arg{1}^2};', 'end'}];
>> c = [c, {'function b = has_jacobian(self)', 'b = true;', 'end'}];
>> c = [c, {'function J = get_jacobian(self, name, inames, onames, opts)'}];
>> c = [c, {'x = casadi.SX.sym(''x''); y = casadi.SX.sym(''y'', casadi.Sparsity(1, 1));'}];
>> c = [c, {'if self.uses_output(), y = casadi.SX.sym(''y'', self.sparsity_out(0)); end'}];
>> c = [c, {'J = casadi.Function(name, {x, y}, {2*x}, inames, onames, opts);'}];
>> c = [c, {'end', 'end', 'end'}];
>> d = tempname; mkdir(d); addpath(d); fid = fopen(fullfile(d, 'SqJac.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> c = {'classdef SqJacU < SqJac', 'methods', 'function self = SqJacU(name)'};
>> c = [c, {'self@SqJac(name);', 'end', 'function b = uses_output(self)', 'b = true;'}];
>> c = [c, {'end', 'end', 'end'}]; fid = fopen(fullfile(d, 'SqJacU.m'), 'w');
>> fprintf(fid, '%s\n', c{:}); fclose(fid);
>> f = SqJac('f'); J = f.jacobian(); disp(J.sparsity_in(1))
1x1,0nz
>> g = SqJacU('g'); J = g.jacobian(); disp(J.sparsity_in(1))
1x1
>> rmpath(d); rmdir(d, 's');
julia> struct Sq <: ca.Callback end
julia> ca.eval_(::Sq, arg) = [arg[1]^2]
julia> ca.has_jacobian(::Sq) = true
julia> function ca.get_jacobian(::Sq, name, inames, onames, opts)
           x = ca.SX.sym("x"); y = ca.SX.sym("y", ca.Sparsity(1, 1))
           ca.Function(name, [x, y], [2x], inames, onames, opts)
       end
julia> ca.sparsity_in(ca.jacobian(ca.callback(Sq(), "f")), 1)
Sparsity(1x1,0nz)

Extra doc | Doc source | Implementation

GlobalOptions

class GlobalOptions(...)

Collects global CasADi options.

Note to developers:

  • use sparingly. Global options are - in general - a rather bad idea

  • this class must never be instantiated. Access its static members directly Joris Gillis 2012 Extra doc: https://github.com/casadi/casadi/wiki/L_23m

static getCasadiIncludePath(...)
getCasadiIncludePath() -> str
static getCasadiPath(...)
getCasadiPath() -> str
static getCopyElisionMinSize(...)
getCopyElisionMinSize() -> int
static getDefaultBlas(...)
getDefaultBlas() -> str
static getHierarchicalSparsity(...)
getHierarchicalSparsity() -> bool
static getMaxNumDir(...)
getMaxNumDir() -> int
static getNumpyMode(...)

Get the current numpy interop mode.

getNumpyMode() -> int

Affects only the Python bindings; see setNumpyMode.

Extra doc | Doc source | Implementation

static getSimplificationOnTheFly(...)
getSimplificationOnTheFly() -> bool
static getTempWorkDir(...)
getTempWorkDir() -> str
static setCasadiIncludePath(...)
setCasadiIncludePath(str path)
static setCasadiPath(...)
setCasadiPath(str path)
static setCopyElisionMinSize(...)
setCopyElisionMinSize(int sz)
static setDefaultBlas(...)
setDefaultBlas(str name)
static setHierarchicalSparsity(...)
setHierarchicalSparsity(bool flag)
static setMaxNumDir(...)
setMaxNumDir(int ndir)
static setNumpyMode(...)

Set the numpy interop mode (issue #2959)

setNumpyMode(int mode)

Affects only the Python bindings; ignored elsewhere.

1 = casadi-aware numpy support, 0 (default) = legacy + FutureWarning, -1 = legacy but silent. Probe with hasattr(casadi.GlobalOptions, "setNumpyMode").

Extra doc | Doc source | Implementation

static setSimplificationOnTheFly(...)
setSimplificationOnTheFly(bool flag)
static setTempWorkDir(...)
setTempWorkDir(str dir)

CasadiMeta

class CasadiMeta(...)

Collects global CasADi meta information.

Authors: Joris Gillis

Extra doc

static build_type(...)

Obtain build type: RELEASE/Debug.

build_type() -> char const *

Extra doc | Doc source | Implementation

static compiler(...)

Obtain compiler.

compiler() -> char const *

Extra doc | Doc source | Implementation

static compiler_flags(...)

Obtain compiler flags.

compiler_flags() -> char const *

Extra doc | Doc source | Implementation

static compiler_id(...)

Obtain compiler identification.

compiler_id() -> char const *

Provided by http://www.cmake.org/cmake/help/v2.8.10/cmake.html#variable:CMAKE_LANG_COMPILER_ID

Extra doc | Doc source | Implementation

static feature_list(...)

Obtain list of features that were compiled into this build.

feature_list() -> char const *

Extra doc | Doc source | Implementation

static git_describe(...)

Obtain the git description of this build.

git_describe() -> char const *

(only available if built from a git repo)

Extra doc | Doc source | Implementation

static git_revision(...)

Obtain the git hash of this build.

git_revision() -> char const *

(only available if built from a git repo)

Extra doc | Doc source | Implementation

static install_prefix(...)

Obtain install prefix.

install_prefix() -> char const *

Extra doc | Doc source | Implementation

static lapack_libraries(...)

LAPACK link line as configured by the build system.

lapack_libraries() -> char const *

Semicolon-separated list of full library paths and/or -l flags (CMake's native LAPACK_LIBRARIES form), mirroring whatever find_package(LAPACK) or WITH_BUILD_LAPACK resolved to. Empty when the build was configured with WITH_LAPACK=OFF.

Extra doc | Doc source | Implementation

static modules(...)

Obtain modules list.

modules() -> char const *

Extra doc | Doc source | Implementation

static object_file_suffix(...)

Obtain object file suffix.

object_file_suffix() -> char const *

Extra doc | Doc source | Implementation

static plugins(...)

Obtain plugins list.

plugins() -> char const *

Extra doc | Doc source | Implementation

static shared_library_prefix(...)

Obtain shared library prefix.

shared_library_prefix() -> char const *

Extra doc | Doc source | Implementation

static shared_library_suffix(...)

Obtain shared library suffix.

shared_library_suffix() -> char const *

Extra doc | Doc source | Implementation

static swig_flags(...)
swig_flags() -> char const *
static version(...)

Obtain the version number of CasADi.

version() -> char const *

The format is 'x.y.z' or 'x.y.z+'

The variant without + indicates that the version is an official release

The variant with + indicates that the version is more recent than 'x.y.z', and might be more recent than 'x.y.w' with w>z.

See also: getGitRevision getGitDescribe

Extra doc | Doc source | Implementation