Suppose I create a SymPy symbol x.
import sympy as sp
x = sp.Symbol('x', commutative = False)
How can I change the commutative assumption to True without creating a new Symbol?
I tried
with sp.assuming( sp.Q.commutative(x) ):
print( sp.ask( Q.commutative(x) ) )
But it still gives False.
SymPy objects are immutable, so this isn't possible. Furthermore commutative is not supported by the new assumptions system (ask, Q, assuming).
What you should do instead is create a new symbol and use subs to replace it in whatever expression you want to make it commutative in.
Related
Given a symbol s, which ultimately will be an Array, I want to define the following expression
A = Array([-s[1]/2, s[0]/2])
but I'd like A to be evaluated only when I compute some other expressions containing it, because s changes over time. I tried
A = UnevaluatedExpr(Array([-s[1]/2,s[0]/2]))
but I got the error TypeError: 'Symbol' object is not subscriptable, which make me think that some evaluation is performed on s.
Thanks for your patience, I'm just learning Sympy and I'm used to Maxima where this kind of construct is straightforward. To be more precise, with Maxima the full working code I'm trying to translate into Sympy is (in Maxima everything is a symbol, colon is the assignment operator, ev forces evaluation with custom values, the dot before diff is the vector scalar product):
A: [-s[2],s[1]]/2; /* define A in terms of subscripted symbols */
P1: [x1,y1];
P2: [x2,y2];
segment: P1+t*(P2-P1); /* --> [t*(x2-x1)+x1,t*(y2-y1)+y1] */
factor(integrate(ev(A,s=segment).diff(segment,t),t,0,1)); /* integrates the scalar product of A evaluated over segment and the derivative of segment */
Follow up
Thanks to Oscar answer I was able to come up with a working Sympy translation of the above Maxima code (improvements are welcomed!):
from sympy import *
def dotprod(*vectors): # scalar product, is there a built in better way?
return sum(Mul(*x) for x in zip(*vectors))
s = IndexedBase('s')
A = Array([-s[1]/2,s[0]/2])
t,x1,y1,x2,y2 = symbols('t x1 y1 x2 y2')
P1 = Array([x1,y1])
P2 = Array([x2,y2])
segment = P1 + t * (P2-P1)
dotprod(A.subs(s,segment),segment.diff(t)).integrate((t,0,1)).factor()
Apart from the IndexedBase magic the structure of the code in Maxima and Sympy is very similar.
I'm not sure I understand what you want. It's possible that your problem is better approached in a different way rather than using Array. In any case a direct answer to your question is that you can use IndexedBase to make a subscriptable symbol:
In [1]: s = IndexedBase('s')
In [2]: A = Array([-s[1]/2, s[0]/2])
In [3]: A
Out[3]:
⎡-s[1] s[0]⎤
⎢────── ────⎥
⎣ 2 2 ⎦
I have need to pass to a function, both the integrand and also the integration variable as string. It is not possible to do it in other ways (too long to explain).
The question is, how to do the standard thing, which is x = symbols('x') to define the integration variable (which is passed as string) inside the called function in order to use it in the next call to integrate?
Here is a MWE, and showing what I tried
from sympy import *
def foo(integrand,var):
var = symbols(var)
anti = integrate(integrand,x)
return anti
foo("x*cos(x)","x")
This ofcourse does not work, since var is string on both sides of var = symbols(var)
Then I tried to use eval to first convert the string var which is "x" to variable x, but this does not work either,
x = eval(var)
x = symbols('x')
This fail since x is not defined.
Ofcourse, I could do this
from sympy import *
x = symbols('x')
def foo(integrand,var):
anti = integrate(integrand,x)
return anti
foo("x*cos(x)","x")
But this is not what I want, since the function foo being called, needs to be called with different integration variables from outside, and these have to be strings.
Any suggestion how to handle this? Notice that the issue is with the integration variable only. sympy integrate accepts the integrand as string with no problem, but not the integration variable. So this would also fail
def foo(integrand,var):
anti = integrate(integrand,var)
Python 4.7 with sympy 1.5
Everything is almost fine. Just use var instead of x as the second arg of integrate: it is the name of the Python variable that is connected to the SymPy symbol x:
>>> def foo(integrand,var):
... var = symbols(var)
... anti = integrate(integrand,var)
... return anti
...
>>> foo("x*cos(x)","x")
x*sin(x) + cos(x)
Let's suppose that the objective function is
max z(x,y) = f1(x) - f2(y)
where f1 is function of variables x and f2 is functions of variables y.
This could be written in Pyomo as
def z(model):
return f1(model) - f2(model)
def f1(model):
return [some summation of x variables with some coefficients]
def f2(model):
return [some summation of y variables with some coefficients]
model.objective = Objective(rule=z)
I know it is possible to get the numeric value of z(x,y) easily by calling (since it is the objective function) :
print(model.objective())
but is there a way to get the numeric value of any of these sub-functions separetedly after the optimization, even if they are not explicitly defined as objectives?
I'll answer your question in terms of a ConcreteModel, since rules in Pyomo, for the most part, are nothing more than a mechanism to delay building a ConcereteModel. For now, they are also required to define indexed objects, but that will likely change soon.
First, there is nothing stopping you from defining those "rules" as standard functions that take in some argument and return a value. E.g.,
def z(x, y):
return f1(x) - f2(y)
def f1(x):
return x + 1
def f2(x):
return y**2
Now if you call any of these functions with a built-in type (e.g., f(1,5)), you will get a number back. However, if you call them with Pyomo variables (or Pyomo expressions) you will get a Pyomo expression back, which you can assign to an objective or constraint. This works because Pyomo modeling components, such as variables, overload the standard algebraic operators like +, -, *, etc. Here is an example of how you can build an objective with these functions:
import pyomo.environ as aml
m = aml.ConcreteModel()
m.x = aml.Var()
m.y = aml.Var()
m.o = aml.Objective(expr= z(m.x, m.y))
Now if m.x and m.y have a value loaded into them (i.e., the .value attribute is something other than None), then you can call one of the sub-functions with them and evaluate the returned expression (slower)
aml.value(f1(m.x))
aml.value(f2(m.y))
or you can extract the value from them and pass that to the sub-functions (faster)
f1(m.x.value)
f2(m.y.value)
You can also use the Expression object to store sub-expressions that you want to evaluate on the fly or share inside multiple other expression on a model (all of which you can update by changing what expression is stored under the Expression object).
Is there a way (within Sympy) to check if two expressions differ by a mere constant? In other words, is there something like a is_constant() function?
My minimum working example:
from sympy import symbols, simplify
x,y = symbols('x y')
expr1 = x+y+1
expr2 = x+y+3
if is_constant(simplify(expr1 - expr2)):
print('expr2 is just expr1 added to a constant!')
You could use the is_constant() method of Sympy objects. For example,
(expr1 - expr2).is_constant()
True
In doing symbolic math with Sympy I encountered the following problem:
from sympy import *
txx, tyx, txy, tyy, tp, tn = symbols('t_xx t_yx t_xy t_yy t_p t_n', complex=True)
#define a complex symbol
tp = txx-I*tyx
Abs(tp), arg(tp)
#will just return |txx-i*tyx|, arg(txx-i*tyx)
However, the absolute value and argument returned is not in the form of sqrt(txx**2+tyx**2), atan(tyx/txx) as you would expect for complex numbers.
I also tried
simplify(Abs(tp).expand(complex=True))
#returns |Retxx-i*Retyx+i*Imtxx+Imtxy|, but no further simplification
which worked again for complex numbers but not the symbol of complex symbol defined here. Is this not implemented yet or am I not doing it right?
If you define your symbol list with the attribute real=True, then you will get the correct expression for Abs(tp). With your sympy symbols given as complex, then Abs() does not know the real and imaginary parts of these pieces txx, tyx, etc so the output of Abs() can not give you what you expected.