2
$\begingroup$

I have two functions Sup and Sdown that take a string of letters with allowed characters "Z","W","P","H" and returns a "sum" of strings with signs:

Sup[simple_String]:=
Block[{char=Characters[simple],z=0,w=0,n},
n=Count[char,"Z"|"P"];
Sum[
Which[
char[[i]]=="P",
z++;w++;0,
char[[i]]=="W",
w++;0,
char[[i]]=="Z",
z++;
Sigg[n,z,w]*StringJoin@@(Join[char[[;;i-1]],{"W"},char[[i+1;;]]]),
True,
0
],{i,Length[char]}
]
]

and

Sdown[simple_String]:=
Block[{char=Characters[simple],z=0,w=0,n},
n=Count[char,"Z"|"P"];
Sum[
Which[
char[[i]]=="P",
z++;w++;0,
char[[i]]=="Z",
z++;0,
char[[i]]=="W",
w++;
Sigg[n,z+1,w]*StringJoin@@(Join[char[[;;i-1]],{"Z"},char[[i+1;;]]]),
True,
0
],{i,Length[char]}
]
]

The sign is simply given by

Sigg[n_,z_,w_]:=If[EvenQ[n+w-z],1,-1]

As expected, this gives me i.e.

In[1]= Sdown["WPWPHH"]
Out[1]= -"WPZPHH" + "ZPWPHH"

Now, I want Sup and Sdown to be linear operators that can act on stuff like Out[1], so I do this:

Sup/:Sup[Plus[x__]]:=Plus@@(Sup/@x)

Sup/:Sup[Times[i_Integer,s_String]]:=Expand[i*Sup[s]]

and the same for Sdown. But when I try to Sup[Sdown["WPWPHH"]] I get

In[2]= Sup[Sdown["WPWPHH"]]
Out[2]= 2 + "WPWPHH"

instead of 2"WPWPHH" as I would expect. The FullForm of Out[1] is Plus[Times[-1,"WPZPHH"],"ZPWPHH"] so when I do

In[3]= Plus @@ (Sup /@ {Times[-1, "WPZPHH"], "ZPWPHH"})

I get

Out[3]= 2 "WPWPHH"

like expected. What's going on here? Can you help me find the error? Also, if there is a better way of implementing this linearity, please let me know :)

$\endgroup$
0

1 Answer 1

1
$\begingroup$

Thank you for a well-written question with complete code that made this reasonable to answer. Welcome to Mathematica Stack Exchange. :-)

  1. You do not need UpValues definitions here. That would only apply if you were attempting to add a rule to e.g. Plus rather than Sup, yet your use of TagSetDelayed makes it clear that you are attaching the rule to Sup.

  2. The major remaining issue is the pattern Plus[x__] which will not work; see: Why is ReplaceAll behaving like this?

  3. In the pattern above, even if it did work, x__ would be a sequence of expressions; you would need to wrap it in something before mapping, e.g. a List: Plus @@ Sup /@ {x}

Fortunately Map will work on expressions of arbitrary head therefore both problems can be avoided by matching the entire Plus object rather than the sequence. Your solution is therefore:

Sup[x_Plus] := Sup /@ x

Now:

Sup[Sdown["WPWPHH"]]
2 "WPWPHH"
$\endgroup$
4
  • $\begingroup$ Thank you for the quick answer. I now have Sup[x_Plus]:=Sup/@x and Sup[i_Integer*s_String]:=i*Sup[s] and it works brilliantly. $\endgroup$ Nov 13, 2014 at 10:41
  • $\begingroup$ @Marius Glad I could help. Another formulation you might consider is: Sup[i_Integer] := i; Sup[x : _[__]] := Sup /@ x. This maps Sup over any compound expression. Atoms such as Strings or Integers are then individually handled. $\endgroup$
    – Mr.Wizard
    Nov 13, 2014 at 12:16
  • $\begingroup$ Will there be any benefits (time, memory, ...) other than conceptual clarity in this case? In any case, thanks for the tip, it will surely help me with some of my other linear functions. $\endgroup$ Nov 13, 2014 at 12:23
  • $\begingroup$ @Marius I don't know without testing. On the surface I wouldn't expect any large performance difference but I have been surprised before. $\endgroup$
    – Mr.Wizard
    Nov 13, 2014 at 12:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.