-
Notifications
You must be signed in to change notification settings - Fork 157
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
Introducing Symbolic Binary operators and i32
to S
Casting function
#1964
Conversation
Once I have an initial review and I get an idea of what sort of tests would be most appropriate here , I'll add few integration tests in this PR . I guess that would be enough for the PR , I will then work towards chaining of operators and introducing a few elementary functions like |
I would say go ahead and add tests for all the new features that you implemented. I also recommend to split PRs into two kinds: "new features but no refactorings" and "refactorings but no new features". That way it's easier to review and see if anything broke. Right now we need a lot more tests to check every corner case. Then we can have more confidence in refactoring that nothing broke. |
I will surely keep this in mind for future work . I will add tests soon . |
I am actually concerned about two things (which could be addressed in subsequent prs or this one ) @certik As we went through Symengine's C wrapper file, most of the functions defined take in basic variable/variables and assign it to another basic variable like
So a program like the following would work because we would have
But something like the following might not because there is no variable to assign the integer to
Well we could have a workaround for this using the following function
where we assign |
Here we might need a dummy variable I guess !? |
This PR looks good, can you please rebase it on top of the latest Yes, I think you need to create a temporary variable when traversing the expression, to be able to handle things like I would also get
To ensure things work (currently we only print it, so if it prints incorrectly, the test would not reveal it). |
Here is how to handle expression evaluation robustly: diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h
index 903ed5eee..cb9cc0d41 100644
--- a/src/libasr/codegen/asr_to_c_cpp.h
+++ b/src/libasr/codegen/asr_to_c_cpp.h
@@ -83,6 +83,34 @@ struct CPPDeclarationOptions: public DeclarationOptions {
}
};
+class SymEngineStack {
+ std::vector<std::string> stack;
+ size_t stack_top = -1;
+ std::string &symengine_src;
+
+ SymEngineStack(std::string symengine_src) : symengine_src{symengine_src} {}
+
+ std::string pop() {
+ LCOMPILERS_ASSERT(stack_pop > 0 && stack_pop < stack.size())
+ std::string top = stack[stack_top];
+ stack_top--;
+ return top;
+ }
+
+ std::string push() {
+ if (stack_top < stack.size()) {
+ // Create a unique name for a symengine variable:
+ std::string var = "stack" + std::to_string(stack.size());
+ stack.push_back(var);
+ symengine_src += "basic " + var + ";";
+ symengine_src += "symengine_basic_new_stack(" + var + ");";
+ }
+ stack_top++;
+ return stack[stack_top];
+ }
+
+}
+
template <class Struct>
class BaseCCPPVisitor : public ASR::BaseVisitor<Struct>
{
@@ -105,6 +133,9 @@ public:
std::map<uint64_t, std::string> const_var_names;
std::map<int32_t, std::string> gotoid2name;
std::map<std::string, std::string> emit_headers;
+ std::string symengine_src;
+ SymEngineStack symengine_stack(symengine_src);
+
// Output configuration:
// Use std::string or char*
@@ -2384,7 +2415,6 @@ R"(#include <stdio.h>
SET_INTRINSIC_NAME(Exp, "exp");
SET_INTRINSIC_NAME(Exp2, "exp2");
SET_INTRINSIC_NAME(Expm1, "expm1");
- SET_INTRINSIC_NAME(SymbolicSymbol, "Symbol");
SET_INTRINSIC_NAME(SymbolicInteger, "Integer");
SET_INTRINSIC_NAME(SymbolicPi, "pi");
case (static_cast<int64_t>(ASRUtils::IntrinsicFunctions::SymbolicAdd)):
@@ -2394,11 +2424,21 @@ R"(#include <stdio.h>
case (static_cast<int64_t>(ASRUtils::IntrinsicFunctions::SymbolicPow)): {
LCOMPILERS_ASSERT(x.n_args == 2);
this->visit_expr(*x.m_args[0]);
- std::string arg1 = src;
this->visit_expr(*x.m_args[1]);
- std::string arg2 = src;
- out = arg1 + "," + arg2;
- src = out;
+ std::string arg2 = symengine_stack.pop()
+ std::string arg1 = symengine_stack.pop()
+ std::string target = symengine_stack.push()
+ symengine_src += "symengine_add(" + target + "," + arg1 + ","
+ + arg2 + ");\n";
+ src = target;
+ break;
+ }
+ SET_INTRINSIC_NAME(SymbolicSymbol, "Symbol"); {
+ LCOMPILERS_ASSERT(x.n_args == 1);
+ this->visit_expr(*x.m_args[0]);
+ std::string target = symengine_stack.push()
+ symengine_src += "symengine_symbol(" + target + "," + src + ");\n";
+ src = target;
break;
}
default : { There are two issues to fix:
The first issue is fixed by: --- a/src/libasr/codegen/asr_to_c.cpp
+++ b/src/libasr/codegen/asr_to_c.cpp
@@ -1233,6 +1233,10 @@ R"( // Initialise Numpy
for (size_t i=0; i<x.n_values; i++) {
this->visit_expr(*x.m_values[i]);
ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_values[i]);
+ if (value_type->type == ASR::ttypeType::SymbolicExpression) {
+ out += symengine_src;
+ symengine_src = "";
+ }
if( ASRUtils::is_array(value_type) ) {
src += "->data";
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that this looks good as is. Thanks!
I'm seeing a rather queue based implementation , I'll try my best to break my thinking down for you . Let's try to solve this program
The C generated code for this should be
I'll discuss the logic in the comment below . |
Let's think for a while that we are using a container and not a stack .
By the end of this our container would have
We would need the first two elements of the container
iV) Finally we push
So basically we are splitting |
I do think this would work , I'll give it a shot and get back to you . As of now , I am seeing positive results . |
@anutosh491 go ahead and see if this works. Make sure you also test a case like |
Yes, I tried these complex cases out (which are nested with brackets like the ones you've mentioned above).
I just have a minute doubt that I'll point out on the pr but other I feel the approach is good . I'll raise a pr soon ! |
Ahh! Adding symbolics to LPython already! 🚀 |
@namannimmo10 absolutely. We are tying up all loose ends, this addition makes LPython complete in terms of scope and I think it will be a big hit for SymPy. |
That's awesome! I would love to see LPython supporting both numerics and symbolics with fast compilation. Would be incredible to use over the years! |
Yes, good idea. I opened up an issue for this: #2075, if you have some CuPy code that you could share, that would be great. |
Adding support for compiling CuPy code would be awesome @namannimmo10 |
Towards #1907 and #1846 (comment)
What all has been addressed
SymbolicAdd
namespace was removed and macro for supporting all symbolic binary operators was introduced.S()
casting function was introduced .A random example would be