SymPy lambdify raises OverflowError: math range error - python

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.

Related

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.

How do I create a constraint using a linear symbolic inequality in Mystic?

I am trying to use Mystic to minimize a nonlinear function with linear constraints.
As a simple example, I have the following:
import numpy as np
import mystic.symbolic as ms
from mystic.symbolic import generate_constraint
from mystic.symbolic import generate_solvers
from mystic.symbolic import linear_symbolic
from mystic.monitors import Monitor
from mystic.solvers import LatticeSolver
from mystic.solvers import NelderMeadSimplexSolver
from mystic.termination import CandidateRelativeTolerance as CRT
# diamond-shaped constraint
# same format as output of mystic.linear_symbolic()
basic_constraint = '''
1.0*x0 + 1.0*x1 <= 5
1.0*x0 - 1.0*x1 >= -5
1.0*x0 + 1.0*x1 >= -5
1.0*x0 - 1.0*x1 <= 5
'''[1:]
def basic_objective(x, *args):
v1 = x[0] * x[1] / (1 + np.abs(x[0] + x[1]))
v2 = np.min(x)
return v1 + v2/(1+np.abs(v1))
When trying to run the code, I do the following:
def test_basic():
stepmon=Monitor()
nbins = [6,6,]
solver = LatticeSolver(len(nbins), nbins)
solver.SetNestedSolver(NelderMeadSimplexSolver)
print('Generating Solvers')
constraint_solver = generate_solvers(
basic_constraint,
nvars=2
)
print(constraint_solver)
# HERE IS ISSUE, IF COMMENTED ISSUE BELOW
print(constraint_solver[0](np.ones(2)))
print('Setting Constraints')
solver.SetConstraints(
generate_constraint(constraint_solver)
)
solver.SetGenerationMonitor(stepmon)
solver.SetTermination(CRT())
print('Solving...')
# ISSUE APPEARS HERE IF print(constraint_solver[0]...)
# IS COMMENTED OUT
solver.Solve(basic_objective)
solution = solver.Solution()
print(solution)
return solution
test_basic()
When I run the above, the error occurs at
print(constraint_solver[0](np.ones(2)))
or, if I comment it out,
solver.Solve(basic_objective)
The only noticeable difference is the size of the call stack.
The error I get is
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 12, in test_basic
File "<string>", line 4, in solver_139632515562208
File "<string>", line 1
SyntaxError: cannot assign to operator
This is a result of Mystic trying to compile Python code from a string and encountering a syntax error, but I do not know how to fix this issue.
I'm the mystic author. You are missing one key function, and a second that is not needed in this case but often is.
If you print the doc for your constraint solvers, you'll see that they are not formed well.
>>> constraint_solver = generate_solvers(basic_constraint, nvars=2)
>>> print(constraint_solver[0].__doc__)
1.0*x[0] - 1.0*x[1] = min(5 - (_tol(5,tol,rel) * any(equal(5,[]))), 1.0*x[0] - 1.0*x[1])
>>>
You need to isolate a single variable on the left-hand side. Hence, we either need to solve or simplify. For inequalities, simplify works better, and for equalities solve generally works. I am not sure the level of documentation that states that. Anyway, I use simplify before building the constraints.
>>> from mystic.symbolic import simplify
>>> constraint_solver = generate_solvers(simplify(basic_constraint), nvars=2)
>>> print(constraint_solver[0].__doc__)
x[0] = max(1.0*x[1] - 5.0 + (_tol(1.0*x[1] - 5.0,tol,rel) * any(equal(1.0*x[1] - 5.0,[]))), x[0])
>>>
>>> print(constraint_solver[0](np.ones(2)))
[1. 1.]
>>>
Now, your code works as expected.
However, I'd generally make one other modification.
>>> from mystic.constraints import and_
>>> c = generate_constraint(constraint_solver, join=and_)
>>> c(np.ones(2)*5)
[0.0, 5.0]
>>> print(c.__doc__)
inner: x[0] = max(1.0*x[1] - 5.0 + (_tol(1.0*x[1] - 5.0,tol,rel) * any(equal(1.0*x[1] - 5.0,[]))), x[0])
inner: x[0] = min(1.0*x[1] + 5.0 - (_tol(1.0*x[1] + 5.0,tol,rel) * any(equal(1.0*x[1] + 5.0,[]))), x[0])
inner: x[0] = min(5.0 - 1.0*x[1] - (_tol(5.0 - 1.0*x[1],tol,rel) * any(equal(5.0 - 1.0*x[1],[]))), x[0])
inner: x[0] = max(-1.0*x[1] - 5.0 + (_tol(-1.0*x[1] - 5.0,tol,rel) * any(equal(-1.0*x[1] - 5.0,[]))), x[0])
Without the join=and_, your code still works. The difference is that without an explicit join statement, it's assumed the constraints are independent of each other, and can be solved one at a time. Using join=and_ forces the constraints to be solved simultaneously, which is slower. There's also or_ and other more complex combinations in building constraints, but the default is to assume independence.
Both points are subtle, and, I believe, in the documentation it should state that the constraints solvers need the symbolic equations need to have a single variable isolated on the left-hand side. However, it's probably not obvious as that's often missed.

