Importing a variable in Python? - python

I'm using sympy to write superscript using the pretty_print command. This needs to be imported along with some variables(algebra(x,y,etc.)) in order for the pretty_print command to work. If you dont import the variables(algebra) from sympy.abc, you will need to put the letters in quote marks '' in which the pretty_print command won't work.
So for example if I print x² on the screen, i need to import x so it can be used in the program. Like this:
import sympy
from sympy import pretty_text as exp
from sympy.abc import x
equation= x**2
exp(equation)
This will print x² on the screen. The problem is if i assign a value to x, then it will no longer be equal to itself. If i print x directly after import from sympy.abc, it does this-
(pretending this is IDLE) >
>>> import sympy
>>> from sympy import pretty_text as exp
>>> from sympy.abc import x
>>> x
x
however if a make x 1
>>> import sympy
>>> from sympy import pretty_text as exp
>>> from sympy.abc import x
>>> x
x
>>> x = 1
>>>x
1
Then i need to square x again,
>>> import sympy
>>> from sympy import pretty_text as exp
>>> from sympy.abc import x
>>> x
x
>>> x = 1
>>>x
1
>>> equation = x**2
>>> exp(equation)
1
It will just square 1. Even if it try to make x = 'x' again it is not the same since it will have the '' around it. I can only fix this by importing it again. However, in my program i could end up needing to import any letter again so I would need to import a variable. I tried
from sympy.abc import x[0]
But that's invalid. So, is there any way i could import a varying letter?

If you want to preserve symbols, do not assign any values to them - keep using symbols until you really need a solution.
For example:
In [15]: equation=sympy.sin(x**2)
In [16]: exp(equation)
⎛ 2⎞
sin⎝x ⎠
In [17]: result = equation.subs({'x': 2})
In [18]: result
Out[18]: sin(4)
In [19]: result.evalf()
Out[19]: -0.756802495307928
This does not change the x itself - later on:
In [23]: exp(sympy.log(x**.5))
⎛ 0.5⎞
log⎝x ⎠
Keep your equations in the symbolic form for as long as needed and don't worry about the values themselves.

You don't need to import symbol names in SymPy. The abc module is just there for convenience for one-letter symbol names.
Just create the Symbol object with whatever name you want (this can be any string, including one created dynamically).
>>> x = Symbol('x')
>>> x
x
Also note that the name you give the symbol and the name of the Python variable holding that symbol need not be related. Indeed a Symbol has no idea what Python variable names it is bound to (this is how everything works in Python, not just SymPy)
>>> x = Symbol('y')
>>> x
y
You can also use symbols to create multiple symbols at once
>>> x, y, z = symbols('x y z')

If you instead do:
import sympy.abc
x = sympy.abc.x
Then whenever you need your original value, just use sympy.abc.x. If you need to dynamically get a name:
getattr(sympy.abc, "x")
Where the literal could be replaced with any variable.

Related

Sympy evalf for real symbol

This Sympy code works as I expect:
>>> x = sp.Symbol("x")
>>> y = sp.Symbol("y")
>>> z = sp.Symbol("z")
>>> (x+y+z).evalf(subs={"x":1, "y":2, "z":3})
6.0
However, if I use real-valued Symbols instead, the expression isn't simplified:
>>> x = sp.Symbol("x", real=True)
>>> y = sp.Symbol("y", real=True)
>>> z = sp.Symbol("z", real=True)
>>> (x+y+z).evalf(subs={"x":1, "y":2, "z":3})
x + y + z
I was unable to find an explanation for this by searching with keywords like sympy symbol real evalf - I only get unrelated results.
Why isn't the expression simplified in the second case? How can I substitute in values for real-valued Symbols and evaluate the expression?
Use the symbols as keys for the dictionary of substitutions, rather than string names:
>>> (x + y + z).evalf(subs={x: 1, y: 2, z: 3})
6.00000000000000
There appears to be an inconsistency between how complex and real symbols are treated:
>>> x = sp.Symbol('x')
>>> x.subs(x, 1)
1
>>> x.subs('x', 1)
1
>>> x = sp.Symbol('x', real=True)
>>> x.subs(x, 1)
1
>>> x.subs('x', 1)
x
I can't find anything relevant about this in the documentation, and the built-in help text isn't useful either. My best guess is that a string 'x' is naively converted using sp.Symbol, and the resulting symbol is always a complex-valued symbol that doesn't match the real-valued one with the same name.
I would consider this behaviour a bug and file a bug report (or look for an existing report). IMO, if a string is usable at all, it should match any symbol with that name; and an expression shouldn't be able to contain two different variables with the same name and different types; and trying to substitute in a variable with a matching name and incompatible type should probably raise an exception:
>>> x = sp.Symbol('x')
>>> # why allow this?
>>> broken = sp.Symbol('x', real=True) + x
>>> broken # if the types matched, it would simplify to 2*x
x + x
>>> # surely 2 is the only value that makes sense?
>>> broken.subs('x', 1)
x + 1
>>> x.subs('x', 1)
1
>>> # If this is allowed at all, surely the result should be 1?
>>> x.subs(sp.Symbol('x', real=True), 1)
x

