Modulo computations in Sympy fail - python

I have a computation in Sympy, which I want to be modulo 2.
However, if I just write
from sympy.abc import x
(((x + 1) % 2) + 1) % 2
Then this has the output Mod(Mod(x + 1, 2) + 1, 2), i.e. the two +1 do not vanish. Even calling .simplify() does not have the desired effect.
Another post (Modulo 2 arithmetics in SymPy) suggested sympy.trunc. But this function does not work if the expression is integer.
I even tried sympy.trunc(sympy.sympify(1),2), but this still raised an Error.
So how do I get a modulo function that works on integers and all coefficients?
PS: I am aware that this is a basic question, and I was confused, that I could not find an answer.

A better way to handle this is to use Poly with the modulus flag:
>>> Poly(x + 1, x, modulus=2) + Poly(1, x, modulus=2)
Poly(x, x, modulus=2)

Related

Anyway to get rid of `math.floor` for positive odd integers with `sympy.simplify`?

I'm trying to simplify some expressions of positive odd integers with sympy. But sympy refuses to expand floor, making the simplification hard to proceed.
To be specific, x is a positive odd integer (actually in my particular use case, the constraint is even stricter. But sympy can only do odd and positive, which is fine). x // 2 should be always equal to (x - 1) / 2. Example code here:
from sympy import Symbol, simplify
x = Symbol('x', odd=True, positive=True)
expr = x // 2 - (x - 1) / 2
print(simplify(expr))
prints -x/2 + floor(x/2) + 1/2. Ideally it should print 0.
What I've tried so far:
Simplify (x - 1) // 2 - (x - 1) / 2. Turns out to be 0.
Multiply the whole thing by 2: 2 * (x // 2 - (x - 1) / 2). Gives me: -x + 2*floor(x/2) + 1.
Try to put more weights on the FLOOR op by customizing the measure. No luck.
Use sympy.core.evaluate(False) context when creating the expression. Nuh.
Tune other parameters like ratio, rational, and play with other function like expand, factor, collect. Doesn't work either.
EDIT: Wolfram alpha can do this.
I tried to look like the assumptions of x along with some expressions. It surprises me that (x - 1) / 2).is_integer returns None, which means unknown.
I'm running out of clues. I'm even looking for alternativese of sympy. Any ideas guys?
I fail to see why sympy can't simplify that.
But, on another hand, I've discovered the existence of odd parameter just now, with your question.
What I would have done, without the knowledge of odd is
k = Symbol('k', positive=True, integer=True)
x = 2*k-1
expr = x // 2 - (x - 1) / 2
Then, expr is 0, without even the need to simplify.
So, can't say why you way doesn't work (and why that odd parameter exists if it is not used correctly to guess that x-1 is even, and therefore (x-1)/2 integer). But, in the meantime, my way of defining an odd integer x works.
There is some reluctance to make too much automatic in SymPy, but this seems like a case that could be addressed (since (x-1)/2 is simpler than floor(x/2). Until then, however, you can run a replacement on your expression which makes this transformation for you.
Let's define a preferred version of floor:
def _floor(x):
n, d = x.as_numer_denom()
if d == 2:
if n.is_odd:
return (n - 1)/2
if n.is_even:
return n/2
return floor(x)
When you have an expression with floor that you want to evaluate, replace floor with _floor:
>>> x = Symbol('x', odd=True)
>>> eq=x // 2 - (x - 1) / 2
>>> eq.replace(floor, _floor)
0

sympy solve function gives wrong result

according to this graph: desmos
print(solve('x**2 + x - 1/x'))
# [-1/3 + (-1/2 - sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3) + 1/(9*(-1/2 - sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3)), -1/3 + 1/(9*(-1/2 + sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3)) + (-1/2 + sqrt(3)*I/2)*(sqrt(69)/18 + 25/54)**(1/3), -1/3 + 1/(9*(sqrt(69)/18 + 25/54)**(1/3)) + (sqrt(69)/18 + 25/54)**(1/3)]
I was expecting [0.755, 0.57], but, I got something I cannot use in my future program. I desire to get a list of floats as result, so refer to this post, I did following, but I got some even more weird:
def solver(solved, rit=3):
res = []
for val in solved:
if isinstance(val, core.numbers.Add):
flt = val.as_two_terms()[0]
flt = round(flt, rit)
else:
flt = round(val, rit)
if not isinstance(flt, core.numbers.Add):
res.append(flt)
return res
print(solver(solve('x**2 + x - 1/x')))
# [-0.333, -0.333, -0.333]
Now I am really disappointed with sympy, I wonder if there is an accurate way to get a list of floats as result, or I will code my own gradient descent algorithm to find the roots and intersection.
sym.solve solves an equation for the independent variable. If you provide an expression, it'll assume the equation sym.Eq(expr, 0). But this only gives you the x values. You have to substitute said solutions to find the y value.
Your equation has 3 solutions. A conjugate pair of complex solutions and a real one. The latter is where your two graphs meet.
import sympy as sym
x = sym.Symbol('x')
# better to represent it like the equation it is
eq = sym.Eq(x**2, 1/x - x)
sol = sym.solve(eq)
for s in sol:
if s.is_real:
s = s.evalf()
print(s, eq.lhs.subs({x: s})) # eq.rhs works too
There are a variety of things you can do to get the solution. If you know the approximate root location and you want a numerical answer, nsolve is simplest since it has no requirements on the type of expression:
>>> from sympy import nsolve, symbols
>>> x = symbols('x')
>>> eq = x**2 + x - 1/x
>>> nsolve(eq, 1)
0.754877666246693
You can try a guess near 0.57 but it will go to the same solution. So is there really a second real roots? You can't use real_roots on this expression because it isn't in polynomial form. But if you split it into numerator and denominator you can check for the roots of the numerator:
>>> n, d = eq.as_numer_denom()
>>> from sympy import real_roots
>>> real_roots(n)
[CRootOf(x**3 + x**2 - 1, 0)]
So there is only one real root for that expression, the one that nroots gave you.
Note: the answer that solve gives is an exact solution to the cubic equation and it can't figure out definitively which ones are a solution to the equation so it returns all three. If you evaluate them you will find that only one of them is real. But since you don't need the symbolic solution, just stick to nroots.

Modular inverse of a function in sympy

For a certain project, I'm using sympy to calculate expressions modulo another function. These functions all have binary coefficients (so x^2 + 2x = x^2$). Their application is in Galois Fields.
My issue is that when using the the sympy rem function with inverses (for example x**-1), is simply returns the inverse of the number (so in this case the answer is 1/x) rather than returning the modular inverse.
Due to the below comment, here is some further clarification. An oversimplified version of what I'm doing is:
from sympy import *
x = symbols('x')
f = raw_input() #here f = '(x^3 + x)*(x + 1)^2 + (x^2 + x)/(x^3) + (x)^-1'
expand(f)
>>> x**5 + 2*x**4 + 2*x**3 + 2*x**2 + x + 2/x + x**(-2)
#this is what I'm currently doing
rem(expand('(x^3 + x)*(x + 1)^2 + (x^2 + x)/(x^3) + (x)^-1'), 'x^2')
>>> x + 2/x + x**(-2)
#not the answer I am looking for, as I want all the degrees to be positive
This remainder function doesn't act as a mod function (ie doesn't keep things as positive powers of x), and I'm trying to find a replacement for it. I want to avoid parsing through the expression searching for inverse mods and just have the function deal with that on it's own. I might be missing a parameter, or just looking at a completely different function.
PS: I know that the ability to compute an expression mod another expression, while simultaneously treating inverses as modular inverses exists in sympy since I did it while testing that sympy will be enough for our purposes but didn't save the code back then.
First off, it's better to immediately convert your string into a SymPy expression with sympify. Passing strings to SymPy functions is bad practice.
When you use a polynomial like x + 1/x, SymPy treats this as a polynomial in x and 1/x.
In [73]: Poly(x + 1/x)
Out[73]: Poly(x + (1/x), x, 1/x, domain='ZZ')
I believe ratsimpmodprime does what you want. You should also be able to pass domain=GF(2), but it seems there are some bugs that prevent that from working.

