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

I am applying a list of complicated substitution rules in cadabra. Schematically, these rules look like A_{i} -> (long expression) for some number (say 100) of the A_i. But the expression is very long.

I find that there is a surprising amount of time communicating with the Cadabra server in trying to apply these rules, versus looking for the rule myself.

Here is a sample code:

megasum := x+y.
for i in range(10000):
   megasum.top().append_child(Ex( r'B'+str(i) ))    

rules = []
for i in range(100):
   rules.append(Ex( r'A'+str(i)+'-> @(megasum)' ))

cdbrules = ListToExList(rules)

All the rules in lst are of the form A_i (from A0 to A99) going to the same giant sum. Then I use my Python function ListToExList to convert a Python list to a cadabra list.

On my laptop, the command

substitute($A0$, cdbrules)

requires about 600,000 us to run, and it appears independent of whether I give it A0 to act on or A99.

On the other hand, if on the Python side, I manually search the list for a rule that applies, it seems to run in about 60,000 us (in the worst case) and 5,000 us (in the best case) depending on if I find the rule quickly or not. A simple implementation:

ex := A0.
for i in range(len(keys)):
    if keys[i].matches(ex):
        substitute(ex, rules[i])
        break

where keys is a list of the LHS of the rules.

I'm trying to understand where the hangup is. My first thought is that Python has to be communicating the entire gargantuan cdbrules, and this is the bottleneck. However, I had the sense from the code that pointers are being used (or aliases to the objects) so that no actual copying is occurring. Does anyone have any ideas?

Apologies in advance for the rather ill-defined question...

in General questions by (1.1k points)

Can you send a minimal but complete working example (so including ListToExList and anything else needed) to me at info@cadabra.science?

My suspicion is that the slowness comes from the fact that substitute goes through all rules and does some pre-processing on them to figure out whether there are dummy indices in them. For the lhs of a rule that will be quick, but for the rhs this will take some time in your situation. This will happen in substitute's constructor, before you even hit can_apply.

The best is probably to defer these checks on the rhs until a rule actually matches (and then do it only once).

In any case, there is definitely no copying (or if there is, that's a bug). The Ex containing the rules is passed by reference into substitute.

Yup, based on the notebook you just sent, almost all that time goes into the preparatory work in the substitute constructor.

I'll fix this tomorrow.

Huh, that's interesting! Thanks, Kasper!

Please log in or register to answer this question.

...