diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index b8566d27ae..745107110b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -333,3 +333,47 @@ jobs: run: | cd integration_tests ./run_tests.py -b cpython_py c_py + + sympy: + name: Run SymPy tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - uses: mamba-org/setup-micromamba@v1 + with: + environment-file: ci/environment.yml + create-args: >- + python=3.10 + bison=3.4 + symengine=0.9.0 + sympy=1.11.1 + + - uses: hendrikmuhs/ccache-action@main + with: + key: ${{ github.job }}-${{ matrix.os }} + + - name: Build + shell: bash -l {0} + run: | + ./build0.sh + cmake . -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Debug \ + -DWITH_LLVM=yes \ + -DLPYTHON_BUILD_ALL=yes \ + -DWITH_STACKTRACE=no \ + -DWITH_RUNTIME_STACKTRACE=no \ + -DCMAKE_PREFIX_PATH="$CONDA_PREFIX" \ + -DCMAKE_INSTALL_PREFIX=`pwd`/inst \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache + + cmake --build . -j16 --target install + + - name: Test + shell: bash -l {0} + run: | + cd integration_tests + ./run_tests.py -b c_sym cpython_sym diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 4b2e730a7b..0f855a7e20 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -140,7 +140,31 @@ macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_ENABLE_CPYTHON RUN if (${fail}) set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) endif() - elseif((KIND STREQUAL "cpython") OR (KIND STREQUAL "cpython_py")) + elseif(KIND STREQUAL "c_sym") + add_custom_command( + OUTPUT ${name}.c + COMMAND ${LPYTHON} ${extra_args} --show-c + ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py > ${name}.c + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py + VERBATIM) + add_executable(${name} ${name}.c ${extra_files}) + target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR} + "${Python_INCLUDE_DIRS}/..") + set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C) + if (APPLE) + set(SYMENGINE_LIB "${Python_LIBRARY_DIRS}/libsymengine.dylib") + else() + set(SYMENGINE_LIB "${Python_LIBRARY_DIRS}/libsymengine.so") + endif() + target_link_libraries(${name} lpython_rtlib ${SYMENGINE_LIB}) + add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name}) + if (labels) + set_tests_properties(${name} PROPERTIES LABELS "${labels}") + endif() + if (${fail}) + set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE) + endif() + elseif((KIND STREQUAL "cpython") OR (KIND STREQUAL "cpython_py") OR (KIND STREQUAL "cpython_sym")) # CPython test if (extra_files) set(PY_MOD "${name}_mod") @@ -267,7 +291,7 @@ macro(RUN) if ((NOT DISABLE_FAST) AND (NOT RUN_NOFAST)) set(RUN_EXTRA_ARGS ${RUN_EXTRA_ARGS} --fast) set(RUN_NAME "${RUN_NAME}_FAST") - list(REMOVE_ITEM RUN_LABELS cpython cpython_py) # remove cpython, cpython_py from --fast test + list(REMOVE_ITEM RUN_LABELS cpython cpython_sym cpython_py) # remove cpython, cpython_sym, cpython_py from --fast test RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_ENABLE_CPYTHON RUN_EXTRAFILES RUN_EXTRA_ARGS) endif() endmacro(RUN) @@ -552,6 +576,9 @@ RUN(NAME structs_24 LABELS cpython llvm c) RUN(NAME structs_25 LABELS cpython llvm c) RUN(NAME structs_26 LABELS cpython llvm c) RUN(NAME structs_27 LABELS cpython llvm c) + +RUN(NAME symbolics_01 LABELS cpython_sym c_sym) + RUN(NAME sizeof_01 LABELS llvm c EXTRAFILES sizeof_01b.c) RUN(NAME sizeof_02 LABELS cpython llvm c) diff --git a/integration_tests/run_tests.py b/integration_tests/run_tests.py index e312dd37e7..f2ea5c310f 100755 --- a/integration_tests/run_tests.py +++ b/integration_tests/run_tests.py @@ -6,7 +6,7 @@ # Initialization DEFAULT_THREADS_TO_USE = 8 # default no of threads is 8 -SUPPORTED_BACKENDS = ['llvm', 'c', 'wasm', 'cpython', 'x86', 'wasm_x86', 'wasm_x64', 'c_py', 'cpython_py'] +SUPPORTED_BACKENDS = ['llvm', 'c', 'wasm', 'cpython', 'x86', 'wasm_x86', 'wasm_x64', 'c_py', 'cpython_py', 'c_sym', 'cpython_sym'] BASE_DIR = os.path.dirname(os.path.realpath(__file__)) LPYTHON_PATH = f"{BASE_DIR}/../src/bin" diff --git a/integration_tests/symbolics_01.py b/integration_tests/symbolics_01.py new file mode 100644 index 0000000000..9c1a0e9096 --- /dev/null +++ b/integration_tests/symbolics_01.py @@ -0,0 +1,11 @@ +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() \ No newline at end of file diff --git a/src/bin/lpython.cpp b/src/bin/lpython.cpp index 9d7cdc6ac5..a6911403b7 100644 --- a/src/bin/lpython.cpp +++ b/src/bin/lpython.cpp @@ -1244,8 +1244,14 @@ int link_executable(const std::vector &infiles, cmd += s + " "; } cmd += " -I " + rtlib_header_dir; + if (compiler_options.enable_symengine) { + cmd += " -I${CONDA_PREFIX}/include"; + } cmd += " -L" + base_path + " -Wl,-rpath," + base_path + " -l" + runtime_lib + " -lm"; + if (compiler_options.enable_symengine) { + cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine"; + } if (compiler_options.enable_cpython) { std::string py_version = "3.10"; std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()"; @@ -1565,6 +1571,7 @@ int main(int argc, char *argv[]) app.add_flag("--get-rtl-dir", print_rtl_dir, "Print the path to the runtime library file"); app.add_flag("--verbose", compiler_options.verbose, "Print debugging statements"); app.add_flag("--enable-cpython", compiler_options.enable_cpython, "Enable CPython runtime"); + app.add_flag("--enable-symengine", compiler_options.enable_symengine, "Enable Symengine runtime"); app.add_flag("--link-numpy", compiler_options.link_numpy, "Enable NumPy runtime (implies --enable-cpython)"); // LSP specific options diff --git a/src/libasr/ASR.asdl b/src/libasr/ASR.asdl index b4467c637d..cdd61a49d3 100644 --- a/src/libasr/ASR.asdl +++ b/src/libasr/ASR.asdl @@ -383,6 +383,7 @@ ttype | Allocatable(ttype type) | Const(ttype type) | CPtr() + | SymbolicExpression() | TypeParameter(identifier param) | Array(ttype type, dimension* dims) | FunctionType(ttype* arg_types, ttype? return_var_type, diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index f53211099f..420686e0ba 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -398,6 +398,9 @@ static inline std::string type_to_str(const ASR::ttype_t *t) ASR::TypeParameter_t* tp = ASR::down_cast(t); return tp->m_param; } + case ASR::ttypeType::SymbolicExpression: { + return "symbolic expression"; + } default : throw LCompilersException("Not implemented " + std::to_string(t->type) + "."); } } @@ -1151,6 +1154,9 @@ static inline std::string get_type_code(const ASR::ttype_t *t, bool use_undersco return "Const[" + get_type_code(p->m_type, use_underscore_sep, encode_dimensions_, set_dimensional_hint) + "]"; } + case ASR::ttypeType::SymbolicExpression: { + return "S"; + } default: { throw LCompilersException("Type encoding not implemented for " + std::to_string(t->type)); @@ -1286,6 +1292,9 @@ static inline std::string type_to_str_python(const ASR::ttype_t *t, ASR::TypeParameter_t *p = ASR::down_cast(t); return p->m_param; } + case ASR::ttypeType::SymbolicExpression: { + return "S"; + } default : throw LCompilersException("Not implemented " + std::to_string(t->type)); } } @@ -1648,6 +1657,7 @@ inline int extract_dimensions_from_ttype(ASR::ttype_t *x, n_dims = extract_dimensions_from_ttype(ASR::down_cast(x)->m_type, m_dims); break; } + case ASR::ttypeType::SymbolicExpression: case ASR::ttypeType::Integer: case ASR::ttypeType::UnsignedInteger: case ASR::ttypeType::Real: @@ -2279,6 +2289,9 @@ inline bool types_equal(ASR::ttype_t *a, ASR::ttype_t *b, case ASR::ttypeType::CPtr: { return true; } + case ASR::ttypeType::SymbolicExpression: { + return true; + } case (ASR::ttypeType::Real) : { ASR::Real_t *a2 = ASR::down_cast(a); ASR::Real_t *b2 = ASR::down_cast(b); diff --git a/src/libasr/codegen/asr_to_c.cpp b/src/libasr/codegen/asr_to_c.cpp index 9e280202be..f6962e68b4 100644 --- a/src/libasr/codegen/asr_to_c.cpp +++ b/src/libasr/codegen/asr_to_c.cpp @@ -486,6 +486,11 @@ class ASRToCVisitor : public BaseCCPPVisitor dims = convert_dims_c(n_dims, m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, type_name, v_m_name, use_ref, dummy); } + } else if (ASR::is_a(*v_m_type)) { + headers.insert("symengine/cwrapper.h"); + std::string type_name = "basic"; + std::string v_m_name = v.m_name; + sub = format_type_c("", type_name, v_m_name, use_ref, dummy); } else if (ASRUtils::is_logical(*v_m_type)) { bool is_fixed_size = true; dims = convert_dims_c(n_dims, m_dims, v_m_type, is_fixed_size); @@ -1261,6 +1266,9 @@ R"( // Initialise Numpy v.pop_back(); v.push_back("creal(" + src + ")"); v.push_back("cimag(" + src + ")"); + } else if(value_type->type == ASR::ttypeType::SymbolicExpression){ + v.pop_back(); + v.push_back("basic_str(" + src + ")"); } if (i+1!=x.n_values) { tmp_gen += "\%s"; diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h index 80b43681e0..3e967e1ab5 100644 --- a/src/libasr/codegen/asr_to_c_cpp.h +++ b/src/libasr/codegen/asr_to_c_cpp.h @@ -435,6 +435,8 @@ R"(#include sub = "double complex "; } } + } else if (ASR::is_a(*return_var->m_type)) { + sub = "basic "; } else if (ASR::is_a(*return_var->m_type)) { sub = "void* "; } else if (ASR::is_a(*return_var->m_type)) { @@ -676,6 +678,10 @@ R"(#include v->m_intent == ASRUtils::intent_return_var ) { d += ";\n"; } + if (ASR::is_a(*v->m_type)) { + std::string v_m_name = v->m_name; + d += indent + "basic_new_stack(" + v_m_name + ");\n"; + } decl += check_tmp_buffer() + d; } if (ASR::is_a(*v->m_type)) { @@ -1026,7 +1032,12 @@ R"(#include src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; } } else { - src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; + if (m_target_type->type == ASR::ttypeType::SymbolicExpression){ + ASR::expr_t* m_value_expr = x.m_value; + src += alloc + indent + c_ds_api->get_deepcopy_symbolic(m_value_expr, value, target) + "\n"; + } else { + src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; + } } } else { src += indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; @@ -2367,7 +2378,6 @@ R"(#include } void visit_IntrinsicFunction(const ASR::IntrinsicFunction_t &x) { - LCOMPILERS_ASSERT(x.n_args == 1) std::string out; switch (x.m_intrinsic_id) { SET_INTRINSIC_NAME(Sin, "sin"); @@ -2383,6 +2393,18 @@ R"(#include SET_INTRINSIC_NAME(Exp, "exp"); SET_INTRINSIC_NAME(Exp2, "exp2"); SET_INTRINSIC_NAME(Expm1, "expm1"); + SET_INTRINSIC_NAME(SymbolicSymbol, "Symbol"); + SET_INTRINSIC_NAME(SymbolicPi, "pi"); + case (static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd)): { + 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; + break; + } default : { throw LCompilersException("IntrinsicFunction: `" + ASRUtils::get_intrinsic_name(x.m_intrinsic_id) @@ -2390,9 +2412,15 @@ R"(#include } } headers.insert("math.h"); - this->visit_expr(*x.m_args[0]); - out += "(" + src + ")"; - src = out; + if (x.n_args == 0){ + src = out; + } else if (x.n_args == 1) { + this->visit_expr(*x.m_args[0]); + if (x.m_intrinsic_id != static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol)) { + out += "(" + src + ")"; + src = out; + } + } } }; diff --git a/src/libasr/codegen/c_utils.h b/src/libasr/codegen/c_utils.h index 31f461c0d0..a8623ff9fe 100644 --- a/src/libasr/codegen/c_utils.h +++ b/src/libasr/codegen/c_utils.h @@ -3,6 +3,7 @@ #include #include +#include namespace LCompilers { @@ -631,6 +632,39 @@ class CCPPDSUtils { return result; } + std::string get_deepcopy_symbolic(ASR::expr_t *value_expr, std::string value, std::string target) { + std::string result; + if (ASR::is_a(*value_expr)) { + result = "basic_assign(" + target + ", " + value + ");"; + } else if (ASR::is_a(*value_expr)) { + ASR::IntrinsicFunction_t* intrinsic_func = ASR::down_cast(value_expr); + int64_t intrinsic_id = intrinsic_func->m_intrinsic_id; + switch (static_cast(intrinsic_id)) { + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicSymbol: { + result = "symbol_set(" + target + ", " + value + ");"; + break; + } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicAdd: { + size_t delimiterPos = value.find(","); + std::string leftPart = value.substr(0, delimiterPos); + std::string rightPart = value.substr(delimiterPos + 1); + result = "basic_add(" + target + ", " + leftPart + ", " + rightPart + ");"; + break; + } + case LCompilers::ASRUtils::IntrinsicFunctions::SymbolicPi: { + result = "basic_const_pi(" + target + ");"; + break; + } + default: { + throw LCompilersException("IntrinsicFunction: `" + + LCompilers::ASRUtils::get_intrinsic_name(intrinsic_id) + + "` is not implemented"); + } + } + } + return result; + } + std::string get_type(ASR::ttype_t *t) { LCOMPILERS_ASSERT(CUtils::is_non_primitive_DT(t)); if (ASR::is_a(*t)) { @@ -698,6 +732,9 @@ class CCPPDSUtils { case ASR::ttypeType::Complex: { return "(%f, %f)"; } + case ASR::ttypeType::SymbolicExpression: { + return "%s"; + } case ASR::ttypeType::Pointer: { if( !deref_ptr ) { return "%p"; diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index 6c36d32416..c52c5fef32 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -64,6 +64,9 @@ enum class IntrinsicFunctions : int64_t { Partition, ListReverse, ListPop, + SymbolicSymbol, + SymbolicAdd, + SymbolicPi, Sum, // ... }; @@ -1994,6 +1997,113 @@ namespace Partition { } // namespace Partition +namespace SymbolicSymbol { + + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { + const Location& loc = x.base.base.loc; + ASRUtils::require_impl(x.n_args == 1, + "SymbolicSymbol intrinsic must have exactly 1 input argument", + loc, diagnostics); + + ASR::ttype_t* input_type = ASRUtils::expr_type(x.m_args[0]); + ASRUtils::require_impl(ASR::is_a(*input_type), + "SymbolicSymbol intrinsic expects a character input argument", + loc, diagnostics); + } + + static inline ASR::expr_t *eval_SymbolicSymbol(Allocator &/*al*/, + const Location &/*loc*/, Vec& /*args*/) { + // TODO + return nullptr; + } + + static inline ASR::asr_t* create_SymbolicSymbol(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + if (args.size() != 1) { + err("Intrinsic Symbol function accepts exactly 1 argument", loc); + } + + ASR::ttype_t *type = ASRUtils::expr_type(args[0]); + if (!ASRUtils::is_character(*type)) { + err("Argument of the Symbol function must be a Character", + args[0]->base.loc); + } + + ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); + return UnaryIntrinsicFunction::create_UnaryFunction(al, loc, args, eval_SymbolicSymbol, + static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol), 0, to_type); + } + +} // namespace SymbolicSymbol + +namespace SymbolicAdd { + + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args == 2, "SymbolicAdd must have exactly two arguments", + x.base.base.loc, diagnostics); + + ASR::ttype_t* left_type = ASRUtils::expr_type(x.m_args[0]); + ASR::ttype_t* right_type = ASRUtils::expr_type(x.m_args[1]); + + ASRUtils::require_impl(ASR::is_a(*left_type) && + ASR::is_a(*right_type), + "Both arguments of SymbolicAdd must be of type SymbolicExpression", + x.base.base.loc, diagnostics); + } + + static inline ASR::expr_t *eval_SymbolicAdd(Allocator &/*al*/, + const Location &/*loc*/, Vec& /*args*/) { + // TODO + return nullptr; + } + + static inline ASR::asr_t* create_SymbolicAdd(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + if (args.size() != 2) { + err("Intrinsic Symbol Add operator accepts exactly 2 arguments", loc); + } + + Vec arg_values; + arg_values.reserve(al, args.size()); + for( size_t i = 0; i < args.size(); i++ ) { + arg_values.push_back(al, ASRUtils::expr_value(args[i])); + } + ASR::expr_t* compile_time_value = eval_SymbolicAdd(al, loc, arg_values); + ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); + return ASR::make_IntrinsicFunction_t(al, loc, + static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), + args.p, args.size(), 0, to_type, compile_time_value); + } + +} // namespace SymbolicAdd + +namespace SymbolicPi { + + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args == 0, "SymbolicPi does not take arguments", + x.base.base.loc, diagnostics); + } + + static inline ASR::expr_t *eval_SymbolicPi(Allocator &/*al*/, + const Location &/*loc*/, Vec& /*args*/) { + // TODO + return nullptr; + } + + static inline ASR::asr_t* create_SymbolicPi(Allocator& al, const Location& loc, + Vec& args, + const std::function /*err*/) { + ASR::expr_t* compile_time_value = eval_SymbolicPi(al, loc, args); + ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); + return ASR::make_IntrinsicFunction_t(al, loc, + static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), + nullptr, 0, 0, to_type, compile_time_value); + } + +} // namespace SymbolicPi + namespace IntrinsicFunctionRegistry { static const std::map(ASRUtils::IntrinsicFunctions::ListReverse), {nullptr, &ListReverse::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol), + {nullptr, &SymbolicSymbol::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), + {nullptr, &SymbolicAdd::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), + {nullptr, &SymbolicPi::verify_args}}, }; static const std::map& intrinsic_function_id_to_name = { @@ -2078,10 +2194,16 @@ namespace IntrinsicFunctionRegistry { "list.reverse"}, {static_cast(ASRUtils::IntrinsicFunctions::ListPop), "list.pop"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol), + "Symbol"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), + "SymbolicAdd"}, + {static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), + "pi"}, {static_cast(ASRUtils::IntrinsicFunctions::Any), "any"}, {static_cast(ASRUtils::IntrinsicFunctions::Sum), - "sum"}, + "sum"} }; @@ -2106,7 +2228,10 @@ namespace IntrinsicFunctionRegistry { {"sum", {&Sum::create_Sum, &Sum::eval_Sum}}, {"list.index", {&ListIndex::create_ListIndex, &ListIndex::eval_list_index}}, {"list.reverse", {&ListReverse::create_ListReverse, &ListReverse::eval_list_reverse}}, - {"list.pop", {&ListPop::create_ListPop, &ListPop::eval_list_pop}} + {"list.pop", {&ListPop::create_ListPop, &ListPop::eval_list_pop}}, + {"Symbol", {&SymbolicSymbol::create_SymbolicSymbol, &SymbolicSymbol::eval_SymbolicSymbol}}, + {"SymbolicAdd", {&SymbolicAdd::create_SymbolicAdd, &SymbolicAdd::eval_SymbolicAdd}}, + {"pi", {&SymbolicPi::create_SymbolicPi, &SymbolicPi::eval_SymbolicPi}}, }; static inline bool is_intrinsic_function(const std::string& name) { @@ -2126,7 +2251,8 @@ namespace IntrinsicFunctionRegistry { id_ == ASRUtils::IntrinsicFunctions::Sin || id_ == ASRUtils::IntrinsicFunctions::Exp || id_ == ASRUtils::IntrinsicFunctions::Exp2 || - id_ == ASRUtils::IntrinsicFunctions::Expm1 ); + id_ == ASRUtils::IntrinsicFunctions::Expm1 || + id_ == ASRUtils::IntrinsicFunctions::SymbolicSymbol); } /* @@ -2212,6 +2338,9 @@ inline std::string get_intrinsic_name(int x) { INTRINSIC_NAME_CASE(Partition) INTRINSIC_NAME_CASE(ListReverse) INTRINSIC_NAME_CASE(ListPop) + INTRINSIC_NAME_CASE(SymbolicSymbol) + INTRINSIC_NAME_CASE(SymbolicAdd) + INTRINSIC_NAME_CASE(SymbolicPi) INTRINSIC_NAME_CASE(Sum) default : { throw LCompilersException("pickle: intrinsic_id not implemented"); diff --git a/src/libasr/utils.h b/src/libasr/utils.h index dfe5ed7d99..a0b0c00451 100644 --- a/src/libasr/utils.h +++ b/src/libasr/utils.h @@ -59,6 +59,7 @@ struct CompilerOptions { bool verbose = false; bool pass_cumulative = false; bool enable_cpython = false; + bool enable_symengine = false; bool link_numpy = false; std::vector import_paths; Platform platform; diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 08bcb28e6b..333e9029f5 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -305,16 +305,21 @@ ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, const Location &loc, diag::Diagnostics &diagnostics, LocationManager &lm, bool intrinsic, std::vector &rl_path, - bool &lpython, bool& enum_py, bool& copy, + bool &lpython, bool& enum_py, bool& copy, bool& sympy, const std::function err, bool allow_implicit_casting) { lpython = false; enum_py = false; copy = false; + sympy = false; if( module_name == "copy" ) { copy = true; return nullptr; } + if (module_name == "sympy") { + sympy = true; + return nullptr; + } LCOMPILERS_ASSERT(symtab); if (symtab->get_scope().find(module_name) != symtab->get_scope().end()) { ASR::symbol_t *m = symtab->get_symbol(module_name); @@ -596,6 +601,8 @@ class CommonVisitor : public AST::BaseVisitor { std::vector rt_vec; SetChar dependencies; bool allow_implicit_casting; + // Stores the name of imported functions and the modules they are imported from + std::map imported_functions; CommonVisitor(Allocator &al, LocationManager &lm, SymbolTable *symbol_table, diag::Diagnostics &diagnostics, bool main_module, @@ -628,10 +635,10 @@ class CommonVisitor : public AST::BaseVisitor { SymbolTable *tu_symtab = ASRUtils::get_tu_symtab(current_scope); std::string rl_path = get_runtime_library_dir(); std::vector paths = {rl_path, parent_dir}; - bool lpython, enum_py, copy; + bool lpython, enum_py, copy, sympy; ASR::Module_t *m = load_module(al, tu_symtab, module_name, loc, diag, lm, true, paths, - lpython, enum_py, copy, + lpython, enum_py, copy, sympy, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, allow_implicit_casting); LCOMPILERS_ASSERT(!lpython && !enum_py) @@ -1080,6 +1087,9 @@ class CommonVisitor : public AST::BaseVisitor { } } } + } else if (var_annotation == "S") { + type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); + return type; } if( raise_error ) { throw SemanticError("Unsupported type annotation: " + var_annotation, loc); @@ -2221,6 +2231,26 @@ class CommonVisitor : public AST::BaseVisitor { tuple_type_vec.p, tuple_type_vec.n)); tmp = ASR::make_TupleConcat_t(al, loc, left, right, tuple_type, value); return; + } else if (ASR::is_a(*left_type) + && ASR::is_a(*right_type)) { + switch (op) { + case ASR::binopType::Add: { + Vec args_with_symbolic; + args_with_symbolic.reserve(al, 2); + args_with_symbolic.push_back(al, left); + args_with_symbolic.push_back(al, right); + ASRUtils::create_intrinsic_function create_function = + ASRUtils::IntrinsicFunctionRegistry::get_create_function("SymbolicAdd"); + tmp = create_function(al, loc, args_with_symbolic, [&](const std::string& msg, const Location& loc) { + throw SemanticError(msg, loc); + }); + return; + } + default: { + throw SemanticError("Not implemented: The following symbolic binary operator has not been implemented", loc); + break; + } + } } else { std::string ltype = ASRUtils::type_to_str_python(ASRUtils::expr_type(left)); std::string rtype = ASRUtils::type_to_str_python(ASRUtils::expr_type(right)); @@ -3112,6 +3142,8 @@ class CommonVisitor : public AST::BaseVisitor { void visit_Name(const AST::Name_t &x) { std::string name = x.m_id; ASR::symbol_t *s = current_scope->resolve_symbol(name); + std::set not_cpython_builtin = { + "pi"}; if (s) { tmp = ASR::make_Var_t(al, x.base.base.loc, s); } else if (name == "i32" || name == "i64" || name == "f32" || @@ -3135,6 +3167,14 @@ class CommonVisitor : public AST::BaseVisitor { ASR::symbol_t *s = current_scope->resolve_symbol(name); LCOMPILERS_ASSERT(s); tmp = ASR::make_Var_t(al, x.base.base.loc, s); + } else if (ASRUtils::IntrinsicFunctionRegistry::is_intrinsic_function(name) && + (not_cpython_builtin.find(name) == not_cpython_builtin.end() || + imported_functions.find(name) != imported_functions.end() )) { + ASRUtils::create_intrinsic_function create_func = + ASRUtils::IntrinsicFunctionRegistry::get_create_function(name); + Vec args_; + tmp = create_func(al, x.base.base.loc, args_, [&](const std::string &msg, const Location &loc) { + throw SemanticError(msg, loc); }); } else { throw SemanticError("Variable '" + name + "' not declared", x.base.base.loc); @@ -4257,13 +4297,13 @@ class SymbolTableVisitor : public CommonVisitor { if (!main_module) { st = st->parent; } - bool lpython, enum_py, copy; + bool lpython, enum_py, copy, sympy; set_module_symbol(msym, paths); t = (ASR::symbol_t*)(load_module(al, st, - msym, x.base.base.loc, diag, lm, false, paths, lpython, enum_py, copy, + msym, x.base.base.loc, diag, lm, false, paths, lpython, enum_py, copy, sympy, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, allow_implicit_casting)); - if (lpython || enum_py || copy) { + if (lpython || enum_py || copy || sympy) { // TODO: For now we skip lpython import completely. Later on we should note what symbols // got imported from it, and give an error message if an annotation is used without // importing it. @@ -4332,13 +4372,13 @@ class SymbolTableVisitor : public CommonVisitor { st = st->parent; } for (auto &mod_sym : mods) { - bool lpython, enum_py, copy; + bool lpython, enum_py, copy, sympy; set_module_symbol(mod_sym, paths); t = (ASR::symbol_t*)(load_module(al, st, - mod_sym, x.base.base.loc, diag, lm, false, paths, lpython, enum_py, copy, + mod_sym, x.base.base.loc, diag, lm, false, paths, lpython, enum_py, copy, sympy, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, allow_implicit_casting)); - if (lpython || enum_py || copy) { + if (lpython || enum_py || copy || sympy) { // TODO: For now we skip lpython import completely. Later on we should note what symbols // got imported from it, and give an error message if an annotation is used without // importing it. @@ -4483,9 +4523,6 @@ class BodyVisitor : public CommonVisitor { public: ASR::asr_t *asr; std::vector do_loop_variables; - // Stores the name of imported functions and the modules they are imported from - std::map imported_functions; - BodyVisitor(Allocator &al, LocationManager &lm, ASR::asr_t *unit, diag::Diagnostics &diagnostics, bool main_module, std::map &ast_overload, @@ -7153,7 +7190,7 @@ class BodyVisitor : public CommonVisitor { if (!s) { std::set not_cpython_builtin = { - "sin", "cos", "gamma", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "exp", "exp2", "expm1", + "sin", "cos", "gamma", "tan", "asin", "acos", "atan", "sinh", "cosh", "tanh", "exp", "exp2", "expm1", "Symbol", "sum" // For sum called over lists }; if (ASRUtils::IntrinsicFunctionRegistry::is_intrinsic_function(call_name) && diff --git a/src/runtime/lpython/lpython.py b/src/runtime/lpython/lpython.py index 2e01b885b0..c4e7895042 100644 --- a/src/runtime/lpython/lpython.py +++ b/src/runtime/lpython/lpython.py @@ -10,7 +10,7 @@ "overload", "ccall", "TypeVar", "pointer", "c_p_pointer", "Pointer", "p_c_pointer", "vectorize", "inline", "Union", "static", "packed", "Const", "sizeof", "ccallable", "ccallback", "Callable", - "Allocatable", "In", "Out", "InOut", "dataclass"] + "Allocatable", "In", "Out", "InOut", "dataclass", "S"] # data-types @@ -32,6 +32,7 @@ "Callable": lambda x: x, "Allocatable": lambda x: x, "Pointer": lambda x: x, + "S": lambda x: x, } class Type: @@ -91,6 +92,7 @@ def __init__(self, type, dims): Callable = Type("Callable") Allocatable = Type("Allocatable") Pointer = PointerType("Pointer") +S = Type("S") class Union: