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

Question:

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:

  1. Simplify (x - 1) // 2 - (x - 1) / 2. Turns out to be 0.
  2. Multiply the whole thing by 2: 2 * (x // 2 - (x - 1) / 2). Gives me: -x + 2*floor(x/2) + 1.
  3. Try to put more weights on the FLOOR op by customizing the measure. No luck.
  4. Use sympy.core.evaluate(False) context when creating the expression. Nuh.
  5. 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?

Asked By: Scott Chang

||

Answers:

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.

Answered By: chrslg

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
Answered By: smichr
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.