Can't integrate with dblquad

So I want to integrate a double integral with constants in it, like a, b, etc where the user can asign the value of this constants:
The limits of the integral are x[0,1] and y[-1,2]
import numpy as np
import scipy.integrate as integrate
def g(y,x,a):
return a*x*y
a = int(input('Insert a value --> '))
result = integrate.dblquad(g, 0, 1, lambda x: -1, lambda x: 2, args=(a))[0]
print(result)
But I get this error and I don't understant why:
TypeError: integrate() argument after * must be an iterable, not int
I don't understand it. Because when I do the same but with quad() Python does it correctly:
import numpy as np
import scipy.integrate as integrate
def g(x,a):
return a*x
a = int(input('Insert a value --> '))
result = integrate.quad(g, 0, 1, args=(a))[0]
print(result)
With the result:
0.5
The problem here is that the value you provide in the optional argument args is a tuple. In the case of quad, it is what the function expects, but for dblquad, a sequence is required. Even though tuples are sequences (immutable ones), it seems that scipy makes a difference here and therefore it is why an error is raised. However it is misleading as a tuple is definitely an iterable. Anyway, this should work:
result = integrate.dblquad(g, 0, 1, lambda x: -1, lambda x: 2, args=[a])[0]

How to Define a Piecewise Function in Python with Multiple Variables

