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])
- 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
- 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)
- 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])
- 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
- 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])
- 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
- 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
- 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
xandymust 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. Whenyis 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))
- 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)
- 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
- 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_offsetand every row block is then split athorz_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]]
- 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-1expression with the spline values atx. 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
knotsm -- 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
- 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
- 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
- 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
- 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:
iis a column index,ja 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)
- 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
- 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
- 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'
- 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
- 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
indevaluates to the integer k, where 0<=k<x.size(), then x[k] is returned, otherwisex_defaultis returned (also for negative or non-integer values). By default this is a chain of if_else expressions, so all cases are evaluated. Withshort_circuittrue (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
- 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)
- 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
- 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
- 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
- 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]."
- 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")
- 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
- 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
- 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
yis 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
- 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)
- 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)
- 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)
- convexify(...)¶
Make a symmetric matrix positive definite at evaluation time.
convexify(MX H, dict opts) -> MX
Returns an expression with the sparsity pattern of
Hthat, when evaluated, modifies the value ofHso that it is positive definite. Intended for Hessians in SQP-type methods.Hmust 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
- 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
xand the sign ofy, as C copysign; a negative zeroycounts as negative. Shape rules as for plus. The derivative with respect toyis 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
- 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)]])
- 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])
- cross(...)¶
Matlab's
crosscommand.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.
aandbmust 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))])
- 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)
- 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)])
- 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
- 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
- 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
- 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))
- 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
- 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))
- 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)
- 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
- 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))
- 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 ofxoutside 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-diagonalx.- 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
- 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;
npasses 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
- difference(...)¶
Return all elements of
athat do not occur inb, 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
aare 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
- doc_archiver(...)¶
Get the documentation string for a plugin.
doc_archiver(str name) -> str
- 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
- doc_dple(...)¶
Get the documentation string for a plugin.
doc_dple(str name) -> str
- doc_expm(...)¶
Get the documentation string for a plugin.
doc_expm(str name) -> str
- doc_filesystem(...)¶
Get the documentation string for a plugin.
doc_filesystem(str name) -> str
- doc_graphmodel(...)¶
Get format-specific documentation.
doc_graphmodel(str name) -> str
- 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
- doc_interpolant(...)¶
Get the documentation string for a plugin.
doc_interpolant(str name) -> str
- 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
- doc_modelicaparser(...)¶
Get solver specific documentation.
doc_modelicaparser(str name) -> str
- 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
- 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
- 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
xandyof 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)))
- dple_in(...)¶
Get DPLE input scheme name by index.
dple_in() -> [str] dple_in(int ind) -> str
Get input scheme of DPLE solvers.
- dple_n_in(...)¶
Get the number of QP solver inputs.
dple_n_in() -> int
- dple_n_out(...)¶
Get the number of QP solver outputs.
dple_n_out() -> int
- dple_out(...)¶
Get DPLE output scheme name by index.
dple_out() -> [str] dple_out(int ind) -> str
Get output scheme of DPLE solvers.
- 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
- 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
- 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
- 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
- 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
- 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
- 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
aandbis 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]])
- 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)
- 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
- 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
- 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
exprand 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
- 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
- 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
- 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)))
- 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
- 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
- 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])
- 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
- expm_n_in(...)¶
Get the number of expm solver inputs.
expm_n_in() -> int
- expm_n_out(...)¶
Get the number of expm solver outputs.
expm_n_out() -> int
- 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
- 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) ordepends.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) ordepends.exe(win) to check which symbols are present in your shared librarybin_name -- File name of the shared library
- external_transform(...)¶
Apply a transformation defined externally.
external_transform(str name, str op, Function f, dict opts) -> Function
- Parameters:
name -- Name of the shared library
op -- Name of the operation
f -- Function to transform
opts -- Options Extra doc: https://github.com/casadi/casadi/wiki/L_27i
- 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
exso that selected intermediate results are replaced by new symbolsvwith definitionsvdef(ex, v and vdef are outputs; in Python the call is extract(ex, opts) -> (ex, v, vdef)). Substitutingvdefforvin 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
- 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.
exprmay also be a list of expressions andpara 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
- 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))
- 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
xwhose value is not zero, or to the length ofxwhen all entries are zero. Structural zeros are skipped. The result is piecewise constant, so its derivative is zero.xmust 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
- 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)))
- 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))
- 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))
- 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
xand 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 ofxstay 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
- 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 ofex: the result is a list over directions of lists overex, 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
argopts -- 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
- 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
fat the five Gauss points of [a, b] and returns the weighted sum, which is exact for polynomials inxup to degree 9. Only defined for SX.- Parameters:
f -- Scalar expression to integrate; it may depend only on
xx -- 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
- 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
- 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 ofarg, also for a matrixarg. A non-scalarexraises 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)]])
- 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
exby vdef[i]. Unlike substitute, which only accepts symbolic primitives forv, 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
vupdated -- 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
- 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
- has_archiver(...)¶
Check if a particular plugin is available.
has_archiver(str name) -> bool
- 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
nameif 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)
- has_dple(...)¶
Check if a particular plugin is available.
has_dple(str name) -> bool
- has_expm(...)¶
Check if a particular plugin is available.
has_expm(str name) -> bool
- has_filesystem(...)¶
Check if a particular plugin is available.
has_filesystem(str name) -> bool
- has_graphmodel(...)¶
Check if a graph-model format plugin is available.
has_graphmodel(str name) -> bool
- has_integrator(...)¶
Check if an integrator plugin is available.
has_integrator(str name) -> bool
Tries to load the plugin
nameif 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)
- has_interpolant(...)¶
Check if a particular plugin is available.
has_interpolant(str name) -> bool
- has_linsol(...)¶
Check if a linear solver plugin is available.
has_linsol(str name) -> bool
Tries to load the plugin
nameif 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)
- has_modelicaparser(...)¶
Check if a particular plugin is available.
has_modelicaparser(str name) -> bool
- has_nlpsol(...)¶
Check if an NLP solver plugin is available.
has_nlpsol(str name) -> bool
Tries to load the plugin
nameif 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)
- has_onnxbackend(...)¶
Check if a given ONNX runtime backend is available.
has_onnxbackend(str solver) -> bool
- has_rootfinder(...)¶
Check if a rootfinder plugin is available.
has_rootfinder(str name) -> bool
Tries to load the plugin
nameif 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)
- 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.
- 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))
- 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.exmust be scalar. The overload withoutput_galso 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)])
- 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
vside 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
- 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
- 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
ncolumn blocks of equal width, in order. An error is raised when the column count ofxis not a multiple ofnornis negative. A matrix without columns givesncopies 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
nmatrices of the same type asx
>>> 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
- 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
- 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_truewherecondis nonzero andif_falseelsewhere.condmay 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. Withshort_circuittrue (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
- 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
- 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
- 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
- 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
- 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
vholds the values at abscissa x[i], sovhas as many rows asxhas entries and every column is interpolated independently. The result has one row per query point xq[j].Queries outside the range of
xare clamped to the first or last data point (no extrapolation). The result is a constant sparse matrix timesv, so for symbolicvthe expression is linear inv.- 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,
xis 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
- 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=truewhich enables correct derivativesOverload:
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=truewhich enables correct derivativesOverload:
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=truewhich enables correct derivativesOverload:
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
- 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)
- 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]])
- 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
- 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
afrom skew(a). A non-3-by-3 argument raises an error.See also:
skew
- 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
- 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
exprdepends onvarwith 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
- 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; henceexprmust 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
- is_slice(...)¶
Check if an index vector can be represented more efficiently as a slice.
is_slice([int] v, bool ind1) -> bool
- is_slice2(...)¶
Check if an index vector can be represented more efficiently as two nested
is_slice2([int] v) -> bool
slices.
- 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
exwith respect toarg, with both treated as column-major vectors of their elements: the result is ex.numel()-by- arg.numel(), one row per element ofexand one column per element ofarg. Entries that are structurally zero are left out of the sparsity pattern.argmust 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
- 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
- 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)ormul(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
exandargare kept:vmust have the shape ofarg(or ofexwhentris 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 whentris true). An inconsistent shape ofvraises 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)])
- 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
aandb. 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)
- kron_contract(...)¶
Kronecker contraction, the adjoint of kron.
kron_contract(MX m, MX x, bool inner) -> MX
Contracts a matrix
mwhose dimensions are multiples of those ofx(as produced by kron) againstx. With mB-by-nB the shape ofxand blocks M[i*mB+r, j*nB+s] ofm:innertrue: Y[i, j] = sum over (r, s) of M[i*mB+r, j*nB+s] * X[r, s]innerfalse: 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
- 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
Das a vector,LTholding the strictly upper triangular entries of L^T (the unit diagonal is omitted), and the permutationp. 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
- 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
bis densifiedD -- 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])
- 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
- 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.
exprmust be a vector (a matrix raises an error).- Parameters:
check[in] -- When true (default),
expris checked to be linear invar(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
- 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
x0must have the shape ofxor 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
- linspace(...)¶
Matlab's
linspacecommand.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
nstepsentries, the endpoints included. For nsteps == 1 the result isb. Whenaandbare matrices, thenstepsintermediate matrices are stacked vertically (vertcat).nstepsmust 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])
- load_archiver(...)¶
Explicitly load a plugin dynamically.
load_archiver(str name)
- 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
- load_dple(...)¶
Explicitly load a plugin dynamically.
load_dple(str name)
- load_expm(...)¶
Explicitly load a plugin dynamically.
load_expm(str name)
- load_filesystem(...)¶
Explicitly load a plugin dynamically.
load_filesystem(str name)
- load_graphmodel(...)¶
Explicitly load a graph-model format plugin.
load_graphmodel(str name)
- 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
- load_interpolant(...)¶
Explicitly load a plugin dynamically.
load_interpolant(str name)
- 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
- load_modelicaparser(...)¶
Explicitly load a plugin dynamically.
load_modelicaparser(str name)
- 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
- load_onnxbackend(...)¶
Load an ONNX runtime backend.
load_onnxbackend(str solver)
- 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
- 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))
- 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
- 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))
- 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
- logic_and(...)¶
Logical
andlogic_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
anddoes 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]])
- 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
- logic_not(...)¶
Logical
notx -> !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
notdoes 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))
- logic_or(...)¶
Logical
orlogic_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))
- 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
- 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
- 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 gridv, 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 ofpand 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
- 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]])
- 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 ofzmust match the product, otherwise an error is raised. Whenxoryis a scalar the result is z + x*y. Seemtimesfor the meaning of theblasargument.mtimes is implemented as mac with a structurally zero
zof 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
- 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
eto scalar SX operations (including inlined Function calls, as Function.expand does) and returns a call to the resulting SXFunction, with the free symbols ofeas arguments. Expressions listed inboundaryare 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
- 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:
iis the column that is removed,jthe 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)
- 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)
- 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])
- 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))
- 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))
- 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
xand a constant integer scalarn, computes the repeated matrix product by squaring. n == 0 gives the (sparse) identity, negativengives the inverse of the positive power (via inv). If both arguments are scalar, this is the elementwise pow. A non-integer or symbolicnfor 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
- 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]])
- 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
exaround the pointawith respect to the symbols inx, keeping all terms whose total degree is at mostorder. The total degree of x^n*y^m is n+m.exandxmust be dense;amust have the same number of entries asx. 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
xorder -- 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
- 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
xmust equal the row count ofy, 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
blasselects 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
- 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
- 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
- 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
- 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
- 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)
- 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)
- 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"
- 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")
- 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
- 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
- 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
exprare 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)
- 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)
- 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
- 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)))
- 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
- 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))))
- 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)))
- 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)
- 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)
- 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
vertis false) of the matrices inv, starting with 0. The result has one entry more thanvand is the offset list that vertsplit (or horzsplit) needs to undo a vertcat (or horzcat) ofv.- 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
- onnxbackend_doc(...)¶
Get documentation for an ONNX runtime backend.
onnxbackend_doc(str solver) -> str
- onnxbackend_solvers(...)¶
List available ONNX runtime backends.
onnxbackend_solvers() -> [str]
- 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
Ais 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)])
- 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
- 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
xraises an error. Only defined for SX.- Parameters:
ex -- Scalar SX expression that is a polynomial in
xx -- 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
- poly_roots(...)¶
Roots of a polynomial given by its coefficients, in closed form.
poly_roots(DM p) -> DM poly_roots(SX p) -> SX
pis 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
- 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 ofx(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))
- 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
xstay 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))
- 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.
xbmust be a unary or binary operation (a symbol or constant raises an error for SX) andargsmust 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)"
- 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
Aoutsidespare dropped; entries ofspnot present inAbecome numerical zeros. The shape ofspmust equal that ofA. Withintersecttrue, the target pattern is the intersection ofspand the pattern ofA, 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]])
- 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().
tvalmust be increasing. The result is a sum of step functions, so it is not smooth; its derivative with respect totis 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
- 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
- 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
- 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
bis densifiedv -- 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])
- 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
Vand scaling factorsbeta), the upper triangular factorRand the row and column permutationsprinvandpcthat 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
- 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
exprraises 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
- 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)))
- 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,
Ais returned unchangedx -- 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))
- 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
xstay structural zeros; dividing by a sparseydensifies.>>> 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]])
- 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])
- 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
xstay 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
- 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
Ainto 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 ofnreferences.- 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)
- 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
Ainto 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 ofAmust be multiples ofnandm.>>> 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
- 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
xin column-major order as a matrix ofnrowbyncol, 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
- 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 ofarg: the result is a list over directions of lists overarg. Not defined for DM.- Parameters:
ex -- List of expressions
arg -- List of symbolic expressions
v -- List of directions, each a list of seeds matching
exopts -- 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
- 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
- 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
- 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
- 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|)"
- 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"
- 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
- 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
- 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
exprmust be listed insym_linorsym_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_linandsym_constmay 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
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+ counterv_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)])
- 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
- 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
- simpleIntegrator(...)¶
Simplified wrapper for the Integrator class.
simpleIntegrator(Function f, str integrator, dict integrator_options) -> Function
- 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
- 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)
- 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))
- 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])
- 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])
- 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
- 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:
A simple forward or backward substitution if A is upper or lower triangular
If the linear system is at most 3-by-3, form the inverse via minor expansion and multiply
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
Agives the elementwise division b/A.bmay have several columns (one right-hand side each). A non-squareAor 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])
- 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
tolis 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
- 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
xin storage order and gives them the patternsp, 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
xwith patternsp
>>> 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
- 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
- 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
- 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
exprin a non-inlined Function call whose derivatives of the given order are declared zero. The value is unchanged. Withorder1 the expression is treated as a constant by all differentiation; withorder2 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)
- 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]
vmust be symbolic and have the same shape asvdef(for SX also the same sparsity). For MX,vmust be a symbolic primitive as created by MX.sym; an element of such a primitive is rejected. Substituting a symbol that does not occur inexis 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
- 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
vout of the expressionsvdefsequentially, as well as out of a number of other expressions piggybackInterprets vdef[k] as the definition of the symbol v[k] and resolves the definitions into each other, so that afterwards neither
vdefnorexcontain any of the symbolsv. Bothvdefandexare modified in place (and returned, in Python).vmust consist of symbolic primitives with the shapes ofvdef.reverseis 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
- 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)
- 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]])
- 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])
- 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))
- 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
- 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])
- 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
exwith respect to a scalararg, computed with one forward-mode sweep and projected onto the sparsity ofex: the result has the shape and pattern ofex. A non-scalarargraises 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])
- 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])
- 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
exaroundawith respect to the scalar symbolxup 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 matrixex; sparseexraises an error.amay 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
- 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
- to_slice(...)¶
Construct from an index vector (requires is_slice(v) to be true)
to_slice([int] v, bool ind1) -> Slice
- 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)
- 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
- 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
passesa 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
- 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
- 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])
- 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
- 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]])
- 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
- 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]])
- 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
AandBat 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
- 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
xon 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')
- 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])
- 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
vstacked 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
- 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
- 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
nrow blocks of equal height, in order. An error is raised when the row count ofxis not a multiple ofnornis negative. A matrix without rows givesncopies 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
nmatrices of the same type asx
>>> 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
- 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
order1, an entry depends if the corresponding Jacobian entry is structurally nonzero; withorder2, 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 ofexprdepend on it. When true, one entry per element ofexpr: does it depend on any element ofvar.
- 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
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)
- 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)
- columns(...)¶
Get the number of columns, Octave-style syntax (same as size2())
columns(self) -> int
- 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)
- 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
- dim(...)¶
Get string representation of dimensions.
dim(self, bool with_nz) -> str
The representation is e.g. "4x5" or, with
with_nztrue, "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")
- 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.
morehas no effect for matrices.
- 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)
- 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
- 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.
rrlists, for every existing row, its index in the enlarged matrix;ccdoes 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
- 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)
- 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
- 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
- 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
- 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.subOverload:
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
rrandccis 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
- 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
- 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
- static get_max_depth(...)¶
Get the depth to which SX subexpressions are compared during simplification.
get_max_depth() -> int
See also:
set_max_depth
- 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
- get_output(...)¶
Get an output.
get_output(self, int oind) -> DM
- static get_precision(...)¶
Get the precision, field width and scientific flag used when printing
get_precision() -> int
nonzeros.
- 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
- has_output(...)¶
Check if a multiple output node.
has_output(self) -> bool
- 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)
- 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]])
- 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"
- is_call(...)¶
Check if function call.
is_call(self) -> bool
- is_column(...)¶
Check if the matrix is a column vector (i.e. size2()==1)
is_column(self) -> bool
- is_commutative(...)¶
Check whether a binary SX is commutative.
is_commutative(self) -> bool
Only defined if symbolic scalar.
- 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
- 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)
- is_empty(...)¶
Check if the matrix is empty, i.e. if one of the dimensions is zero.
is_empty(self, bool both) -> bool
With
bothtrue, 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
- is_eye(...)¶
check if the matrix is an identity matrix (note that false negative answers
is_eye(self) -> bool
are possible)
- is_half(...)¶
check if the matrix is 0.5 (note that false negative answers are possible)
is_half(self) -> bool
- is_inf(...)¶
check if the matrix is inf (note that false negative answers are possible)
is_inf(self) -> bool
- is_integer(...)¶
Check if the matrix is integer-valued.
is_integer(self) -> bool
(note that false negative answers are possible)
- is_leaf(...)¶
Check if SX is a leaf of the SX graph.
is_leaf(self) -> bool
Only defined if symbolic scalar.
- is_minus_inf(...)¶
check if the matrix is -inf (note that false negative answers are possible)
is_minus_inf(self) -> bool
- is_minus_one(...)¶
check if the matrix is -1 (note that false negative answers are possible)
is_minus_one(self) -> bool
- is_nonnegative(...)¶
check if the matrix is not negative
is_nonnegative(self) -> bool
(note that false negative answers are possible)
- is_one(...)¶
check if the matrix is 1 (note that false negative answers are possible)
is_one(self) -> bool
- is_op(...)¶
Is it a certain operation.
is_op(self, int op) -> bool
- is_output(...)¶
Check if evaluation output.
is_output(self) -> bool
- 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
- is_row(...)¶
Check if the matrix is a row vector (i.e. size1()==1)
is_row(self) -> bool
- 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)
- 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)
- is_square(...)¶
Check if the matrix is square, i.e. size1() equals size2()
is_square(self) -> bool
- 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
- is_tril(...)¶
Check if the matrix is lower triangular.
is_tril(self) -> bool
Decided on the sparsity pattern alone, see is_triu.
- 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)
- 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
- is_value(...)¶
check if the matrix is value
is_value(self, float val) -> bool
- 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)
- is_zero(...)¶
check if the matrix is 0 (note that false negative answers are possible)
is_zero(self) -> bool
- 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
- 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
- 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
- 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
- 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)
- 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)
- 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)
- nonzeros(...)¶
Get all nonzeros.
nonzeros(self) -> [float]
- 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
- 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
spto 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]])
- op(...)¶
Get operation type.
op(self) -> int
- 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
- 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
- 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
- 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"])
- 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]
- 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
- 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
- reserve(...)¶
reserve(self, int nnz) reserve(self, int nnz, int ncol)
Reserve storage for the given number of nonzeros (performance hint, no visible effect)
- 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
- 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
- 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)
- rows(...)¶
Get the number of rows, Octave-style syntax (same as size1())
rows(self) -> int
- 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
- 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.
mmust 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 ofm(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
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.
mmust 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 sparsemfirst 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
- 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
- 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).
mmust 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
- 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
- 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)
- 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)
- size2(...)¶
Get the second dimension (i.e. number of columns)
size2(self) -> int
- 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
- str(...)¶
Get the string representation that disp prints.
str(self, bool more) -> str
- 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
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
spbecome 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.
- 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
formatis 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
- 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
- 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")
- static unary(...)¶
unary(int op, DM x) -> DM
- which_function(...)¶
Get function - only valid when is_call() is true.
which_function(self) -> Function
- which_output(...)¶
Get the index of evaluation output - only valid when is_output() is true.
which_output(self) -> int
- 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))
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)
- 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)
- columns(...)¶
Get the number of columns, Octave-style syntax (same as size2())
columns(self) -> int
- 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)
- 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
- dim(...)¶
Get string representation of dimensions.
dim(self, bool with_nz) -> str
The representation is e.g. "4x5" or, with
with_nztrue, "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")
- 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.
morehas no effect for matrices.
- 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)
- 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
- 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.
rrlists, for every existing row, its index in the enlarged matrix;ccdoes 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
- 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)
- 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
- 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
- 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
- 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.subOverload:
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
rrandccis 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
- 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
- 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
- static get_max_depth(...)¶
Get the depth to which SX subexpressions are compared during simplification.
get_max_depth() -> int
See also:
set_max_depth
- 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
- get_output(...)¶
Get an output.
get_output(self, int oind) -> SX
- static get_precision(...)¶
Get the precision, field width and scientific flag used when printing
get_precision() -> int
nonzeros.
- 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
- has_output(...)¶
Check if a multiple output node.
has_output(self) -> bool
- 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)
- 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]])
- 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"
- is_call(...)¶
Check if function call.
is_call(self) -> bool
- is_column(...)¶
Check if the matrix is a column vector (i.e. size2()==1)
is_column(self) -> bool
- is_commutative(...)¶
Check whether a binary SX is commutative.
is_commutative(self) -> bool
Only defined if symbolic scalar.
- 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
- 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)
- is_empty(...)¶
Check if the matrix is empty, i.e. if one of the dimensions is zero.
is_empty(self, bool both) -> bool
With
bothtrue, 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
- is_eye(...)¶
check if the matrix is an identity matrix (note that false negative answers
is_eye(self) -> bool
are possible)
- is_half(...)¶
check if the matrix is 0.5 (note that false negative answers are possible)
is_half(self) -> bool
- is_inf(...)¶
check if the matrix is inf (note that false negative answers are possible)
is_inf(self) -> bool
- is_integer(...)¶
Check if the matrix is integer-valued.
is_integer(self) -> bool
(note that false negative answers are possible)
- is_leaf(...)¶
Check if SX is a leaf of the SX graph.
is_leaf(self) -> bool
Only defined if symbolic scalar.
- is_minus_inf(...)¶
check if the matrix is -inf (note that false negative answers are possible)
is_minus_inf(self) -> bool
- is_minus_one(...)¶
check if the matrix is -1 (note that false negative answers are possible)
is_minus_one(self) -> bool
- is_nonnegative(...)¶
check if the matrix is not negative
is_nonnegative(self) -> bool
(note that false negative answers are possible)
- is_one(...)¶
check if the matrix is 1 (note that false negative answers are possible)
is_one(self) -> bool
- is_op(...)¶
Is it a certain operation.
is_op(self, int op) -> bool
- is_output(...)¶
Check if evaluation output.
is_output(self) -> bool
- 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
- is_row(...)¶
Check if the matrix is a row vector (i.e. size1()==1)
is_row(self) -> bool
- 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)
- 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)
- is_square(...)¶
Check if the matrix is square, i.e. size1() equals size2()
is_square(self) -> bool
- 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
- is_tril(...)¶
Check if the matrix is lower triangular.
is_tril(self) -> bool
Decided on the sparsity pattern alone, see is_triu.
- 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)
- 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
- is_value(...)¶
check if the matrix is value
is_value(self, float val) -> bool
- 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)
- is_zero(...)¶
check if the matrix is 0 (note that false negative answers are possible)
is_zero(self) -> bool
- 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
- 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
- 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
- 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
- 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)
- 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)
- 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)
- nonzeros(...)¶
Get all nonzeros.
nonzeros(self) -> [SXElem]
- 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
- 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
spto 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]])
- op(...)¶
Get operation type.
op(self) -> int
- 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
- 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
- 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
- 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"])
- 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]
- 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
- 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
- reserve(...)¶
reserve(self, int nnz) reserve(self, int nnz, int ncol)
Reserve storage for the given number of nonzeros (performance hint, no visible effect)
- 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
- 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
- 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)
- rows(...)¶
Get the number of rows, Octave-style syntax (same as size1())
rows(self) -> int
- 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
- 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.
mmust 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 ofm(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
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.
mmust 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 sparsemfirst 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
- 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
- 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).
mmust 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
- 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
- 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)
- 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)
- size2(...)¶
Get the second dimension (i.e. number of columns)
size2(self) -> int
- 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
- str(...)¶
Get the string representation that disp prints.
str(self, bool more) -> str
- 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
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
spbecome 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.
- 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
formatis 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
- 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
- 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")
- static unary(...)¶
unary(int op, SX x) -> SX
- which_function(...)¶
Get function - only valid when is_call() is true.
which_function(self) -> Function
- which_output(...)¶
Get the index of evaluation output - only valid when is_output() is true.
which_output(self) -> int
- 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))
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])
Authors: Joel Andersson
- 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
yis evaluated too and a runtime error withfail_messageis raised unlessyequals 1. Useful to check preconditions inside a Function. A non-scalaryraises 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
- 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
- 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
- class_name(...)¶
Get class name.
class_name(self) -> str
- 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)
- columns(...)¶
Get the number of columns, Octave-style syntax (same as size2())
columns(self) -> int
- debug_repr(...)¶
debug_repr(self) -> str
- dep(...)¶
Get the
ch-thdependency (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)
- static deserialize(...)¶
Deserialize an expression from a stream, with type disambiguation.
deserialize(casadi::DeserializingStream & s) -> MX
Counterpart of serialize; use StringDeserializer.unpack from Python.
- dim(...)¶
Get string representation of dimensions.
dim(self, bool with_nz) -> str
The representation is e.g. "4x5" or, with
with_nztrue, "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")
- disp(...)¶
Print a description of the object.
disp(self, bool more)
- 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_filenameand 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
- 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
aandbis 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]])
- enlarge(...)¶
Enlarge matrix.
enlarge(self, int nrow, int ncol, [int] rr, [int] cc, bool ind1)
Makes the matrix
nrow-by-ncolbyinserting 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
- 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
rrholds 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
rrand columnsccfrom 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
- 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
arginstead of the node's own dependencies, with the usual simplifications.argmust 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
- static eye(...)¶
Identity matrix constant of size
n-by-n, with a diagonal sparsityeye(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)
- 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)
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.
rrandccselect 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
- 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
- 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
- static get_max_depth(...)¶
Get the depth to which equalities are checked for simplifications.
get_max_depth() -> int
See also:
set_max_depth
- 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)
- 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 onlyoind== 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
- 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
- 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))
- 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}()
- 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
- 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)
- 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)
- 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
- is_column(...)¶
Check if the matrix is a column vector (i.e. size2()==1)
is_column(self) -> bool
- 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)
- 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
- 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)
- 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)
- is_empty(...)¶
Check if the matrix is empty, i.e. if one of the dimensions is zero.
is_empty(self, bool both) -> bool
With
bothtrue, 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
- 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)
- is_half(...)¶
Check if the node is a constant with all nonzeros 0.5 (false negatives
is_half(self) -> bool
possible)
- 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
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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)
- 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
- 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
- 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
- is_row(...)¶
Check if the matrix is a row vector (i.e. size1()==1)
is_row(self) -> bool
- 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)
- is_square(...)¶
Check if the matrix is square, i.e. size1() equals size2()
is_square(self) -> bool
- 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
- 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
- is_tril(...)¶
Check if the matrix is lower triangular.
is_tril(self) -> bool
Decided on the sparsity pattern alone, see is_triu.
- 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)
- 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)
- 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
- 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
- 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)
- 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
- 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:
vholds 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
- 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
- monitor(...)¶
Return the expression with the side effect of printing its value.
monitor(self, str comment) -> MX
When the returned expression is evaluated,
commentfollowed 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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)
- 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)
- 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)
- 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
- 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
- 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
spto 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]])
- 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
- 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
- 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
bis 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
- reset_dump_count(...)¶
Reset the file counter of a dump node; raises an error on any other node.
reset_dump_count(self)
- 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)
- rows(...)¶
Get the number of rows, Octave-style syntax (same as size1())
rows(self) -> int
- 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
- 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 sparsemfirst erases the targeted elements.mmust 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)
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.
mmust 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
- 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
- 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.
mmust 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
- 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)
- 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)
- size2(...)¶
Get the second dimension (i.e. number of columns)
size2(self) -> int
- sparsity(...)¶
Get an owning reference to the sparsity pattern.
sparsity(self) -> Sparsity
- 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:
xmust 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
- str(...)¶
Get string representation.
str(self, bool more) -> str
- 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
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
spbecome 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.
- static test_cast(...)¶
Check if a SharedObjectInternal pointer refers to an MX node (C++ only)
test_cast(casadi::SharedObjectInternal const * ptr) -> bool
- to_DM(...)¶
to_DM(self) -> DM
- static type_name(...)¶
Get type name.
type_name() -> str
- 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
- 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
- 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
- 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))
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:
"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].
"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:
MatrixAuthors: Joel Andersson
- 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
- 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
amdargument 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
- 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
- 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
- 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
- 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 negativepan 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)
- 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
- 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
- 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)
- class_name(...)¶
Get class name.
class_name(self) -> str
- 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_colindColumn 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
- columns(...)¶
Number of columns, Octave-style alias of size2.
columns(self) -> int
- 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
canonicalfalse, 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
- 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)
- 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
- 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
- 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
- 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)
- 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
- disp(...)¶
Print a description of the object.
disp(self, bool more)
- 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
- 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
- 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
- erase(...)¶
Turn the entries with flat (column-major) indices
rrinto structuralerase(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),findTurn the entries with rows
rrand columnsccinto 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
rrand its column is incc, so an emptyrrorccremoves 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]])
- 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
atafalse the result matches MATLAB's etree(A) with zero- based indices (the pattern is treated as symmetric, only the upper triangular part is used); withatatrue 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]
- 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
- 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[])
- 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
- 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
- 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
- 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
- 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[])
- 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])
- 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
indicesis 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
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,findOverload:
get_nz(self, [int] rr, [int] cc)Nonzero indices of the block of entries with rows
rrand columnscc.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
- 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])
- get_upper(...)¶
Nonzero indices of the entries in the upper triangular part (row <= col)
get_upper(self) -> [int]
- 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
- 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
- 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}()
- 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
- 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
- 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
- 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)
- 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)
- 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
- 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_emptythe pattern must also be square with exactly one nonzero per row and column (a permutation pattern). Withallow_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
- is_orthonormal_columns(...)¶
Check whether the columns are orthonormal (see is_orthonormal_rows)
is_orthonormal_columns(self, bool allow_empty) -> bool
Without
allow_emptythe pattern must have at most as many columns as rows and exactly one nonzero per column. Withallow_empty, columns without nonzeros are disregarded.- Parameters:
allow_empty -- Disregard empty columns in the analysis
See also:
is_orthonormal_rows,is_orthonormal
- 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_emptythe pattern must have at most as many rows as columns and exactly one nonzero per row. Withallow_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
- 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
- is_reshape(...)¶
Check whether
yis 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
- 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
- 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)
- 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
- 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
- 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
- is_stacked(...)¶
Check whether the pattern is
ncopies ofyplaced side by side.is_stacked(self, Sparsity y, int n) -> bool
True when this pattern equals horzcat(y, ..., y) with
nrepetitions, 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
- 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
- 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
- is_transpose(...)¶
Check whether
yis 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
- 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)
- 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)
- 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
- 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 JacobianJ(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
Hwith_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
- 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
- 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
- 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]])
- 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])
- 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).
- nnz_diag(...)¶
Number of nonzeros on the main diagonal, i.e. entries (i, i)
nnz_diag(self) -> int
- 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)
- 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)
- 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
- 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)
- 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)
- 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
inverttrue 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
- 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
- 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_permutationthe 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 (ifpermute_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
- postfix_dim(...)¶
Dimension string to append to a name, as used when printing symbolic
postfix_dim(self) -> str
primitives.
Rules:
Dense scalar: ""
0-by-0: "[]"
Dense column vector: "[5]"
Other dense pattern: "[5x10]"
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
- 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
- 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
- repr_el(...)¶
Describe the position of nonzero
kas 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).
kmust 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)"
- resize(...)¶
Change the shape in place, keeping the nonzeros that still fit.
resize(self, int nrow, int ncol)
Nonzeros with row >=
nrowor column >=ncolare 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)
- 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_rowRow 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
- static rowcol(...)¶
Create the pattern of a block: all entries (i, j) with i in
rowand j inrowcol([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
- rows(...)¶
Number of rows, Octave-style alias of size1.
rows(self) -> int
- 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
- 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
- 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])
- 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
- 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)
- 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)
- size2(...)¶
Number of columns.
size2(self) -> int
- sparsity_cast_mod(...)¶
Propagate a subset of a pattern through a sparsity cast.
sparsity_cast_mod(self, Sparsity X, Sparsity Y) -> Sparsity
XandYhave 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 ofX, the result is the subset ofYmade of the nonzeros ofYwhose counterpart inXis 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
- 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
- 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
- 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
- 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
- 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
- str(...)¶
Get string representation.
str(self, bool more) -> str
- 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])
rrlists one flat (column-major) element index per nonzero ofsp. The result has the shape ofspand keeps the nonzeros ofspwhose 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
Pattern of the submatrix with rows
rrand columnscc.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
- static test_cast(...)¶
Check if a particular cast is allowed.
test_cast(casadi::SharedObjectInternal const * ptr) -> bool
- 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_hintis 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
- 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_mappingtrue, 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
- 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
rowinvert_mapping -- Selects the direction of the returned mapping (see below)
The overload with
invert_mappingadditionally returns a mapping between the given entries and the nonzeros of the result (which are in column-major order). Withinvert_mappingfalse, mapping[k] is the position in the input of nonzero k (length nnz(); for duplicates the first occurrence). Withinvert_mappingtrue, 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)
- static type_name(...)¶
Readable name of the public class.
type_name() -> str
- 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
- 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
- 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)
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
- activity(...)¶
Output signal activity induced by a given input activity.
activity(self, [bool] arg) -> [bool]
argis 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.
- assert_size_in(...)¶
Raise an error unless input
iisnrow-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
- assert_size_out(...)¶
Raise an error unless output
iisnrow-by-ncol.assert_size_out(self, int i, int nrow, int ncol)
- assert_sparsity_out(...)¶
Raise an error unless output
ihas the sparsitysprepeatedn.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.
- 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
coeffswith 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 ofknotsanddegreeraises 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
- 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"
- 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
- 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
- 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
- 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)
- class_name(...)¶
Get class name.
class_name(self) -> str
- static conditional(...)¶
Create a function that calls
fwhen 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
fentirely.>>> 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_elseCreate 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 fromf_defand 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
- 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
- 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
- debug_repr(...)¶
debug_repr(self) -> str
- default_in(...)¶
Get the value used for input
indwhen 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
- 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
- disp(...)¶
Print a description of the object.
disp(self, bool more)
- 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
- 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
- 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.
- 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_inand returns the outputs listed ins_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_inis 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
- 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
- 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
- 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
- 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_accuminputs are accumulators: in every step they take the value of the firstn_accumoutputs 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
baseiterations (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 listsaccum_inandaccum_outof 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
- forward(...)¶
Get a function computing
nfwdforward 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.
nfwdmust 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))
- 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)
- free_sx(...)¶
Get the free variables of an SXFunction as SX symbols; other classes raise.
free_sx(self) -> [SX]
- 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
- 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
fnameand 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
- 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) tofname; 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
- 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.
- 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
- get_free(...)¶
Get the names of the free variables; empty when there are none.
get_free(self) -> [str]
- 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_functionGet 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
- 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
- has_function(...)¶
Check if a particular dependency exists.
has_function(self, str fname) -> bool
True if
fnameis among the names returned by get_function().See also:
get_function
- 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)
- 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
- has_out(...)¶
Check whether an output with the given name exists.
has_out(self, str name) -> bool
- 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
- 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
- hessian_old(...)¶
[DEPRECATED] Hessian and gradient of scalar output
oindw.r.t. inputhessian_old(self, int iind, int oind) -> Function
iind, followed by all outputs; use factory with "hess:out:in:in" instead
- static if_else(...)¶
Create a function that evaluates
f_trueorf_falsedepending 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 selectsf_false. Only the selected branch is evaluated numerically. The signature is taken fromf_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
- 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
- index_out(...)¶
Get the index of the output with a given name; unknown names raise an error.
index_out(self, str name) -> int
- 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}()
- instruction_MX(...)¶
Get the MX expression computed by instruction
kof 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
- 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
- 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
- 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
- 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
- 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
- is_a(...)¶
Check whether the function is of a given class.
is_a(self, str type, bool recursive) -> bool
typeis a class name as printed after the signature: "SXFunction", "MXFunction", "Map", "Switch", "External", "Nlpsol", "Conic", "Integrator", "Rootfinder" and the plugin names (e.g. "Ipopt"). Withrecursivetrue (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
- 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
- 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
- is_null(...)¶
is_null(self) -> bool
- jac_sparsity(...)¶
Get the sparsity pattern of the Jacobian of output
oindw.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:
jacobianGet 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
- 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
- jacobian_old(...)¶
[DEPRECATED] Jacobian of output
oindw.r.t. inputiind, followed byjacobian_old(self, int iind, int oind) -> Function
all outputs; use factory with "jac:out:in" instead
- 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.
bodyis 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
- 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
- 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,callOverload:
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_inare not widened: the same value is used in all n evaluations. Outputs listed inreduce_outare summed over the evaluations instead of stacked. The index and name overloads build an MXFunction around a plain map (parallelizationas in map;optsis currently ignored). The boolean-mask overload creates a dedicated serial MapSum node wrapped in an MXFunction built withopts; masks must have length n_in and n_out (an emptyreduce_outmeans 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]])
- 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_accuminputs are accumulators: in every step they take the value of the firstn_accumoutputs 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
baseiterations (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 listsaccum_inandaccum_outof 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
- 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)
- 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
- 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
- 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
- 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.
- 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
- 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
- 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
- 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
- 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
- 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"])
- 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"
- 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
- 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
- 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
- nominal_out(...)¶
Get the nominal value of each nonzero of output
ind; all ones bynominal_out(self, int ind) -> [float]
default.
See also:
nominal_in
- 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)
- 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)
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- print_ptr(...)¶
print_ptr(self)
- release(...)¶
Give back a memory object obtained with checkout.
release(self, int mem)
- 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
- reverse(...)¶
Get a function computing
nadjreverse (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.
nadjmust 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])
- 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")
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
oindw.r.t. inputiind; use jac_sparsity(oind, iind) (note the reversed argument order)
- 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
- 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
- str(...)¶
Get string representation.
str(self, bool more) -> str
- 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
- 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.
- 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)
- sz_iw(...)¶
Get the length of the integer work vector needed to evaluate.
sz_iw(self) -> size_t
- sz_res(...)¶
Get the length of the output pointer array needed to evaluate (at least.
sz_res(self) -> size_t
n_out)
- sz_w(...)¶
Get the length of the real work vector needed to evaluate.
sz_w(self) -> size_t
- 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
optsaccepts 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
- 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"
- 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
- 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 outputss_outdepends on that entry (order1) or depends on it nonlinearly (order2). Withtrtrue the relation is flipped: one boolean per nonzero of the vertically concatenated outputs, true when it depends on any entry ofs_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
- 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
- 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 whenoptsis empty andnameequals 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
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
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
mosekoption 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
xpressoption 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
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
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
See also
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=bby 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=bby 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
- class_name(...)¶
Get class name.
class_name(self) -> str
- 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
Afirst.>>> 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
- disp(...)¶
Print a description of the object.
disp(self, bool more)
- 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
- 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)
- 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
- 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
- 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
- plugin_name(...)¶
Query plugin name.
plugin_name(self) -> str
- 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
- 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.
- 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
trtrue)For DM arguments, factorizes
Aand solves for all columns ofBat once; the result is dense. For MX arguments, returns an expression node that is differentiable. The row count ofAandBmust 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
Ainstead
- 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
- sparsity(...)¶
Get the sparsity pattern of A fixed at construction.
sparsity(self) -> Sparsity
- 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
- str(...)¶
Get string representation.
str(self, bool more) -> str
- static type_name(...)¶
Get type name.
type_name() -> str
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,qpsolAuthors: Joris Gillis, Erik Lambrechts, Joel Andersson
- 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
lbandubare 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))
- 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.
- class_name(...)¶
Get class name.
class_name(self) -> str
- 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)
- 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. })
- dual(...)¶
Get the dual variable (Lagrange multiplier) of a constraint.
dual(self, MX m) -> MX
mmust 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
- 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
- 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.
- 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
- 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).
hmust 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
- set_domain(...)¶
Set the domain of a decision variable.
set_domain(self, MX x, str domain)
Marks all scalars of
xas 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
- 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.
xmay 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
- 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
- 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().
xmay 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
- 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
- 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)
- 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}} inplugin_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
- 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)
- str(...)¶
Get string representation.
str(self, bool more) -> str
- 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
resinto 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
optsare 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
- type_name(...)¶
Readable name of the class.
type_name(self) -> str
- 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
metainto 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"
- 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.
- 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
- 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
- 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
- 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")
- 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.
valuesoverrules 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)
- 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
- 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.
- 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]
- active_values(...)¶
Initial guesses (or parameter values) of the symbols returned by
active_values(self, casadi::VariableType type) -> [DM]
active_symvar.
- arg(...)¶
Solver arguments prepared by solve_prepare (x0, p, lam_g0, lbg, ubg)
arg(self) -> dict:DM
- assert_active_symbol(...)¶
Raise an error unless
mis a symbol of this instance that appears in theassert_active_symbol(self, MX m)
problem.
- assert_baked(...)¶
Raise an error when the problem is dirty.
assert_baked(self)
- assert_empty(...)¶
Raise an error if an objective or constraints are present.
assert_empty(self)
- assert_solved(...)¶
Raise an error unless solved()
assert_solved(self)
- 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.
- baked_copy(...)¶
Copy of the instance with the problem baked (see bake)
baked_copy(self) -> OptiAdvanced
- 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
- 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))]
- 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 ...
- 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.
- 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)
- 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
- g_index_unreduce_g(...)¶
Row of g for row i of the reduced g.
g_index_unreduce_g(self, int i) -> int
- 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])))
- get_meta(...)¶
Get meta-data of symbol (for internal use only)
get_meta(self, MX m) -> MetaVar
- get_meta_con(...)¶
Get meta-data of symbol (for internal use only)
get_meta_con(self, MX m) -> MetaCon
- instance_number(...)¶
Sequence number of this Opti instance in the process; prefixes the symbol
instance_number(self) -> int
names.
- 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)
- mark_problem_dirty(...)¶
Flag that the problem structure changed since the last bake.
mark_problem_dirty(self, bool flag)
- mark_solved(...)¶
Set or clear the solved state.
mark_solved(self, bool flag)
- mark_solver_dirty(...)¶
Flag that the solver must be reconstructed (solver() was called)
mark_solver_dirty(self, bool flag)
- objective(...)¶
Objective expression; same as f()
objective(self) -> MX
- problem_dirty(...)¶
True when the problem must be baked again before solving.
problem_dirty(self) -> bool
- 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)
- set_meta(...)¶
Set meta-data of an expression.
set_meta(self, MX m, MetaVar meta)
- set_meta_con(...)¶
Set meta-data of an expression.
set_meta_con(self, MX m, MetaCon meta)
- 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 ...
- solve_actual(...)¶
Run the solver on an argument dict (see solve_prepare)
solve_actual(self, dict:DM args) -> dict:DM
- 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"])
- solved(...)¶
True when a solver result is available for value()
solved(self) -> bool
- property solved_¶
solved_(self) -> bool
- solver_dirty(...)¶
True when the solver must be reconstructed.
solver_dirty(self) -> bool
- 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 thatexprdepends on, optionally filtered bytype. 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]
- 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.
- 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
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,whenand friends, or imported from an FMU /modelDescription.xml(constructor with a path,load_fmi_description). Numerical evaluation goes through the function factorycreate, 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 byall,inputs,outputs,createand the other category-based members. Internal helper variables (namedder(x),__alg__0,__assign__..,__when__0, ...) are created as equations are added; they show up inall().>>> 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
- 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.
exprmust be a pure symbol (is_symbolic()) whose name equalsname; 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 plainadd(name)gives a continuous local variable of categoryz.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
numelelements (the product of the dimensions). The category follows from causality and variability and may change later when equations are added:"parameter":"tunable"givesp(cfor non-floating-point types),"fixed"givesc; other variabilities are an error"calculatedParameter":d; requires"fixed"or"tunable""input":u; requires"continuous"or"discrete""output"and"local":"constant"givesc,"discrete"gives a statexwith zero derivative,"continuous"giveszuntil 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 iny(). 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, seeget"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, seeget"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
- 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
namefrom the compiled sources or shared library behindcompiler(seeexternal) and stores it.Overload:
add_fun(self, Function f)Add an already existing function.
Stores
funder 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
argto the binding expressions of the dependent variablesresand stores it in the instance. Stored functions are listed bydispand retrieved withfun.- 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 erroropts -- 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
- 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
createcan produce its Hessian blockshess_<name>_<in1>_<in2>with the multiplierslam_<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
- alg(...)¶
[DEPRECATED] Replaced with outputs("alg")
alg(self) -> [MX]
- 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 byeq,when,assignandreinit.>>> 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)__"])
- assign(...)¶
Assignment inside a when-equation or if-else equation.
assign(self, str name, MX val) -> str
Creates a helper variable holding the expression
valassigned to the variablenamewhen the event fires, and returns the helper's name for use inwhen. Intended for discrete-valued variables;reinitis 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
- 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, seeget). 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
- 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))
- c(...)¶
Named constants.
c(self) -> [str]
Names of the variables of category
c(fixed parameters and constants), in category order. Equivalent toall("c"). Constants are never function inputs:createsubstitutes their current value, seeset.
- categories(...)¶
Which categories are possible for a variable?
categories(self, str name) -> [str]
The categories
set_categoryaccepts 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
- 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
- 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
- cdef(...)¶
Definitions of named constants.
cdef(self) -> [MX]
The binding expressions of the constants
c, one per entry ofc(). Only constants that have a binding equation (imported from a symbolic model description) are supported; a constant without one raises an error.
- class_name(...)¶
Get class name.
class_name(self) -> str
- compile_fmu(...)¶
Compile the sources produced by export_fmu.
compile_fmu(self, dict files, dict opts) -> dict
Compiles all
.centries offiles(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 locationbinaries/<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
- 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 tointegrator. 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:
transitionOverload:
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; constantscare never inputs, their current values (seeset) are substituted. Outputs areode,alg,quad,zero,ddef,wdef,y. Dependent variableswand parametersdnot given as inputs are substituted out. Derivative outputs use the Function factory naming with underscores:jac_ode_x(Jacobian block) orhess_<lc>_x_xfor a linear combination declared withadd_lc, with the multiplierslam_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 instats()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,transitionOverload:
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) andlifted_calls(account for function calls lifted intow, seelift) instead; neither is available for an imported FMU.
- 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 toall("d"). They are defined by binding equations and are calculated bydependent_fun.See also:
ddef,dependent_fun,nd
- 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 (seesort). Equivalent tooutputs("ddef"). A dependent parameter without a binding equation raises an error.
- 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
dand/or dependent variableswfrom 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
- 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)forx.Overload:
der(self)Model structure: All time derivatives.
Names of all derivative variables, in creation order: the
der(x)variables created byderfor 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
xthe derivative variableder(x)is returned, created on first use (as an algebraic variable untileqgives 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
- derivatives(...)¶
[DEPRECATED] Renamed "der"
derivatives(self) -> [str]
- description(...)¶
Get/set description.
description(self, str name) -> str
Free-text description of a variable, also settable with the
"description"option ofadd.>>> 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"
- dimension(...)¶
Get the dimensions of a variable.
dimension(self, str name) -> [int]
The
"dimension"list given toadd(default[1]). The expression is always flattened to a column vector.See also:
numel
- disp(...)¶
Print a description of the object.
disp(self, bool more)
- 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 ofadd.
- 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 withsort). The variables keep existing but becomecalculatedand the category is left empty. For"q"the quadrature states are turned into regular statesxinstead. 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
- eq(...)¶
Add a simple equation.
eq(self, MX lhs, MX rhs, dict opts)
Adds the equation
lhs == rhsand reclassifies variables accordingly:lhsis the derivative of a state (der(x)): the equation becomes the ODE ofx, which moves fromztox;der(x)becomes a dependent variablewlhsis a variable of categoryz: the equation is its binding equation and the variable moves tow; it must not have a binding equation alreadylhsis a concatenation of such variables: split into one equation per componentlhsis anything else, typically0: an implicit (algebraic) equation0 == lhs - rhsis added tooutputs("alg"); a second equation for a variable that already has a binding equation is treated this way too
A derivative
der(x)that appears inrhsbefore it was defined is replaced by a new algebraic variableder_xwith the trivial ODEder(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 inrhsare marked as used, so a quadrature stateqreferenced there becomes a regular statex.- 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
- 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.xmland, with serialization, the oracle asoracle.casadiplus a layered-standard manifest. Quadrature states are not supported. The result maps each local file name to its path inside the FMU archive, ready forcompile_fmuandpack_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
- 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
- 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;
-1for 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"
- 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.
- 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)
- 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.
- 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_funorgather_fun.
- 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.
- 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)])
- init_rhs(...)¶
Initial conditions, right-hand-side.
init_rhs(self) -> [MX]
The right-hand sides of the initial equations, matching
init_lhs().
- initial(...)¶
Get/set the initial property.
initial(self, str name) -> str
The FMI
initialattribute:"exact","approx","calculated"or"na". The default follows from causality and variability per the FMI specification; it can be given with the"initial"option ofadd. 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"
- initial_unknowns(...)¶
Model structure: initial unknowns.
initial_unknowns(self) -> [str]
Names of the variables listed under
InitialUnknownsin the model structure of an imported model description. Empty for a symbolically constructed model.See also:
load_fmi_description,der
- 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
- 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
onameswith respect toinames, 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 byexport_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)bylen(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
- 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 towwith their definitions. The lifted definitions become part ofwdef;createwith"w"as input then exposes them, andcreatewithlifted_callsaccounts for the calls injac_wdef_wand Hessians. A warning is issued whenwis 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)
- 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_timeetc.), the model structure (der,initial_unknowns, dependencies used byjac_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
- 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 (
infby default)
- 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;-infby 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])
- 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)
- nc(...)¶
Named constants.
nc(self) -> int
Number of variables of category
c, i.e. the length ofc().See also:
c
- nd(...)¶
Dependent parameters.
nd(self) -> int
Number of variables of category
d, i.e. the length ofd().See also:
d
- 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)
- np(...)¶
Parameters.
np(self) -> int
Number of variables of category
p, i.e. the length ofp().See also:
p
- nq(...)¶
Quadrature states.
nq(self) -> int
Number of variables of category
q, i.e. the length ofq().See also:
q
- nu(...)¶
Free controls.
nu(self) -> int
Number of variables of category
u, i.e. the length ofu().See also:
u
- 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))
- nw(...)¶
Dependent variables.
nw(self) -> int
Number of variables of category
w, i.e. the length ofw().See also:
w
- nx(...)¶
Differential states.
nx(self) -> int
Number of variables of category
x, i.e. the length ofx(). 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
- ny(...)¶
Output variables.
ny(self) -> int
Number of output variables, i.e. the length of
y().See also:
y
- nz(...)¶
Algebraic variables.
nz(self) -> int
Number of variables of category
z, i.e. the length ofz().See also:
z
- nzero(...)¶
Zero-crossing functions.
nzero(self) -> int
Number of event indicators, one per
whenequation; the length ofoutputs("zero").See also:
when,transition
- ode(...)¶
[DEPRECATED] Replaced with outputs("ode")
ode(self) -> [MX]
- oracle(...)¶
Get the (cached) oracle, SX or MX.
oracle(self, bool sx, bool elim_w, bool lifted_calls) -> Function
The Function behind
createfor a symbolic model: inputs are all input categories exceptc(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
wout and drop them as inputlifted_calls -- Replace embedded function calls in
wdefby zeros, for use withcreatewithlifted_calls; incompatible withelim_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"])
- 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 statesx),"alg"(residuals),"quad"(right-hand sides ofq),"zero"(zero-crossing functions of the when equations),"ddef"and"wdef"(binding expressions ofdandw),"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
- p(...)¶
Parameters.
p(self) -> [str]
Names of the variables of category
p(causality"parameter", variability"tunable", floating-point type), in category order. Equivalent toall("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
- 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
filesat their archive paths and removes the local files afterwards. Requires a build withWITH_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
- parse_fmi(...)¶
Import existing problem from FMI/XML, alias of load_fmi_description
parse_fmi(self, str filename)
- 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:
reinitOverload:
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)).
- print_ptr(...)¶
print_ptr(self)
- provides_directional_derivative(...)¶
Does the FMU provide support for analytic derivatives (FMI 2 naming)
provides_directional_derivative(self) -> bool
- provides_directional_derivatives(...)¶
Does the FMU provide support for analytic derivatives.
provides_directional_derivatives(self) -> bool
Reads the
providesDirectionalDerivativesflag of an imported FMU. Calling it on a symbolic instance is an error.See also:
symbolic,load_fmi_description
- prune(...)¶
Prune unused controls.
prune(self, bool prune_p, bool prune_u)
Intended to drop the parameters
pand/or controlsuthat do not appear in any model equation from their categories (the variables themselves remain).- Parameters:
prune_p -- Consider the parameters
pprune_u -- Consider the controls
u
- 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 toall("q"). A state is only placed here byset_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
- quad(...)¶
[DEPRECATED] Replaced with outputs("quad")
quad(self) -> [MX]
- reinit(...)¶
Reinitialize a state inside when-equations.
reinit(self, str name, MX val) -> str
Creates a helper variable holding the new value
valof the statenameafter the event, and returns the helper's name for use inwhen. Usepre(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
- 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 bycreate(e.g. ofxandode).- 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
- 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.
- 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
dispwithmoreset and byadd_lc.>>> dae = DaeBuilder("m") >>> dae.sanity_check()
>> dae = DaeBuilder('m'); >> dae.sanity_check()
julia> dae = ca.DaeBuilder("m"); julia> ca.sanity_check(dae)
- 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
getreturns and whatcreatesubstitutes for the constantsc; 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,cOverload:
set(self, str name, str val)Set the current value, single value (string), for variables of type
"String"
- set_all(...)¶
Set all variables within a a category.
set_all(self, str v, [str] name)
Makes
namethe complete, ordered content of categoryv, 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 withset_category; members not listed become constantsc(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
- 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)
- set_category(...)¶
Set the variable category, if permitted.
set_category(self, str name, str val)
The following changes are permitted:
Controls
ucan be changed to/from tunable parameterspor fixed parameterscDifferential states that do not appear in the right-hand-sides can be changed between regular states
x, quadrature statesqand 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
- 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 parametersp(variability"tunable", causality"parameter") and fixed parametersc(variability"fixed", causality"parameter"), causality can only be changed indirectly, by updating the variabilityAdd or remove an output
yby 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
- set_description(...)¶
Get/set description.
set_description(self, str name, str val)
Free-text description of a variable, also settable with the
"description"option ofadd.>>> 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"
- 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 ofadd.
- set_init(...)¶
Specify the initial equation for a variable.
set_init(self, str name, MX init_rhs)
Sets
name == init_rhsas initial equation, replacing any previous one for the same variable. An emptyinit_rhsremoves 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[])
- set_initial(...)¶
Get/set the initial property.
set_initial(self, str name, str val)
The FMI
initialattribute:"exact","approx","calculated"or"na". The default follows from causality and variability per the FMI specification; it can be given with the"initial"option ofadd. 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"
- 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.
- 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.
- 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.
- 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)
valholds 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)
- set_start_time(...)¶
Set the start time of the default experiment.
set_start_time(self, float val)
- set_step_size(...)¶
Set the step size of the default experiment.
set_step_size(self, float val)
- set_stop_time(...)¶
Set the stop time of the default experiment.
set_stop_time(self, float val)
- set_tolerance(...)¶
Set the tolerance of the default experiment.
set_tolerance(self, float val)
- 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, withfmi_version2, 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
- 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 ofadd.>>> 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"
- 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
- set_variability(...)¶
Set the variability, if permitted.
set_variability(self, str name, str val)
For controls
u(variability"continuous", causality"input"), free parametersp(variability"tunable", causality"parameter") and fixed parametersc(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
- set_y(...)¶
[DEPRECATED] Replaced with set_all("y", name)
set_y(self, [str] name)
- 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)])
- 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
numelentries, 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
- 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
- step_size(...)¶
Get the step size of the default experiment, nan when unknown.
step_size(self) -> float
- stop_time(...)¶
Get the stop time of the default experiment, nan when unknown.
stop_time(self) -> float
- str(...)¶
Get string representation.
str(self, bool more) -> str
- 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
- 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").
- 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 fromzanduand appended toz, so thatzandalgmatch up. Hold markers are not implemented and only produce a warning.
- 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 inall()but is not categorized ast.>>> 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
- tolerance(...)¶
Get the tolerance of the default experiment, nan when unknown.
tolerance(self) -> float
- 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 ofintegrator, with an eventindexas first input: for a single event the function oftransition(fname, 0)with a dummy index input, for several events aswitchover 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)
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,uand outputspost_x,post_z: the states after the event with indexindex(0-based, in the order thewhenequations 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
- 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, withfmi_version2, 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
- type_name(...)¶
Readable name of the class.
type_name(self) -> str
- u(...)¶
Free controls.
u(self) -> [str]
Names of the variables of category
u(causality"input"), in category order. Equivalent toall("u").See also:
p,nu,set_category
- 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 ofadd.>>> 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"
- 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
- var(...)¶
Get variable expression by name.
var(self, str name) -> MX
The symbolic expression of a model variable: a dense column vector with
numelentries, 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
- variability(...)¶
Get the variability.
variability(self, str name) -> str
One of
"constant","fixed","tunable","discrete","continuous".See also:
set_variability,causality
- w(...)¶
Dependent variables.
w(self) -> [str]
Names of the variables of category
w, in category order. Equivalent toall("w"). A variable becomes dependent when it is the left-hand side of an explicit equationeq(v, expr); the derivative variablesder(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
- 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 (seesort). Equivalent tooutputs("wdef").
- when(...)¶
Add when equations.
when(self, MX cond, [str] eqs, dict opts)
Adds an event: whenever the zero-crossing function of
condbecomes negative, the assignments ineqsare executed. The condition must be a strict inequalitya < b(ora > b); it is stored as the zero- crossing functiona - binoutputs("zero"). The event transition can be obtained withtransition.- Parameters:
cond -- Strict inequality between model expressions;
<=or any other expression is an erroreqs -- Names returned by
reinitorassign; may be emptyopts -- 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
- x(...)¶
Differential states.
x(self) -> [str]
Names of the variables of category
x, in category order. Equivalent toall("x"). A continuous variable becomes a differential state once its time derivative is given a defining equation witheq; it is an algebraic variablezbefore 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)
- y(...)¶
Outputs.
y(self) -> [str]
Names of the variables with causality
"output", in category order. Equivalent toall("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
- ydef(...)¶
[DEPRECATED] Replaced with outputs("y")
ydef(self) -> [MX]
- z(...)¶
Algebraic variables.
z(self) -> [str]
Names of the variables of category
z, in category order. Equivalent toall("z"). Every continuouslocaloroutputvariable starts in this category and leaves it when it gets a defining equation (w) or an equation for its derivative (x).
- zero(...)¶
[DEPRECATED] Replaced with outputs("zero")
zero(self) -> [MX]
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
Authors: Joris Gillis, Joel Andersson
- 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
- 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
- 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])
- 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.
- 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.
- 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)
- 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
oindwith respect to inputiind. 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]])
- 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,onamesandoptspassed 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]])
- get_n_in(...)¶
Get the number of inputs.
get_n_in(self) -> int
Called during construct(). Default: 1.
- 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)
- 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
- get_name_out(...)¶
Get the name of an output.
get_name_out(self, int i) -> str
Called during construct(). Default: "o0", "o1", ...
- 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)
- 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)
- 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.
- 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.
- 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)
- 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
oindwith respect to inputiind. 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]])
- 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,onamesandoptspassed 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]])
- 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)
- 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
- static type_name(...)¶
Get type name.
type_name() -> str
- 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)
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.
- 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").
- static setSimplificationOnTheFly(...)¶
setSimplificationOnTheFly(bool flag)
- static setTempWorkDir(...)¶
setTempWorkDir(str dir)
CasadiMeta¶
- class CasadiMeta(...)¶
Collects global CasADi meta information.
Authors: Joris Gillis
- static build_type(...)¶
Obtain build type: RELEASE/Debug.
build_type() -> char const *
- static compiler(...)¶
Obtain compiler.
compiler() -> char const *
- static compiler_flags(...)¶
Obtain compiler flags.
compiler_flags() -> char const *
- 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
- static feature_list(...)¶
Obtain list of features that were compiled into this build.
feature_list() -> char const *
- static git_describe(...)¶
Obtain the git description of this build.
git_describe() -> char const *
(only available if built from a git repo)
- static git_revision(...)¶
Obtain the git hash of this build.
git_revision() -> char const *
(only available if built from a git repo)
- static install_prefix(...)¶
Obtain install prefix.
install_prefix() -> char const *
- 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)orWITH_BUILD_LAPACKresolved to. Empty when the build was configured with WITH_LAPACK=OFF.
- static modules(...)¶
Obtain modules list.
modules() -> char const *
- static object_file_suffix(...)¶
Obtain object file suffix.
object_file_suffix() -> char const *
- static plugins(...)¶
Obtain plugins list.
plugins() -> char const *
Obtain shared library prefix.
shared_library_prefix() -> char const *
Obtain shared library suffix.
shared_library_suffix() -> char const *
- 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