lcompilers / lpython

Python compiler
https://lpython.org/
Other
1.47k stars 157 forks source link

Issues while trying to print symbolic expressions #2533

Closed anutosh491 closed 4 months ago

anutosh491 commented 5 months ago

Consider the following minimalistic example

from lpython import S
from sympy import Symbol, log

def mmrv(e: S, x: S) -> list[S]:
    if e == x:
        list1: list[S] = [x]
        return list1
    else:
        list2: list[S] = mmrv(x, x)
        return list2

def test_mrv():
    x: S = Symbol("x")
    ans3: list[S] = mmrv(log(x), x)
    ele2: S = ans3[0]
    print(ele2)

test_mrv()

Mostly this works

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=llvm integration_tests/test_gruntz.py 
x
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=c integration_tests/test_gruntz.py 
x
anutosh491 commented 5 months ago

But if we add some print statements here

def mmrv(e: S, x: S) -> list[S]:
    print(e)
    print(x)
    if e == x:
        list1: list[S] = [x]
        return list1
    else:
        print(e)
        list2: list[S] = mmrv(x, x)
        return list2
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=llvm integration_tests/test_gruntz.py
The stack address was not found in any shared library or the main program, the stack is probably corrupted. Aborting.
The stack address was not found in any shared library or the main program, the stack is probably corrupted. Aborting.
The stack address was not found in any shared library or the main program, the stack is probably corrupted. Aborting.
The stack address was not found in any shared library or the main program, the stack is probably corrupted. Aborting.
The stack address was not found in any shared library or the main program, the stack is probably corrupted. Aborting.
The stack address was not found in any shared library or the main program, the stack is probably corrupted. Aborting.
........

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=c integration_tests/test_gruntz.py 
log(x)
x
0x7ffefd4a7b98
x
x
x

The llvm backend gives an error indefinitely and as shown in the C backend, the 2nd print(e) or the print inside the if blocks isn't executed correctly !

anutosh491 commented 5 months ago

I was able to boil down the reason for this. Conside the following function (symbolics_13.py)

from lpython import S
from sympy import pi

def func() -> S:
    return pi

def test_func():
    z: S = func()
    print(y)

test_func()

Now if we check the ASR for it after the subroutine_from_function call the ReturnVar is update to Out intent and the code is transformed to something like

def func(r: Out[S]) -> None:
    r = pi

So now we have the ASR for this we have

                                        [(=
                                            (Var 3 r)
                                            (IntrinsicScalarFunction
                                                SymbolicPi
                                                []
                                                0
                                                (SymbolicExpression)
                                                ()
                                            )
                                            ()
                                        )]

If you see carefully the return node has been taken care of and we don't have a return node anymore (because obviously the function is not returning anything)

anutosh491 commented 5 months ago

But if you see this function

from lpython import S
from sympy import pi

def func() -> S:
    if True:
        return pi

def test_func():
    z: S = func()
    print(y)

test_func()

We end up with the ASR

                                        [(=
                                            (Var 3 _lpython_return_variable)
                                            (IntrinsicScalarFunction
                                                SymbolicPi
                                                []
                                                0
                                                (SymbolicExpression)
                                                ()
                                            )
                                            ()
                                        )
                                        (Return)]

Now we don't take care of the Return node in this case ( I think we would encounter this if we are using any sort of loop or conditional block like if,while , for) . Now as you can see we don't really need the Return node there and hence we need some code segment that will keep removing the Return Node depth wise I suppose .

So how this relates to my issue is if the return node is present (which shouldn't be) , we enter visit_Return in the symbolic pass and things go wrong from there. @Thirumalai-Shaktivel could you please help me address this

anutosh491 commented 5 months ago

For eg we might have

if x == pi:
    if x != y:
        return x
    else:
        return 2*x
else:
    return 3*x

And if we are using the subroutine_from_function, we would end up with

if x == pi:
    if x != y:
        r = x
    else:
        r = 2*x
else:
    r = 3*x

But we might need a method to get rid of the return nodes overall because we would be having them but we wouldn't be needing them. I can think of something to address this.

certik commented 4 months ago

Yes, the return is not needed there in ASR, however, it also does not hurt (and cannot hurt) to have it there.

It seems there is some issue how the Return statement is handled in the symbolic pass, and it looks like there is a bug with multiple present return statements.

We need to create a good robust design how freeing variables should be handled in the return visitor. Here are three ways:

anutosh491 commented 4 months ago

A much more smaller/simpler example to consider here

from lpython import S
from sympy import Symbol, log

def mmrv(e: S, x: S) -> S:
    print(e)
    if e == x:
        return x
    print(e)
    return e

def test_mrv():
    x: S = Symbol("x")
    ans3: S = mmrv(log(x), x)
    print(ans3)

test_mrv()
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine examples/expr2.py --backend=c 
log(x)
0x7ffcac7b0838
Segmentation fault