Using patterns in ReplaceAll to match different symbols

I have an expression

expr = kb.kpb+kb.kb+knb.knb+kpb.knb+kd.kpd+kd.kd+knd.knd+kpd.knd;


and I want to make replacement rules as:

{kb.kb->kb^2,kd.kd->kd^2,kb.knb->knb^2,kb.kpb->kpb^2,
kpb.knb->0,kd.kd->kd^2,kd.knd->knd^2,kd.kpd->kpd^2,kpb.knb->0}


Instead of writing down every possible combination, I want it to be general, so I try:

rule1 = {k_ . k_ -> k^2, kp_ . kn_ -> 0, k_ . kp_ -> kp^2, k_ . kn_ -> kn^2};


but when I run my code, the output is:

expr1 /. rule1
(* kb^2+kd^2+knb^2+knd^2 *)


the term is kpd^2+kpb^2 missing.

What is the problem with my replacement rules?

• Welcome to Mathematica StackExchange! Unfortunately, that is not exactly how patterns work. I suggest you read Introduction to Patterns. Namely, when you write k_, this does not mean "any symbol which starts with the letter k", but it means "any symbol, which I will temporarily name with k". That is why, for example, k_ . k_ -> k^2, matches and replaces all terms in your expression (try expr /. k_ . k_ -> k^2). Commented Jan 7 at 11:33
• @Domen thanks for your reference. I learn a lot. is there any way to choose variables of my expression by their name in a general mode? Commented Jan 7 at 13:18
• You can do more complicated rules which look at the string form of your symbol, and then check which letters this string contains. However, a slightly more elegant way is to use a more "structured" version of your variables, for example: k[b] and k[p, b] instead of kb and kpb because these are then much easier to match in replacement rules. Commented Jan 7 at 13:55
• A random example: k[b] + k[d] + 2 k[p, b] + k[p, b]^2 /. {k[x_] :> k[x]^3, k[x_, y_] :> k[x] k[y]} Commented Jan 7 at 14:01
• You don't need Except in this case, just write the condition. Oh, and you have to put it outside so that it sees b: (S[k[a_, b_], p[c_]] /; c =!= b) :> 0 Commented Jan 9 at 10:27

If I understand the question, then k1 and k2 (shown below) are two groups that dictate the outcomes of the dot products.

Clear["Global*"];
expr = kb . kpb + kb . kb + knb . knb + kpb . knb + kd . kpd +
kd . kd + knd . knd + kpd . knd;
k1 = {kb, kd};
k2 = {kpb, knb, kpd, knd};

rule = {Dot[a_, a_] /; MemberQ[k1, a] :> a^2
, Dot[a_ /; (MemberQ[k1, a]), b_ /; (MemberQ[k2, b])] :> b^2
, Dot[a_ /; (MemberQ[k2, a]), b_ /; (MemberQ[k1, b])] :> a^2
, Dot[a_ /; (MemberQ[k2, a]), b_ /; (MemberQ[k2, b])] :> 0
};

expr /. rule


kb^2 + kd^2 + kpb^2 + kpd^2

• thanks, its brilliant. in my expression k and kp and kn are constant and d or b is indicators. so, indicators may change. Can I write the rule which can affect more general? I mean despite of what indicator used; it could dose its work. Commented Jan 7 at 13:16
• Can you include more indicators to the list k2? If you have test cases that can't be handled with this strategy, then you can add those to the post. If you have a different (more general) problem to solve, then you can also ask a separate question. Thanks.
– Syed
Commented Jan 7 at 13:28

Your first pattern is o.k., it replaces all squares. However, the second one is disastrously. "kp_ . kn_ -> 0" is the same pattern as "x_ . y_ -> 0". It replaces everything by 0. That is why you are getting only square terms.

It is not 100% clear to me what your output should be. I assume that you want: This can be achieved by:

rule = {k_ . k_ -> k^2,
kb . knb -> knb^2,
kb . kpb -> kpb^2,
kd . knd -> knd^2,
kd . kpd -> kpd^2
};
expr /. rule


The best way to solve this problem is to use a more intelligent way of naming variables. Generally, the difference between variables is applied by changing their names, while in Wolfram language, variables can be written as functions and finally treated as a variable. For example, to solve the mentioned problem, the code can be rewritten in the following way to solve the problems completely.

expr = Dot[k[b, 4],k[b, p]] + Dot[k[b, 4],k[b, 4]] +
Dot[k[b, n],k[b, n]] + Dot[k[b, p],k[b, n]] + Dot[k[d, 4],k[d, p]] +
Dot[k[d, 4],k[d, 4]] + Dot[k[d, n],k[d, n]] + Dot[k[d, p],k[d, n]];


Now it's easy to write a comprehensive replacement rule for it that easily covers all possibilities. While this is not possible in the usual way of naming variables and using patterns.

replacementRules = {
Dot[k[qIn_, vIn1_], k[qIn_, vIn2_]] :>
Which[
vIn1 == vIn2, k[qIn, vIn1]^2
, vIn1 == 4   , k[qIn, vIn2]^2
, vIn2 == 4   , k[qIn, vIn1]^2
, vIn1 != vIn2, 0
]
};
`