Integration with sympy

I'm trying to perform the following integration using sympy;
x = Symbol('x')
expr = (x+3)**5
integrate(expr)
The answer that I'm expecting is:
But what's being returned is:
The following code works in MATLAB:
syms x
y = (x+3)^5;
int(y)
I'm unsure what I'm doing wrong in order to perform this using sympy.
This is actually a common problem seen in Calculus where for these kinds of polynomial expressions, you do get two answers. The coefficients for each of the powers of x exist but the constant factor is missing between them.
As such, there are two methods you can use to find the indefinite integral of this expression.
The first method is to perform a substitution where u = x+3, then integrate with respect to u. Then, the indefinite integral would be (1/6)*(x + 3)^6 + C as you expect.
The second method is to fully expand out the polynomial and integrate each term individually.
MATLAB elects to find the integral the first way:
>> syms x;
>> out = int((x+3)^5)
out =
(x + 3)^6/6
Something to note for later is that if we expand out this polynomial expression, we get:
>> expand(out)
ans =
x^6/6 + 3*x^5 + (45*x^4)/2 + 90*x^3 + (405*x^2)/2 + 243*x + 243/2
sympy elects to find the integral the second way:
In [20]: from sympy import *
In [21]: x = sym.Symbol('x')
In [22]: expr = (x+3)**5
In [23]: integrate(expr)
Out[23]: x**6/6 + 3*x**5 + 45*x**4/2 + 90*x**3 + 405*x**2/2 + 243*x
You'll notice that the answer is the same between both environments, but the constant factor is missing. Because the constant factor is missing, there is no neat way to factor this into the neat polynomial that you are expecting from your output seen in MATLAB.
As a final note, if you would like to reproduce what sympy generates, expand out the polynomial, then integrate. We get what sympy generates:
>> syms x;
>> out = expand((x+3)^5)
out =
x^5 + 15*x^4 + 90*x^3 + 270*x^2 + 405*x + 243
>> int(out)
ans =
x^6/6 + 3*x^5 + (45*x^4)/2 + 90*x^3 + (405*x^2)/2 + 243*x
The constant factor though shouldn't worry you. In the end, what you are mostly concerned with is a definite integral, and so the subtraction of these constant factors will happen, which won't affect the final result.
Side Note
Thanks to DSM, if you specify the manual=True flag for integrate, this will attempt to mimic performing integration by hand, which will give you the answer you're expecting:
In [26]: from sympy import *
In [27]: x = sym.Symbol('x')
In [28]: expr = (x+3)**5
In [29]: integrate(expr, manual=True)
Out[29]: (x + 3)**6/6