I am trying to develop a plot for my helioseismology class and the question had provided a piecewise function describing the dynamics of the "fluids" in a star as if it is one thing its this and if its another its that. I am receiving over and over again this 'Mul' object cannot be interpreted as an integer but I am working with numbers in the reals not just the integer set. I do not know how to get around this and need guidance. The code is as follows.
import sympy as sy
from sympy import *
from sympy.physics.units import Unit
import numpy as np
import sys
import math
import scipy as sp
from scipy import special
phi = Symbol('phi', Variable = True)
x = Symbol('x', Variable = True, Real = True)
t = Symbol('t', Variable = True, Real = True)
xi = Symbol('xi', Function = True)
Solar_Radius = Symbol('R', Constant = True, unit = "meters")
Sound_Speed = Symbol('c', Constant = True, unit = "meters per second", Real = True)
gamma = Symbol('gamma', Constant = True)
gravity = Symbol('g', Constant = True, unit = "meters per second per second")
Solar_Radius = 6.963 * 10 ** 6
gamma = 5/3
g = 274.8265625336
gas_constant = 8201.25
c = 8.1 * 10 ** 3
for t in range(0,x/c):
xi[x,t] = 0
for t in range(x/c,00):
xi[x,t] = (1/2)*sy.exp(gamma*g*x/(2*c**2))*mpmath.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - ((x/c)**2))),derivative = 0)
Full Traceback:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-50-3506376f1686> in <module>()
----> 1 for t in range(0,x/c):
2 xi[x,t] = 0
3 for t in range(x/c,00):
4 xi[x,t] = (1/2)*sy.exp(gamma*g*x/(2*c**2))*mpmath.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - ((x/c)**2))),derivative = 0)
TypeError: 'Mul' object cannot be interpreted as an integer
There are quite a few issues here:
None of the keyword arguments (Constant, Variable, unit, Real) that you are passing to Symbol are things that are recognized by SymPy. The only one that is close is real, which should be lowercase (like Symbol('x', real=True)). The rest do nothing. If you want units, you should use the SymPy units module in sympy.physics.units. There is no need to specify if a symbol is constant or variable.
You have redefined Solar_Radius and gamma as numbers. That means that the Symbol definitions for those variables are pointless.
If you are using Python 2, make sure to include from __future__ import division at the top of the file, or else things like 1/2 and 5/3 will be truncated with integer division (this isn't an issue in Python 3).
range(0, x/c) doesn't make sense. range creates a list of numbers, like range(0, 3) -> [0, 1, 2]. But x/c is not a number, it's a symbolic expression.
Additionally, xi[x, t] = ... doesn't make sense. xi is a Symbol, which doesn't allow indexing and certainly doesn't allow assignment.
Don't mix numeric (math, mpmath, numpy, scipy) functions with SymPy functions. They won't work with symbolic expressions. You should use only SymPy functions. If you create a symbolic expression and want to convert it to a numeric one (e.g., for plotting), use lambdify.
What you want here is Piecewise. The syntax is Piecewise((expr, cond), (expr, cond), ..., (expr, True)), where expr is an expression that is used when cond is true ((expr, True) is the "otherwise" condition).
For your example, I believe you want
expr = Piecewise((0, t < x/c), (sy.exp(gamma*g*x/(2*c**2))*sy.besselj(0, (gamma*g/(2*c)*sy.sqrt(t**2 - (x/c)**2)))/2, t >= x/c))
If you want to turn this into a numeric function in x and t, use
xi = lambdify((x, t), expr)

Why does calling this function twice cause an error?

I am having a problem with calling a function twice. If I comment my last 3 lines and keep show(), I don't get any errors and things come as they are suppose to. However, if I don't comment them out calling the last function again gives me this error:
Traceback (most recent call last):
File "second_1.py", line 29, in <module>
domega=c_d(len(t),t,z)
File "second_1.py", line 25, in c_d
dy[1:-1]=(y[2:]-y[0:-2])/(x[2:]-x[0:-2])
TypeError: unsupported operand type(s) for -: 'list' and 'list'
Here is the function:
import numpy as np
from pylab import *
import time
t_initial=time.time()
clf()
t,hp,hn= np.loadtxt("Richardson.dat", usecols=(0,1,2),comments='#', unpack=True) # to select just a few columns
print(time.time()-t_initial)
def phi(y,x):
return(np.arctan(y/x))
phase=[0.0]*len(t)
phase=phi(hp[0:],hn[0:])
#plot(t,phase)
#show()
def c_d(order,x,y):
dy=[0.0]*order
dy[0]=(y[1]-y[0])/(x[1]-x[0])
dy[-1]=(y[-1]-y[-2])/(x[-1]-x[-2])
dy[1:-1]=(y[2:]-y[0:-2])/(x[2:]-x[0:-2])
return(dy);
z=c_d(len(t),t,phase);
plot(t,z)
print(len(z)-len(t))
domega=c_d(len(t),t,z)
plot(t,domega)
show()
The problem is very clearly explained in the error message:
The '-' operand is not applicable for the type list.
(y[2:]-y[0:-2])/(x[2:]-x[0:-2])
y[2:] slices a list and returns a list. y[0:-2] slices also a list and returns a list. So there you have 2 lists.
y[2:] (a list) -(your operator) y[0:-2] (a list)
And list - list is not defined (there is no syntax for: 'listObject' - 'listObject').
BUT: the + operator is defined for lists (example):
l = ["ja"]
m = ["nein"]
n = l + m
print n
# output: ['ja', 'nein']
Take a look here for these different kind of possible operators:
https://docs.python.org/2/library/stdtypes.html
As explained in the other answers, you can not subtract regular Python lists. So why does it work the first time, and fails the second? Let's take a look at the code.
t, hp, hn = np.loadtxt(...)
...
def c_d(order, x, y):
dy = [0.0] * order
dy[ 0] = (y[1] -y[0]) / (x[ 1]-x[0])
dy[-1] = (y[-1]-y[-2]) / (x[-1]-x[-2])
dy[1:-1] = (y[2:]-y[0:-2]) / (x[2:]-x[0:-2])
return dy
z = c_d(len(t), t, phase)
...
domega = c_d(len(t), t, z)
...
When you first call c_d, the parameters x and y seem to be numpy arrays (at least t and phase are results of numpy function calls), and for those, - is a legal operation. But inside c_d, you create and finally return a regular Python list, dy, so when you then call c_d again with the result of the first call as y, this part y[2:]-y[0:-2] will fail, as y now is a regular list.
Make sure your dy is a numpy array, too, i.e. dy = np.array([0.0] *order) or just dy = np.zeros(order), then it should work.
As stated by Cyber and ProgrammingIsAwsome the error is on line
(y[2:]-y[0:-2])/(x[2:]-x[0:-2])
where you actually try to substract lists.
You could write explicitely :
for i in range(1, order - 1):
dy[i]=(y[i+1]-y[i-1])/(x[i+1]-x[1-1])

Categories

Resources