TOMLAB Appendix C
This page is part of the TOMLAB Manual. See TOMLAB Manual.
- 1 TomSym - the Modeling Engine
- 1.1 Main functions
- 1.1.1 tom - Generate a tomSym symbol
- 1.1.2 toms - Create tomSym objects
- 1.1.3 tomSym/tomSym - Class constructor
- 1.1.4 ezsolve - Solve a tomSym optimization problem
- 1.1.5 sym2prob - Compile symbolic function/constraints into a Prob struct
- 1.1.6 getSolution - Extract variables from a solution retuned by tomRun
- 1.1.7 tomDiagnose - Determine the type for of tomSym optimization problem
- 1.1.8 tomCleanup - Remove any temporary files created for a tomSym problem.
- 1.2 Using MAD
- 1.3 Sub function details
- 1.1 Main functions
TomSym - the Modeling Engine
This appendix describes the details and functions of relevance to the user when modeling optimization and optimal control problems with TomSym. It is possible to solve the modeling problems, either with ezsolve or by converting the problem to a standard TOMLAB Prob struct with sym2prob. The latter provides for the option of controlling all solver settings per the TOMLAB standard (see the solver manuals for more information). The procedure for using MAD (Matlab Automatic Differentiation) is also described in the sections below.
The following Matlab functions are used directly by the user when modeling problems for processing by the TOMLAB solvers.
tom - Generate a tomSym symbol
x = tom creates a scalar tomSym symbol with an automatic name. x = tom(label) creates a scalar symbol with the provided name. x = tom(label,m,n) creates a m-by-n matrix symbol. x = tom(,m,n) creates a matrix symbol with an automatic name. x = tom(label,m,n,'int') creates an integer matrix symbol. x = tom(label,m,n,'symmetric') creates a symmetric matrix symbol.
Because constructs like
"x = tom('x')" are very common, there is the shorthand notation "toms x". See also: toms, tomSym
toms - Create tomSym objects
Toms is a shorthand notation, possibly replacing several calls to 'tom'.
A symbol is created in the current workspace for each name listed. If a size is specified on the format "NxM" where N and M are integers, then all subsequent symbols will get that size. If the size specification ends with an exclamation point (as in "3x4!") then a symbolic array of concatenated scalar symbols is created instead of one matrix symbol.
The flags "integer" (or "int") and "symmetric" are recognized. If a flag is encountered, then all subsequent symbols will get the properties of that flag.
-integer: The variable is constrained to integer values, resulting in a
mixed-integer problem (which requires a compatible solver.)
-symmetric: The variable is symmetric, so that
x' == x. This requires that
the dimensions be square. An NxN symmetric matrix only contains N*(N+1)/2 unknowns, and the resulting symbolic object uses the setSymmetric function.
toms x y z is equivalent to x = tom('x'); y = tom('z'); z = tom('z'); toms 2x3 Q 3x3 -integer R -symmetric S is equivalent to Q = tom('Q', 2, 3); R = tom('R', 3, 3, 'integer'); S = tom('S', 3, 3, 'integer', 'symmetric') toms 3x1! v is equivalent to v1 = tom('v1'); v2 = tom('v2'); v3 = tom('v3'); v = [v1;v2;v3];
In the last example, with the exclamation point, the result is a vector containing scalar symbols. This works differently from the matrix symbols used in the previous examples. Mathematically this v is equivalent to "toms 3x1 v", but the auto-generated code will be different. Expressions such as
v(1)+sin(v(2))*v(3) will be more efficient, while expressions such as
A*v will be less efficient.
Note: While the "toms" shorthand is very convenient to use prototyping code, it is recommended to only use the longhand "tom" notation for production code. The reason is that Matlab's internal compiler tries to guess whether a statement like
"x(1)" is an index into a vector or a call to a function. Since it does not realize that the call to "toms" creates new variables is will make the wrong guess if that function (named "x" in this example) is on the Matlab path when the script is loaded into memory. This will cause strange and unexpected results.
See also: tom, tomSym, setSymmetric
tomSym/tomSym - Class constructor
NOTE: Use toms or tom to create tomSym symbols.
p = tomSym(a,m,n,arguments...) creates a tomSym using the operator a. p = tomSym(const) creates a tomSym constant with the value const. p = tomSym(struct) converts a struct into a tomSym, if the struct has the required fields.
See also: toms, tom, tomSym/funcs, tomSym/tomSym
ezsolve - Solve a tomSym optimization problem
[solution, result] = ezsolve(f,c) returns the solution to the minimization problem that is defined by the objective function f and the constraints c. The result structure from tomRun is provided in a second output argument.
Ezsolve can also be used to find least-square solutions to equations. If options.norm is set to 'L2', then f can be a set of equations. (If there are equations both in f and c, then the ones in c are considered as strict, and will be solved to tolerances, while the ones in f are solved in a least-square sense. If f is a vector, then the L2 norm of f is minimized.
Ezsolve is meant to be as simple to use as possible. It automatically determines the problem type and finds a suitable solver.
The returned solution is a struct, where the fields represent the unknown variables. This struct can be used by subs to convert a tomSym to a numeric value.
s = ezsolve(f,c,x0) uses the initial guess x0. The input argument x0 can be a struct containing fields names as the unknown symbols, for example a previously returned solution. Alternatively, x0 can be a cell array of simple tomSym equation that can be converted to a struct using tom2struct.
s = ezsolve(f,c,x0,name) sets the problem name.
s = ezsolve(f,c,x0,OPTIONS) where
OPTIONS is a structure sets solver options. The options structure can have the following fields.
OPTIONS.name - The name of the problem OPTIONS.type - The problem type, e.g. 'lp', 'qp', 'con', ... OPTIONS.solver - The solver to use, e.g. 'snopt', 'knitro', ... OPTIONS.prilev - The ezsolve and tomRun print level (default 1) OPTIONS.use_d2c - (boolean) true = compute symbolic d2c OPTIONS.use_H - (boolean) true = compute symbolic H
See also: tomDiagnose, sym2prob, tomRun
sym2prob - Compile symbolic function/constraints into a Prob struct
Prob = sym2prob(type,f,c) creates a Prob structure, suitable for tomRun, with the objective of minimizing f, subject to c, with respect to all symbols that they contain.
The problem type can be (among others):
'lp' - Linear programming 'qp' - Quadratic programming 'con' - Nonlinear programming 'qpcon' - Quadratic problem with nonlinear constraints 'minlp' - Mixed integer nonlinear programming 'sdp' - Linear semidefinite programming 'bmi' - Bilinear semidefinite programming
Prob = sym2prob(f,c) calls tomDiagnose to attempt to guess the problem type, and prints a warning.
The objective f must be a tomSym symbolic object, while the constraints list c should be a cell array.
If the objective f is a vector or matrix, then a least-square problem is solved, minimizing 0.5*sum(vec(f)) (Half the sum-of-squares of the elements of f ). If f is an equality on the form lhs == rhs, then the sum-of-squares of the difference (rhs-lhs) is minimized.
sym2prob(type,f,c,x0) supplies an initial guess for one or more of the unknowns. The guess x0 should be a struct, where each field is named as a symbol and contains a numeric array of the correct size.
sym2prob(type,f,c,x0,OPTIONS) where OPTIONS is a structure sets options. The options structure can have the following fields.
OPTIONS.name - The name of the problem OPTIONS.use_d2c - (boolean) true = compute symbolic d2c OPTIONS.use_H - (boolean) true = compute symbolic H
Linear and box constraints will be automatically detected, if they are formulated using simple addition and multiplication. For example,
-3*(x+2) <= 4+x
is automatically converted to
x >= -2.5
For nonlinear problems, sym2prob will generate temporary m-files representing the nonlinear functions and their derivatives (These files are usually small and harmless, and many modern operating systems automatically clean up old temporary files). In order to remove these files when they are no longer needed, it is recommended to run tomCleanup(Prob) after the problem has been solved.
Overloaded methods: tomSym/sym2prob
getSolution - Extract variables from a solution retuned by tomRun
s = getSolution(solution) returns a struct where each field corresponds to one of the symbols used in the tomSym problem formulation.
tomDiagnose - Determine the type for of tomSym optimization problem
type = tomDiagnose(f,c) returns a text string, defining the problem type that is represented by the objective function f and the constraints c.
Some possible return values:
'lp' - Linear programming 'qp' - Quadratic programming 'cls' - Least squares with linear constraints 'nls' - Nonlinear least squares 'con' - Nonlinear programming 'qpcon' - Quadratic problem with nonlinear constraints 'minlp' - Mixed integer nonlinear programming 'sdp' - Linear semidefinite programming 'bmi' - Bilinear semidefinite programming
The objective f must be a tomSym symbolic object, while the constraints list c should be a cell array of tomSym objects.
tomCleanup - Remove any temporary files created for a tomSym problem.
tomCleanup(Prob) removes any temporary files (created by sym2prob) that are referenced in the problem structure Prob. This should be done after a problem has been solved, to avoid leaving garbage in the system's "temp" directory (although most modern operating system will clean up these files eventually anyway.)
WARNING: IF THE AUTOGENERATED FILES HAVE BEEN EDITED, THEN RUNNING
TOMCLEANUP WILL CAUSE ALL CHANGES TO BE LOST.
tomCleanup('all') will remove all files and directories that are judged to be tomSym files from the system's "temp" directory. All files that contain a certain "marker" in the filename will be removed. This might be useful if a large number of temporary files were created accidentally, such as when running sym2prob inside a for-loop without calling
tomCleanup(Prob) at the end of the loop.
Note: Under normal circumstances there is never a need to run
tomCleanup('all'). The operating system should remove old temporary files as required.
After running tomCleanup, all Prob structures that reference the deleted files will be useless. See also: sym2prob
Some models require the use of alternative method for partial derivatives. If TomSym cannot be used, one alternative is to use MAD.
madWrap - Compute a Jacobian using MAD.
J = madWrap(FUN,N,...) uses MAD to call
FUN(...) and returns the Jacobian matrix with respect to the N:th input argument.
FUN must be the name of an existing function. N must be an integer between one and
J = madWrap(M,FUN,N,...) computes the Jacobian matrix of the Mth output argument, instead of the first one.
J will be a Jacobian matrix on the form that is used by tomSym.
Sub function details
Advanced users may need to understand how and what some sub functions execute in TomSym. This section describes how to add functionality to TomSym and some more details "under the hood".
ifThenElse - Smoothened if/then/else.
y = ifThenElse(cmp1, op, cmp2, yTrue, yFalse, s) replicates the behavior of the C-language construction
y = ( condition ? yTrue : yFalse ) but with a smoothing sigmoid function, scaled by s. (Setting s=0 gives discontinuous "standard" if-then-else.)
The operand string op must be the name of one of the comparison operators ('eq', 'lt', 'le', etc.)
Example: The absolute value of x is
Overloaded methods: tomSym/ifThenElse
The symbolic derivative of a tomSym object.
df_dx = derivative(f,x) computes the derivative of a tomSym object f with respect to a symbol x.
d2f_dxdy = derivative(f,x,y,..) computes the second (third, ...) derivative of f with respect to the symbols x, y, ...
Both f and x can be matrices.
The symbol x can either be a tomSym symbol, or a concatenation of tomSym symbols.
There exist several conventions for how the elements are arranged in the derivative of a matrix. This function uses the convention that
vec(df) = df_dx*vec(dx). This means that if
size(f) = [m n] and
size(x) = [p q] then
size(df_dx) = [m*n, p*q]. Thus, the derivative of a matrix or vector with respect to a scalar is a column vector, the derivative of a scalar is a row vector, and the derivative of any matrix with respect to itself is an identity matrix.
- If f and x are vectors, then
J = derivative(f,x)computes the Jacobian matrix.
- If f is scalar and x is a vector, then
H = derivative(f,x,x)computes the Hessian matrix.
For functions that tomSym/derivative is unfamiliar with, it assumes that there also exists a derivative function for each argument. For example, when computing the derivative of a function "userfun", it is assumed that "userfunJ1" gives the derivative of userfun with respect to its first input argument. Reference: Brookes, M., "The Matrix Reference Manual"
ppderivative - The derivative of a piecewise polynomial.
dpp = ppderivative(pp) returns a piecewise polynomial which is the derivative of pp, except at points where pp is discontinuous.
dpp = ppderivative(pp,n) returns the nth derivative. A negative n results in the antiderivative (integral) of pp.
Generate m-code from a tomSym object.
[code, data, header] = mcode(f) generates m-code, representing an object f.
All constants are moved to a data object, which needs to be supplied in the function call.
The returned function header lists all symbols alphabetically, and the data input last.