Week 6

Before starting the blog, I would like to ask if y’all remember what I was struggling with last week? I’ll recap it for y’all. So I was basically struggling to add support for chaining of symbolic operators and executing print statements without assignment statements. Well, this was because we had to think of a correct framework, that could provide us with a dummy or a temporary variable which could be declared and used to generate C code from the backend.

I spent the first 2 days thinking about the approach and ended up implementing a SymEngineQueue structure that would

  • Either use up the first element of the queue, if the queue wasn’t empty.
  • Or create a unique dummy variable, push it into the queue and use it up if the queue was empty.

I came up the following Pr #2051 after doing a good amount of careful testing and got it reviewd by Ondřej in our weekly meeting. I give him an overview of the approach I had designed and he ended up merging the Pr. So we could essentially acheive the following now

(lf) anutosh491@spbhat68:~/lpython/lpython$ cat examples/expr2.py 
from sympy import pi
def main0():
    print(pi + pi)

main0()

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --show-c examples/expr2.py 

// Implementations
void main0()
{
    basic queue0;
    basic_new_stack(queue0);
    basic queue1;
    basic_new_stack(queue1);
    basic_const_pi(queue1);
    basic queue2;
    basic_new_stack(queue2);
    basic_const_pi(queue2);
    basic_add(queue0, queue1, queue2);
    printf("%s\n", basic_str(queue0));
}

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --backend=c --enable-symengine examples/expr2.py 
2*pi

A more complex program demonstrating chaining of operators would look like the following

(lf) anutosh491@spbhat68:~/lpython/lpython$ cat examples/expr2.py 
from sympy import Symbol, pi
def main0():
    x: S = Symbol('x')
    y: S = Symbol('y')
    z: S = (x - S(20)) * (pi + y + S(40))
    x = z
    y = x
    z = y + pi
    print(z)

main0()

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --backend=c --enable-symengine examples/expr2.py 
(-20 + x)*(40 + y + pi) + pi

Once the above Pr was merged, the next few things which were to be addressed were the following

  • Adding support for assert statements - As of then, we only had the print utility in place, so we could only print out things but the LPython compiler lacked any functionality to compare if two symbolic expressions were equal or not.This was handled by introducing a SymbolicCompare node in the ASR. I had raised a Pr for this #2057 which ended up getting merged the next day itself.
  • Freeing basic variables defined in the generated C code - It was the correct time to address this as it would be a good practice if we could free up any stack space that was being consumed by the basic variables that would be defined in our generated C code. I had raised a Pr for this #2064 which also ended up getting merged the next day itself.

So now that we could use assert statements and also free up defined basic variables, we had the following

(lf) anutosh491@spbhat68:~/lpython/lpython$ cat examples/expr2.py 
from sympy import Symbol, pi
from lpython import S

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

main0()

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --show-c examples/expr2.py 
// Implementations
void main0()
{
    basic x;
    basic_new_stack(x);
    basic y;
    basic_new_stack(y);
    basic z;
    basic_new_stack(z);
    basic_const_pi(x);
    symbol_set(y, "y");
    basic_add(z, x, y);
    basic queue6;
    basic_new_stack(queue6);
    basic queue7;
    basic_new_stack(queue7);
    basic_const_pi(queue7);
    basic_add(queue6, queue7, y);
    ASSERT(basic_eq(z, queue6)  ==  1);
    basic_free_stack(queue6);
    basic_free_stack(z);
    basic_free_stack(queue7);
    basic_free_stack(y);
    basic_free_stack(x);
}

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --backend=c --enable-symengine examples/expr2.py

Lastly, I also ended up raising a Pr to handle symbolic operations like expansion and differentiation. The Pr for that can be found here #2077. Is is still under review but we can accomplish the following through it.

(lf) anutosh491@spbhat68:~/lpython/lpython$ cat examples/expr2.py 
from sympy import Symbol, expand

def main0():
    x: S = Symbol('x')
    y: S = Symbol('y')
    z: S = (x + y)**S(3)
    print(z.expand())
    print(expand((x + y)**S(4)))

main0()

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --backend=c --enable-symengine examples/expr2.py 
3*x*y**2 + 3*x**2*y + x**3 + y**3
4*x*y**3 + 6*x**2*y**2 + 4*x**3*y + x**4 + y**4

Overall it was a good week for me as I was able to get 3 Prs merged. Talking about my plans for the next week.

  • Get the above pull request reviewed and merged.
  • Introduce a couple elementary functions like abs and sin.
  • Maybe start adding some support through the LLVM backend.

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

Address

Mumbai, Maharashtra, India