public class Equation
extends java.lang.Object
Equation allows the user to manipulate matrices in a more compact symbolic way, similar to Matlab and Octave. Aliases are made to Matrices and scalar values which can then be manipulated by specifying an equation in a string. These equations can either be "pre-compiled" [1] into a sequence of operations or immediately executed. While the former is more verbose, when dealing with small matrices it significantly faster and runs close to the speed of normal hand written code.
Each string represents a single line and must have one and only one assignment '=' operator. Temporary variables are handled transparently to the user. Temporary variables are declared at compile time, but resized at runtime. If the inputs are not resized and the code is precompiled, then no new memory will be declared. When a matrix is assigned the results of an operation it is resized so that it can store the results.
The compiler currently produces simplistic code. For example, if it encounters the following equation "a = b*c' it will not invoke multTransB(b,c,a), but will explicitly transpose c and then call mult(). In the future it will recognize such short cuts.
Usage example:Equation eq = new Equation(); eq.alias(x,"x", P,"P", Q,"Q"); eq.process("x = F*x"); eq.process("P = F*P*F' + Q");Which will modify the matrices 'x' and 'P'. Support for sub-matrices and inline matrix construction is also available.
eq.process("x = [2 1 0; 0 1 3;4 5 6]*x"); // create a 3x3 matrix then multiply it by x eq.process("x(1:3,5:9) = [a ; b]*2"); // fill the sub-matrix with the result eq.process("x(:) = a(4:2:20)"); // fill all elements of x with the specified elements in 'a' eq.process("x( 4 3 ) = a"); // fill only the specified number sequences with 'a' eq.process("x = [2:3:25 1 4]"); // create a row matrix from the number sequenceTo pre-compile one of the above lines, do the following instead:
Sequence predictX = eq.compile("x = F*x"); predictX.perform();Then you can invoke it as much as you want without the "expensive" compilation step. If you are dealing with larger matrices (e.g. 100 by 100) then it is likely that the compilation step has an insignificant runtime cost. Variables can also be lazily declared and their type inferred under certain conditions. For example:
eq.alias(A,"A", B,"B"); eq.process("C = A*B"); DMatrixRMaj C = eq.lookupMatrix("C");In this case 'C' was lazily declared. To access the variable, or any others, you can use one of the lookup*() functions. Sometimes you don't get the results you expect and it can be helpful to print out the tokens and which operations the compiler selected. To do this set the second parameter to eq.compile() or eq.process() to true:
Code: eq.process("C=2.1*B'*A",true); Output: Parsed tokens: ------------ Word:C ASSIGN VarSCALAR TIMES VarMATRIX TRANSPOSE TIMES VarMATRIX Operations: ------------ transpose-m multiply-ms multiply-mm copy-mm
pi = Math.PI e = Math.E
eye(N) Create an identity matrix which is N by N. eye(A) Create an identity matrix which is A.numRows by A.numCols normF(A) Frobenius normal of the matrix. normP(A,p) P-norm for a matrix or vector. p=1 or p=2 is typical. sum(A) Sum of every element in A sum(A,d) Sum of rows for d = 0 and columns for d = 1 det(A) Determinant of the matrix inv(A) Inverse of a matrix pinv(A) Pseudo-inverse of a matrix rref(A) Reduced row echelon form of A trace(A) Trace of the matrix zeros(r,c) Matrix full of zeros with r rows and c columns. ones(r,c) Matrix full of ones with r rows and c columns. rand(r,c) Matrix filled with i.i.d uniform numbers from 0 to 1 randn(r,c) Matrix filled with i.i.d normal distribution with mean of zero and stdev of 1 rng(seed) Specifies the random number generator's seed diag(A) If a vector then returns a square matrix with diagonal elements filled with vector diag(A) If a matrix then it returns the diagonal elements as a column vector dot(A,B) Returns the dot product of two vectors as a double. Does not work on general matrices. solve(A,B) Returns the solution X from A*X = B. kron(A,B) Kronecker product abs(A) Absolute value of A. max(A) Element with the largest value in A. max(A,d) Vector containing largest element along the rows (d=0) or columns (d=1) min(A) Element with the smallest value in A. min(A,d) Vector containing largest element along the rows (d=0) or columns (d=1) pow(a,b) Computes a to the power of b. Can also be invoked with "a^b" scalars only. sqrt(a) Computes the square root of a. sin(a) Math.sin(a) for scalars only cos(a) Math.cos(a) for scalars only atan(a) Math.atan(a) for scalars only atan2(a,b) Math.atan2(a,b) for scalars only exp(a) Math.exp(a) for scalars is also an element-wise matrix operator log(a) Math.log(a) for scalars is also an element-wise matrix operator
'*' multiplication (Matrix-Matrix, Scalar-Matrix, Scalar-Scalar) '+' addition (Matrix-Matrix, Scalar-Matrix, Scalar-Scalar) '-' subtraction (Matrix-Matrix, Scalar-Matrix, Scalar-Scalar) '/' divide (Matrix-Scalar, Scalar-Scalar) '/' matrix solve "x=b/A" is equivalent to x=solve(A,b) (Matrix-Matrix) '^' Scalar power. a^b is a to the power of b. '\' left-divide. Same as divide but reversed. e.g. x=A\b is x=solve(A,b) '.*' element-wise multiplication (Matrix-Matrix) './' element-wise division (Matrix-Matrix) '.^' element-wise power. (scalar-scalar) (matrix-matrix) (scalar-matrix) (matrix-scalar) ''' matrix transpose '=' assignment by value (Matrix-Matrix, Scalar-Scalar)Order of operations: [ ' ] precedes [ ^ .^ ] precedes [ * / .* ./ ] precedes [ + - ]
Extracts a sub-matrix from A with rows 1 to 10 (inclusive) and column 3. A(1:10,3) Extracts a sub-matrix from A with rows 2 to numRows-1 (inclusive) and all the columns. A(2:,:) Will concat A and B along their columns and then concat the result with C along their rows. [A,B;C] Defines a 3x2 matrix. [1 2; 3 4; 4 5] You can also perform operations inside: [[2 3 4]';[4 5 6]'] Will assign B to the sub-matrix in A. A(1:3,4:8) = B
1) Explicit: Example: "1 2 4 0" Example: "1 2,-7,4" Commas needed to create negative numbers. Otherwise it will be subtraction. 2) for: Example: "2:10" Sequence of "2 3 4 5 6 7 8 9 10" Example: "2:2:10" Sequence of "2 4 6 8 10" 3) for-range: Example: "2:" Sequence of "2 3 ... max" Example: "2:2:" Sequence of "2 4 ... max" 4) combined: Example: "1 2 7:10" Sequence of "1 2 7 8 9 10"
eq.process("macro ata( a ) = (a'*a)"); eq.process("b = ata(c)");The first line defines a macro named "ata" with one parameter 'a'. When compiled the equation in the second line is replaced with "b = (a'*a)". The "(" ")" in the macro isn't strictly necissary in this situation, but is a good practice. Consider the following.
eq.process("b = ata(c)*r");Will become "b = (a'*a)*r" but with out () it will be "b = a'*a*r" which is not the same thing!
NOTE:In the future macros might be replaced with functions. Macros are harder for the user to debug, but functions are harder for EJML's developer to implement.
[1] It is not compiled into Java byte-code, but into a sequence of operations stored in a List.
Modifier and Type | Class and Description |
---|---|
protected static class |
Equation.TokenType |
Constructor and Description |
---|
Equation() |
Modifier and Type | Method and Description |
---|---|
void |
alias(org.ejml.data.DMatrixRMaj variable,
java.lang.String name)
Adds a new Matrix variable.
|
void |
alias(double value,
java.lang.String name)
Adds a new floating point variable.
|
void |
alias(org.ejml.data.FMatrixRMaj variable,
java.lang.String name) |
void |
alias(int value,
java.lang.String name)
Adds a new integer variable.
|
void |
alias(java.lang.Object... args)
Creates multiple aliases at once.
|
void |
alias(SimpleMatrix variable,
java.lang.String name) |
Sequence |
compile(java.lang.String equation) |
Sequence |
compile(java.lang.String equation,
boolean assignment,
boolean debug)
Parses the equation and compiles it into a sequence which can be executed later on
|
protected org.ejml.equation.TokenList.Token |
createFunction(org.ejml.equation.TokenList.Token name,
java.util.List<org.ejml.equation.TokenList.Token> inputs,
org.ejml.equation.TokenList tokens,
Sequence sequence)
Adds a new operation to the list from the operation and two variables.
|
protected org.ejml.equation.TokenList.Token |
createOp(org.ejml.equation.TokenList.Token left,
org.ejml.equation.TokenList.Token op,
org.ejml.equation.TokenList.Token right,
org.ejml.equation.TokenList tokens,
Sequence sequence)
Adds a new operation to the list from the operation and two variables.
|
protected org.ejml.equation.TokenList |
extractTokens(java.lang.String equation,
ManagerTempVariables managerTemp)
Parses the text string to extract tokens.
|
ManagerFunctions |
getFunctions()
Returns the functions manager
|
protected void |
handleParentheses(org.ejml.equation.TokenList tokens,
Sequence sequence)
Searches for pairs of parentheses and processes blocks inside of them.
|
protected org.ejml.equation.TokenList.Token |
insertTranspose(org.ejml.equation.TokenList.Token variable,
org.ejml.equation.TokenList tokens,
Sequence sequence)
Adds a new operation to the list from the operation and two variables.
|
protected static boolean |
isLetter(char c)
Returns true if the character is a valid letter for use in a variable name
|
protected static boolean |
isOperatorLR(Symbol s)
Operators which affect the variables to its left and right
|
protected boolean |
isReserved(java.lang.String name)
Returns true if the specified name is NOT allowed.
|
protected static boolean |
isSymbol(char c) |
protected static boolean |
isTargetOp(org.ejml.equation.TokenList.Token token,
Symbol[] ops)
Checks to see if the token is in the list of allowed character operations.
|
org.ejml.data.DMatrixRMaj |
lookupDDRM(java.lang.String token) |
double |
lookupDouble(java.lang.String token) |
org.ejml.data.FMatrixRMaj |
lookupFDRM(java.lang.String token) |
int |
lookupInteger(java.lang.String token) |
Macro |
lookupMacro(java.lang.String token) |
SimpleMatrix |
lookupSimple(java.lang.String token) |
<T extends Variable> |
lookupVariable(java.lang.String token)
Looks up a variable given its name.
|
protected org.ejml.equation.TokenList.Token |
parseBlockNoParentheses(org.ejml.equation.TokenList tokens,
Sequence sequence,
boolean insideMatrixConstructor)
Parses a code block with no parentheses and no commas.
|
protected void |
parseBracketCreateMatrix(org.ejml.equation.TokenList tokens,
Sequence sequence)
Searches for brackets which are only used to construct new matrices by concatenating
1 or more matrices together
|
protected void |
parseCombineIntegerLists(org.ejml.equation.TokenList tokens)
Looks for sequences of integer lists and combine them into one big sequence
|
protected void |
parseIntegerLists(org.ejml.equation.TokenList tokens)
Searches for a sequence of integers
example:
1 2 3 4 6 7 -3
|
protected void |
parseNegOp(org.ejml.equation.TokenList tokens,
Sequence sequence)
Searches for cases where a minus sign means negative operator.
|
protected void |
parseOperationsL(org.ejml.equation.TokenList tokens,
Sequence sequence)
Parses operations where the input comes from variables to its left only.
|
protected void |
parseOperationsLR(Symbol[] ops,
org.ejml.equation.TokenList tokens,
Sequence sequence)
Parses operations where the input comes from variables to its left and right
|
protected java.util.List<org.ejml.equation.TokenList.Token> |
parseParameterCommaBlock(org.ejml.equation.TokenList tokens,
Sequence sequence)
Searches for commas in the set of tokens.
|
protected void |
parseSequencesWithColons(org.ejml.equation.TokenList tokens,
Sequence sequence)
Searches for descriptions of integer sequences and array ranges that have a colon character in them
Examples of integer sequences:
1:6
2:4:20
:
Examples of array range
2:
2:4:
|
protected org.ejml.equation.TokenList.Token |
parseSubmatrixToExtract(org.ejml.equation.TokenList.Token variableTarget,
org.ejml.equation.TokenList tokens,
Sequence sequence)
Converts a submatrix into an extract matrix operation.
|
void |
print(java.lang.String equation)
Prints the results of the equation to standard out.
|
void |
process(java.lang.String equation)
Compiles and performs the provided equation.
|
void |
process(java.lang.String equation,
boolean debug)
Compiles and performs the provided equation.
|
void |
setSeed()
Sets the random seed using a seed based on the current time
|
void |
setSeed(long seed)
Specifies the seed used in random number generators
|
public void setSeed(long seed)
seed
- New seed for random number generatorpublic void setSeed()
public void alias(org.ejml.data.DMatrixRMaj variable, java.lang.String name)
variable
- Matrix which is to be assigned to namename
- The name of the variablepublic void alias(org.ejml.data.FMatrixRMaj variable, java.lang.String name)
public void alias(SimpleMatrix variable, java.lang.String name)
public void alias(double value, java.lang.String name)
value
- Value of the numbername
- Name in codepublic void alias(int value, java.lang.String name)
value
- Value of the numbername
- Name in codepublic void alias(java.lang.Object... args)
public Sequence compile(java.lang.String equation)
public Sequence compile(java.lang.String equation, boolean assignment, boolean debug)
equation
- String in simple equation format.assignment
- if true an assignment is expected and an exception if thrown if there is nondebug
- if true it will print out debugging informationprotected void handleParentheses(org.ejml.equation.TokenList tokens, Sequence sequence)
tokens
- List of parsed tokenssequence
- Sequence of operatorsprotected java.util.List<org.ejml.equation.TokenList.Token> parseParameterCommaBlock(org.ejml.equation.TokenList tokens, Sequence sequence)
protected org.ejml.equation.TokenList.Token parseSubmatrixToExtract(org.ejml.equation.TokenList.Token variableTarget, org.ejml.equation.TokenList tokens, Sequence sequence)
variableTarget
- The variable in which the submatrix is extracted fromprotected org.ejml.equation.TokenList.Token parseBlockNoParentheses(org.ejml.equation.TokenList tokens, Sequence sequence, boolean insideMatrixConstructor)
protected void parseSequencesWithColons(org.ejml.equation.TokenList tokens, Sequence sequence)
protected void parseIntegerLists(org.ejml.equation.TokenList tokens)
protected void parseCombineIntegerLists(org.ejml.equation.TokenList tokens)
protected void parseBracketCreateMatrix(org.ejml.equation.TokenList tokens, Sequence sequence)
protected void parseNegOp(org.ejml.equation.TokenList tokens, Sequence sequence)
protected void parseOperationsL(org.ejml.equation.TokenList tokens, Sequence sequence)
tokens
- List of all the tokenssequence
- List of operation sequenceprotected void parseOperationsLR(Symbol[] ops, org.ejml.equation.TokenList tokens, Sequence sequence)
ops
- List of operations which should be parsedtokens
- List of all the tokenssequence
- List of operation sequenceprotected org.ejml.equation.TokenList.Token insertTranspose(org.ejml.equation.TokenList.Token variable, org.ejml.equation.TokenList tokens, Sequence sequence)
protected org.ejml.equation.TokenList.Token createOp(org.ejml.equation.TokenList.Token left, org.ejml.equation.TokenList.Token op, org.ejml.equation.TokenList.Token right, org.ejml.equation.TokenList tokens, Sequence sequence)
protected org.ejml.equation.TokenList.Token createFunction(org.ejml.equation.TokenList.Token name, java.util.List<org.ejml.equation.TokenList.Token> inputs, org.ejml.equation.TokenList tokens, Sequence sequence)
public <T extends Variable> T lookupVariable(java.lang.String token)
public Macro lookupMacro(java.lang.String token)
public org.ejml.data.DMatrixRMaj lookupDDRM(java.lang.String token)
public org.ejml.data.FMatrixRMaj lookupFDRM(java.lang.String token)
public int lookupInteger(java.lang.String token)
public double lookupDouble(java.lang.String token)
protected org.ejml.equation.TokenList extractTokens(java.lang.String equation, ManagerTempVariables managerTemp)
public SimpleMatrix lookupSimple(java.lang.String token)
protected static boolean isTargetOp(org.ejml.equation.TokenList.Token token, Symbol[] ops)
token
- Token being checkedops
- List of allowed character operationsprotected static boolean isSymbol(char c)
protected static boolean isOperatorLR(Symbol s)
protected static boolean isLetter(char c)
protected boolean isReserved(java.lang.String name)
public void process(java.lang.String equation)
equation
- String in simple equation formatpublic void process(java.lang.String equation, boolean debug)
equation
- String in simple equation formatpublic void print(java.lang.String equation)
public ManagerFunctions getFunctions()