Symbolic Submodules
klampt.math.symbolic module
symbolic module
Overview
A framework for declaring and manipulating symbolic expressions. Suitable for automatic differentiation and developing computation graph models of functions for use in optimization.
Inspired by Sympy, SCIP models, Gurobi models, as well as TensorFlow / PyTorch, this framework has the following features:
Saving and loading of expressions is fully supported. Strings and JSON formats are supported.
Supports black-box functions inside expressions.
Allows references to arbitrary non-serializable user data.
Allows new functions to be user-defined in a straightforward way.
Symbolic auto-differentiation.
Conversion to and from Sympy.
Numeric, vector, and matrix variables are allowed. Many native numpy operations are supported.
Could it be used for learning? Yes, but it is not as fast as GPU-based learning libraries like TensorFlow / PyTorch.
How does it compare to Sympy? This module does a better job of handling large matrix expressions and variable indexing. For example, the multiplication of 5 symbolic 2x2 matrices takes ~200 microseconds, which is a bit slower than direct numpy evaluation of ~50 microseconds. On the other hand, the Sympy expression takes over 4s to construct, and each entry of the matrix contains hundreds of terms!
This module can also take derivatives with respect to vectors using matrix calculus. It can even auto-differentiate with nested lists/arrays! However, function simplification is not as complete as Sympy, and derivatives for some functions are not available. There are conversions to and from Sympy in the symbolic_sympy module, and these are complete for most “tame” expressions.
Basic usage
In standard usage, first create a Context
and declare any extra
functions to be used in your library. Then, and add variables and declare
expressions as necessary.:
ctx = Context()
x = ctx.addVar("x",'N')
y = ctx.addVar("y",'N')
print(x + y) #(x+y) is an Expression object, which has not been evaluated yet
print(flatten(x,y)) #flatten(x,y) is an Expression object, which has not been evaluated yet
print((x + y).eval({'x':5,'y':3})) #prints 8 (a ConstantExpression)
print(flatten(x,y).eval({'x':5,'y':3})) #prints [5,3] (a ConstantExpression
print(flatten(x,y).eval({'y':[1,2]})) #prints [x,1,2] (an Expression object)
x.bind(5) #x is now treated as a constant
y.bind(3) #y is now treated as a constant
print((x+y).eval()) #prints 8 (a ConstantExpression)
print((x+y).evalf()) #prints 8 (as an integer)
x.unbind() #x is now a variable
y.unbind() #y is now a variable
An Expression
can take on a form x OP y
or OP(x,y,z)
, where
x,y, and z are either Variable
, Expression
, or constant
values, and OP
is either a builtin function or a declared Function
type. Expressions can be evaluated to other Expressions via
Expression.eval()
, or to constants using
Expression.evalf()
.
There are two kinds of Variable
:
Standard Variable: This type is managed by
Context
and contains information in theVariable
class. Such a variable can either be numeric, vector, or matrix type. It will contain size information and will be saved to and loaded from disk with theContext
.User-data Variable. This type is an unmanaged variable. These have unlimited type, and can be complex Python objects, but the user must set these up in the context manually. Hence, if you wish to reuse Expressions of user-data variables loaded from disk, you will need to first set up the
Context
appropriately with a similar user-data object.
By default, expressions constructed in Python refer to user-data objects with
strings, e.g., setConfig("robot",q)
runs the
symbolic_klampt.setConfig()
Function on the “robot” user data and the
q
Variable.
The expr()
function is run on each argument to a Function
.
This will leave a Variable
and Expression
as is,
and most Python constants will be converted to a ConstantExpression
.
However, Python strings will be converted to references to user-data variables.
Constant values can be floats, integers, booleans, strings, lists, and numpy
arrays (Dictionaries are not supported as constant values.) Constants are
converted to expressions using const()
, or expr()
.
Type specifiers are used for type checking and to determine the type of
expressions, particularly for Jacobians. The Type
class is used for
this. The type member specifies the general type of object, and is given by a
character:
N: generic numeric
I: integer
B: boolean
X: index (either an integer or a slice)
V: 1D vector
M: 2D matrix
A: n-D array
L: list
U: user data
None: indicates an unknown type
as well as an optional size and sub-type. For L and V types, size is the length
of the array. For M and A types, size is the Numpy shape of the array. For
the U type, the subtype member indicates __class__.__name__
if known.
Standard functions
Standard operations on expressions include:
expr(x)
: returns anExpression
corresponding to x, whether x is a constant,Variable
, orExpression
deriv(expr,var)
: take the derivative of expr with respect to var. If no derivative information is available for some of the expressions in expr, returns None.simplify(expr,context=None)
: simplifies the expression in the optimal given context. Note: this is not terribly powerful in terms of rearranging expressions (like x - x is not converted to 0).is_const(x)
: returns True if x evaluates to a constant.to_const(x)
: returns the constant to which x evaluates, ifis_const(x)
.is_expr(x)
: returns True if x is anExpression
.is_var(x)
: returns True if x is aVariable
or aVariableExpression
(i.e., monomial).to_var(x)
: returns theVariable
corresponding to theVariable
or monomial x.is_op(x,func=None)
: returns True if x is an operator. If func is given, checks whether this is the the name of the function.is_zero(x)
: returns True if x is the zero(…) operator or a scalar equal to 0.is_scalar(x,val=None)
: returns True if x is known to evaluate to a scalar. If val is provided, it checks whether x is equal to val.type_of(x)
: returns the Type corresponding to x.
Note
These are Python functions, not symbolic Functions.
Symbolic Functions
You can build an Expression
by calling a symbolic Function
,
many of which duplicate the functions of plain Python, the math module, or
Numpy. Calling a Function
does not immediately evaluate
the function on its arguments, but instead builds an Expression
that
is the root of a symbolic Expression Graph.
Built-in symbolic Functions include:
Shape functions
range_(n)
: Evaluates to range(n). The result can be treated like a vector or a list.dims(x)
: Returns the dimensionality of the input. Equivalent tolen(shape(x))
.len_(x)
: Evaluates to len(x), except if x is a scalar then it evaluates to 0. If x is a multi-dimensional array, this is the length of its first dimension. Undefined for other forms of user data.count(x)
: Evaluates the number of numeric parameters in x. Works with scalars, arrays, and lists. If x is a scalar then it evaluates to 1. Lists are evaluated recursively. Undefined for other forms of user data.shape(x)
: Evaluates tox.shape
if x is a Numpy array,(len_(x),)
if x is a vector, and () if x is a scalar. If x is a list, this is(len_(x),)+shape(item)
if all of the items have the same shape, and otherwise it is a hyper-shape. (shortcut: “x.shape”)reshape(x,s)
: Evaluates to x reshaped to the shape s. If x is a scalar, this evaluates to a constant matrix.transpose(x)
: Evaluates to np.transpose(x). (shortcut: “x.T”)transpose2(x,axes)
: Tensor transpose; evaluates to np.transpose(x,axes).basis(i,n)
: Evaluates to the i’th elementary basis vector in dimension n.eye(n)
: Evaluates to np.eye(n) if n > 0, otherwise returns 1.zero(s)
: Evaluates to np.zeros(s) if s is a matrix shape or scalar > 0, otherwise evaluates to 0.diag(x)
: Evaluates to np.diag(x).flatten(*args)
: Evaluates to a vector where all arguments are stacked (concatenated) into a single vector. Arrays are reduced to vectors by Numpy’s flatten(), and complex objects are reduced via recursive flattening.row_stack(*args)
: Evaluates to a matrix where all arguments are stacked vertically. 1D arrays are treated as row vectors. If only a single list element is provided, then all arguments are stacked.column_stack(*args)
: Evaluates to a matrix where all arguments are stacked horizontally. 1D arrays are treated as column vectors. If only a single list element is provided, then all arguments are stacked.
Comparisons and logical functions
eq(lhs,rhs)
: Evaluates to lhs = rhs (shortcut: “lhs = rhs”).ne(lhs,rhs)
: Evaluates to lhs != rhs (shortcut: “lhs != rhs”).le(lhs,rhs)
: Evaluates to lhs <= rhs (shortcut: “lhs <= rhs”).ge(lhs,rhs)
: Evaluates to lhs >= rhs (shortcut: “lhs >= rhs”).not_(x)
: Evaluates to not x (shortcut: “not x”).or_(x,y)
: Evaluates to x or y (shortcut: “x or y”).and_(x,y)
: Evaluates to x and y (shortcut: “x and y”).any_(*args)
: Evaluates toany(*args)
all_(*args)
: Evaluates toall(*args)
Arithmetic functions
neg(x)
: Evaluates to -x (shorcut “-x”).abs_(x)
: Evaluates to abs(x) (shortcut: “abs(x)”). Works with arrays too (elementwise)sign(x)
: Evaluates the sign of x. Works with arrays too (elementwise).add(x,y)
: Evaluates to x + y (shortcut: “x + y”). Works with arrays too.sub(x,y)
: Evaluates to x - y (shortcut: “x - y”). Works with arrays too, and vector - scalar.mul(x,y)
: Evaluates to x * y (shortcut: “x * y”). Works with arrays too (elementwise multiplication).div(x,y)
: Evaluates to x / y (shortcut: “x / y”). Works with arrays too (elementwise division), and vector / scalar.pow_(x,y)
: Evaluates topow(x,y)
(shortcut “x**y”).dot(x,y)
: Evaluates tonp.dot(x,y)
.outer(x,y)
: Evaluates tonp.outer(x,y)
.tensordot(x,y,axes)
: Evaluates tonp.tensordot(x,y,axes)
.max_(*args)
: Evaluates to the maximum of the arguments.min_(*args)
: Evaluates to the minimum of the arguments.argmax(*args)
: Evaluates to the index of the maximum of the argments.argmin(*args)
: Evaluates to the index of the minimum of the argments.cos(x)
: Evaluates to math.cos(x).sin(x)
: Evaluates to math.sin(x).tan(x)
: Evaluates to math.tan(x).sqrt(x)
: Evaluates to math.sqrt(x).exp(x)
: Evaluates to math.exp(x).log(x)
: Evaluates to math.log(x) (base 10).ln(x)
: Evaluates to math.ln(x) (natural log).sum_(*args)
: Evaluates to sum(args). If arguments are vectors or matrices, then the result is also a vector or matrix. This is somewhat different behavior from sum(x) if x is a list.weightedsum(v1,...,vn,w1,...,wn)
: Evaluates to \(w1*v1+...+wn*vn\).
Accessors
getitem(vec,index)
: Evaluates tovec[index]
. This also supports slices and tuples, as well as lists (Numpy fancy indexing). (shortcut: “vec[index]”)setitem(vec,index,val)
: Evaluates to vec except with vec[index] set to val. Equivalent to Python code:temp = vec[:] vec[index]=val return temp
getattr_(object,attr)
: returns the value of a given attribute under the given object. For example,getattr_(traj,const("milestones"))
gets the milestone list of a user-dataTrajectory
namedtraj
.If the result is a function, it will be called with no arguments. For example,
getattr_(robot,const("getJointLimits"))
will return the robot’s joint limits.(shortcut: “object.attr”, where object is a UserDataExpression)
setattr_(object,attr,val)
: returns a modified version of the given class object, wherevalue
is assigned to the attributeattr
. For example,setattr_(traj,const("times"),[0,0.5,0.1])
sets thetimes
attribute of aTrajectory
to [0,0.5,1].Note: this operation modifies the object itself.
If the attribute
attr
is a function, it will be called with the argumentval
. This allows setting operations to be called.
Conditionals
if_(cond,trueval,falseval)
: If cond evaluates to True, this expression evaluates to trueval. Otherwise, it evaluates to falseval.
Arrays
Arrays are mostly interchangable with vectors (numpy 1-D arrays), except they
can contain objects of varying type/size. Arrays of varying type/size should
only be used as arguments in the flatten or the special looping functions
(forall
, summation
, etc). In many cases the Python construction
[e1,e2,...,en]
where en is an Expression
, will be interpreted correctly
as an array
Expression. To handle nested lists of Expressions, and
to ensure that your lists can be saved and loaded, you may need to use these
functions.
array(*args)
: Creates a list or numpy array of the given arguments. This can accept arbitrary arguments, such as variable size vectors. A Numpy array is produced only if the items have compatible types and dimensions.list_(*args)
: Creates a list of the given arguments. This can accept arbitrary arguments, such as variable size vectors. No attempt is made to convert to a numpy array.tuple_(*args)
: Creates a tuple of the given arguments. This can accept arbitrary arguments, such as variable size vectors.zip_(collection1,collection1,...)
: Does the same thing as the Python zip function, returning a list of tuples.
Looping
Special functions are available for temporary variable substitution and
emulation of for
loops. In each of the following, var can be a variable
or userData referenced in the Expression
expr
:
subs(expr,var,value)
: evaluates expr with var substituted with value. For example,subs(const(2)*"i","i",3.5)
yields 2*3.5map_(expr,var,values)
: like the Pythonmap
function, evaluates to a list where each entry evaluatesexpr
withvar
substituted with a value from the listvalues
. For example, if x is aVariable
, thenmap_(x**"i","i",range_(3))
yields the list[x**0, x**1, x**2]
forall(expr,var,values)
: True if, for every value in the listvalues
,expr
evaluates to nonzero whenvar
is substituted with that value. Equivalent toall_(*[subs(expr,var,value) for value in values])
forsome(expr,var,values)
: True if, for some value in the listvalues
,expr
evaluates to nonzero whenvar
is substituted with that value. Equivalent toany_(*[subs(expr,var,value) for value in values])
summation(expr,var,values)
: The sum ofexpr
overvar
whenvar
is substituted with each value in the listvalues
. Equivalent tosum_(*[subs(expr,var,value) for value in values])
Nested iteration can be performed, such as
summation(summation(expr("x")**"y","x",[1,2]),"y",[0,1])
Defining your own Functions
If you want to use your own Python functions, you can use Context.declare
.
By default this will use the same function signature that you used to define
the function, or you can provide a new signature (name, arguments).
The convention used in the built-in symbolic libraries is to prepend an
underscore to the underlying Python function, and then declare the function
to the undecorated name.:
def _f(x,y):
return 2*x*y
ctx = Context()
f = ctx.declare(_f,"f")
print(f(3,4)) #prints f(3,4)
print(f(3,4).evalf()) #prints 24, since 2*3*4=12.
At this point, the module does not know how to take derivatives, so any
deriv(f(...),arg)
call will return None. To set derivatives, you can
use the setDeriv
or setJacobian
functions:
f.setDeriv("x",(lambda x,y,dx:2*dx*y))
f.setDeriv("y",(lambda x,y,dy:2*x*dy))
OR:
f.setJacobian("x",(lambda x,y:2*y))
f.setJacobian("y",(lambda x,y:2*x))
Alternatively, you can declare an Expression
as a Function
. Here you
need to define the function name and argument list so that unbound variables in
the Expression
are bound to the arguments.:
f = ctx.declare(const(2)*expr("x")*expr("y"),"f",["x","y"])
This form will automatically obtain derivatives for you.
Functions can also specify argument types and return types, which are used
for type checking at Expression creation time. This is quite helpful for
debugging, since you do not have to evaluate the Expression
to find
mismatched types, like indexing a vector with a list. To declare types for
custom functions, use the setArgType
and setReturnType
methods:
#numeric input and output
f.setArgType(0,'N')
f.setArgType(1,'N')
f.setReturnType('N')
Gotchas
Most conversions of arguments to Expressions are done for you during the
course of calling operators or calls to symbolic functions, but if you call
operators on Python constants, you will invoke the standard Python operation.
For example, 5 + 7 produces 12 because 5 and 7 are Python constants, but if you
want to build the symbolic Expression
that represents “5 + 7”, you will need
to use const(5)+const(7)
or expr(5)+expr(7)
.
Since raw strings are interpreted as references to user-data variables, to
create string constants, you will need to wrap the string using the const()
function, e.g., const("text")
. This is mostly relevant for the
get/setattr_
functions. Suppose Point is a class with members Point.x and
Point.y, the expression that accesses the x member of the user data Point p
is built with getattr_("p",const("x"))
. Using __getattr__
operator
overloading you can also use expr("p").x
Python Lists as arguments are handled in somewhat of a tricky way. If the list
is compatible with a Numpy array (i.e., each element is numeric or equal-sized
arrays), it will be converted to a Numpy array. Otherwise, (e.g., a non-
constant Expression is inside or the elements do not have the same size) it will
be converted to an array(e1,...,en)
Expression. Tuples are NOT
converted in the same way, so that Numpy matrix indices can be preserved.
Tuples of expressions are not supported implicitly, instead you will have to use
tuple_(e1,...,en)
.
Comparison testing on Expressions, such as e != 0
or e1 == e2
, do
not return True or False. Instead, they return Expressions themselves! As
a result, standard Python if statements cannot be used on Expressions. Instead,
you will need to run eval()
or evalf()
on the result if you want to get
its truth value. (eval()
does return an Expression, but if the result of
eval()
is a ConstantExpression then it may be directly tested for its truth
value.) To help you remember this, an exception will be raised if you try to use
an expression as a condition in a Python if
statement.
Note also that e1 == e2
does NOT test for whether the two expressions are
logically equivalent. As an example, the expression x1+x2 == x2+x1
does not
test equivalence as you might expect, nor would even eval()
to true unless
x1 and x2 were given. In order to test whether two expressions are
syntactically equivalent, you can use e1.match(e2)
. It is computationally
intractable in general to determine whether two expressions are logically
equivalent, so we don’t even try.
Derivatives are handled as usual for scalar/vector quantities, giving Jacobian matrices in the form:
[df1/dx1 ... df1/dxn ]
[... ]
[dfm/dx1 ... dfm/dxn ].
However, if the function or variable has an “exotic” type, like a matrix, tensor, or nested list, then the Jacobian is taken with respect to the flattened version of the function and the variable. The way this is handled can be seen in some complex derivative expressions, which will have various reshape operations.
Many standard Python operators – +,-,*,/,**, and, or, not, comparison tests,
the [] indexing operator, and list construction via [a,b] – are supported
directly on Variables and Expressions. Compound slices (matrix[:,:]
) have
not yet been thoroughly tested. Other standard functions – len, min, max, sum,
abs, any, and all – have direct analogues in this package, with a trailing
underscore added. If statements and list comprehensions can be emulated via the
if_(cond,trueval,falseval)
statement and the map_(expr,var,range)
statement
. There is no support for the in statement, bitwise operators, or
procedural code (e.g., statements with side-effects).
If-elif-…-else blocks can be emulated using a multiplexer
array(expr1,expr2,...,exprn)[switch]
where switch
takes on the values
0,…,n-1. This expression is lazy-evaluated so that only the selected
expression is expanded. Standard if_
statements are also lazy-evaluated.
Thread-safety: Expression evaluation, derivatives, and simplification are NOT thread safe. Common Expressions used between threads should be deep-copied before use.
Performance and Expression DAGs
If your expression repeatedly performs computationally expensive operations, it is helpful to gather sub-expressions into the same Python objects. As an example, consider a Variable a, and the expression d given by the following construction:
b = (a+a)
c = (b+b)
d = (c+c)
Expanded, d = (c+c) = ((b+b)+(b+b)) = (((a+a)+(a+a))+((a+a)+(a+a)). However,
when d.eval({'a':1})
is called, this module is smart enough to evaluate a,
b, and c only once. This becomes really helpful in derivative evaluation as
well, since the derivative expression will also try to reuse common sub-
expressions.
Now what if we want to evaluate several expressions at once? This naive code will evaluate a, b, c, and d 1000 times:
ds = [(d+i).eval({'a':1}) for i in range(1000)]
In order to take advantage of the sub-expression d, we can put everything into a
single array()
expression:
ds = array(*[(d+i) for i in range(1000)]).eval({'a':1})
which will only evaluate a,b,c, and d once.
IO
There are three forms of Expression IO in symbolic_io:
Standard Python printing:
str(expr)
(output only)Human-readable strings:
symbolic_io.toStr()
(output) /symbolic_io.fromStr()
(input)JSON-like objects:
symbolic_io.toJson()
(output) /symbolic_io.fromJson()
(input)
Method 1 is the most readable when printed to the console, but can’t be read.
Method 2 is somewhat readable, and is compatible with the optimization problem editor. Note that there may be some subtle problems with IO for lists vs numpy arrays, since lists are automatically converted to numpy arrays when possible. It hasn’t been tested extremely thoroughly yet.
Method 3 is the least ambiguous but it uses a nested JSON structure to represent the expression graph. Hence it is rather verbose.
In Methods 2 and 3, if the expression graph is a DAG rather than a tree, a special notation is used to represent repeated references to nodes. In particular, any common ConstantExpression and OperatorExpression objects are “tagged” with a unique id string.
In Method 2, the first time a sub-expression appears it’s tagged with a suffix
#id. Then, subsequent references are retrieved with the expression @id. As an
example, the string (x+y)#1*@1
evaluates to (x+y)*(x+y)
, since ‘#1’
assigns (x+y)
to the id ‘1’ and ‘@1’ retrieves it.
Code generation
context.makePyFunction(expr,varorder=None): creates a Python function that evaluates
expr
given arguments whose values are to be assigned to eachVariable
invarorder
.context.makeFlatFunction(expr,varorder=None): creates a Python function that evaluates
expr
given a flattened list or vector of parameters, which can be unraveled to values to be assigned to each Variable invarorder
.symbolic_io.latex(expr): produces a LaTex string representing the expression (requires Sympy)
symbolic_io.codegen(exprs,language): produces C / Matlab code to evaluate the
Function
or named expressions (requires Sympy).
Sympy integration
Sympy integration is quite automatic. See symbolic_sympy.exprToSympy()
and symbolic_sympy.exprFromSympy()
in symbolic_sympy.py. Built-in
functions are converted mostly bidirectionally and hence support all aspects of
both libraries.
Array operations are converted to Sympy Matrix operations, which expand all entries into scalar expressions, so array operations like dot() cannot be converted to Sympy and then back into the equvalent symbolic operation.
Custom symbolic functions are converted to sympy Function(f) objects, and it should be noted that these do not support code generation.
Special Sympy functions are automatically converted for use in the symbolic module, including differentiation. (Note that they cannot be saved to / loaded from disk, though.)
Wish list
Sparse matrix support when obtaining jacobians – especially in block matrix form.
Compiled code generation on vectors/matrices – maybe integration with TensorFlow / PyTorch?
Module summary
External interface
|
Converts x to an appropriate Expression as follows: |
|
A specification of a variable/expression type. |
|
|
|
|
|
|
|
|
|
|
|
Returns True if v is a constant value or constant expression. |
|
Returns the value corresponding to a constant value or expression v. |
|
Returns True if v evaluates to a scalar. |
|
Returns the value of v if v is a scalar |
|
Returns true if v represents a 0 value |
|
Returns True if v is equivalent to a stand-alone variable. |
|
If v is equivalent to a stand-alone variable, returns the Variable. |
|
|
|
|
|
Returns true if v is a sparse array, with #nonzeros(v) < threshold(shape(v)). |
|
If v is a monomial of a single variable, returns (x,d) where x is the Variable and d is the degree. |
|
If expr is a polynomial of a single variable, returns x,[c1,...,cn],[d1,...,dn] where expr = c1 x^d1 + . |
Internal implementation
|
A specification of a variable/expression type. |
|
Base class for all symbolic operations. |
|
A symbolic function. |
|
|
|
Used for matching / finding |
|
|
|
|
|
|
|
A compound function of individual Expressions |
Symbolic standard functions
|
range(n) |
|
len(x) |
|
count(x) |
|
shape(x) |
|
reshape(x,s) |
|
transpose(x) |
|
transpose2(x,axes) |
|
dims(x) |
|
eye(n) |
|
basis(i,n) |
|
zero(n) |
|
diag(x) |
|
eq(lhs,rhs) |
|
ne(lhs,rhs) |
|
le(lhs,rhs) |
|
ge(lhs,rhs) |
|
not(x) |
|
or(x,y) |
|
and(x,y) |
|
neg(x) |
|
abs(x) |
|
sign(x) |
|
add(x,y) |
|
sub(x,y) |
|
mul(...) |
|
div(x,y) |
|
pow(x,y) |
|
dot(x,y) |
|
outer(x,y) |
|
tensordot(x,y,axes) |
|
if(cond,trueval,falseval) |
|
max(...) |
|
min(...) |
|
argmax(...) |
|
argmin(...) |
|
cos(x) |
|
sin(x) |
|
tan(x) |
|
arccos(x) |
|
arcsin(x) |
|
arctan(x) |
|
arctan2(x) |
|
sqrt(x) |
|
exp(x) |
|
log(x) |
|
ln(x) |
|
sum(...) |
|
any(...) |
|
all(...) |
|
getitem(vec,index) |
|
setitem(vec,index,val) |
|
getattr(object,attr) |
|
setattr(object,attr,val) |
|
flatten(...) |
|
row_stack(...) |
|
column_stack(...) |
|
array(...) |
|
list(...) |
|
tuple(...) |
|
zip(...) |
|
weightedsum(...) |
|
subs(expr,var,value) |
|
map(expr,var,values) |
|
forall(expr,var,values) |
|
forsome(expr,var,values) |
|
summation(expr,var,values) |
- class klampt.math.symbolic.Type(type, size=None, subtype=None)[source]
Bases:
object
A specification of a variable/expression type.
- char
a character defining the type. Valid values are N, I, B, X, A, V, M, L, U, and None.
- Type:
str
- size
None (no size specified), the length of the array (L and V types), or the Numpy shape (A, M types)
- subtype
U type: the name of the class, if known.
L type: either a single Type defining the list’s element types, or a list of Types defining individual element types (of the same length as size).
- Type:
str, Type, or list of Types, optional
- shape(hypershape=True)[source]
Returns the Numpy shape or hypershape of this type. If it’s array- like, the return value is a tuple. Otherwise, it’s a dict.
A ValueError is raised if no size is specified.
- len()[source]
Returns the number of first-level sub-items of this type. None is returned if no size is specified.
- count()[source]
Returns the number of free parameters in this type. None is returned if no size is specified.
- dims()[source]
Returns the number of entries in the shape of this type. For compound list types, this is 1+subtype.dims().
- match(obj, strict=False)[source]
Returns true if the given object type matches all aspects of this specification. Integers and booleans match with numeric, vectors and matrices match with array.
obj is a Type, str, or Python object. If obj is a str, it is either a character specifier or a class name, and sizes aren’t checked. If obj is an object this is equivalent to self.match(type_of(obj)).
If obj doesn’t have a size then it matches only strict = False, or if this specification also doesn’t have a size.
- class klampt.math.symbolic.Context[source]
Bases:
object
Base class for all symbolic operations. Define variables, expressions, and user data here.
- addVar(name, type='V', size=None)[source]
Creates a new Variable with the given name, type, and size.
Valid types include: - V: vector (default) - M: matrix - N: numeric (generic float or integer) - B: boolean - I: integer - A: generic array - X: index
size is a hint for vector variables to help determine how many entries the variable should contain. It can be None, in which case the size is assumed unknown.
- addVars(prefix, N, type='N', size=None)[source]
Creates N new Variables with the names prefix+str(i) for i in 1,…,N. type is the same as in addVar, but by default it is numeric.
- addUserData(name, value)[source]
Adds a new item to user data. These are un-serializable objects that can be referred to by functions, but must be restored after loading.
- declare(func, fname=None, fargs=None)[source]
Declares a custom function. If fname is provided, this will be how the function will be referenced. Otherwise, the Python name of the function is used.
- Parameters:
func (function or
Expression
) – the function / expression objectfname (str, optional) – the name of the new Function. If func is an Expression this is mandatory. Otherwise it is taken from the Python function name.
fargs (list of str, optional) – the argument names. If func is an
Expression
this is mandatory.
To convert Expressions into Functions, the fargs list declares the order in which variables in func will be bound to arguments. E.g.,
Context.declare(2*expr("x")*expr("y"),"twoxy",["x","y"])
produces a two argument functiontwoxy(x,y): 2*x*y
.
- include(context, prefix=None, modify=False)[source]
Adds all items inside another context as a sub-context.
If prefix != None,
self.[prefix]
is set tocontext
, and all names in that context are prepended by the given prefix and a ‘.’.If
modify=True
, then all the Variable and Function names inside the given sub-context are modified to fit the self context. This is useful if you are saving/loading expressions and using the convenience form self.[prefix].[functionName] to instantiate Functions embedded inside the sub-context.Note
When using modify=True, be careful not to re-use the sub-context inside multiple super-contexts.
- bindFunction(function, remapping=None)[source]
Produces an Expression that evalutes the function, where its arguments are bound to variables / user data in the current environment. The argument names should map to similarly named variables or user data.
If remapping is provided, then it maps function arguments to variables or values, either as
a dictionary mapping a function argument arg to remapping[arg].
a list or tuple mapping the i’th function argument to remapping[i].
- get(name, *args)[source]
Retrieves a named reference to a userData or variable.
Can be called as
get(name)
, in which case a KeyError is raised if the key does not exist, orget(name,defaultValue)
in which case the default value is returned if the key does not exist.
- makePyFunction(expr, varorder=None)[source]
Converts an Expression or Function to a Python function
f(x)
that takesx
as a list of scalar values, maps those to Variable values, and returns the result of evaluating the expression / function.- Parameters:
expr (
Function
orExpression
) – the function or expression to evaluatevarorder (list, optional) –
If given, the list of Variables that should appear in the flattened argument list
x
.If this isn’t provided, then the Variables in
expr
are ordered by the order in which were added to thisContext
.
- Returns:
A pair
(f,varorder)
, where:f(x)
is a 1-argument Python function equivalent toexpr
but where
x
is a list of variable values.
varorder
gives the order of variables that should besent in
x
- Return type:
tuple
- makeFlatFunction(expr, varorder=None, defaultsize=1)[source]
Given an expression expr, return
(f,varorder)
, wheref
is an equivalent 1-argument Python function that takes a list of numbers or numpy array. The order of variables that should be provided tof
in this tuple is returned invarorder
.If vector variables are not given size hints, then they are assumed to have
defaultsize
.See also
makePyFunction()
.
- makeFlatFunctionDeriv(expr, varorder=None, defaultsize=1)[source]
Given a differentiable expression expr, return
(df,varorder)
, where df is an 1-argument Python function that that takes a list of numbers or numpy array and outputs the derivative (Jacobian matrix) of expressionexpr
.The order of variables that should be provided to
df
in this tuple is returned invarorder
.If
expr
is not differentiable, thendf=None
is returned.If vector variables are not given size hints, then they are assumed to have
defaultsize
.See also
makeFlatFunction()
.
- class klampt.math.symbolic.Function(name, func, argNames=None, returnType=None)[source]
Bases:
object
A symbolic function. Contains optional specifications of argument and return types, as well as derivatives.
- Parameters:
name (str) –
func (Python function or
Expression
) –argNames (list of str, optional) –
returnType (str or function, optional) – sets
self.returnType
orself.returnTypeFunc
.
If
func
is a Python function, the argument list will be derived from the declaration of the Python function. Otherwise, it must be anExpression
, andargNames
needs to be provided. The expression must be closed, meaning that all unspecified variables in the expression must be named inargNames
.Examples
Basic instantiation:
#standard function method def f(x,y): ... symfunc = Function("f",f) a = context.addVar("a") b = context.addVar("b") c = context.addVar("c") print(symfunc(a,b)) # prints f($a,$b)
Creating a Function from an Expression (sort of like a lambda function):
expr = a + 2*b symfunc2 = Function("f2", expr, ["a","b"]) #when symfunc2 is called, its first argument will be bound to a, and its second will be bound to b print(symfunc2(c,4)) #prints f2(c,4) print(symfunc2(c,4).eval({'c':5})) #prints 13, because c + 2*4 = 5 + 2*4 = 13
If
func
is an Expression, then you can automatically set derivatives if all the sub-expressions have derivatives. To do so, use theautoSetJacobians()
method.- Defining derivatives:
There are three ways to define derivatives:
setDeriv()
,setJacobian()
, andautoSetJacobians()
(available iffunc
is an expression. InsetDeriv()
you provide Jacobian-vector products. InsetJacobian()
you provide Jacobian matrices (or tensors).
- name
name of function used in printing and IO.
- Type:
str
- description
text description of function.
- Type:
str, optional
- func
the function to be evaluated.
- Type:
Python function or
Expression
- argNames
names of arguments.
- Type:
list of strs, optional
- argDescriptions
strings describing each argument
- Type:
list of strs, optional
- returnTypeFunc
a function that takes argument types and produces a more specific return
Type
thanreturnType
- Type:
function, optional
- returnTypeDescription
description of the return type
- Type:
str, optional
- deriv
Can be either:
a list of Jacobian-vector products with respect to a derivative of each argument:
[df1(*args,darg1),...,dfn(*args,dargn)]
. Here,dargi
is an argument of the same shape asargs[i]
, giving the derivative \(\frac{dargs[i]}{dx}\) w.r.t. some scalar parameter x. The functiondfi
gives \(\frac{df}{dargs[i]}\cdot\frac{dargs[i]}{dx}\) where \(\frac{df}{dargs[i]}\) is the partial ofself
with respect to the i’th argument.a function
df(args,dargs)
giving the total derivative of f given directional derivatives of each of the argmuments. Here,dargs
is a list of derivatives[darg1,...,dargn]
. The result should be equal to \(\frac{df}{dx} = \frac{df}{dargs[0]}\cdot \frac{dargs[0]}{dx} + ... + \frac{df}{dargs[n-1]}\cdot\frac{dargs[n-1]}{dx}\).
The return value should have the same shape as
self.returnType()
- Type:
optional
- colstackderiv
same as
deriv
, except that each function accepts stacked argument derivatives. This can be more efficient than filling inderiv
, since taking derivatives w.r.t. k variables x1,…,xk can be done by setting updargi
as a matrix[dflatten(argi)/dx1 | ... | dflatten(argi)/dxk]
, i.e.,. the column stacking of each of the flattened argument derivatives. dargi has shape(count(argi),k)
.- Type:
optional
- rowstackderiv
same as
colstackderiv
, except that row- wise stacked argument derivatives are accepted. In other words,dargi
is a matrix \([\frac{d\text{flatten(args[i])}}{dx1}, ... , \frac{d\text{flatten(args[i])}}{dxk}]\) which has shape(k,count(argi))
. This is more efficient thancolstackderiv
but corresponds less directly to standard mathematical notation.- Type:
optional
- jacobian
list of Jacobian functions with respect to each argument. Has the form
[Jf1(*args),...,Jfn(*args)]
where Jfi returns a matrix of shape(count(self),count(args[i]))
. The total derivative with respect to some variablex
is \(\frac{df}{dx} =\)reshape(dot(Jf1,flatten(darg1)) + dot(Jfn,flatten(dargn)),shape(self))
- Type:
list of functions, optional
- presimplifier
- Type:
function, optional
- simplifier
- Type:
function, optional
- presimplifierDict
a nested dict, mapping argument signatures to simplification functions. See
addSimplifier()
for more details.- Type:
dict, optional
- simplifierDict
a nested dict, mapping argument signatures to simplification functions. See
addSimplifier()
for more details.- Type:
dict, optional
- properties
possible properties of this function, such as associativity, etc.
- Type:
dict
- printers
a dict containing code generation methods. Each entry, if present, is a function
printer(expr,argstrs)
that returns a string. Common key values are:“str”: for printing to console
“parse”: for parseCompatible=True exprToStr
- Type:
dict of functions
- optimized(*args)[source]
Similar to
self(*args).simplify(depth=1)
, but optimized to reduce complexity earlier. In particular, this directly applies the operation if all arguments are constants, and it will try to apply the simplifier immediately.
- checkArg(arg)[source]
Verifies that a named or indexed argument is valid, and normalizes it. Returns an (index,name) tuple
- setDeriv(arg, dfunc, asExpr=False, stackable=False)[source]
Declares a (partial) derivative of the function with respect to argument arg. The function
dfunc
is a function that takes arguments(arg1,...,argn,dx)
, wheredx
is the derivative ofarg
with respect to some variable x, and returns \(df/darg(arg1,...,argn) * darg/dx\).For vector-valued arguments and functions, the * is a matrix-vector product, and
dfunc
is required to produce what’s commonly known as the Jacobian-vector product.For matrix-valued arguments or functions, the * is a tensor product.
- Parameters:
arg (int or str) – either an argument index or name.
dfunc –
either:
an Expression of variables arg1,…,argn,darg,
a
Function
of n+1 variables mapping toarg1,...,argn,dx
,- a Python function of n+1 variables
(arg1,...,argn,dx)
that either returns a value (setting
asExpr=False
) or anExpression
of the derivative (ifasExpr=True
).
- a Python function of n+1 variables
None, to indicate that the derivative is not defined,
0, to indicate that the derivative is identically 0.
In the normal case (
stackable=False
), the shape ofdx
is the same asarg
, and the result has the same shape as self.asExpr (bool, optional) – if
dfunc
is a Python function, this flag says that it will return anExpression
. Using anExpression
allows taking multiple derivatives.stackable (bool or str, optional) –
states whether
dfunc
can accept stacked derivative arguments. IfTrue
or'col'
, then it can acceptdvar
as a column-stacked array of derivatives. In other words,dvar[...,0]
is the derivative w.r.t. x0,dvar[...,1]
is the derivative w.r.t. x1, etc.E.g., for vector arguments, dvar can be thought of as a matrix with k=``dvar.shape[-1]`` derivatives in its columns.
In this case,
dfunc
should return an array of shape shape(self) x k (i.e., f’s derivatives are stacked in columns.)stackable
can also be'row'
in which casedfunc
acceptsdvar
as a row-stacked array of derivatives. I.e,dvar[0,...]
is the derivative w.r.t. x0,dvar[1,...]
is the derivative w.r.t., x1, etc. In this case,dfunc
should return a list of derivatives.If the argument is not an array or its type cannot be determined (see
setArgType
) thendvar
will be passed as acount(arg)
x k matrix (for column-stacking) or a k xcount(arg)
matrix (for row stacking).If the function does not return an array or the return type cannot be determined (see
setReturnType
), the shape of the returned matrix must becount(self)
x k (for column- stacking) or k xcount(self)
(for row-stacking).
- setJacobian(arg, dfunc, asExpr=False)[source]
Declares a (partial) derivative of the function with respect to argument
arg
.This only makes sense when the arguments are all arrays or scalars; no complex types are supported.
- Parameters:
arg (int or str) – same as
setDeriv
.dfunc – similar to
setDeriv
, but a function that takes n arguments (arg1,…,argn) and returns the matrix \(df/darg(arg1,...,argn)\).
The return value of
dfunc
must have shape shape(self) + shape(arg), so that:If self and arg are scalars, the Jacobian is also a scalar
If self and arg are a scalar and a vector (or vice versa) the Jacobian is a vector.
If self and arg contain a scalar and an N-D array, the Jacobian is an N-D array.
If self and arg are both vectors, the Jacobian is a matrix.
- autoSetJacobians(args=None)[source]
For
Expression
-based functions, can automatically set the Jacobians. Ifargs
is not None, only the arguments inargs
are set.
- getArgType(arg)[source]
Retrieves an argument type.
- Parameters:
arg (int or str) – the index or string naming an argument.
- addSimplifier(signatures, func, pre=False)[source]
For a signature tuple, sets the simplifier to
func
.- Parameters:
signatures (list) –
a list of argument signatures. A signature can be:
the operation name for an OperatorExpression, passing the arg directly to func(…)
’_scalar’: matches to a constant scalar, and passes that constant to func(…)
’_const’: matches to constant, and passes that constant to
func(...)
’_returnType’: passes the argument’s
returnType()
tofunc(...)
None: match all. The arg is passed directly to func(…)
func (callable) – a callable that takes a list of function arguments, possibly transformed by _const or _returnType. This returns a simplified
Expression
orNone
.pre (bool, optional) – if True, the simplifier is called before arguments are simplified.
If multiple matches are present then they are tested in order
operation name
_const
_returnType
None
- class klampt.math.symbolic.Expression[source]
Bases:
object
- depth(cache=True)[source]
Returns the depth of the deepest leaf of this expression tree (i.e., its height). If cache = True, depths are cached as attribute ‘depth’ to speed up subsequent depth() calls.
- isConstant()[source]
Returns true if this expression is identically a constant. If so, then the expression can be safely replaced with its evalf() value without any possible change in meaning.
- returnConstant(context=None)[source]
Returns true if the evaluation of the expression in the given context results in a constant. If so, then
evalf()
can safely be applied without error.
- eval(context=None)[source]
Evaluates the expression while substituting all constant values. The result can be a constant or an Expression if the result is not constant.
- Parameters:
context (Context or dict, optional) – a map of variable names to constant values.
- evalf(context=None)[source]
Evaluates the expression while substituting all constant values, enforcing that the result is a constant. If the result is not constant, a ValueError is returned.
- deriv(var, context=None)[source]
Returns a new expression where all bound variables and variables in context are reduced to constant values. If all arguments are constant, returns a constant.
- Parameters:
var – either a Variable, a string naming a Variable, or a dictionary mapping variable names to derivatives. For example, in the latter case, if this is an expression f(x,y),and var is a dictionary {“x”:dx,”y”:dy}, then the result is
df/dx(x,y)dx + df/dy(x,y)dy
context (Context or dict, optional) – a map of variable names to constant values.
- vars(context=None, bound=False)[source]
Returns a list of all free Variables under this expression.
If bound is True, any Variables currently bound to values are returned, otherwise they are not.
- match(val)[source]
Returns true if self is equivalent to the given expression. Note: no rearrangement is attempted, so x+y does not match y+x.
- find(val)[source]
Returns self if self contains the given expression as a sub-expression, or None otherwise.
- replace(val, valReplace, error_no_match=False)[source]
Returns a copy of this expression where any sub-expression matching val gets replaced by valReplace. If val doesn’t exist as a subexpression, self is returned.
- simplify(context=None, depth=None)[source]
Returns a simplified version of self, or self if it cannot be simplified.
- Parameters:
context (dict or
Context
) – any Variable / UserData whose name appears in here will be substituted with its value.depth (int, optional) – None for full-depth simplification, or the max depth to explore.
- Returns:
- Return type:
- class klampt.math.symbolic.Wildcard(name='*')[source]
Bases:
Expression
Used for matching / finding
- class klampt.math.symbolic.ConstantExpression(value)[source]
Bases:
Expression
- isConstant()[source]
Returns true if this expression is identically a constant. If so, then the expression can be safely replaced with its evalf() value without any possible change in meaning.
- class klampt.math.symbolic.UserDataExpression(name)[source]
Bases:
Expression
- isConstant()[source]
Returns true if this expression is identically a constant. If so, then the expression can be safely replaced with its evalf() value without any possible change in meaning.
- returnConstant(context=None)[source]
Returns true if the evaluation of the expression in the given context results in a constant. If so, then
evalf()
can safely be applied without error.
- class klampt.math.symbolic.VariableExpression(var)[source]
Bases:
Expression
- isConstant()[source]
Returns true if this expression is identically a constant. If so, then the expression can be safely replaced with its evalf() value without any possible change in meaning.
- returnConstant(context=None)[source]
Returns true if the evaluation of the expression in the given context results in a constant. If so, then
evalf()
can safely be applied without error.
- class klampt.math.symbolic.OperatorExpression(finfo, args, op=None)[source]
Bases:
Expression
A compound function of individual Expressions
- isConstant()[source]
Returns true if this expression is identically a constant. If so, then the expression can be safely replaced with its evalf() value without any possible change in meaning.
- returnConstant(context=None)[source]
Returns true if the evaluation of the expression in the given context results in a constant. If so, then
evalf()
can safely be applied without error.
- eval(context=None)[source]
Returns a new expression where all bound variables and variables in context are reduced to constant values. If all arguments are constant, returns a constant expression.
- deriv(var, context=None)[source]
Returns an expression for the derivative dself/dvar, where all bound variables and variables in context are reduced to constant values.
Normally,
var
is aVariable
orstr
.The derivative/Jacobian size is determined as follows:
If both var and self are scalar, the result is a scalar.
If self is scalar and var is non-scalar, the result has the same shape as var.
If self is non-scalar and var is scalar, the result the same shape as self.
If both self and var are arrays, the result is an n-D array with shape shape(self)+shape(var).
If other self or var are compound (i.e., unstructured lists), the result is an m x n matrix, where m = count(self) and n = count(var).
If no derivative can be determined, this returns None.
If the expression evaluates to a constant, the result will be either 0 or a constant expression.
Another option is for
var
to be a dict of variable names to their derivatives.
- vars(context=None, bound=False)[source]
Returns a list of all free Variables under this expression.
If bound is True, any Variables currently bound to values are returned, otherwise they are not.
- match(expr)[source]
Returns true if self is equivalent to the given expression. Note: no rearrangement is attempted, so x+y does not match y+x.
- klampt.math.symbolic.is_const(v, context=None, shallow=False)[source]
Returns True if v is a constant value or constant expression.
If context is not None, then Variables and user data that are bound to values are considered to be constants. Otherwise, they are not considered to be constants.
If shallow=True, this doesn’t try to convert Expressions.
- klampt.math.symbolic.to_const(v, context=None, shallow=False)[source]
Returns the value corresponding to a constant value or expression v. Otherwise returns None.
If context is not None, then Variables and user data that are bound to values are considered to be constants. Otherwise, they are not considered to be constants.
If shallow=True, this doesn’t try to convert Expressions.
- klampt.math.symbolic.is_scalar(v, value=None)[source]
Returns True if v evaluates to a scalar. If value is provided, then returns True only if v evaluates to be equal to value
- klampt.math.symbolic.to_var(v)[source]
If v is equivalent to a stand-alone variable, returns the Variable. Otherwise returns None.
- klampt.math.symbolic.is_sparse(v, threshold='auto')[source]
Returns true if v is a sparse array, with #nonzeros(v) < threshold(shape(v)).
- Parameters:
v (Expression) – the array
threshold (optional) – either ‘auto’, a constant, or a function of a shape. If threshold=auto, the threshold is sqrt(product(shape))
- klampt.math.symbolic.expr(x)[source]
Converts x to an appropriate Expression as follows:
If x is a Variable, returns a VariableExpression.
If x is a non-str constant, returns a ConstantExpression.
If x is a str, then a UserDataExpression is returned.
If x is already an Expression, x is returned.
- If x is a list containing expressions, then
array(*x)
is returned. This adds some ambiguity to lists containing strings, like
expr(['x','y'])
. In this case, strings are recursively converted to UserDataExpressions.
- If x is a list containing expressions, then
- klampt.math.symbolic.to_monomial(v)[source]
If v is a monomial of a single variable, returns (x,d) where x is the Variable and d is the degree. Otherwise returns None.
- klampt.math.symbolic.to_polynomial(expr, x=None, const_only=True)[source]
If expr is a polynomial of a single variable, returns x,[c1,…,cn],[d1,…,dn] where expr = c1 x^d1 + … + cn x^dn. Otherwise returns None.
If x is given, the polynomial must be a polynomial in x. If const_only=True, the coefficients and degrees must be constants,
klampt.math.symbolic_io module
I/O from symbolic expressions.
Functions:
|
|
|
|
|
Converts an Expression to a printable or parseable string. |
|
Returns an Expression from a string. |
|
|
|
Creates an Expression from a JSON object previously saved by expr.toJson() |
|
|
|
|
|
Produces a JSON object from a context. |
|
Creates a context from a JSON object previously saved by context.toJson(). |
|
|
|
|
|
Returns LaTeX code for the Expression expr. |
|
Pretty-prints the Expression expr. |
|
Similar to sympy.codegen. |
- klampt.math.symbolic_io.exprToStr(expr, parseCompatible=True, expandSubexprs='auto')[source]
Converts an Expression to a printable or parseable string.
- Parameters:
expr (Expression) – the Expression to convert
parseCompatible (bool, optional) – if True, the result is readable via exprFromStr()
expandSubexprs (str or bool, optional) –
whether to expand subexpressions. Can be:
’auto’: if parseCompatible, equivalent to False. if parseCompatible=False, equivalent to True.
True: expands all common subexpressions
False: does not expand common subexpressions.
’show’: Internally used.
- Returns:
a printable or parsable string representing expr.
- Return type:
(str)
- klampt.math.symbolic_io.exprFromStr(context, string, fmt=None, add=False)[source]
Returns an Expression from a string. In auto mode, this reads in constants in klampt.loader JSON- compatible format, standard variables in the form “x”, user data in the form of strings prepended with $ (e.g., “$x”), and named expression references in the form of strings prepended with @.
- Parameters:
context (Context) – the context containing possible functions in string
string (str) – the string to parse.
fmt (str, optional) – specifies a format for the string. Can be None (auto), ‘auto’, or ‘json’
add (bool, optional) – if true, adds all variables referenced in the string to the context. Otherwise, undefined variables are referred to as user data.
An exception is raised on parsing failure.
(Parsing is a little slow, so try not to use it in tight inner loops)
- Returns:
the expression represented by str.
- Return type:
- klampt.math.symbolic_io.exprFromJson(context, jsonObj, taggedExpressions=None)[source]
Creates an Expression from a JSON object previously saved by expr.toJson()
- klampt.math.symbolic_io.contextToJson(ctx, saveFunctions=False)[source]
Produces a JSON object from a context. Only the names for userData and customFunctions are saved. If saveFunctions=False, customFunctions are not saved
- klampt.math.symbolic_io.contextFromJson(context, jsonObj)[source]
Creates a context from a JSON object previously saved by context.toJson(). userData is not restored and customFunctions are not restored, but rather, userData and customFunctions are assumed to have been set up with exactly the same keys as when toJson was called.
Modifies context in-place.
- klampt.math.symbolic_io.latex(expr)[source]
Returns LaTeX code for the Expression expr. Requires Sympy.
- klampt.math.symbolic_io.pprint(expr)[source]
Pretty-prints the Expression expr. If Sympy is installed it will use the sympy pretty-printer.
- klampt.math.symbolic_io.codegen(name_expr, language=None, **options)[source]
Similar to sympy.codegen. Generates one or more expressions in the target language. Requires Sympy.
- Parameters:
name_expr –
multiple interpretations:
A single (name, Expression) tuple: generates code for one function
A list of (name, Expression) tuples: generates code for multiple functions
one or more Function objects: generates code for one or more functions, as long as the Function is defined via symbolic Expressions rather than Python functions.
A list of (Variable == Expression) expressions. Generates a function with multiple return values
language (str, optional) – any language accepted by Sympy.
options – other options for sympy.codegen.
See the Sympy codegen documentation for more information.
klampt.math.symbolic_klampt module
Defines many functions of Klampt as symbolic Functions.
Currently implemented:
so3, se3
ik
some collide functions
RobotModel kinematics
TODO:
RobotModel dynamics
Trajectories
Geometries
support polygons
Classes:
Defines some functions in the so3 module: |
|
Defines some functions in the se3 module under the se3 namespace |
|
Performs operations on IKObjective user data objects. |
|
Performs operations on Geometry3D user data objects. |
|
Defines the functions -- |
|
|
Includes all Klampt-related functions. |
- class klampt.math.symbolic_klampt.SO3Context[source]
Bases:
Context
Defines some functions in the so3 module:
identity, matrix, inv, mul, apply, rotation, error, distance
from_matrix, from_rpy, rpy, from_quaternion, quaternion, from_rotation_vector, rotation_vector
eq_constraint: equality constraint necessary for SO3 variables
quaternion_constraint: equality constraint necessary for quaternion variables
Completeness table
Function
Derivative
Simplification
identity
N/A
N/A
matrix
Y
Y
inv
Y
Y
mul
apply
Y,Y
rotation
N,Y
from_matrix
Y
from_rpy
rpy
from_quaternion
Y
quaternion
from_rotation_v
rotation_vector
axis
angle
Y
error
distance
eq_constraint
Y
quaternion_cons
Y
- class klampt.math.symbolic_klampt.SE3Context[source]
Bases:
Context
Defines some functions in the se3 module under the se3 namespace
make(R,t): makes an SE3 element from a rotation and a translation (equivalent to list(R,t))
identity, homogeneous, matrix (alias for homogeneous), inv, mul, apply
from_homogeneous: converts from a 4x4 matrix
rotation(T): retrieves the rotation corresponding to T
translation(T): retrieves the translation corresponding to T
Completeness table
Function
Derivative
Simplification
make
Y
N/A
identity
Y
homogeneous
Y
matrix
Y
from_homogeneou
Y
inv
Y
mul
apply
N,Y
rotation
Y
Y
translation
Y
Y
- class klampt.math.symbolic_klampt.IKContext[source]
Bases:
Context
Performs operations on IKObjective user data objects.
Defines the functions
link(ikobj): returns the link index of an IKObjective
robot(ikobj): returns the RobotModel of an IKObjective
targetPos(ikobj): returns the target position of an IKObjective
targetRot(ikobj): returns the target rotation of an IKObjective
targetXform(ikobj): returns the target transform of an IKObjective
localPos(ikobj): returns the local position of an IKObjective
worldPos(ikgoal,robot): returns the world position of the IKObjective at the robot’s current configuration (same as klampt.worldPos(robot,link(ikobj),localPos(ikobj)))
worldRot(ikgoal,robot): returns the world rotation of the IKObjective at the robot’s current configuration (same as klampt.worldRot(robot,link(ikobj)))
residual(ikgoal,robot): returns the combined position and orientation residual of an IKObjective at the robot’s current configuration
Completeness table
Function
Derivative
Simplification
link
N/A
N/A
robot
N/A
N/A
targetPos
N/A
N/A
targetRot
N/A
N/A
targetXform
N/A
N/A
localPos
N/A
N/A
worldPos
N/A,Y(1)
N/A
worldRot
N/A,Y(1)
N/A
residual
N/A,Y(1)
N/A
Y(1): yes, for the first derivative
- class klampt.math.symbolic_klampt.GeometryContext[source]
Bases:
Context
Performs operations on Geometry3D user data objects. Derivatives of geom arguments are taken with respect to the geometry transforms.
Defines the functions:
geometry(object): calls the function object.geometry() (e.g., object can be a RobotModelLink)
setTransform(geom,T): sets the current transform of the geometry and returns it.
setCollisionMargin(geom,margin): sets the current collision of the geometry and returns it.
bbox(geom): returns the bounding box of the geometry at its current transform.
collision(geom1,geom2): returns True if the geometries are colliding.
distance(geom1,geom2): returns the distance between the geometries, and if penetrating and the two geometries support signed distance, returns the negative penetation distance.
closestPoints(geom1,geom2): returns the pair of closest points between geom1 and geom2.
distancePoint(geom,pt): returns the closest point from geom to pt.
closestPoint(geom,pt): returns the closest point to pt on geom.
rayCast(geom,src,dir): returns the distance t>=0 along the ray src + t*dir that intersects geom, or inf if there is no intersection.
NOT IMPLEMENTED YET
Completeness table
Function
Derivative
Simplification
setTransform
N/A
N/A
setCollisionMar
N/A
N/A
bbox
N/A
collision
Y
N/A
distance
N/A
closestPoints
N/A
distancePoint
N/A
closestPoint
N/A
rayCast
N/A
- class klampt.math.symbolic_klampt.CollideContext[source]
Bases:
Context
Defines the functions –
robotSelfCollision(q,robot): returns True if the robot has a collision at q
robotCollision(q,context): returns True if the robot has a collision in the world. Saves a collider into the context
robotSelfCollisionFree(q,robot): the opposite of robotSelfCollision
robotCollisionFree(q,context): the opposite of robotCollision
- class klampt.math.symbolic_klampt.KlamptContext(world=None)[source]
Bases:
Context
Includes all Klampt-related functions.
Namespaces:
so3: SO3Context
se3: SE3Context
ik: IKContext
collide: CollideContext
[main]: functions to perform kinematics operations on WorldModel, RobotModel, and RobotModelLink user data objects.
The main namespace defines the functions:
robot(world,index): returns the index’th robot in the world
rigidObject(world,index): returns the index’th robot in the world
terrain(world,index): returns the index’th terrain in the world
config(robot): returns the current configuration of the robot or object
setConfig(robot,q): sets the current configuration of the robot and returns the robot
link(robot,index): returns the index’th link of the robot. (If you want to use a named string as the index, use const(name))
transform(object): gets the current transform of the object
setTransform(object,T): sets the current transform of the object and returns the object
velocity(robot): returns the current velocity of the robot
setVelocity(robot,dq): sets the current velocity of the robot and returns the robot
worldPos(robot,link,localPos): returns the world position of the point on the given link in the robot’s current configuration.
localPos(robot,link,worldPos): returns the local position of the point on the given link in the robot’s current configuration.
worldRot(robot,link): returns the rotation matrix of the given link in the robot’s current configuration.
com(robot): returns the center of mass of robot at its current configuration
gravityTorque(gravity,robot): returns the generalized gravity vector
inJointLimits(q,robot): returns True if q is in the robot’s joint limits
getJson(object,path): returns the value of a given path under the given object’s json representation. For example, getJson(ikobjective,const(“endPosition[0]”)) retrieves the x coordinate of the target position of an IKObjective.
setJson(object,path,val): returns a modified copy of the given object, where value is assigned to the given path under the objects json representation. For example, setJson(ikobjective,const(“endPosition[0]”),p) sets the x coordinate of the target position of an IKObjective to p. Note: this operation returns a copy of the object, modified.
Also includes modules linalg, so3, se3, ik, and collide
Function
Derivative
Simplification
robot
N/A
N/A
rigidObject
N/A
N/A
terrain
N/A
N/A
config
Y
N/A
setConfig
Y
N/A
link
N/A
N/A
transform
N/A
setTransform
N/A
velocity
N/A
setVelocity
N/A
worldPos
Y(1)
N/A
localPos
N/A
worldRot
N/A
com
Y(1)
N/A
gravityTorque
N/A
inJointLimits
N/A
N/A
getJson
N/A
N/A
setJson
N/A
N/A
Y(1): yes, for the first derivative
klampt.math.symbolic_linalg module
Defines symbolic linear algebra functions.
Function list:
norm(x): returns the L-2 norm of a vector
norm2(x): returns the squared L-2 norm of a vector
norm_L1(x): returns the L-1 norm of a vector
norm_Linf(x): returns the L-infinity norm of a vector
norm_fro(A): returns the Frobeneus norm of a matrix
distance(x,y): returns the L-2 distance between two vectors
distance2(x,y): returns the squared L-2 distance between two vectors
distance_L1(x,y): returns the L-1 distance between two vectors
distance_Linf(x,y): returns the L-infinity distance between two vectors
mahalanobis_distance(x,y,A): returns the mahalanobis distance between two vectors weighted by A, i.e. \(\sqrt((x-y)^T A (x-y))\)
mahalanobis_distance2(x,y,A): returns the squared mahalanobis distance between two vectors weighted by A
unit(x): returns the unit vector in the direction x
inv(A): returns the inverse of a matrix
pinv(A): returns the pseudoinverse of a matrix
linear(x,A): the linear function \(A x\)
quadratic(x,A): the quadratic function \(x^T A x\)
bilinear(x,y,A): the bilinear function \(x^T A y\)
bound_contains(xmin,xmax,x): returns True if xmin <= x <= xmax element-wise
bound_margin(xmin,xmax,x): returns the distance from x to boundaries of the bounding box [xmin,xmax], if inside (positive is inside)
bound_overlaps(xmin,xmax,ymin,ymax): returns True if xmin <= x <= xmax element-wise
Also defines a context LinAlgContext that can be included into a Context under “linalg”
Completeness table
Function |
Derivative |
Simplification |
---|---|---|
norm |
Y |
|
norm2 |
Y |
|
norm_L1 |
Y |
|
norm_Linf |
Y |
|
norm_fro |
Y |
|
distance |
Y |
|
distance2 |
Y |
|
distance_L1 |
Y |
|
distance_Linf |
Y |
|
mahalanobis_dis |
Y,Y,N |
|
mahalanobis…2 |
Y,Y,N |
|
unit |
Y |
|
inv |
Y |
|
pinv |
Y |
|
linear |
Y |
|
quadratic |
Y,Y,N |
|
bilinear |
Y,Y,N |
|
bound_contains |
N/A |
|
bound_margin |
||
bound_overlaps |
N/A |
Module contents
|
norm(x) |
|
norm2(x) |
|
norm_L1(x) |
|
norm_Linf(x) |
|
norm_fro(A) |
|
distance(x,y) |
|
distance2(x,y) |
|
distance_L1(x,y) |
|
distance_Linf(x,y) |
|
mahalanobis_distance(x,y,A) |
|
mahalanobis_distance2(x,y,A) |
|
unit(x) |
|
inv(A) |
|
pinv(A) |
|
linear(x,A) |
|
quadratic(x,A) |
|
bilinear(x,A,y) |
|
bound_contains(xmin,xmax,x) |
|
bound_margin(xmin,xmax,x) |
|
bound_overlaps(xmin,xmax,ymin,ymax) |
klampt.math.symbolic_sympy module
Functions:
|
|
|
Converts a Sympy expression to a symbolic.py expression. |
Classes:
|
Defines a Function from a Sympy expression. |
|
Defines a Function from a Sympy function. |
- class klampt.math.symbolic_sympy.SympyFunction(name, expr, symbol_order=None)[source]
Bases:
Function
Defines a Function from a Sympy expression.
Example:
x,y = sympy.symbols("x y") twoxy = SympyFunction("twoxy",2*x*y)
name: the symbolic module name of the function.
expr: the Sympy function
symbol_order: if you don’t want to use lexicographical order for the unbound variables in expr, this will contain the desired argument order.
- class klampt.math.symbolic_sympy.SympyFunctionAdaptor(name, func, argnames=None)[source]
Bases:
Function
Defines a Function from a Sympy function.
Example:
heaviside = SympyFunctionAdaptor("heaviside",sympy.Heaviside,["x"])
- Parameters:
name (str) – the symbolic module name of the function.
func (sympy.Function) – the Sympy function
argnames (list of strs, optional) – provided if you don’t want to use ‘x’,’y’, ‘z’ for the argument names.
- klampt.math.symbolic_sympy.exprFromSympy(context, sexpr, addFuncs=True)[source]
Converts a Sympy expression to a symbolic.py expression.
- Parameters:
context (Context) – a Context object that captures variable references and custom functions. This may be None.
sexpr (sympy.Expr) – the Sympy expression.
addFuncs (bool, optional) – if True, any Sympy functions without a direct match to symbolic functions are added to sexpr’s customFunctions list.