1

I am trying to remap And in sympy when using lambdify, but it seems not working...

import sympy
x, y = sympy.symbols('x y')
f = sympy.And(x, y)


def my_and(x, y):
    print("inside my_and")
    return x and y

f_fn = sympy.lambdify([x, y], f, {"And": my_and})
print(f_fn(True, False))

The result will not display "inside my_and", which means that my_and doesn't work. Other functions like sin work well as follows. I don't where it goes wrong...

import sympy
x = sympy.symbols('x')
f = sympy.sin(x)


def my_sin(x):
    print("inside my_sin")
    return 0.


f_fn = sympy.lambdify([x], f, {"sin": my_sin})
print(f_fn(0.))

This one will output exactly inside my_sin and 0.

I want to remap And to my function, so what sould I do?

DustDuck
  • 11
  • 1

1 Answers1

0

help(f_fn) for sin example shows:

Help on function _lambdifygenerated:

_lambdifygenerated(x)
    Created with lambdify. Signature:
    
    func(x)
    
    Expression:
    
    sin(x)
    
    Source code:
    
    def _lambdifygenerated(x):
        return sin(x)
    

and after poking around as bit I found the mapping is defined the __globals__ of this function:

In [224]: f_fn.__globals__.keys()
Out[224]: dict_keys(['sin', 'x', 'builtins', 'range', '__builtins__'])

In [225]: f_fn.__globals__['sin']
Out[225]: <function __main__.my_sin(x)>

The help for your 'and' example:

Help on function _lambdifygenerated:

_lambdifygenerated(x, y)
    Created with lambdify. Signature:
    
    func(x, y)
    
    Expression:
    
    x & y
    
    Source code:
    
    def _lambdifygenerated(x, y):
        return x and y

while there's a similar mapping:

In [229]: f_and.__globals__.keys()
Out[229]: dict_keys(['and', 'y', 'x', 'builtins', 'range', '__builtins__'])

In [230]: f_and.__globals__['and']
Out[230]: <function __main__.my_and(x, y)>

but I think this doesn't work because, and in x and y is a Python keyword, in an operator role, not a function. It can't be mapped to something else.

It's the normal short-circuited and of Python:

In [231]: f_and(False,'foo')
Out[231]: False

In [232]: f_and(True,'foo')
Out[232]: 'foo'

In [240]: f_and(x>0,y)
...
TypeError: cannot determine truth value of Relational

Just realized I used and, while you used And:

In [241]: f_and = lambdify([x,y],f,{"And": my_and})

    def _lambdifygenerated(x, y):
        return x and y

In [242]: f_and.__globals__.keys()
Out[242]: dict_keys(['And', 'y', 'x', 'builtins', 'range', '__builtins__'])

In [243]: f_and.__globals__['And']
Out[243]: <function __main__.my_and(x, y)>

There's even less of a connection between the mapping and function.

Mappings like {"And": my_and} don't affect the code translation directly. That is they don't produce

def foo(x,y):
   return my_and(x,y)   # if my_sin(x)

rather they determine how the Python code is run.


If I omit the mapping

f_and1 = lambdify([x,y], f)

the code is

def _lambdifygenerated(x,y):
        return logical_and.reduce((x,y))

f_and1.__globals__ gives a whole raft of numpy functions, including

In [254]: f_and1.__globals__['logical_and']
Out[254]: <ufunc 'logical_and'>

and the behavior is numpy wise:

In [261]: f_and1([True,True],[True,False])
Out[261]: array([ True, False])

lambdify([x,y],f,[{"And": my_and},'numpy']) also gives me the logical_and translation.

hpaulj
  • 221,503
  • 14
  • 230
  • 353