A protected division is a normal division but when you divide by 0 it returns a fixed constant (usually 1).
def protected_div(x, y):
if y == 0:
return 1
return x/y
Is there a way to use this as an operator on sympy (For example replacing the standard division)?
Here is an example of what I want:
>>> import sympy as sym
>>> x = sym.Symbol('x')
>>> expr = 1/x #(protected division goes here?)
>>> expr.subs(x, 0)
1
The division has to be protected at evaluation time.
EDIT 1:
What I've tried:
1. Using sym.lambidify with the modules parameter set:
>>> x = sym.Symbol('x')
>>> expr = 1/x
>>> lamb = sym.lambdify(x, expr, modules={'/':protected_div})
>>> print(lamb(0))
ZeroDivisionError: 0.0 cannot be raised to a negative power
This does not work because sympy converts 1/x
to x**(-1)
when lambidifying. I tried overriding the power operator but I don't know the function name. I've tried 'Pow', 'pow', '**' and none worked.
However if i declare the expression as expr = 1.0/x
it actually does not convert to a negative power, however it does not use my custom division function. I think these types of functions are not overridable using the module
parameter.
2. @Zaz suggestion:
class floatsafe(float):
def __truediv__(self, __x):
if __x == 0:
return floatsafe(1)
return super().__truediv__(__x)
x = sym.Symbol('x')
expr = floatsafe(1)/x
print(expr.subs(x, floatsafe(0)))
Returns
zoo
Which is complex infinity.
I tried combining this approach with sym.lambdify
, but the dividend is converted to a float after I lambdify the function.
In the case that the dividend is variable it also does not work:
x = sym.Symbol('x')
expr = x/0.0
a = sym.lambdify(x, expr, modules={'/':floatsafe.__truediv__})
print(inspect.getsource(a))
print(a(floatsafe(0)))
Outputs
def _lambdifygenerated(x):
return nan*x
nan
EDIT: There seems to some confusion around why I'd want that. It's for a genetic programming algorithm using sympy. A protected division is a common operator in GP so that the created solutions are valid.