Week 4

If y’all do recollect where we left off last week, I was working towards introducing symbolic binary operators. I had just introduced SymbolicAdd as an intrinsic function to add two symbolic expressions. Now I had to get it working with the ASR and the C backend . Well, I was able to get this running successfully. Along with this I thought that adding a symbolic constant would also make sense at this stage, hence I ended up introducing the pi constant.

Demonstrating a working example which we also ended up adding as an integration test

from sympy import Symbol, pi
from lpython import S

def main0():
    x: S = Symbol('x')
    y: S = Symbol('y')
    x = pi
    z: S = x + y
    print(z)

main0()

# The relevant parts from the ASR
[(=
    (Var 2 x)
    (IntrinsicFunction
        SymbolicSymbol
        [(StringConstant
            "x"
            (Character 1 1 ())
        )]
        0
        (SymbolicExpression)
        ()
    )
    ()
)
(=
    (Var 2 y)
    (IntrinsicFunction
        SymbolicSymbol
        [(StringConstant
            "y"
            (Character 1 1 ())
        )]
        0
        (SymbolicExpression)
        ()
    )
    ()
)
(=
    (Var 2 x)
    (IntrinsicFunction
        SymbolicPi
        []
        0
        (SymbolicExpression)
        ()
    )
    ()
)
(=
    (Var 2 z)
    (IntrinsicFunction
        SymbolicAdd
        [(Var 2 x)
        (Var 2 y)]
        0
        (SymbolicExpression)
        ()
    )
    ()
)
(Print
    ()
    [(Var 2 z)]
    ()
    ()
)]

# The relevant parts from the generated C code
// Implementations
void main0()
{
    basic x;
    basic_new_stack(x);
    basic y;
    basic_new_stack(y);
    basic z;
    basic_new_stack(z);
    symbol_set(x, "x");
    symbol_set(y, "y");
    basic_const_pi(x);
    basic_add(z, x, y);
    printf("%s\n", basic_str(z));
}

void _lpython_main_program()
{
    main0();
}

# The result through LPython and linking SymEngine
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --backend=c --enable-symengine examples/expr2.py 
y + pi

This was followed by the weekly meet scheduled with my mentor, Ondřej. He essentially guided me on the linking process for SymEngine and how we could produce an output through LPython. He also gave me a bunch of ToDo’s to work on. Some of which were the following:

  • Introduce an option named --enable-symengine and add it to CompilerOptions . This option essentially signifies the compiler to enable symengine at runtime which by default would be false.
  • Add a dedicated new GitHub Action test for sympy. Here we would be installing sympy and symengine into the conda environment and we would be using this action to test out all integration tests that deal with symbolic stuff.
  • Add support for two new backends.
    • cpython_sym : A Cpython test that uses sympy.
    • c_sym : A C test with symengine included.

I would also like to highlight some benchmarks . These were pointed out by Ondřej on my pull request #1846.

# 1 SymPy:
$ time PYTHONPATH=src/runtime/lpython python integration_tests/symbolics_01.py
y + pi
PYTHONPATH=src/runtime/lpython python integration_tests/symbolics_01.py  0.16s user 0.03s system 97% cpu 0.187 total

# 2 LPython+SymEngine via the C backend:
$ time lpython --backend=c --enable-symengine integration_tests/symbolics_01.py
y + pi
lpython --backend=c --enable-symengine integration_tests/symbolics_01.py  0.08s user 0.02s system 92% cpu 0.104 total

# 3 Excluding compilation and just running the binary:
$ time ./symbolics_01.out
y + pi
./symbolics_01.out  0.00s user 0.01s system 74% cpu 0.013 total

These results look great to get started with. We can clearly exactly the same source code is faster to compile and run via LPython than it is to run via CPython + SymPy.

Finally, as Ondřej and I discussed during our meeting, we decided to start working on some numeric stuff too. He opened up an issue for addressing this 1907. Here we essentially use a casting operation to convert an integer of i32 type to a SymbolicInteger of SymbolicExpression type using the S function call. An example of a program we would like to solve through this would be:

from sympy import Symbol, pi
from lpython import S

def main0():
    x: S = pi
    y: S = Symbol('y')
    z: S = S(45)*S(3)*x + S(45.5)*y
    e: S = S(45) # SymPy Integer
    print(z)

main0()

I was able to get this working. I shared relevant ASR, C code and output for a similar program as a comment on the issue. I work continue to polish the work here once my first pull request gets merged.

I would now like to point out some tasks which I plan to tackle for the upcoming week.

  • Finish any minor tasks left on my first pr and get it merged.
  • Open up a second pr to address the casting operation and introduce a few more symbolic operators.
  • Introduce a couple elementary functions like abs and sin.

Thank You for going through the blog. I hope you like it. Stick around for what’s next to come. Moving into Week 5!

Address

Mumbai, Maharashtra, India