I'm new to using Sympy, and wish to use it to integrate the following function. Although, I get this error which I'm not sure how to resolve.
import sympy as sy
A = sy.Symbol('A')
B = sy.Symbol('B')
C = sy.Symbol('C')
D = sy.Symbol('D')
x = sy.Symbol('x', positive=True)
y = sy.Symbol('y', positive=True)
def func(x,y):
return (1.0/(4.0*x*y))*(A*sy.log( ((y+x)**2 + C**2)/((y-x)**2 + C**2) ) - B*sy.log( ((y+x)**2 + D**2)/((y-x)**2 + D**2) ))
sy.integrate(func(x,y), (x,0,10))
Although, when I run this I get the following error and I'm not sure how to resolve this.
sympy.polys.polyerrors.PolynomialDivisionFailed: couldn't reduce degree in a polynomial division
algorithm when dividing [(-1.13305359211433e+221*y**2 + 5.66526796057163e+220*D**2 +
5.66526796057163e+220*C**2)/1.57368554460323e+219, 0.0, (3.39916077634298e+221*y**4 -
1.13305359211433e+221*y**2*D**2 - 1.13305359211433e+221*y**2*C**2 + 5.66526796057163e+220*D**4 +
2.26610718422865e+221*D**2*C**2 + 5.66526796057163e+220*C**4)/1.57368554460323e+219, 0.0,
(-3.39916077634298e+221*y**6 - 1.69958038817149e+221*y**4*D**2 - 1.69958038817149e+221*y**4*C**2
- 1.69958038817149e+221*y**2*D**4 + 6.79832155268595e+221*y**2*D**2*C**2 -
1.69958038817149e+221*y**2*C**4 + 1.69958038817149e+221*D**4*C**2 +
1.69958038817149e+221*D**2*C**4)/1.57368554460323e+219, 0.0, (1.13305359211433e+221*y**8 +
2.26610718422865e+221*y**6*D**2 + 2.26610718422865e+221*y**6*C**2 +
1.13305359211433e+221*y**4*D**4 + 4.5322143684573e+221*y**4*D**2*C**2 +
1.13305359211433e+221*y**4*C**4 + 2.26610718422865e+221*y**2*D**4*C**2 +
2.26610718422865e+221*y**2*D**2*C**4 + 1.13305359211433e+221*D**4*C**4)/1.57368554460323e+219,
0.0] by [(-2.0203139355353e+661*y**6 + 3.93961217429382e+662*y**4*D**2 +
3.93961217429382e+662*y**4*C**2 - 2.42437672264235e+662*y**2*D**4 -
3.03047090330294e+662*y**2*D**2*C**2 - 2.42437672264235e+662*y**2*C**4 +
2.52539241941912e+661*D**6 - 1.51523545165146e+661*D**4*C**2 - 1.51523545165146e+661*D**2*C**4 +
2.52539241941912e+661*C**6)/3.15674052427389e+659, 0.0, (6.06094180660588e+661*y**8 -
8.08125574214117e+662*y**6*D**2 - 8.08125574214117e+662*y**6*C**2 +
3.18199444846809e+662*y**4*D**4 + 2.47488457103073e+663*y**4*D**2*C**2 +
3.18199444846809e+662*y**4*C**4 - 1.51523545165147e+661*y**2*D**6 -
7.92973219697602e+662*y**2*D**4*C**2 - 7.92973219697602e+662*y**2*D**2*C**4 -
1.51523545165147e+661*y**2*C**6 + 2.52539241941911e+661*D**8 + 1.51523545165147e+661*D**6*C**2 -
2.02031393553529e+661*D**4*C**4 + 1.51523545165147e+661*D**2*C**6 +
2.52539241941911e+661*C**8)/3.15674052427389e+659, 0.0, (-6.06094180660588e+661*y**10 +
3.93961217429382e+662*y**8*D**2 + 3.93961217429382e+662*y**8*C**2 -
6.06094180660588e+661*y**6*D**4 + 9.6975068905694e+662*y**6*D**2*C**2 -
6.06094180660588e+661*y**6*C**4 + 1.38707976084194e+646*y**4*D**6 -
4.24265926462411e+662*y**4*D**4*C**2 - 4.24265926462411e+662*y**4*D**2*C**4 +
1.38707976084194e+646*y**4*C**6 - 3.03047090330294e+661*y**2*D**8 -
2.42437672264235e+662*y**2*D**6*C**2 - 2.42437672264235e+662*y**2*D**4*C**4 -
2.42437672264235e+662*y**2*D**2*C**6 - 3.03047090330294e+661*y**2*C**8 +
3.03047090330294e+661*D**8*C**2 + 1.73384970105243e+646*D**6*C**4 +
1.73384970105243e+646*D**4*C**6 + 3.03047090330294e+661*D**2*C**8)/3.15674052427389e+659, 0.0,
(2.02031393553529e+661*y**12 + 2.02031393553529e+661*y**10*D**2 +
2.02031393553529e+661*y**10*C**2 - 1.51523545165147e+661*y**8*D**4 +
1.01015696776765e+661*y**8*D**2*C**2 - 1.51523545165147e+661*y**8*C**4 -
1.01015696776765e+661*y**6*D**6 - 3.03047090330294e+661*y**6*D**4*C**2 -
3.03047090330294e+661*y**6*D**2*C**4 - 1.01015696776765e+661*y**6*C**6 +
5.05078483883823e+660*y**4*D**8 - 1.01015696776765e+661*y**4*D**6*C**2 -
1.01015696776765e+661*y**4*D**4*C**4 - 1.01015696776765e+661*y**4*D**2*C**6 +
5.05078483883823e+660*y**4*C**8 + 1.01015696776765e+661*y**2*D**8*C**2 +
1.01015696776765e+661*y**2*D**6*C**4 + 1.01015696776765e+661*y**2*D**4*C**6 +
1.01015696776765e+661*y**2*D**2*C**8 + 5.05078483883823e+660*D**8*C**4 +
1.01015696776765e+661*D**6*C**6 + 5.05078483883823e+660*D**4*C**8)/3.15674052427389e+659].
This can happen when it's not possible to detect zero in the coefficient domain. The domain of
computation is RR(B,y,D,C). Zero detection is guaranteed in this coefficient domain. This may
indicate a bug in SymPy or the domain is user defined and doesn't implement zero detection
properly.
Has anyone had this issue before and if so, how exactly can this be solved? I have varied the limits of $x$ but I get the same error!
Thank you in advance!
I have the following expression in Sympy
s = e0*a01*d1**2*u0 - e0*a01*d1**2*u1 - e0*a11*d1**2*u0 - e0*a11*d1**2*u1 + e0*d0*a00*d1*u1 + e0*d0*a01*d1*u0 + e0*d0*a10*d1*u0 - e0*d0*a11*d1*u1 + e0*d0*b0*u0 - e0*d0*b1*u1 + e0*d1*a00*d1*u0 - e0*d1*a01*d1*u1 - e0*d1*a10*d1*u1 - e0*d1*a11*d1*u0 - e0*d1*b0*u1 - e0*d1*b1*u0 - e1*a00*d1**2*u0 + e1*a00*d1**2*u1 + e1*a10*d1**2*u0 + e1*a10*d1**2*u1 - e1*d0*a00*d1*u0 + e1*d0*a01*d1*u1 + e1*d0*a10*d1*u1 + e1*d0*a11*d1*u0 + e1*d0*b0*u1 + e1*d0*b1*u0 + e1*d1*a00*d1*u1 + e1*d1*a01*d1*u0 + e1*d1*a10*d1*u0 - e1*d1*a11*d1*u1 + e1*d1*b0*u0 - e1*d1*b1*u1
So first I simpify it:
s = sympify(s,locals=T)
(T contains all these symbols in the string, that are non commutative). And I want to get the coefficient of
d1**2*u0
after "factoring" it. So I did the following:
e=sympify(d1**2*u0,locals=T)
collected_expr = collect(s,e,exact=True)
print(collected_expr)
coeff = collected_expr.coeff(e)
print(coeff)
The result of collected_expr is ok:
d1**2*u0*(e0*a01 - e0*a11 - e1*a00 + e1*a10) - e0*a01*d1**2*u1 - e0*a11*d1**2*u1 + e0*d0*a00*d1*u1 + e0*d0*a01*d1*u0 + e0*d0*a10*d1*u0 - e0*d0*a11*d1*u1 + e0*d0*b0*u0 - e0*d0*b1*u1 + e0*d1*a00*d1*u0 - e0*d1*a01*d1*u1 - e0*d1*a10*d1*u1 - e0*d1*a11*d1*u0 - e0*d1*b0*u1 - e0*d1*b1*u0 + e1*a00*d1**2*u1 + e1*a10*d1**2*u1 - e1*d0*a00*d1*u0 + e1*d0*a01*d1*u1 + e1*d0*a10*d1*u1 + e1*d0*a11*d1*u0 + e1*d0*b0*u1 + e1*d0*b1*u0 + e1*d1*a00*d1*u1 + e1*d1*a01*d1*u0 + e1*d1*a10*d1*u0 - e1*d1*a11*d1*u1 + e1*d1*b0*u0 - e1*d1*b1*u1
But coeff is not ok, as it returns 1, but I really want
e0*a01 - e0*a11 - e1*a00 + e1*a10
EDIT: I also tried
coeff = collected_expr.coeff(u0).coeff(d1).coeff(d1)
and
coeff = collected_expr.coeff(u0).coeff(d1**2)
But both things returned 0
The docstring of Expr.coeff says
When x is noncommutative, the coefficient to the left (default) or
right of x can be returned. The keyword 'right' is ignored when
x is commutative.
collect does not seem to be noncommutative-aware, however, so the factors that were on the right may collect to the left.
>>> var("A B", commutative=False)
(A, B)
>>> collect(A*B+B*A**2,B)
B*(A + A**2)
I have two univariate functions, f(x) and g(x), and I'd like to substitute g(x) = y to rewrite f(x) as some f2(y).
Here is a simple example that works:
In [240]: x = Symbol('x')
In [241]: y = Symbol('y')
In [242]: f = abs(x)**2 + 6*abs(x) + 5
In [243]: g = abs(x)
In [244]: f.subs({g: y})
Out[244]: y**2 + 6*y + 5
But now, if I try a slightly more complex example, it fails:
In [245]: h = abs(x) + 1
In [246]: f.subs({h: y})
Out[246]: Abs(x)**2 + 6*Abs(x) + 5
Is there a general approach that works for this problem?
The expression abs(x)**2 + 6*abs(x) + 5 does not actually contain abs(x) + 1 anywhere, so there is nothing to substitute for.
One can imagine changing it to abs(x)**2 + 5*(abs(x) + 1) + abs(x), with the substitution result being abs(x)**2 + 5*y + abs(x). Or maybe changing it to abs(x)**2 + 6*(abs(x) + 1) - 1, with the result being abs(x)**2 + 6*y - 1. There are other choices too. What should the result be?
There is no general approach to this task because it's not a well-defined task to begin with.
In contrast, the substitution f.subs(abs(x), y-1) is a clear instruction to replace all occurrences of abs(x) in the expression tree with y-1. It returns 6*y + (y - 1)**2 - 1.
The substitution above of abs(x) + 1 in abs(x)**2 + 6*abs(x) + 5 is a clear instruction too: to find exact occurrences of the expression abs(x) + 1 in the syntax tree of the expression abs(x)**2 + 6*abs(x) + 5, and replace those subtrees with the syntax tree of the expression abs(x) + 1. There is a caveat about heuristics though.
Aside: in addition to subs SymPy has a method .replace which supports wildcards, but I don't expect it to help here. In my experience, it is overeager to replace:
>>> a = Wild('a')
>>> b = Wild('b')
>>> f.replace(a*(abs(x) + 1) + b, a*y + b)
5*y/(Abs(x) + 1) + 6*y*Abs(x*y)/(Abs(x) + 1)**2 + (Abs(x*y)/(Abs(x) + 1))**(2*y/(Abs(x) + 1))
Eliminate a variable
There is no "eliminate" in SymPy. One can attempt to emulate it with solve by introducing another variable, e.g.,
fn = Symbol('fn')
solve([Eq(fn, f), Eq(abs(x) + 1, y)], [fn, x])
which attempts to solve for "fn" and "x", and therefore the solution for "fn" is an expression without x. If this works
In fact, it does not work with abs(); solving for something that sits inside an absolute value is not implemented in SymPy. Here is a workaround.
fn, ax = symbols('fn ax')
solve([Eq(fn, f.subs(abs(x), ax)), Eq(ax + 1, y)], [fn, ax])
This outputs [(y*(y + 4), y - 1)] where the first term is what you want; a solution for fn.
I want to be able to simplify the ellipse equation:
sqrt((x + c)^2 + y^2) + sqrt((x - c)^2 + y^2) = 2a
into its canonical form:
x^2/a^2 + y^2/(a^2 - c^2) = 1
using CAS. I actually want to know how to do that in sympy, but any other CAS will do.
If it is not possible to do that in one call, then may be by transforming the original equation using operations like "get square of the both sides; move non-radicals (e.g. by enumerating them manually) to the right side; get square of the both sides again; simplify"
unrad will do most of the heavy lifting for you in SymPy:
>>> l # your original expression with the 2a subtracted from the lhs
-2*a + sqrt(y**2 + (-c + x)**2) + sqrt(y**2 + (c + x)**2)
>>> unrad(_)
(-a**4 + a**2*c**2 + a**2*x**2 + a**2*y**2 - c**2*x**2, [], [])
>>> neg_i, dep = _[0].as_independent(x,y)
>>> xpart, ypart = [dep.coeff(i**2) for i in (x,y)]
>>> Eq(-x**2*cancel(xpart/neg_i)-y**2*cancel(ypart/neg_i), neg_i/neg_i)
y**2/(a**2 - c**2) + x**2/a**2 == 1
Subtract the doubled second sqrt from both sides.
Multiply respective sides of the new equation and the original one.
Reduce LHS applying (m+n)(m-n) = m^2 - n^2.
You'll get (if i did it right): -4xc = 4a(a - sqrt(something))
Then: -xc/a = a - sqrt(something)
and: sqrt(something) = a + xc/a
Square both sides and see what happens.
I did it wrong. Should be: 4xc = 4a(a - sqrt(something))
so sqrt(something) = a - xc/a.
in order to code the DEL2 matlab function in c++ I need to understand the algorithm. I've managed to code the function for elements of the matrix that are not on the borders or the edges.
I've seen several topics about it and read the MATLAB code by typing "edit del2" or "type del2" but I don't understand the calculations that are made to obtain the borders and the edges.
Any help would be appreciated, thanks.
You want to approximate u'' knowing only the value of u on the right (or the left) of a point.
In order to have a second order approximation, you need 3 equations (basic taylor expansion):
u(i+1) = u(i) + h u' + (1/2) h^2 u'' + (1/6) h^3 u''' + O(h^4)
u(i+2) = u(i) + 2 h u' + (4/2) h^2 u'' + (8/6) h^3 u''' + O(h^4)
u(i+3) = u(i) + 3 h u' + (9/2) h^2 u'' + (27/6) h^3 u''' + O(h^4)
Solving for u'' gives (1):
h^2 u'' = -5 u(i+1) + 4 u(i+2) - u(i+3) + 2 u(i) +O(h^4)
To get the laplacian you need to replace the traditional formula with this one on the borders.
For example where "i = 0" you'll have:
del2(u) (i=0,j) = [-5 u(i+1,j) + 4 u(i+2,j) - u(i+3,j) + 2 u(i,j) + u(i,j+1) + u(i,j-1) - 2u(i,j) ]/h^2
EDIT clarifications:
The laplacian is the sum of the 2nd derivatives in the x and in the y directions. You can calculate the second derivative with the formula (2)
u'' = (u(i+1) + u(i-1) - 2u(i))/h^2
if you have both u(i+1) and u(i-1). If i=0 or i=imax you can use the first formula I wrote to compute the derivatives (notice that due to the simmetry of the 2nd derivative, if i = imax you can just replace "i+k" with "i-k"). The same applies for the y (j) direction:
On the edges you can mix up the formulas (1) and (2):
del2(u) (i=imax,j) = [-5 u(i-1,j) + 4 u(i-2,j) - u(i-3,j) + 2 u(i,j) + u(i,j+1) + u(i,j-1) - 2u(i,j) ]/h^2
del2(u) (i,j=0) = [-5 u(i,j+1) + 4 u(i,j+2) - u(i,j+3) + 2 u(i,j) + u(i+1,j) + u(i-1,j) - 2u(i,j) ]/h^2
del2(u) (i,j=jmax) = [-5 u(i,j-1) + 4 u(i,j-2) - u(i,j-3) + 2 u(i,j) + u(i+1,j) + u(i-1,j) - 2u(i,j) ]/h^2
And on the corners you'll just use (1) two times for both directions.
del2(u) (i=0,j=0) = [-5 u(i,j+1) + 4 u(i,j+2) - u(i,j+3) + 2 u(i,j) + -5 u(i,j+1) + 4 u(i+2,j) - u(i+3,j) + 2 u(i,j)]/h^2
Del2 is the 2nd order discrete laplacian, i.e. it permits to approximate the laplacian of a real continuous function given its values on a square cartesian grid NxN where the distance between two adjacent nodes is h.
h^2 is just a constant dimensional-factor, you can get the matlab implementation from these formulas by setting h^2 = 4.
For example, if you want to compute the real laplacian of u(x,y) on the (0,L) x (0,L) square, what you do is writing down the values of this function on an NxN cartesian grid, i.e. you calculate u(0,0), u(L/(N-1),0), u(2L/(N-1),0) ... u( (N-1)L/(N-1) =L,0) ... u(0,L/(N-1)), u(L/(N-1),L/(N-1)) etc. and you put down these N^2 values in a matrix A.
Then you'll have
ans = 4*del2(A)/h^2, where h = L/(N-1).
del2 will return the exact value of the continuous laplacian if your starting function is linear or quadratic (x^2+y^2 fine, x^3 + y^3 not fine). If the function is not linear nor quadratic, the result will be more accurate the more points you use (i.e. in the limit h -> 0)
I hope this is more clear, notice that i used 0-based indices for accessing matrix (C/C++ array style), while matlab uses 1-based.
DEL2 in MatLab represents Discrete Laplace operator, you can find some information about it here.
The main thing about the edges is that elements in the interior of the matrix have four neighbors, while elements on the edges and corners have three or two neighbors respectfully. So you calculate the corners and edges the same way, but using less elements.
Here is a module I wrote in Fortran 90 that replicates the "del2()" operator in MATLAB implementing the above ideas. It only works for arrays that that are atleast 4x4 or larger. It works successfully when I run it so I thought I would post it so that other people dont have to waste time making their own.
module del2_mod
implicit none
real, private :: pi
integer, private :: nr, nc, i, j, k
contains
! nr is number of rows in array, while nc is the number of columns in the array.
!!----------------------------------------------------------
subroutine del2(in, out)
real, dimension(:,:) :: in, out
real, dimension(nr,nc) :: interior, left, right, top, bottom, ul_corner, br_corner, disp
integer :: i, j
real :: h, ul, ur, bl, br
! Zero out internal arrays
out = 0.0; interior=0.0; left = 0.0; right = 0.0; top = 0.0; bottom = 0.0; ul_corner = 0.0; br_corner = 0.0;
h=2.0
! Interior Points
do j=1,nc
do i=1,nr
! Interior Point Calculations
if( j>1 .and. j<nc .and. i>1 .and. i<nr )then
interior(i,j) = ((in(i-1,j) + in(i+1,j) + in(i,j-1) + in(i,j+1)) - 4*in(i,j) )/(h**2)
end if
! Boundary Conditions for Left and Right edges
left(i,1) = (-5.0*in(i,2) + 4.0*in(i,3) - in(i,4) + 2.0*in(i,1) + in(i+1,1) + in(i-1,1) - 2.0*in(i,1) )/(h**2)
right(i,nc) = (-5.0*in(i,nc-1) + 4.0*in(i,nc-2) - in(i,nc-3) + 2.0*in(i,nc) + in(i+1,nc) + in(i-1,nc) - 2.0*in(i,nc) )/(h**2)
end do
! Boundary Conditions for Top and Bottom edges
top(1,j) = (-5.0*in(2,j) + 4.0*in(3,j) - in(4,j) + 2.0*in(1,j) + in(1,j+1) + in(1,j-1) - 2.0*in(1,j) )/(h**2)
bottom(nr,j) = (-5.0*in(nr-1,j) + 4.0*in(nr-2,j) - in(nr-3,j) + 2.0*in(nr,j) + in(nr,j+1) + in(nr,j-1) - 2.0*in(nr,j) )/(h**2)
end do
out = interior + left + right + top + bottom
! Calculate BC for the corners
ul = (-5.0*in(1,2) + 4.0*in(1,3) - in(1,4) + 2.0*in(1,1) - 5.0*in(2,1) + 4.0*in(3,1) - in(4,1) + 2.0*in(1,1))/(h**2)
br = (-5.0*in(nr,nc-1) + 4.0*in(nr,nc-2) - in(nr,nc-3) + 2.0*in(nr,nc) - 5.0*in(nr-1,nc) + 4.0*in(nr-2,nc) - in(nr-3,nc) + 2.0*in(nr,nc))/(h**2)
bl = (-5.0*in(nr,2) + 4.0*in(nr,3) - in(nr,4) + 2.0*in(nr,1) - 5.0*in(nr-1,1) + 4.0*in(nr-2,1) - in(nr-3,1) + 2.0*in(nr,1))/(h**2)
ur = (-5.0*in(1,nc-1) + 4.0*in(1,nc-2) - in(1,nc-3) + 2.0*in(1,nc) - 5.0*in(2,nc) + 4.0*in(3,nc) - in(4,nc) + 2.0*in(1,nc))/(h**2)
! Apply BC for the corners
out(1,1)=ul
out(1,nc)=ur
out(nr,1)=bl
out(nr,nc)=br
end subroutine
end module
It's so hard! I wasted a few hours to understand and implement it in Java.
Here is: https://gist.github.com/emersonmoretto/dec8f7125c032775da0d
Tested and compared to the original function DEL2 (Matlab)
I've found a typo in sbabbi response:
del2(u) (i=0,j=0) = [-5 u(i,j+1) + 4 u(i,j+2) - u(i,j+3) + 2 u(i,j) + -5 u(i,j+1) + 4 u(i+2,j) - u(i+3,j) + 2 u(i,j)]/h^2
is
del2(u) (i=0,j=0) = [-5 u(i,j+1) + 4 u(i,j+2) - u(i,j+3) + 2 u(i,j) + -5 u(i+1,j) + 4 u(i+2,j) - u(i+3,j) + 2 u(i,j)]/h^2