I am coding the quadratic formula in Python. The following function is supposed to solve x^2-x-20. If you do the math you get -4 and 5.
# Quadratic Formula
from math import sqrt
def findsolutions(a, b, c):
"""
Find solutions to quadratic equations.
"""
x1 = (-b + sqrt(b^2-4*a*c))/(2*a)
x2 = (-b - sqrt(b^2-4*a*c))/(2*a)
return x1, x2
x1, x2 = findsolutions(1,-1,-20)
print("The solutions to x^2-x-20 are", x1, "and", x2)
However, if you run it, you get:
Traceback (most recent call last):
File "C:/Users/Atharv 2020/Desktop/Python/1. Quadratic Formula.py", line 11, in <module>
x1, x2 = findsolutions(1,-1,-20)
File "C:/Users/Atharv 2020/Desktop/Python/1. Quadratic Formula.py", line 7, in findsolutions
x1 = (-b + sqrt(b^2-4*a*c))/(2*a)
ValueError: math domain error
So what is going on?
In Python, ^ is a Bitwise operator called XOR (Exclusive-OR)
I think you've mistook it for calculating power. In python you calculate power using **.
x ** y - x raised to the power y
So fix your code like this
x1 = (-b + sqrt(b**2-(4*a*c)))/(2*a)
Related
I am currently using a sweep loop to solve a differential equation (eq0) with respect to my cell variable phi using FiPy in python. Because my equation is non-linear, I am using a sweep loop as shown in an extract of my code below.
while res0 > resphi_tol:
res0 = eq0.sweep(var=phi, dt=dt)
But I keep getting the following error:
C:\Python27\lib\site-packages\fipy\variables\variable.py:1100: RuntimeWarning: invalid value encountered in power
return self._BinaryOperatorVariable(lambda a,b: pow(a,b), other, value1mattersForUnit=True)
C:\Python27\lib\site-packages\fipy\variables\variable.py:1186: RuntimeWarning: invalid value encountered in less_equal
return self._BinaryOperatorVariable(lambda a,b: a<=b, other)
Traceback (most recent call last):
.. File "SBM_sphere3.py", line 59, in
....res0 = eq0.sweep(var=phi, dt=dt)
..
File "C:\Python27\lib\site-packages\fipy\terms\term.py", line 207, in sweep
....solver._solve()
.. File "C:\Python27\lib\site-packages\fipy\solvers\pysparse\pysparseSolver.py", line 68, in _solve
....self.solve(self.matrix, array, self.RHSvector)
.. File "C:\Python27\lib\site-packages\fipy\solvers\pysparse\linearLUSolver.py", line 53, in _solve__
....LU = superlu.factorize(L.matrix.to_csr())
.. File "C:\Python27\lib\site-packages\pysparse\misc__init__.py", line 29, in newFunc
....return func(*args, **kwargs)
.. File "C:\Python27\lib\site-packages\pysparse__init__.py", line 47, in factorize
....return self.factorizeFnc(*args, **kwargs)
RuntimeError: Factor is exactly singular
I am pretty sure this error is due to term phi^(2/3) present in eq0. If I replace this term by abs(phi)^(2/3), the error goes away.
I assume the sweep loop returns a negative value for a few cells in phi at some point, resulting in error since we can't power a negative value with a non-integer exponent.
So my question is: is there a way to force sweep to avoid negative solutions?
I have tried to include a line that sets all negative values to 0 before sweeping:
while res0 > resphi_tol:
phi.setValue(0.,where=phi<0.)
res0 = eq0.sweep(var=phi, dt=dt)
The error is still there (because sweep tries to calculate the new matrix of coefficients just after solving the linearized system?).
Edit: I'm using Python 2.7.14 with FiPy 3.2. I'm sharing below the parts of my code which I think are relevant for the query. The entire code is quite extense.
Some context: I'm solving balance equations for suspension flow. eq0 corresponds to the mass balance equation for the particle phase, and phi is the volume fraction of particles.
from pylab import *
from fipy import *
from fipy.tools import numerix
from scipy import misc
import osmotic_pressure_functions as opf
kic=96.91
lic=0.049
dt=1.e-2
steps=10
tol=1.e-6
Nx=8
Ny=4
Lx=Nx/Ny
dL=1./Ny
mesh = PeriodicGrid2DTopBottom(nx=Nx, ny=Ny, dx=dL, dy=dL)
x, y = mesh.cellCenters
phi = CellVariable(mesh=mesh, hasOld=True, value=0.,name='Volume fraction')
phi.constrain(0.01, mesh.facesLeft)
phi.constrain(0., mesh.facesRight)
rad=0.1
var1 = DistanceVariable(name='distance to center', mesh=mesh, value=numerix.sqrt((x-Nx*dL/2.)**2+(y-Ny*dL/2.)**2))
pi_ci = CellVariable(mesh=mesh, value=0.,name='Colloid-interface energy map')
pi_ci.setValue(kic*exp(-1.*(var1-rad)/(1.*lic)), where=(var1 > rad))
pi_ci.setValue(kic, where=(var1 <= rad))
def pi_cc_entr(x):
return opf.vantHoff(x)
def pi_cc_vdw(x):
return opf.van_der_waals(x,0.74,0.1)
def pi_cc(x):
return pi_cc_entr(x) + pi_cc_vdw(x)
diffusioncoeff = misc.derivative(pi_cc,phi,dx=1.e-6)
eq0 = TransientTerm() + ConvectionTerm(-pi_ci.faceGrad) == DiffusionTerm(coeff=diffusioncoeff)
step=0
t=0.
for step in range(steps):
print 'Step ', step
phi.updateOld()
res0 = 1e+10
while res0 > tol :
phi.setValue(0., where=phi<0)
res0 = eq0.sweep(var=phi, dt=dt) #ERROR HAPPENS HERE
Functions vantHoff and van_der_waals are being defined in a separate file.
def vantHoff(phi):
return phi
def van_der_waals(phi,phi_cp,nd_v):
return (nd_v*phi**3) / ((phi_cp-(phi_cp)**(1./3.)*(phi)**(2./3.))**2)
The error arises because the coefficient of the DiffusionTerm is all nan. This, in turn, is because the diffusion coefficient is defined as
(((((((Volume fraction + -1e-06) + (((pow((Volume fraction + -1e-06), 3)) * 0.1) / (pow((0.74 - ((pow((Volume fraction + -1e-06), 0.6666666666666666)) * 0.9045041696510275)), 2)))) * -0.5) + 0.0) + (((Volume fraction + 0.0) + (((pow((Volume fraction + 0.0), 3)) * 0.1) / (pow((0.74 - ((pow((Volume fraction + 0.0), 0.6666666666666666)) * 0.9045041696510275)), 2)))) * 0.0)) + (((Volume fraction + 1e-06) + (((pow((Volume fraction + 1e-06), 3)) * 0.1) / (pow((0.74 - ((pow((Volume fraction + 1e-06), 0.6666666666666666)) * 0.9045041696510275)), 2)))) * 0.5)) / 1e-06)
and Volume fraction (phi) is all zero, so -1e-06 is being raised to fractional powers, which is undefined.
The factors of -1e-06 arise from your use of scipy.misc.derivative() to apparently calculate symbolic derivatives? I don't believe it's intended for that. You'll likely have better luck with SymPy.
Here is the content of my script:
from sympy import *
x = symbols('x')
init_printing(use_unicode=True)
f = symbols('f', cls=Function)
diffeq = Eq(x**2 * f(x).diff(x, x) + x * f(x).diff(x) - f(x) , 1/((1+x**2)**(3)) )
print dsolve(diffeq, f(x))
This program returns the following output:
Eq(f(x), (C1*x**2 + C1 + C2*x**4 + C2*x**2 - 15*x**4*atan(x) - 15*x**3 - 18*x**2*atan(x) - 13*x - 3*atan(x))/(16*x*(x**2 + 1)))
But when I define the variable diffeq like this:
diffeq = Eq(f(x).diff(x, x) + f(x).diff(x)/x - f(x)/x**(2) , 1 / ((1+x**2)**(3) * x**(2)) )
then I receive the output:
Traceback (most recent call last):
File "/home/foo/odeSympyTrial01.py", line 12, in <module>
print dsolve(diffeq, f(x))
File "/usr/lib/python2.7/dist-packages/sympy/solvers/ode.py", line 625, in dsolve
x0=x0, n=n, **kwargs)
File "/usr/lib/python2.7/dist-packages/sympy/solvers/deutils.py", line 235, in _desolve
raise NotImplementedError(dummy + "solve" + ": Cannot solve " + str(eq))
NotImplementedError: solve: Cannot solve Derivative(f(x), x, x) + Derivative(f(x), x)/x - f(x)/x**2 - 1/(x**2*(x**2 + 1)**3)
And when I define the variable diffeq like this:
diffeq = Eq(f(x).diff(x, x) * x**(2) + f(x).diff(x) * x**(2) /x - f(x) * x**(2) /x**(2) , 1* x**(2)/((1+x**2)**(3) * x**(2)) )
then I receive the output:
Eq(f(x), (C1*x**2 + C1 + C2*x**4 + C2*x**2 - 15*x**4*atan(x) - 15*x**3 - 18*x**2*atan(x) - 13*x - 3*atan(x))/(16*x*(x**2 + 1)))
In every one of these cases, the differential equations diffeq are mathematically equal. Therefore in my opinion dsolve() should return the same output for each case. Somebody please help me to understand why dsolve() returns an error in the second case. How should the nonhomogeneous linear ordinary differential equation be expressed to ensure dsolve() does not return an error?
Short explanation: the logic of SymPy ODE module is often naive and sometimes incorrect.
As written originally, with
x**2 * f(x).diff(x, x) + x * f(x).diff(x) - f(x)
this matches the form of Cauchy–Euler equation (also known as Euler's equation): the power of x in each coefficient is the order of derivative. SymPy detects this structure and applies an appropriate method. But if you divide by x**2,
f(x).diff(x, x) + f(x).diff(x)/x - f(x)/x**(2)
this is no longer the case: the second derivative does not have the power of x**2 so the match fails. A more careful check could detect the latent Cauchy-Euler structure here, but that's not implemented, as one can see by looking at the source.
You can check that this is indeed what's going on with
classify_ode(diffeq, f(x))
which will return 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters' in the first case but not the second.
While looking at the source, one can also seen an example of wrong logic.
if coeff.is_Mul:
if coeff.has(f(x)):
return False
return x**order in coeff.args
For example, x**2*sin(x) will pass this check with order=2, which means that SymPy will mistake x**2*sin(x)*f(x).diff(x, x) - f(x) = 0 for Euler's equation. And indeed,
dsolve(x**2*sin(x)*f(x).diff(x, x) - f(x), f(x))
"solves" the equation incorrectly. Do not trust ODE solutions from SymPy.
I am trying to solve a set of nonlinear equations using Sympy. This is my code with a few numbers changed and only one input value (the real code runs through 170,000 lines of data):
import sympy as sp
K0 = 2.00*10**-4
x2, y2 = sp.symbols('x2, y2')
x0 = 500
y0 = 500
R1 = ((x2 - x0)**2 + (y2 - y0)**2)**0.5
R2 = K0 * R1
H2 = sp.atan(R2 * (x2 - x0)/R1)
V2 = sp.atan(R2 * (y2 - y0)/R1)
x, y = sp.symbols('x, y')
x0 = 1.0
y0 = 2.0
x = R1 * H2
y = R1 * V2
dat = sp.nsolve([x - x0, y - y0], [x2, y2], [512, 512]) # This line is the problem
print "dat = %f, %f" % (dat[0], dat[1])
Purely with Python, the code runs fine and produces a good output - but it's very slow. To speed up the process, I used Cython to compile a .pyx file with the exact same code (in a definition, def test()), yet during run-time I'm met with:
File "test.py", line 3, in <module>
demo.test()
File "demo.pyx", line 17, in demo.test
dat = sp.nsolve([x - x0, y - y0], [x2, y2], [512, 512])
File "C:\...\site-packages\sympy\utilities\decorator.py", line 91, in func_wrapper
return func(*args, **kwargs)
File "C:\...\site-packages\sympy\solvers\solvers.py", line 2847, in nsolve
x = findroot(f, x0, J=J, **kwargs)
File "C:\...\site-packages\mpmath\calculus\optimization.py", line 960, in findroot
for x, error in iterations:
File "C:\...\site-packages\mpmath\calculus\optimization.py", line 658, in __iter__
s = self.ctx.lu_solve(Jx, fxn)
File "C:\...\site-packages\mpmath\matrices\linalg.py", line 227, in lu_solve
A, p = ctx.LU_decomp(A)
File "C:\...\site-packages\mpmath\matrices\linalg.py", line 137, in LU_decomp
raise ZeroDivisionError('matrix is numerically singular')
ZeroDivisionError: matrix is numerically singular
I have narrowed down the problem to the x - x0 and y - y0 part. For some reason, the compiled code cannot handle finding the roots when they're not equal to 0. Can nsolve simply not be converted to C using Cython? Is there something I'm missing that I have to do with Cython?
You can use sympy.lambdify together with e.g. SciPy's solvers. If that is not fast enough you could use symengine.Lambdify.
Getting the function signatures right, and deriving the Jacobian, requires you to jump through hoops. If you want to use a library for that I have written pyneqsys:
>>> from pyneqsys.symbolic import SymbolicSys
>>> neqsys = SymbolicSys([x2, y2], [x - x0, y - y0])
>>> neqsys.solve([512, 512])
Out[4]:
(array([ 547.28609349, 594.58064617]),
fjac: array([[ 0.91320338, 0.4075041 ],
[-0.4075041 , 0.91320338]])
fun: array([ -1.37667655e-13, 1.52011737e-12])
message: 'The solution converged.'
nfev: 17
njev: 2
qtf: array([ 1.55620322e-10, 4.63225371e-10])
r: array([ 0.02751454, 0.023682 , 0.03261983])
status: 1
success: True
x: array([ 547.28609349, 594.58064617]))
If those 170 000 solves involves gradually changing parameters pyneqsys can exploit that (by propagating the solution as guess between solves). It can also use symengine.Lambdify automatically by setting the environment variable SYM_BACKEND=sympysymengine
I have written the following code:
import math
import scipy
def steffensen(equation, f_prime, x, er, N):
for i in range(1, N):
y1 = x
r = equation(x)
dx = (-r)/(f_prime(x))
y2 = y1 + dx
y3 = y2 + dx
x = y1-(((y2-y1)**2)/(y3-2*y2+y1))
z = abs(equation(x))
print("|f(x)| = %e"%z)
if z < e:
print("Converged!")
break
return x
#This will be used for testing
def equation(x):
return math.exp(-x**2 + x)-(0.5*x)
def f_prime(x):
return (1-2*x)*math.exp(x-(x**2))-0.5
#def main():
x0 = 1
N = 5
er = 1e-6
x = steffensen(equation, f_prime, x0, er, N)
print("Finished!")
When compiled, the code returns saying that there is a zero division error: float division by zero on the line that says: x = y1-(((y2-y1)**2)/(y3-2*y2+y1)). When computed by hand, I don't get 0. Please help me find the bug.
You're getting a zero division error because your program divides by zero. The question you should focus on is "how do I figure out what's wrong?" Do it by adding a diagnostic statement just before the line that throws the error. I'd start with this one:
print(i, dx, y1, y2, y3, y3-2*y2+y1)
You'll get this output,
1 0.3333333333333333 1 1.3333333333333333 1.6666666666666665 0.0
showing that the error occurs on the first pass through the loop (i == 1), and that dx has the value 1/3. Take it from there, and figure out why your program diverges from the calculation you did by hand.
I am using sympy and numpy to solve the following the problem:
Given a point (x0, y0) and a curve y=a*x**2+b*x+c, compute the minimal distances of (x0, y0) to (x,y).
from sympy.core.symbol import symbols
from sympy.solvers.solvers import solve
from sympy.utilities.lambdify import lambdify
x, y = symbols('x y')
a,b,c, x0, y0 = symbols('a b c x0 y0')
y = a*x**2 + b*x + c
dist2 = (x-x0)**2 + (y-y0)**2
sol = solve(dist2.diff(x), x)
dist2_diff_solve = lambdify( (x0,y0,a,b,c), solve(dist2.diff(x),x), modules='numpy')
Until now, every thing is fine. I can even get some results:
dist2_diff_solve(1, 1, 1, 1, 1)
[0.31718264650678707, (-0.9085913232533936-0.8665105933073626j),
(-0.9085913232533936+0.8665105933073626j)]
However, with another group of parameters, I have problems:
dist2_diff_solve(664515.9375, 3998106.0, 0.053674994761459802, -71340.561832823907, 23709057427.266102)
*** ValueError: negative number cannot be raised to a fractional power
I think this is a bug from lambdify, as I can do the following:
sol[0].evalf(subs={x0:664515.9375, y0:3998106.0, a:0.053674994761459802, b:-71340.561832823907, c:23709057427.266102})
664515.759983973 + .0e-19*I
I need lambdify because I need to compute a large number (~100K) of computation (vectorize) at one time. Can any one confirm this is a bug from lambdify? Any comments / suggestions are welcome.
I found one related question: negative pow in python
and solved this problem simply by adding +0j to a, that is:
dist2_diff_solve(664515.9375+0j, 3998106.0, 0.053674994761459802, -71340.561832823907, 23709057427.266102)
[(664515.7418921513+3.552713678800501e-15j), (664600.9266076663+5.329070518200751e-15j), (664564.8069210749-1.4210854715202004e-14j)]