Any way to do integer division in sympy?

放肆的年华 提交于 2019-12-08 16:37:23

问题


I have a very long expression that I think can be simplified, and I thought sympy would be the perfect way to do it. Unfortunately the formula relies on a couple of integer divides, and I can't find any way to represent those in sympy.

>>> x=Symbol('x')
>>> (x+1)/2
x/2 + 1/2

Clearly not what I want, 1/2 isn't an integer.

>>> (x+1)//2
TypeError: unsupported operand type(s) for //: 'Add' and 'int'

Obviously sympy doesn't handle //.

>>> Integer((x+1)/2)
#   A long list of error messages, ending with ...
TypeError: Integer can only work with integer expressions.

It seems that Integer is only intended to work on constant numbers, not formulas.

There's a function trunc but it doesn't seem to do anything similar to what I want.

Is there any way to represent an integer division in sympy?


回答1:


Criteria

I assume that you want a function div that passes the following tests:

from sympy import sympify, simplify, Symbol

def test_div(div):
    # check that div behaves as intended for integers
    for i in range(-5,5):
        for j in range(-5,5):
            if j==0: continue
            assert i//j == div(sympify(i),sympify(j))

    # check that div’s output can be simplified
    x = Symbol("x", integer=True)
    assert simplify( div(x+1,2) - div(x-1,2) ) == 1

Modulo

You can realise an integer division using the modulo operator as follows:

div = lambda x,y: (x-x%y)/y

As SymPy supports modulo arithmetics and is capable of simplifying it, this function passes the above tests. However, if no full simplification is possible, you will end up with modulo expressions that may be undesired.

Floor

As already mentioned in the comments, SymPy provides a floor function, which could be used to acquire an integer division as (which is also how the // operator for expressions is implemented):

div = lambda x,y: sympy.floor(x/y)

However, floor does not support simplifications and therefore fails the second test.




回答2:


Creating a Piecewise function might be the way to go. It will respond to simplification request and will hold the varieties of solutions possible depending on the modulus of the argument relative to the integer by which you are dividing. Using piecewise_flatten on an expression in which there are multiple integer divisions will likely be necessary to collapse everything together.

def idiv(n, d):
  from sympy.core.compatibility import as_int
  d = as_int(d); assert d > 0
  args = []
  for i in range(d):
    N = n - i
    args.append((N/d, Eq(Mod(N, d), i)))
  args[-1] = (args[-1][0], True)
  return Piecewise(*args)

For example,

>>> print(factor_terms(idiv(x+1,3)))
Piecewise(
((x + 1)/3, Eq(Mod(x + 1, 3), 0)), 
(x/3, Eq(Mod(x, 3), 1)), 
((x - 1)/3, True))


来源:https://stackoverflow.com/questions/43796658/any-way-to-do-integer-division-in-sympy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!