Symbolic conditional sum

Is there a way to calculate, or at least state properly, a symbolic sum which iterates over a sequence conditionally?
For example, if a(n) is a sequence (of reals) and c(n) is a "condition" (boolean function defined on the integers), then I wish to compute, or at least state, the sum over all a(n)'s for which c(n).
Formally, I'd like to do something like this:
n = Symbol('n', integer=True, positive=True)
a = 1 / n**2
c = Eq(n%3, 1)
## s = Sum(a, (n, 0, oo), condition=c)
So s should be the following sum:
1/1 + 1/16 + 1/49 + 1/100 + 1/169 + ...
Of course, in this case I can define s manually, but I wonder whether I can do it automatically somehow.
Edit:
By manually I mean
Sum(1/(3*n+1)**2, (n, 0, oo))
This can be evaluated (and it is about 1.12173301393634).
An attempt I've made (which failed) is as follows:
Sum(Eq(n%3, 1) * (1/n**2), (n, 0, oo))
Trying to evaluate this using .evalf() resulted
AttributeError: 'BooleanFalse' object has no attribute '_eval_evalf'
Edit (2):
Here's another attempt, which yields a wrong result:
p = Piecewise((1/(n**2), Eq(n%3, 1)), (0, True))
Sum(p, (n, 0, oo)).evalf()
## returns 1.00000000000000
Either I've done something wrong, or this is a sympy bug.
Using a Piecewise is definitely the correct way to do this. The wrong result is a bug in SymPy, which you should report at https://github.com/sympy/sympy/issues/new. Your second method won't work because in SymPy booleans are not implicitly integers (True and False are not 1 and 0).
Or avoid piecewise by defining your function as 1/(3*n+1)**2
>>> Sum((3*n + 1)**(-2), (n, 0, oo))
Sum((3*n + 1)**(-2), (n, 0, oo))
>>> print filldedent(_.doit())
exp(-4*I*pi/3)*polylog(2, exp_polar(4*I*pi/3))/3 + pi**2/18 +
exp(-2*I*pi/3)*polylog(2, exp_polar(2*I*pi/3))/3
>>> Sum((3*n + 1)**(-2), (n, 0, oo)).n()
1.12173301393634
You can see that the remapping works by using Symbol-trickery. e.g. the 1st 6 terms:
>>> Add(*[(1/n).subs(n,Symbol(str((3*i+1)**2))) for i in range(5)])
1/49 + 1/169 + 1/16 + 1/100 + 1/1
If it's a linear sequence then you could use Integal's transform method to do the transformation for you:
>>> i=Integral(1/x**2,(x,1,oo))
>>> i.transform(x,3*x - 2)
Integral(3/(3*x - 2)**2, (x, 1, oo))
>>> (Sum(*_.args)/3).n(3) # divide by 3 to handle renorm
1.12

Categories

Resources