Obtaining a function given by the user in Python

I'm having a problem to read a function using the parse_expr sympy function.
Here's how I'm using it:
from sympy import*
import sympy as smp
import numpy as np
from sympy.parsing.sympy_parser import parse_expr
print("Welcome...")
x=smp.Symbol('x')
function=input("Enter your function in terms of X\nIf you want to use Fixed point method input de G(x) expresion\n")
function=parse_expr(function, x)
And here's what I'm getting:
Welcome...
Enter your function in terms of X
If you want to use Fixed point method input de G(x) expresion
2*x
Traceback (most recent call last):
File "c:\Users\jp159\Desktop\Desktop\Studies\Exercises.py", line 8, in <module>
function=parse_expr(function, x)
File "C:\Users\jp159\AppData\Local\Programs\Python\Python39\lib\site-packages\sympy\parsing\sympy_parser.py", line 988, in parse_expr
raise TypeError('expecting local_dict to be a dict')
TypeError: expecting local_dict to be a dict
In an isympy session initialized with:
>>> from __future__ import division
>>> from sympy import *
>>> x, y, z, t = symbols('x y z t')
>>> k, m, n = symbols('k m n', integer=True)
>>> f, g, h = symbols('f g h', cls=Function)
>>> init_printing()
Documentation can be found at https://docs.sympy.org/1.8/
Since local_dict is optional, lets omit it:
In [1]: parse_expr('2*x')
Out[1]: 2⋅x
but we can make a dict - that references one of the defined symbols:
In [4]: parse_expr('2*x',{'x':x})
Out[4]: 2⋅x
In [5]: parse_expr('2*x',{'x':y})
Out[5]: 2⋅y
I can also use a string that doesn't look like any defined symbol:
In [7]: parse_expr('2*X')
Out[7]: 2⋅X
In [8]: _.free_symbols
Out[8]: {X}
One key skill for new programmers is reading the documentation. Yes, often that can be hard to understand, but still it should be the first stop. SO (and general web searches) should come later.
sympy is written in Python, so as basic knowledge of that language is assumed.

Python equation inputed by user

I'm trying to make some program which involves typing formulas in input by a user.
My code for now looks like so:
import numpy as np
n = int(input('Dim = '))
g = np.zeros((n, n))
for a in range(0, n):
print('Define the metric. \n g_', a, a,'=')
metric_component = 'lambda x, y: ' + str(input())
g[a, a] = eval(metric_component)
print(g)
I tried to search for answers but those i found didn't work. eval() function gives me error there: float() argument must be a string or a number, not 'function': sympify() gives basically the same "can't convert expression to float"
Also i want to work on those constants not their numeric values, so i'm interesting to keep them through all program and have the final output expressed by them. Is it even possible?
input() will return a string
>>> type(input()) # I type 1
1
<class 'str'>
So if you are expecting numeric input from the user and it can be non-integer, then just wrap the input with float.
import numpy as np
n = int(input('Dim = '))
g = np.zeros((n, n))
for a in range(0, n):
print('Define the metric. \n g_', a, a,'=')
g[a, a] = float(input())
print(g)
It's hard to tell what you want to be able to interpret from the user. If the user is going to give some expression of x and y and you are going to replace both those values with a you would either have to build a lambda that could be evaluated or do a substitution into a sympified expression:
>>> eval('(lambda x,y:'+'x + 2*y'+')(%s,%s)'%(a,a))
3*a
>>> sympify('x+2*y').subs(dict(x=a,y=a))
3*a
If you want the user to input expressions and then do something to them later, SymPy is ideally suited for this. Here, the user is prompted to fill items in a list and then those items are differentiated wrt x. It's just a toy example:
>>> from sympy import S # shortcut for sympify
>>> from sympy.abc import x
>>> [S(input('?')) for i in range(2)]
?R**2
?R**2*sin(x)**2
[R**2, R**2*sin(x)**2]
>>> [i.diff(x) for i in _]
[0, 2*R**2*sin(x)*cos(x)]

Setting the domain of a function in Python SymPy

I was wondering if it is somehow possible to set the domain of a math. function. For example, when I define the following expression
>>> import sympy as syp
>>> x = syp.Symbol('x')
>>> miles_to_km = x * 1.609344
>>> miles_to_km.evalf()
1.609344*x
Is it possible to limit the domain so that x is in the range [0, inf)? So the goal is that I could then use the sympy.plot function that produces a graph that starts at 0 and only includes positive x-values in contrast to
If we check the manual by doing:
help(syp.plot)
You will get:
...
expr : Expression representing the function of single variable
range: (x, 0, 5), A 3-tuple denoting the range of the free variable.
...
So, you can:
>>> import sympy as syp
>>> x = syp.Symbol('x')
>>> miles_to_km = x * 1.609344
>>> syp.plot(miles_to_km, (x,0,10))
which will give you the following output:

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