SymPy: Swap two variables - python

In an expression like
import sympy
a = sympy.Symbol('a')
b = sympy.Symbol('b')
x = a + 2*b
I'd like to swap a and b to retrieve b + 2*a. I tried
y = x.subs([(a, b), (b, a)])
y = x.subs({a: b, b: a})
but neither works; the result is 3*a in both cases as b, for some reason, gets replaced first.
Any hints?

There is a simultaneous argument you can pass to the substitution, which will ensure that all substitutions happen simultaneously and don't interfere with one another as they are doing now.
y = x.subs({a:b, b:a}, simultaneous=True)
Outputs:
2*a + b
From the docs for subs:
If the keyword simultaneous is True, the subexpressions will not be evaluated until all the substitutions have been made.

Related

optimize.curve_fit: how to bound one parameter respective to another?

When doing (ad hoc example)
from scipy import optimize
def fit_func(x, a, b):
return a*x + b
optimize.curve_fit(fit_func, x_data, y_data)
how can I put bounds like a>b? I know the option bounds, but it appears it does accept only explicit numbers.
Maybe some if in the definition of fit_func?
You can try with a workaround, instead of defining the function as:
def fit_func1(x, a, b):
return a*x + b
with constraint a>b, you can do:
def fit_func2(x, this_much_a_is_bigger_than_b, b):
return (a+this_much_a_is_bigger_than_b)*x + b
with constraint this_much_a_is_bigger_than_b > 0, 0 being an explicit number, and fit_func2 function is equivalent to the fit_func1 from a mathematical perspective.
Then you can have:
a = b + this_much_a_is_bigger_than_b
b = b
Curce_fit only supports box constraints (via least_squares). There are workarounds, but I'd rather change variables to e.g a and b-a

Python SymPy weird expression result

import sympy
import math
from sympy import *
a, b, c, d, stf, lc = symbols('a b c d stf lc')
init_printing()
expr = (2*(sin (a) + sin (b)/2)*(sin (c) + sin (d)/2)*stf)+(2*(cos (a) + cos (b)/2)*(cos (c)+ cos (d)/2)*lc)*2
expr
when I run this ine ig gives me as result:
2*lc*(2*cos(a) + cos(b))(cos(c) + cos(d)/2) + stf(2*sin(a) + sin(b))*(sin(c) + sin(d)/2)
I realize that first formula in expr is not the simplest, but when I try to only print it out, it makes some weird simplification.
when I
substiute all variables and print it out again, it goes even further:
(2sin(30)+sin(40))(250sin(30)+500sin(60))+(cos(40)+2cos(30))(5000cos(60)+2500cos(30))
is there any option to make SymPy not to change the order of elements in formula and just print it out in nice latex and then substiute variables and print again but keeping order of all elements from first formula?
I don't want to call any kind of simplification, at least not yet, as this formula is simple enough.
The order of the elements that is printed is the order in which it is stored -- and because the operator "+" is commutative by fiat, you can't specify an order for them to be printed.
For multiplication and multiplicative operators, you can specify that the indeterminate are non-commutative; e.g.
A,B = symbols('A B', commutative=False)
B*A
# B*A
A*B
# A*B
What you want to keep in mind is that, when you type something like "a+b" in the REPL loop, the interpreter creates a new object with a SymPy class, evaluates the expression "a+b", and sets the created object to the result of that evaluation. What is being stored isn't the formula "a+b", but an object that represents the mathematical object that "a+b" represents. Likewise, if you type:
a = 3 + 4
a is set to 7, not to the "formula" 3+4.
On the other hand, if you do not want to actually evaluate the expression, or want to keep track of its original string form, you can use the UnevaluatedExpr property:
from sympy import UnevaluatedExpr
UnevaluatedExpr( A ) + UnevaluatedExpr( B )
# A + B
UnevaluatedExpr( B ) + UnevaluatedExpr( A )
# B + A
Be careful though:
UnevaluatedExpr( A + B)
# A + B
UnevaluatedExpr( B + A)
# A + B

SymPy: Evaluate given expression with given variables

I have a sympy expression involving two variables a, b. I would now like to evaluate this expression for specific values of a and b. Using a lambda like
import sympy
def get_expression(a, b):
# Complex function with a simple result. I have no control here.
return a*b + 2
a = sympy.Symbol('a')
b = sympy.Symbol('b')
z = get_expression(a, b)
f = lambda a, b: z
print(f(1, 1))
only gives
a*b + 2
though.
Any hints?
Turns out that lambdify is what I need:
f = sympy.lambdify([a, b], z)
print(f(1, 1))

Plotting with SymPy

