Welcome to Cadabra Q&A, where you can ask questions and receive answers from other members of the community.
+1 vote

According to the (source) documentation, the weight property:

Attach a labelled weight to an object, which can subsequently be used in the algorithms keep_weight and drop_weight. See the documentation of those algorithms for examples.

Examples of it use can be found on the manual pages of the algorithms keep_weight and drop_weight

Question

Is it possible to get the weight of an object?

My question is inspire in the uses of algorithms like n_args or n_indices (See util.node).

in General questions by (15.0k points)

2 Answers

0 votes

Here is a partial solution. In principle, one can call

x::Weight(value=1, label=field);
Weight.get($x$, label="field").value("field");

This returns an error because an underlying function is returning value in the mpq_class for precision rational numbers. This needs to be recast.

A bugfix is to edit cadabra2/core/pythoncdb/py_properties.cc and replace

        def_abstract_prop<Py_WeightBase>(m, "WeightBase")
        .def("value", [](const Py_WeightBase & p, 
            const std::string& forcedLabel) { 
        return p.get_prop()->
        value(p.get_kernel(), p.get_it(), forcedLabel); });

with

        def_abstract_prop<Py_WeightBase>(m, "WeightBase")
            .def("value", [](const Py_WeightBase & p, const std::string& forcedLabel) {
                // This is mpq_class. We convert it to a string.
            return p.get_prop()->
            value(p.get_kernel(), p.get_it(), forcedLabel).get_str();
                 });

Then the given Weight.get routine will work. (It returns the rational as a string. If you want some other return form, you can use a different function than get_str in the mpq_class.)

Unfortunately, it does not seem smart enough to handle more than single term arguments.

Similarly, you can use WeightInherit to get the weights of operators that carry weight, but it doesn't account for the weights of their arguments. In principle, these two functions can be chained together to find the Weight of any expression (assuming it has a definite weight).

I've been trying to write something that will do the trick on the C++ side, but I think the Python side should be straightforward with the above fix.

by (1.0k points)
edited by

The multiplier_t returned by the C++ function value() can be passed to the Python side as a proper rational, similar to what we do in Ex_get_mult in py_ex.cc.

Ah, ok, to do that one can replace the "return" statement in the above code snippet with

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;
0 votes

I have pushed a fix based on dbutter's suggestion, so in short, you can now do

x::Weight(value=1, label=field);
weight = Weight.get($x$, label="field").value("field")

to get the weight on the Python side.

by (82.6k points)
...