# Replacement rules for Power, Times and Ordered Objects

I'm trying to replace products of functions (with or without powers) that may not be found together in expressions.

For example, I want to take Spaa[1, 2] Spbb[2, 1] -> -Spaa[1, 3] Spbb[3, 1] in every expression.

However, my expressions might look like

 Spaa[1, 2]^2 Spaa[2, 3]^2 Spbb[2, 1]^3


How do I replace something like this? I have tried using

% /. Times[___, Spaa[1, 3], ___, Spbb[3, 1]] -> -Spaa[1, 2] Spbb[2, 1]


Which works for some expressions, but not others, and doesn't include the powers.

• what is desired result for the input Spaa[1,2]^2 Spaa[2,3]^2 Spbb[2,1]^3?
– kglr
Apr 8, 2018 at 13:46
• Spaa[1, 2]^2 Spaa[2, 3]^2 Spbb[2, 1]^3 /. Times[a___, Spaa[1, 2]^b_., c___, Spbb[2, 1]^d_.] :> -a Spaa[1, 3]^b c Spbb[3, 1]^d?
– kglr
Apr 8, 2018 at 13:48
• PolynomialReduce can be used for this. In[268]:= PolynomialReduce[Spaa[1, 2]^2 Spaa[2, 3]^2 Spbb[2, 1]^3, Spaa[1, 2] Spbb[2, 1] - (-Spaa[1, 3] Spbb[3, 1]), {Spaa[1, 2], Spbb[2, 1], Spaa[1, 3], Spbb[3, 1]}][[2]] Out[268]= Spaa[1, 3]^2 Spaa[2, 3]^2 Spbb[2, 1] Spbb[3, 1]^2 Apr 8, 2018 at 14:16

PolynomialReduce is useful for this.

In[1587]:=
PolynomialReduce[Spaa[1, 2]^2 Spaa[2, 3]^2 Spbb[2, 1]^3,
Spaa[1, 2] Spbb[2, 1] - (-Spaa[1, 3] Spbb[3, 1]), {Spaa[1, 2],
Spbb[2, 1], Spaa[1, 3], Spbb[3, 1]}][[2]]

(* Out[1587]= Spaa[1, 3]^2 Spaa[2, 3]^2 Spbb[2, 1] Spbb[3, 1]^2 *)

• Would you be able to comment here? (You commented on related topics multiple times.) Apr 24, 2019 at 8:46

You have to treat separately the cases with powers and the cases without powers. This is because patterns match the form of the expression and Times[Power[a,n],Power[b,n]] does not contain anywhere the expression Times[a,b]. I think the following solution might fork for you:

r = {Spaa[1, 2]^n_ Spbb[2, 1]^m_ :> (-Spaa[1, 3] Spbb[3, 1])^# Spaa[1, 2]^(n - #) Spbb[2, 1]^(m - #) &@Min[n, m], Spaa[1,2]Spbb[2,1] -> -Spaa[1,3]Spbb[3,1]};


And then do expr/.r to any expression expr to which you want to apply the rule.

The rule you defined in the question, namely

Times[___, Spaa[1, 2], ___, Spbb[2, 1]] -> -Spaa[1, 3] Spbb[3, 1]


(I'm assuming you mistakenly flipped 2 and 3), does not help because Times has attributes Flat so all its subsequences are assumed to be wrapped by Times for the purpose of pattern matching. Let me be clearer: for any function f so that Attributes[f] contains {Flat} this happens

 In[1]:= f[a,b,c,d]/.f[b,c]->something
Out[1]:= f[a,something,d]


Moreover it has attribute Orderless, so the blank in the middle is not needed. Because of these reasons the blanks actually never match anything, if it were otherwise whatever is matched by them would not appear in the r.h.s. (which is not what you wanted I assume).

• You don't need to treat the case without power separately because Power is also OneIdentity. Try this: a*b /. a_^n_.*b_^m_. :> {{a, n}, {b, n}}. Dec 13, 2018 at 8:28
• You are right, I discovered this too after I published the answer, I should have edited it. But I don't agree with your explanation when you say that this is because Power is OneIdentity. The reason is that a_^n_. is a pattern with an optional argument and _. means that when the optional argument is omitted it should be replaced by the default value globally specified for the function in which it occurs (namely Power). You can verify that indeed Default[Power, 2] returns 1. And you can also Unprotect[Power], set the default value to another constant and retry your example. Dec 13, 2018 at 18:42
• Remove OneIdentity attribute form Power and try the replacement above... Unprotect[Power]; ClearAttributes[Power, OneIdentity]; a*b /. a_^n_.*b_^m_. :> {{a, n}, {b, n}}. Dec 14, 2018 at 11:50
• But you are right in the point that for the replacement I suggested above to work both OneIdentity and Default matter. It's just that, from my point of view, OneIdentity is much more crucial here. It allows expressions without head Power at all (before we started talking about any arguments) be matched by patterns that do include Power. Default merely allows specifying a global default value, as opposed to Optional patterns, which define default values locally. The replacement a*b /. a_^(n_:1)*b_^(m_:1) :> {{a, n}, {b, n}} doesn't need Default but needs OneIdentity. Dec 14, 2018 at 12:06