With SymPy, I can plot a function with:
f, a = symbols('f a')
f = a + 10
plot(f)
However, if I define the function as:
f, a, b = symbols('f a b')
f = a + b
b = 10
plot(f)
Then I get an error stating:
ValueError: The same variable should be used in all univariate
expressions being plotted.
How can I plot f if I define f = a + b, considering that b is assigned a constant value before plotting the function?
The lines
f, a, b = symbols('f a b')
f = a + b
b = 10
don't change b in the expression. If you print f you'll see that it is still defined as a + b.
You are confusing Python variables with SymPy symbols. In the first line, the Python variable b points to a SymPy symbol named b (in fact, they need not be the same name; you could have also written x = Symbol('b') and y = a + x). In the second line, the variable f points to a SymPy expression containing the symbol b. In the third line, the variable b points to the integer 10. This doesn't not change any previous lines that used the variable b, since they have already been run. It's no different than if you ran
a = 1
b = 1
c = a + b
b = 2
You would expect the value of c at the end to be 2, not 3. Similarly, when b points to a Symbol, expressions you create with it use a Symbol, but if you change it to point to a number, it doesn't affect previous lines from when it was a Symbol.
The recommended way to deal with this in SymPy is to avoid assigning the same variable to a symbol and then later to a non-symbol (it's worth pointing out that your definition of f in the first line is completely useless, since you immediately redefine it in the second line). To replace a symbol in an expression, use subs:
a, b = symbols('a b')
f = a + b
f1 = f.subs(b, 10)
Note that subs does not change the original f. It returns a new expression.
This document may also help clear this confusion up.
If you didn't want to use substitution as in the other answer, you could make f an actual function of course
def f(a, b):
return a + b
a = symbols('a')
b = 10
plot(f(a,b))
You must substitute b into f:
plot(f.subs('b', b))

Sympy "global" substitution

I have a number of symbolic expressions in sympy, and I may come to realize that one of the coefficients is zero. I would think, perhaps because I am used to mathematica, that the following makes sense:
from sympy import Symbol
x = Symbol('x')
y = Symbol('y')
f = x + y
x = 0
f
Surprisingly, what is returned is x + y. Is there any way, aside from explicitly calling "subs" on every equation, for f to return just y?
I think subs is the only way to do this. It looks like a sympy expression is something unto itself. It does not reference the pieces that made it up. That is f only has the expression x+y, but doesn't know it has any link back to the python objects x and y. Consider the code below:
from sympy import Symbol
x = Symbol('x')
y = Symbol('y')
z = Symbol('z')
f1 = x + y
f2 = z + f1
f1 = f1.subs(x,0)
print(f1)
print(f2)
The output from this is
y
x + y + z
So even though f1 has changed f2 hasn't. To my knowledge subs is the only way to get done what you want.
I don't think there is a way to do that automatically (or at least no without modifying SymPy).
The following question from SymPy's FAQ explains why:
Why doesn't changing one variable change another that depends it?
The short answer is "because it doesn't depend on it." :-) Even though
you are working with equations, you are still working with Python
objects. The equations you are typing use the values present at the
time of creation to "fill in" values, just like regular python
definitions. They are not altered by changes made afterwards. Consider
the following:
>>> a = Symbol('a') # create an object with name 'a' for variable a to point to
>>> b = a + 1; b # create another object that refers to what 'a' refers to
a + 1
>>> a = 4; a # a now points to the literal integer 4, not Symbol('a')
4
>>> b # but b is still pointing at Symbol('a')
a + 1
Changing quantity a does not change b; you are not working with a set
of simultaneous equations. It might be helpful to remember that the
string that gets printed when you print a variable refering to a sympy
object is the string that was give to it when it was created; that
string does not have to be the same as the variable that you assign it
to:
>>> r, t, d = symbols('rate time short_life')
>>> d = r*t; d
rate*time
>>> r=80; t=2; d # we haven't changed d, only r and t
rate*time
>>> d=r*t; d # now d is using the current values of r and t
160
Maybe this is not what you're looking for (as it was already explained by others), but this is my solution to substitute several values at once.
def GlobalSubs(exprNames, varNames, values=[]):
if ( len(values) == 0 ): # Get the values from the
for varName in varNames: # variables when not defined
values.append( eval(varName) ) # as argument.
# End for.
# End if.
for exprName in exprNames: # Create a temp copy
expr = eval(exprName) # of each expression
for i in range(len(varNames)): # and substitute
expr = expr.subs(varNames[i], values[i]) # each variable.
# End for.
yield expr # Return each expression.
# End for.
It works even for matrices!
>>> x, y, h, k = symbols('x, y, h, k')
>>> A = Matrix([[ x, -h],
... [ h, x]])
>>> B = Matrix([[ y, k],
... [-k, y]])
>>> x = 2; y = 4; h = 1; k = 3
>>> A, B = GlobalSubs(['A', 'B'], ['x', 'h', 'y', 'k'])
>>> A
Matrix([
[2, -1],
[1, 2]])
>>> B
Matrix([
[ 4, 3],
[-3, 4]])
But don't try to make a module with this. It won't work. This will only work when the expressions, the variables and the function are defined into the same file, so everything is global for the function and it can access them.

Categories

Resources