1 #pragma once 2 3 #include <pybind11/pybind11.h> 4 #include "py_ex.hh" 5 #include "py_helpers.hh" 6 #include "py_kernel.hh" 7 #include "py_progress.hh" 8 9 namespace cadabra { 10 11 /// \ingroup pythoncore 12 /// 13 /// Generic internal entry point for the Python side to execute a 14 /// C++ algorithm. This gets called by the various apply_algo 15 /// functions below, which in turn get called by the def_algo 16 /// functions. 17 template <class Algo> apply_algo_base(Algo & algo,Ex_ptr ex,bool deep,bool repeat,unsigned int depth,bool pre_order=false)18 Ex_ptr apply_algo_base(Algo& algo, Ex_ptr ex, bool deep, bool repeat, unsigned int depth, bool pre_order=false) 19 { 20 Ex::iterator it = ex->begin(); 21 if (ex->is_valid(it)) { 22 ProgressMonitor* pm = get_progress_monitor(); 23 algo.set_progress_monitor(pm); 24 if(pre_order) 25 ex->update_state(algo.apply_pre_order(repeat)); 26 else 27 ex->update_state(algo.apply_generic(it, deep, repeat, depth)); 28 call_post_process(*get_kernel_from_scope(), ex); 29 } 30 31 return ex; 32 } 33 34 template <class Algo> apply_algo(Ex_ptr ex,bool deep,bool repeat,unsigned int depth)35 Ex_ptr apply_algo(Ex_ptr ex, bool deep, bool repeat, unsigned int depth) 36 { 37 Algo algo(*get_kernel_from_scope(), *ex); 38 return apply_algo_base(algo, ex, deep, repeat, depth, false); 39 } 40 41 template <class Algo, typename Arg1> apply_algo(Ex_ptr ex,Arg1 arg1,bool deep,bool repeat,unsigned int depth)42 Ex_ptr apply_algo(Ex_ptr ex, Arg1 arg1, bool deep, bool repeat, unsigned int depth) 43 { 44 Algo algo(*get_kernel_from_scope(), *ex, arg1); 45 return apply_algo_base(algo, ex, deep, repeat, depth, false); 46 } 47 48 template <class Algo, typename Arg1, typename Arg2> apply_algo(Ex_ptr ex,Arg1 arg1,Arg2 arg2,bool deep,bool repeat,unsigned int depth)49 Ex_ptr apply_algo(Ex_ptr ex, Arg1 arg1, Arg2 arg2, bool deep, bool repeat, unsigned int depth) 50 { 51 Algo algo(*get_kernel_from_scope(), *ex, arg1, arg2); 52 return apply_algo_base(algo, ex, deep, repeat, depth, false); 53 } 54 55 template <class Algo, typename Arg1, typename Arg2, typename Arg3> apply_algo(Ex_ptr ex,Arg1 arg1,Arg2 arg2,Arg3 arg3,bool deep,bool repeat,unsigned int depth)56 Ex_ptr apply_algo(Ex_ptr ex, Arg1 arg1, Arg2 arg2, Arg3 arg3, bool deep, bool repeat, unsigned int depth) 57 { 58 Algo algo(*get_kernel_from_scope(), *ex, arg1, arg2, arg3); 59 return apply_algo_base(algo, ex, deep, repeat, depth, false); 60 } 61 62 63 /// \ingroup pythoncore 64 /// 65 /// Method to declare a Python function with variable number of 66 /// arguments, and make that call a C++ algorithm as specified in 67 /// the Algo template parameter. This will make the algorithm 68 /// traverse post-order, that is to say, first on the innermost 69 /// child (or leaf) of an expression tree, and then, if that fails, 70 /// on parent nodes, and so on. 71 template<class Algo, typename... Args, typename... PyArgs> def_algo(pybind11::module & m,const char * name,bool deep,bool repeat,unsigned int depth,PyArgs...pyargs)72 void def_algo(pybind11::module& m, const char* name, bool deep, bool repeat, unsigned int depth, PyArgs... pyargs) 73 { 74 m.def(name, 75 &apply_algo<Algo, Args...>, 76 pybind11::arg("ex"), 77 std::forward<PyArgs>(pyargs)..., 78 pybind11::arg("deep") = deep, 79 pybind11::arg("repeat") = repeat, 80 pybind11::arg("depth") = depth, 81 pybind11::doc(read_manual("algorithms", name).c_str()), 82 pybind11::return_value_policy::reference_internal); 83 } 84 85 template <class Algo> apply_algo_preorder(Ex_ptr ex,bool deep,bool repeat,unsigned int depth)86 Ex_ptr apply_algo_preorder(Ex_ptr ex, bool deep, bool repeat, unsigned int depth) 87 { 88 Algo algo(*get_kernel_from_scope(), *ex); 89 return apply_algo_base(algo, ex, deep, repeat, depth, true); 90 } 91 92 template <class Algo, typename Arg1> apply_algo_preorder(Ex_ptr ex,Arg1 arg1,bool deep,bool repeat,unsigned int depth)93 Ex_ptr apply_algo_preorder(Ex_ptr ex, Arg1 arg1, bool deep, bool repeat, unsigned int depth) 94 { 95 Algo algo(*get_kernel_from_scope(), *ex, arg1); 96 return apply_algo_base(algo, ex, deep, repeat, depth, true); 97 } 98 99 template <class Algo, typename Arg1, typename Arg2> apply_algo_preorder(Ex_ptr ex,Arg1 arg1,Arg2 arg2,bool deep,bool repeat,unsigned int depth)100 Ex_ptr apply_algo_preorder(Ex_ptr ex, Arg1 arg1, Arg2 arg2, bool deep, bool repeat, unsigned int depth) 101 { 102 Algo algo(*get_kernel_from_scope(), *ex, arg1, arg2); 103 return apply_algo_base(algo, ex, deep, repeat, depth, true); 104 } 105 106 /// \ingroup pythoncore 107 /// 108 /// Method to declare a Python function with variable number of arguments, and 109 /// make that call a C++ algorithm as specified in the Algo template parameter. 110 /// In contrast to def_algo, this one will apply the algorithm in pre-order 111 /// traversal style, that is, it will first attempt to apply on a node itself 112 /// before traversing further down the child nodes and attempting there. 113 template<class Algo, typename... Args, typename... PyArgs> def_algo_preorder(pybind11::module & m,const char * name,bool deep,bool repeat,unsigned int depth,PyArgs...pyargs)114 void def_algo_preorder(pybind11::module& m, const char* name, bool deep, bool repeat, unsigned int depth, PyArgs... pyargs) 115 { 116 m.def(name, 117 &apply_algo_preorder<Algo, Args...>, 118 pybind11::arg("ex"), 119 std::forward<PyArgs>(pyargs)..., 120 pybind11::arg("deep") = deep, 121 pybind11::arg("repeat") = repeat, 122 pybind11::arg("depth") = depth, 123 pybind11::doc(read_manual("algorithms", name).c_str()), 124 pybind11::return_value_policy::reference_internal); 125 } 126 127 128 void init_algorithms(pybind11::module& m); 129 } 130