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.
Related
import math
import numpy as np
import matplotlib.pyplot as plt
import simpy as sp
init_printing()
var('x,y,z')
a = math.sqrt(10/7)
c = (y-math.sqrt(18/7)-1)
b = np.sin(math.pi/2*c)-z
f = lambda x,y,z: x**2+y**2+z**2-4
g = lambda x, y, z: (9/2)*(x**2+z**2)+y**2-9
h = lambda y, z: np.sqrt(10/7) * np.sin((np.pi/2) * y - np.sqrt(18/7)-1)- z
F = [[f(x, y, z)],
[g(x, y, z)],
[h(y, z)]]
As I try to define the fuction h(x) I get this:
AttributeError Traceback (most recent call last)
AttributeError: 'Add' object has no attribute 'sin'
The above exception was the direct cause of the following exception:
TypeError Traceback (most recent call last)
<ipython-input-68-da3a7e28861c> in <module>
10 a = math.sqrt(10/7)
11 c = (y-math.sqrt(18/7)-1)
---> 12 b = np.sin((math.pi/2*c))-z
13
14
TypeError: loop of ufunc does not support argument 0 of type Add which has no callable sin method
I tried to separete the function in parts a, b and c so the error could be more easy to find. Now I know I have some problem with the var('x, y, z') and the np.sin()/math.sin(), but I can't find how to fix it.
Pay close attention to the type of the variables. When in doubt, check, don't just guess or assume
var('x,y,z')
these are sympy symbols (though here I'm guessing what var is doing)
a = math.sqrt(10/7)
this must be a python float, produced by the math.sqrt function.
c = (y-math.sqrt(18/7)-1)
Assuming y is sympy, then c itself is a sympy expression, probably an Add.
b = np.sin(math.pi/2*c)-z
math.pi/2*c is sympy expression.
np.sin is a numpy ufunc, and only works with numpy arrays. That means it first does
np.array(math.pi/2*c)
making a single element object dtype array.
np.sin given an object dtype array, passes the task to the sin method of that object. But noone defines a sin method. It's always a function.
Using np.sin, or many other numpy functions on sympy expressions just does not work. Don't mix sympy and numpy until you know what you are doing!
In [5]: sp.var('x,y,z')
Out[5]: (x, y, z)
In [6]: y
Out[6]: y
In [7]: a = math.sqrt(10/7)
...: c = (y-math.sqrt(18/7)-1)
In [8]: a
Out[8]: 1.1952286093343936
In [9]: c
Out[9]: y - 2.60356745147455
In [10]: type(c)
Out[10]: sympy.core.add.Add
In [11]: math.pi/2*c
Out[11]: 1.5707963267949*y - 4.08967418933897
In [12]: np.array(_)
Out[12]: array(1.5707963267949*y - 4.08967418933897, dtype=object)
In [13]: np.sin(_)
AttributeError: 'Add' object has no attribute 'sin'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<ipython-input-13-2b409a55b2a2>", line 1, in <module>
np.sin(_)
TypeError: loop of ufunc does not support argument 0 of type Add which has no callable sin method
pure sympy
In [14]: a = sp.sqrt(10/7)
...: c = (y-sp.sqrt(18/7)-1)
In [15]: c
Out[15]: y - 2.60356745147455
In [16]: sp.pi/2*c
Out[16]: pi*(y - 2.60356745147455)/2
In [17]: sp.sin(sp.pi/2*c)
Out[17]: sin(pi*(y/2 - 1.30178372573727))
I'm asking is it possible to get np.linalg.solve() out of the lambdify on an expression involving solving?
For example, let
from sympy import MatrixSymbol, linsolve, lambdify
A = MatrixSymbol('A', 3, 3)
b = MatrixSymbol('b', 3, 1)
func = lambdify((A, b), linsolve((A, b)), modules="numpy")
Is it possible to generate the func(A, b) = np.linalg.solve(A, b)?
The above code for sure does not work. It will first fail at linsolve((A, b)).
My attempt would be somehow mark linsolve((A, b)) as an implicit expression so that lambdify can recognize it and thus link it with np.linalg.solve. But I don't find if sympy support this.
You can use function sympy.codegen.matrix_nodes.MatrixSolve instead of sympy.linsolve.
from sympy import MatrixSymbol, lambdify
from sympy.codegen.matrix_nodes import MatrixSolve
A = MatrixSymbol('A', 3, 3)
b = MatrixSymbol('b', 3, 1)
func = lambdify((A, b), MatrixSolve(A, b), modules="numpy")
With MatrixSolve, lambdify performs a simple lexical replacement:
In [87]: MatrixSolve(A,b)
Out[87]: MatrixSolve(MatrixSymbol(Str('A'), Integer(3), Integer(3)), vector=MatrixSymbol(Str('b'), Integer(3), Integer(1)))
In [88]: func = lambdify((A, b), MatrixSolve(A, b), modules="numpy")
In [89]: func
Out[89]: <function _lambdifygenerated(A, b)>
In [90]: func?
Signature: func(A, b)
Docstring:
Created with lambdify. Signature:
func(A, b)
Expression:
MatrixSolve(A, vector=b)
Source code:
def _lambdifygenerated(A, b):
return (solve(A, b))
Or use print(func.__doc__) to display that doc if not in ipython/isympy.
Your original problem was with using sympy.linsolve:
In [81]: linsolve((A,b))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-81-9ddeeeb0f242> in <module>
----> 1 linsolve((A,b))
/usr/local/lib/python3.8/dist-packages/sympy/solvers/solveset.py in linsolve(system, *symbols)
2630 if not isinstance(system[0], MatrixBase):
2631 if sym_gen or not symbols:
-> 2632 raise ValueError(filldedent('''
2633 When passing a system of equations, the explicit
2634 symbols for which a solution is being sought must
ValueError:
When passing a system of equations, the explicit symbols for which a
solution is being sought must be given as a sequence, too.
I expect the following code evaluates derivative of sin(t)
import sympy as sy
t = sy.Symbol('t', real=True)
expr = sy.sympify('sin(t)')
dexpr = sy.diff(expr, t)
print dexpr
But actually it prints 0. If I change the first line by t = sy.Symbol('t'), it works well. It looks like sympy thinks there are 2 different t.
The question: how to say to sympy that my string expression depends on the real valued argument t, and how to sympify this string correctly?
If you declare t as a real variable, it will be considered a different variable to Symbol('t') (with no assumptions).
Try this way:
In [1]: treal = Symbol('t', real=True)
In [2]: t = Symbol('t')
In [3]: expr = sympify('sin(t)')
In [4]: expr.diff(treal)
Out[4]: 0
In [5]: expr.diff(t)
Out[5]: cos(t)
In [6]: treal == t
Out[6]: False
In [7]: expr_real = expr.subs(t, treal)
In [8]: expr_real.diff(treal)
Out[8]: cos(t)
In input [6] you may see that the two variables are considered different, even if both print as t. If you differentiate by the real variable your sympified expression (input [4]), your expression will be considered a constant, because the two ts do not identify as the same variable.
In input [7] I replaced t with treal, so that in input [8] I was able to correctly derive the expression.
EDIT
A fast form to import is by specifying in sympify a mapping between string-variables and local-variables:
In [1]: t = Symbol('t', real=True)
In [2]: expr = sympify('sin(t)', locals={'t': t})
In [3]: expr
Out[3]: sin(t)
In [4]: expr.diff(t)
Out[4]: cos(t)
In this way, t will be set to the variable defined in input [1].
So, I have this code
from __future__ import division, print_function
import sympy as sp
import numpy as np
from sympy.utilities.lambdify import *
u = np.random.uniform(4, 6, 500)
w, k = sp.symbols('w k')
f = sp.log((k - w) * sp.exp((k - w)**5))
l = sum(f.subs(dict(k=k)) for k in u)
And now I want to use l as a function of w. So I know of some options
z_lambdify = lambdify(w, l)
z_subs = lambda x: l.subs(w, x)
The first function gives an error
>>> z_lambdify(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <lambda>
OverflowError: math range error
>>> z_lambdify(4)
40.862695278600114
While the second gives answers
>>> z_subs(1)
11469.9130597554
>>> z_subs(4)
40.8626952786003
I would just use this, but it is very slow. Any way to get around this (fixing the lamdify error or a way of using l as a function that is not so slow)?
Version: Python 2.7.6, NumPy 1.8.1, SymPy 0.7.4.1
Answering your question:
The problem is that:
z_lambdify = lambdify(w, l)
tells the new function to perform the calculations using the built-in math functions, which you can check running with cProfile.run('z_lambdify(1)'); while doing z_subs(1) calls sympy functions. To get the same behavior you should tell lambdify() to use the same module:
z_lambdify = lambdify(w, l, "sympy")
Important suggestion:
You should simplify your function already at its definition and then useNumPy to perform the calculations much more efficiently. Using some simple algebra your function can be rewritten in a "non-overflowing" format as:
f = lambda k, w: np.log(k - w) + (k - w)**5
such that your desired answer can be achieved doing:
f(k=u, w=1).sum()
when you do f(k=u, w=1) you get an array with the same shape of u, where each value represents the result of the function evaluated with each value of u. You can use this function to simultaneously evaluate f() for different values of k and w, i.e. passing w as another array with the same shape of u instead of using a constant value.
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.