Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Implementing symbolic get args method #2396

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

anutosh491
Copy link
Collaborator

Trying to execute something like this

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

def main0():
    x: S = Symbol("x")
    y: S = x**pi
    z: list[S] = y.args
    print(z[0], z[1])

@anutosh491
Copy link
Collaborator Author

I'm not fully sure how we design this through the pass. As in we would have the following

  1. After creating of an expression let's say z, we would need to extract the arguments using basic_get_args. That would be done using
    args: CPtr = vecbasic_new()
    basic_get_args(z, args)
  1. Now we would like to end up with a list of type CPtr correct ? For that we would have to transfer all elements from the args (CPtr) variable we have to the list we would like to return. I'm thinking of how we could appraoch this. What comes across my mind is
    i) Extract the number of elements vecbasic_size
    ii) Run a for loop. Each time define a local temp variable temp1
    iii) Store the argument in the temporary variable using vecbasic_get for eg vecbasic_get(args, 0, ele1)
    iv) Define a temporary list which we would need and keep appending in the list after we pass. Return the list after the for loop ends.

Do you know of anything else we could do @certik ?

@anutosh491
Copy link
Collaborator Author

BTW this is the design for the 2nd approach we were discussing here (#2393 (comment))

The first design won't look too different.
In that case we are not returning a list[CPtr] but a CPtr variable only and as we would have the nth index which we would like to extract, it would be something as follows

  1. After creating of an expression let's say z, we would need to extract the arguments using basic_get_args. That would be done using
    args: CPtr = vecbasic_new()
    basic_get_args(z, args)

i) Now we might need a check if the argument index isn't out of bounds so we could use vecbasic_size to check
ii) If it is in bounds, we could create a temporary variable, tmp and run vecbasic_get(args, n, tmp)
iii) Return this tmp variable !

We could maybe choose what suits us better here !

@certik
Copy link
Contributor

certik commented Oct 26, 2023

I think indeed you need to convert the vec_basic from SymEngine into list[S]. Yes, doing the loop is the way to do it.

Once you have list[S], then you get everything else for free.

@anutosh491
Copy link
Collaborator Author

Actually I see something strange when I was writing the code for this. Consider the following. We have x**y and we are extracting its arguments. For now the program tries to get the 0th index from the args list

def main0():
    _x: i64 = i64(0)
    x: CPtr = empty_c_void_p()
    p_c_pointer(pointer(_x, i64), x)
    basic_new_stack(x)
    symbol_set(x, "x")
    _y: i64 = i64(0)
    y: CPtr = empty_c_void_p()
    p_c_pointer(pointer(_y, i64), y)
    basic_new_stack(y)
    symbol_set(y, "y")
    _z: i64 = i64(0)
    z: CPtr = empty_c_void_p()
    p_c_pointer(pointer(_z, i64), z)
    basic_new_stack(z)
    basic_pow(z, x, y)
    args: CPtr = vecbasic_new()
    basic_get_args(z, args)
    _ele: i64 = i64(0)
    ele: CPtr = empty_c_void_p()
    p_c_pointer(pointer(_ele, i64), ele)
    basic_new_stack(ele)
    tmp_list : list[CPtr] = []
    vecbasic_get(args, 0, ele)
    print(basic_str(ele))
    tmp_list.append(ele)
    vecbasic_get(args, 1, ele)
    print(basic_str(ele))
    tmp_list.append(ele)
    print(basic_str(tmp_list[0]))

main0()
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=c integration_tests/symbolics_08.py 
x
y
y

Why do I get y as the output for print(basic_str(tmp_list[0])) ? Shouldn't it be x

@anutosh491
Copy link
Collaborator Author

anutosh491 commented Oct 27, 2023

Okay If I just add one line to the above block

    tmp_list : list[CPtr] = []
    vecbasic_get(args, 0, ele1)
    print(basic_str(ele1))
    tmp_list.append(ele1)
+   print(basic_str(tmp_list[0]))
    vecbasic_get(args, 1, ele1)
    print(basic_str(ele1))
    tmp_list.append(ele1)
    print(basic_str(tmp_list[0]))

I get

(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=c integration_tests/symbolics_08.py 
x
x
y
y

The second x here is due to the new line. So once print(basic_str(tmp_list[0])) gives x and the later it gives y

EDIT:
I think each index needs it's own temporary variable ?!

    tmp_list : list[CPtr] = []
    vecbasic_get(args, 0, ele1)
    print(basic_str(ele1))
    tmp_list.append(ele1)
    print(basic_str(tmp_list[0]))
    vecbasic_get(args, 1, ele2)
    print(basic_str(ele2))
    tmp_list.append(ele2)
    print(basic_str(tmp_list[0]))
(lf) anutosh491@spbhat68:~/lpython/lpython$ lpython --enable-symengine --backend=c integration_tests/symbolics_08.py 
x
x
y
x

@certik
Copy link
Contributor

certik commented Oct 27, 2023

I think a slow but hopefully straightforward way to implement print(e.args[0], e.args[1]) is to generate a new list for each call to args. Once this fully works, this can be upgraded to reuse the list whenever possible.

@anutosh491
Copy link
Collaborator Author

I'm actually pretty confused at this point . Let's say our expression is (x**y) and we have the following

    args: CPtr = vecbasic_new()
    basic_get_args(x, args)
    _ele1: i64 = i64(0)
    ele1: CPtr = empty_c_void_p()
    p_c_pointer(pointer(_ele1, i64), ele1)
    i: i32 = 0
    tmp_list: list[CPtr] = []
    for i in range(vecbasic_size(args)):
        vecbasic_get(args, i, ele1)
        tmp_list.append(ele1)
        print(basic_str(tmp_list[i]))
        basic_const_zero(ele1)
    print(basic_str(tmp_list[0]))

The output

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

I am quite clueless as to how we get this output. We are printing the elements of the list through print(basic_str(tmp_list[i])) and then we get the correct output and just to nullify everything I am using basic_const_zero(ele1). But then after the loop if we use print(basic_str(tmp_list[0])) we get 0 which is pretty strange.

@anutosh491
Copy link
Collaborator Author

I think a slow but hopefully straightforward way to implement print(e.args[0], e.args[1]) is to generate a new list for each call to args. Once this fully works, this can be upgraded to reuse the list whenever possible.

I guess this would be more supportive of the first design which we were talking about (where our SymbolicGetArguments takes in the symbolic expression and the integer). As far as the current design is concerned we never really use e.args[0]. I think what we discussed what to first extract everything into a list (list[S]) and then only use extraction from the list to move forward.

@anutosh491
Copy link
Collaborator Author

I've created a draft PR through design 1 too #2399 . I think it's a more simpler and accessible approach than this one. We can choose if we prefer a method over the other.

@anutosh491
Copy link
Collaborator Author

Closing as we have an implementation for extracting args for now. (Can be opened if we plan on changing the design later)

@anutosh491 anutosh491 closed this Nov 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants