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

In some cases, it would be useful to rename a specific subset of indices (dummy or not). In my particular case I am doing Hilbert metric variations of a matter Lagrangian and trying to reach a final expression that factors out a single metric variation coefficient.

What is happening is that I have many terms with metric variation factors, but each having different dummy indices. Even rename_dummies doesn't really help as it's a global action and I don't see a way to rename only the dummies of the \delta{g} terms.

What other strategy could be useful here? I'm thinking into a pseudo-code doing this:

  • for each \delta{g}^{?a ?b} term matching with a \delta{g} factor:
  • rename indices ?a to something unused or reserved in entire term
  • rename indices ?b to something unused or reserved in entire term
in General questions by (230 points)

2 Answers

0 votes
 
Best answer

Ok I ended up implementing something in line with the pseudo-code I was thinking:

from cdb.utils.indices import replace_index

def unify_variations_inplace(ex, symbol_name, target_indices):
    # 1. Helper to find the sum node (integrand)
    def find_sum_node(node):
        if node.name == r'\sum': return node
        for child in node.children():
            res = find_sum_node(child)
            if res: return res
        return None

    # Locate the node inside the original expression (ex)
    sum_node = find_sum_node(ex.top())
    if not sum_node: 
        return ex

    # 2. Build the unified integrand as a new Ex
    new_sum = Ex('0')
    for term_node in sum_node.children():
        t_ex = term_node.ex()
        matches = list(t_ex[symbol_name])

        if matches:
            current_indices = [str(idx.name) for idx in matches[0].indices()]
            for i in range(min(len(current_indices), len(target_indices))):
                old_idx, new_idx = current_indices[i], target_indices[i]
                if old_idx != new_idx:
                    t_ex = replace_index(t_ex, "", old_idx, new_idx)

        # We skip canonicalise here to prevent index shuffling
        new_sum += t_ex

    # 3. REINSERT the result into the original expression tree
    # This physically overwrites the sum inside the integral context
    sum_node.replace(new_sum)

    return ex

Then I use this like this:

dg{#}::LaTeXForm("\delta{g}").
action_test := \int{ W^{\mu}_{\nu \rho} g_{\mu \alpha} D^{\alpha} dg^{\rho \nu} + C_{\beta \mu} dg^{\beta \mu}}{x};
unify_variations_inplace(action_test, "dg", ['\psi', '\chi']);
factor_out(_, $dg^{\psi \chi}$);

The only shortcoming of this function is that as it is, it doesn't check if the target_indices are being already used inside the expression, but it shouldn't be too difficult to add

by (230 points)
selected by
0 votes

Can you not use zoom to focus on particular terms, do your rename_dummies, and then unzoom? E.g. if you have

{a,b,c,d}::Indices(position=fixed);
ex:= \delta{g}^{c d} A_{c d} + \delta{\phi} B_{c d} D^{c d};
zoom(ex, $\delta{g}^{a b} Q??$);
rename_dummies(ex);
unzoom(ex);

This will only rename the dummies in the first term.

If not, can you give an example of the terms that you want to change, and an example of the terms that you want to keep unmodified?

by (86.5k points)

Suppose I have terms like:

\delta{g}^{a b} C_{a b} + \delta{g}^{c d} D_{c d} + \delta{g}^{a c} E_{c f} F_{a h} U^{f h}

I want to canonicalise the delta{g} to common indices (ignoring symmetrization for now) so that it looks like:

\delta{g}^{a b} C_{a b} + \delta{g}^{a b} D_{a b} + \delta{g}^{a b} E_{b f} F_{a h} U^{f h}

This will allow a subsequent invocation of factor_out to succeed

Using the example code in your post, I would have to loop over every term, retrieve the current indices being used by the \delta{g}, but rename_dummies will not make any guarantees about keeping indices consistent across invocations

Ah, you are being bitten by the infamous rename_dummies parent ordering issue.

What happens is that the indices are renamed not in the order in which they appear in each term, but in the order determined by the name of the tensor on which they sit. In that order, \delta{g} comes last, and so that last term in your expression will not get the same index names on \delta{g} as the other two.

You can work around this by temporarily substituting \delta{g}^{a b} -> A^{a b} so that the A indices get relabelled first, and then substitute back.

This, admittedly, is non-intuitive, but it somehow slipped by todo list. Have created an issue now (https://github.com/kpeeters/cadabra2/issues/387) so it will not get lost again (and hopefully get fixed at some point).

Thank you, it's good to know that. Trying to understand the node API I ended up implementing something that directly targets the indices I want to rename and nothing else. I'm still relying on having spare indices not being used anywhere but it sort of works

...