2

I'm using Sympy to evaluate symbolic expressions provided by users, but the division operator isn't behaving like any other mathematical operator. When evaluating an expression on objects with overridden operators, I get the expected result for addition, subtraction, and multiplication, but not division. The code below illustrates my problem:

import sympy
import numpy

class NewMath(int):

    def __add__(self, other):
        print "Adding!"
        return

    def __sub__(self, other):
        print "Subtracting!"
        return

    def __mul__(self, other):
        print "Multiplying!"
        return

    def __div__(self, other):
        print "Dividing!"
        return

three = NewMath(3)
four = NewMath(4)

three + four
three - four
three * four
three / four

# Override sympys default math
func_map = {'+':NewMath.__add__,
            '/':NewMath.__div__}

lambda_args = [sympy.Symbol(arg) for arg in ['three', 'four']]

print "Now sympy math:"
lambda_addition = sympy.lambdify(lambda_args, sympy.Symbol('three') + sympy.Symbol('four'), modules=func_map)
lambda_addition(three, four)

lambda_subtraction = sympy.lambdify(lambda_args, sympy.Symbol('three')  - sympy.Symbol('four'), modules=func_map)
lambda_subtraction(three, four)

lambda_multiplucation = sympy.lambdify(lambda_args, sympy.Symbol('three')  * sympy.Symbol('four'), modules=func_map)
lambda_multiplucation(three, four)

lambda_division = sympy.lambdify(lambda_args, sympy.Symbol('three')  / sympy.Symbol('four'), modules=func_map)
lambda_division(three, four)

The output:

Adding!
Subtracting!
Multiplying!
Dividing!
Now sympy math:
Adding!
Subtracting!
Multiplying!
0.75

I've read the Sympy Docs and seen that the / operator is a common gotcha, but the docs just seem to indicate that division will default to integer division, I can't see anything that indicates / can't be overridden. You can see in my example I even attempted to use the modules argument to manually replace division with my custom operator, to no avail.

I've also seen that division in sympy is really just a power of -1 and multiplication, does this mean my cause is hopeless?

I'm using python 2.7 and sympy 1.0

Kyle Heuton
  • 9,318
  • 4
  • 40
  • 52
  • If you have `from __future__ import division` in your code (which I recommend for Python 2), you will need to override `__truediv__` instead of `__div__`. – asmeurer Aug 05 '16 at 16:38
  • 1
    Your `func_map` isn't doing anything. The function map only works to map Python names to other Python names (i.e., it defines variables in the namespace where the lambdified function is executed). `+` and `/` are operators, not names, so this doesn't work. – asmeurer Aug 05 '16 at 16:39

1 Answers1

0

Your cause is certainly not completely hopeless. Here are a few options to get you started.

First off, it seems as if you understand the difference between \__div__ \__truediv__ and \__floordiv__ but if you didn't already, here is some python 2.7 documentation for them.

In python 2.7, overriding \__div__ seems like it should do what you want, except for that sympy documentation you found about a/b being evaluated as a * b^(-1). To get around that, you could also override the exponentiation operator.

I tried running your code in my python3 environment, changing all instances of print so they have parentheses and replacing all instances of div with truediv.

This isn't really a complete answer, but I can't post comments, so this is what you get!

Dadep
  • 2,796
  • 5
  • 27
  • 40
asky
  • 1,520
  • 12
  • 20