#include "py_properties.hh" #include "py_kernel.hh" #include "py_helpers.hh" #include "properties/Accent.hh" #include "properties/AntiCommuting.hh" #include "properties/AntiSymmetric.hh" #include "properties/Commuting.hh" #include "properties/Coordinate.hh" #include "properties/Depends.hh" #include "properties/DependsInherit.hh" #include "properties/Derivative.hh" #include "properties/Determinant.hh" #include "properties/Diagonal.hh" #include "properties/DifferentialForm.hh" #include "properties/DiracBar.hh" #include "properties/GammaMatrix.hh" #include "properties/CommutingAsProduct.hh" #include "properties/CommutingAsSum.hh" #include "properties/DAntiSymmetric.hh" #include "properties/Diagonal.hh" #include "properties/Distributable.hh" #include "properties/EpsilonTensor.hh" #include "properties/ExteriorDerivative.hh" #include "properties/FilledTableau.hh" #include "properties/ImaginaryI.hh" #include "properties/ImplicitIndex.hh" #include "properties/Indices.hh" #include "properties/IndexInherit.hh" #include "properties/Integer.hh" #include "properties/InverseMetric.hh" #include "properties/KroneckerDelta.hh" #include "properties/LaTeXForm.hh" #include "properties/Matrix.hh" #include "properties/Metric.hh" #include "properties/NonCommuting.hh" #include "properties/NumericalFlat.hh" #include "properties/PartialDerivative.hh" #include "properties/RiemannTensor.hh" #include "properties/SatisfiesBianchi.hh" #include "properties/SelfAntiCommuting.hh" #include "properties/SelfCommuting.hh" #include "properties/SelfNonCommuting.hh" #include "properties/SortOrder.hh" #include "properties/Spinor.hh" #include "properties/Symbol.hh" #include "properties/Symmetric.hh" #include "properties/Tableau.hh" #include "properties/TableauInherit.hh" #include "properties/TableauSymmetry.hh" #include "properties/Trace.hh" #include "properties/Traceless.hh" #include "properties/Vielbein.hh" #include "properties/Weight.hh" #include "properties/WeightInherit.hh" #include "properties/WeylTensor.hh" #include "DisplayTeX.hh" #include "DisplayTerminal.hh" #include "Media.hh" namespace cadabra { namespace py = pybind11; BoundPropertyBase::BoundPropertyBase() : prop(nullptr) , for_obj(nullptr) { } BoundPropertyBase::BoundPropertyBase(const property* prop, Ex_ptr for_obj) : prop(prop) , for_obj(for_obj) { } BoundPropertyBase::~BoundPropertyBase() { } std::string BoundPropertyBase::str_() const { std::ostringstream str; str << "Property "; // std::cerr << "going to print" << std::endl; prop->latex(str); // FIXME: this should call 'str' on the property, which does not exist yet str << " attached to " + Ex_as_str(for_obj) + "."; return str.str(); } std::string BoundPropertyBase::latex_() const { std::ostringstream str; // HERE: this text should go away, property should just print itself in a python form, // the decorating text should be printed in a separate place. str << "\\text{Property "; prop->latex(str); std::string bare = Ex_as_latex(for_obj); if (dynamic_cast(prop)) { bare = std::regex_replace(bare, std::regex(R"(\\)"), "$\\backslash{}$}"); bare = std::regex_replace(bare, std::regex(R"(#)"), "\\#"); str << " attached to {\\tt " + bare + "}."; } else { str << " attached to~}" + bare + "."; } return str.str(); } std::string BoundPropertyBase::repr_() const { // FIXME: this needs work, it does not output things which can be fed back into python. return "Property::repr: " + prop->name(); } Kernel& BoundPropertyBase::get_kernel() { return *get_kernel_from_scope(); } Properties& BoundPropertyBase::get_props() { return get_kernel_from_scope()->properties; } Ex& BoundPropertyBase::get_ex() const { return *for_obj; } Ex::iterator BoundPropertyBase::get_it() const { return for_obj->begin(); } template BoundProperty::BoundProperty() : BoundPropertyBase() { } template BoundProperty::BoundProperty(const PropT* prop, Ex_ptr for_obj) : BoundPropertyBase(prop, for_obj) { } template BoundProperty::BoundProperty(Ex_ptr ex, Ex_ptr param) : BoundPropertyBase(nullptr, ex) { auto new_prop = new cpp_type(); get_kernel_from_scope()->inject_property(new_prop, ex, param); BoundPropertyBase::prop = new_prop; } template std::shared_ptr> BoundProperty::get_from_kernel(Ex::iterator it, const std::string& label, bool ignore_parent_rel) { int tmp; auto res = get_kernel_from_scope()->properties.get_with_pattern( it, tmp, label, false, ignore_parent_rel); if (res.first) { return std::make_shared>( res.first, res.second ? std::make_shared(res.second->obj) : nullptr); } else { return nullptr; } } template const PropT* BoundProperty::get_prop() const { return dynamic_cast(BoundPropertyBase::prop); } template void BoundProperty::attach(Ex_ptr obj) const { // std::cerr << "Attaching property to " << obj << std::endl; Kernel *kernel = get_kernel_from_scope(); Properties& props = kernel->properties; const auto *thisprop = get_prop(); thisprop->validate(*kernel, *obj); props.master_insert(*obj, thisprop); } template std::string BoundProperty::str_() const { return BoundPropertyBase::str_(); } template std::string BoundProperty::latex_() const { return BoundPropertyBase::latex_(); } template std::string BoundProperty::repr_() const { return BoundPropertyBase::str_(); } template typename BoundPropT::py_type def_abstract_prop(pybind11::module& m, const std::string& name) { using base_type = BoundPropT; // using cpp_type = typename base_type::cpp_type; using py_type = typename base_type::py_type; return py_type(m, name.c_str(), py::multiple_inheritance(), read_manual("properties", name.c_str()).c_str()) .def_static("get", [](Ex_ptr ex, const std::string& label, bool ipr) { return base_type::get_from_kernel(ex->begin(), label, ipr); }, py::arg("ex"), py::arg("label") = "", py::arg("ignore_parent_rel") = false) .def_static("get", [](ExNode node, const std::string& label, bool ipr) { return base_type::get_from_kernel(node.it, label, ipr); }, py::arg("exnode"), py::arg("label") = "", py::arg("ignore_parent_rel") = false) .def("attach", &BoundPropT::attach) .def("__str__", &BoundPropT::str_) .def("__repr__", &BoundPropT::repr_) .def("_latex_", &BoundPropT::latex_); } template typename BoundPropT::py_type def_prop(pybind11::module& m) { using base_type = BoundPropT; using cpp_type = typename base_type::cpp_type; using py_type = typename base_type::py_type; return py_type(m, std::make_shared()->name().c_str(), py::multiple_inheritance(), read_manual("properties", std::make_shared()->name().c_str()).c_str()) .def(py::init(), py::arg("ex"), py::arg("param")=Ex{}) .def_static("get", [](Ex_ptr ex, const std::string& label, bool ipr) { return base_type::get_from_kernel(ex->begin(), label, ipr); }, py::arg("ex"), py::arg("label") = "", py::arg("ignore_parent_rel") = false) .def_static("get", [](ExNode node, const std::string& label, bool ipr) { return base_type::get_from_kernel(node.it, label, ipr); }, py::arg("exnode"), py::arg("label") = "", py::arg("ignore_parent_rel") = false) .def("attach", &BoundPropT::attach) .def("__str__", &BoundPropT::str_) .def("__repr__", &BoundPropT::repr_) .def("_latex_", &BoundPropT::latex_) ; } pybind11::list list_properties() { // This function is fundamentally limited. We would *like* to return a list of // BoundProperties, so that you can do something with the output. But we cannot // walk the full property list and create a BoundProperty for each of them, as // we do not know the type (we can only dynamic_cast). // // So for now this is just returning a list of LaTeXStrings, obtained by asking // each property to print itself. Kernel *kernel = get_kernel_from_scope(); Properties& props = kernel->properties; pybind11::dict globals = get_globals(); bool handles_latex_view = globals["server"].attr("handles")(pybind11::str("latex_view")).cast(); pybind11::list ret; std::string res; bool multi = false; for (auto it = props.pats.begin(); it != props.pats.end(); ++it) { if (it->first->hidden()) continue; // print the property name if we are at the end or if the next entry is for // a different property. decltype(it) nxt = it; ++nxt; if (res == "" && (nxt != props.pats.end() && it->first == nxt->first)) { if(handles_latex_view) res += "\\{"; else res += "{"; multi = true; } std::ostringstream str; if(handles_latex_view) { DisplayTeX dt(*get_kernel_from_scope(), it->second->obj); dt.output(str); } else { DisplayTerminal dt(*get_kernel_from_scope(), it->second->obj); dt.output(str); } res += str.str(); if (nxt == props.pats.end() || it->first != nxt->first) { if (multi) { if(handles_latex_view) res += "\\}"; else res += "}"; } multi = false; res += "::\\texttt{"; res += (*it).first->name() + "}"; ret.append(LaTeXString(res)); res = ""; } else { res += ", "; } } return ret; } std::vector indices_get_all(const Indices* indices, bool include_wildcards) { auto kernel = get_kernel_from_scope(); auto its = kernel->properties.pats.equal_range(indices); std::vector res; for (auto it = its.first; it != its.second; ++it) { if (it->second->obj.begin()->is_autodeclare_wildcard() && !include_wildcards) continue; res.push_back(it->second->obj); } return res; } Ex indices_get_dummy(const Indices* indices, const Ex_ptr& ex) { IndexClassifier ic(*get_kernel_from_scope()); return ic.get_dummy(indices, ex->begin()); } void init_properties(py::module& m) { m.def("properties", &list_properties); py::class_>(m, "Property") .def_property_readonly("for_obj", &BoundPropertyBase::get_ex); // Abstract base types = these are visible in Python but cannot be injected into the Kernel using Py_list_property = BoundProperty; using Py_labelled_property = BoundProperty; using Py_CommutingBehaviour = BoundProperty; using Py_SelfCommutingBehaviour = BoundProperty; using Py_TableauBase = BoundProperty; using Py_DependsBase = BoundProperty; using Py_WeightBase = BoundProperty; using Py_DifferentialFormBase = BoundProperty; def_abstract_prop(m, "list_property"); def_abstract_prop(m, "labelled_property") .def_property_readonly("label", [](const Py_labelled_property & p) { return p.get_prop()->label; }); def_abstract_prop(m, "CommutingBehaviour") .def("sign", [](const Py_CommutingBehaviour & p) { return p.get_prop()->sign(); }); def_abstract_prop(m, "SelfCommutingBehaviour") .def("sign", [](const Py_SelfCommutingBehaviour & p) { return p.get_prop()->sign(); }); def_abstract_prop(m, "TableauBase") .def("size", [](const Py_TableauBase & p) { return p.get_prop()->size(p.get_props(), p.get_ex(), p.get_it()); }) .def("get_tab", [](const Py_TableauBase & p, unsigned int num) { return p.get_prop()->get_tab(p.get_props(), p.get_ex(), p.get_it(), num); }) .def("only_column_exchange", [](const Py_TableauBase & p) { return p.get_prop()->only_column_exchange(); }) .def("get_indexgroup", [](const Py_TableauBase & p, int group) { return p.get_prop()->get_indexgroup(p.get_props(), p.get_ex(), p.get_it(), group); }) .def("is_simple_symmetry", [](const Py_TableauBase & p) { return p.get_prop()->is_simple_symmetry(p.get_props(), p.get_ex(), p.get_it()); }); def_abstract_prop(m, "DependsBase") .def("dependencies", [](const Py_DependsBase & p) { return p.get_prop()->dependencies(p.get_kernel(), p.get_it()); }); def_abstract_prop(m, "WeightBase") .def("value", [](const Py_WeightBase & p, const std::string& forcedLabel) { // This is mpq_class, convert to the Python equivalent. pybind11::object mpq = pybind11::module::import("gmpy2").attr("mpq"); auto m = p.get_prop()->value(p.get_kernel(), p.get_it(), forcedLabel); pybind11::object mult = mpq(m.get_num().get_si(), m.get_den().get_si()); return mult; }); def_abstract_prop(m, "DifferentialFormBase") .def("degree", [](const Py_DifferentialFormBase & p) { return p.get_prop()->degree(p.get_props(), p.get_it()); }); // Base types - inherit only from BoundPropertyBase, list_property or labelled_property using Py_IndexInherit = BoundProperty; using Py_NumericalFlat = BoundProperty; using Py_Traceless = BoundProperty; using Py_Coordinate = BoundProperty; using Py_CommutingAsProduct = BoundProperty; using Py_CommutingAsSum = BoundProperty; using Py_Distributable = BoundProperty; using Py_Determinant = BoundProperty; using Py_FilledTableau = BoundProperty; using Py_ImplicitIndex = BoundProperty; using Py_ImaginaryI = BoundProperty; using Py_Indices = BoundProperty; using Py_Integer = BoundProperty; using Py_LaTeXForm = BoundProperty; using Py_SortOrder = BoundProperty; using Py_Symbol = BoundProperty; using Py_Tableau = BoundProperty; using Py_TableauInherit = BoundProperty; using Py_Vielbein = BoundProperty; using Py_InverseVielbein = BoundProperty; def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m) .def_property_readonly("obj", [](const Py_Determinant & p) { return p.get_prop()->obj; }); def_prop(m) .def_property_readonly("dimension", [](const Py_FilledTableau & p) { return p.get_prop()->dimension; }); def_prop(m) .def_property_readonly("explicit_form", [](const Py_ImplicitIndex & p) { return p.get_prop()->explicit_form; }); def_prop(m); auto py_indices = def_prop(m) .def("get_indices", [](const Py_Indices& p, bool wc) { return indices_get_all(p.get_prop(), wc); }, py::arg("include_wildcards") = false) .def("get_dummy", [](const Py_Indices& p, const Ex_ptr& ex) { return indices_get_dummy(p.get_prop(), ex);}) .def_property_readonly("set_name", [](const Py_Indices & p) { return p.get_prop()->set_name; }) .def_property_readonly("parent_name", [](const Py_Indices & p) { return p.get_prop()->parent_name; }) .def_property_readonly("values", [](const Py_Indices & p) { return p.get_prop()->values; }); def_prop(m) .def_property_readonly("from", [](const Py_Integer & p) { return p.get_prop()->from; }) .def_property_readonly("to", [](const Py_Integer & p) { return p.get_prop()->to; }) .def_property_readonly("difference", [](const Py_Integer & p) { return p.get_prop()->difference; }); def_prop(m) .def("latex_form", [](const Py_LaTeXForm & p) { return p.get_prop()->latex_form(); }); def_prop(m); def_prop(m); def_prop(m) .def_property_readonly("dimension", [](const Py_Tableau & p) { return p.get_prop()->dimension; }); def_prop(m); def_prop(m); def_prop(m); py::enum_(py_indices, "position_t", "How to interpret the sub/super-script position of the indices.") .value("free", Indices::free, "Index positions are arbitrary.") .value("fixed", Indices::fixed, "Index positions are fixed, but can be changed by canonicalisation.") .value("independent", Indices::independent, "Index positions are independent and should never change.") .export_values(); // Derived types using Py_Accent = BoundProperty; using Py_AntiCommuting = BoundProperty; using Py_Commuting = BoundProperty; using Py_AntiSymmetric = BoundProperty; using Py_DAntiSymmetric = BoundProperty; using Py_Depends = BoundProperty; using Py_Derivative = BoundProperty; using Py_Symmetric = BoundProperty; using Py_DifferentialForm = BoundProperty; using Py_DiracBar = BoundProperty; using Py_EpsilonTensor = BoundProperty; using Py_ExteriorDerivative = BoundProperty; using Py_Matrix = BoundProperty; using Py_GammaMatrix = BoundProperty; using Py_TableauSymmetry = BoundProperty; using Py_InverseMetric = BoundProperty; using Py_KroneckerDelta = BoundProperty; using Py_Metric = BoundProperty; using Py_NonCommuting = BoundProperty; using Py_PartialDerivative = BoundProperty; using Py_RiemannTensor = BoundProperty; using Py_SatisfiesBianchi = BoundProperty; using Py_SelfAntiCommuting = BoundProperty; using Py_SelfCommuting = BoundProperty; using Py_SelfNonCommuting = BoundProperty; using Py_Spinor = BoundProperty; using Py_Trace = BoundProperty; using Py_Weight = BoundProperty; using Py_WeightInherit = BoundProperty; using Py_WeylTensor = BoundProperty; def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m) .def_property_readonly("metric", [](const Py_EpsilonTensor& p) { return p.get_prop()->metric; }) .def_property_readonly("krdelta", [](const Py_EpsilonTensor& p) { return p.get_prop()->krdelta; }); def_prop(m); def_prop(m); def_prop(m) .def_property_readonly("metric", [](const Py_GammaMatrix& p) { return p.get_prop()->metric; }); def_prop(m); def_prop(m) .def_property_readonly("signature", [](const Py_InverseMetric& p) { return p.get_prop()->signature; }); def_prop(m); def_prop(m) .def_property_readonly("signature", [](const Py_Metric& p) { return p.get_prop()->signature; });; def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); def_prop(m); using Py_Diagonal = BoundProperty; def_prop(m); auto py_spinor = def_prop(m) .def_property_readonly("dimension", [](const Py_Spinor& p) { return p.get_prop()->dimension; }) .def_property_readonly("weyl", [](const Py_Spinor& p) { return p.get_prop()->weyl; }) .def_property_readonly("chirality", [](const Py_Spinor& p) { return p.get_prop()->chirality; }) .def_property_readonly("majorana", [](const Py_Spinor& p) { return p.get_prop()->majorana; }); def_prop(m) .def_property_readonly("obj", [](const Py_Trace& p) { return p.get_prop()->obj; }) .def_property_readonly("index_set_name", [](const Py_Trace& p) { return p.get_prop()->index_set_name; }); def_prop(m); auto py_weight_inherit = def_prop(m) .def("combination_type", [](const Py_WeightInherit& p) { return p.get_prop()->combination_type; }); def_prop(m); py::enum_(py_spinor, "Chirality") .value("positive", Spinor::positive) .value("negative", Spinor::negative) .export_values(); py::enum_(py_weight_inherit, "CombinationType") .value("multiplicative", WeightInherit::multiplicative) .value("additive", WeightInherit::additive) .value("power", WeightInherit::power) .export_values(); } }