# Issue with Upvalues

I want to introduce two variables (I call them EXt and EXtC, where "C" stands for complex conjugate) which would mimic the behavior of a phase of a complex number. For that, I use the following tags:

 EXt /: EXt EXtC := 1;
EXtC /: EXtC EXt := 1;
EXt /: EXt EXtC^n_ := EXtC^(n - 1);
EXtC /: EXtC EXt^n_ := EXt^(n - 1);
EXt /: EXt^(n_?Negative) := EXtC^(-n);
EXtC /: EXtC^(n_?Negative) := EXt^(-n);
EXt /: Conjugate[EXt] := EXtC;
EXtC /: Conjugate[EXtC] := EXt;


With that, I can simplify expressions like

EXt^2 EXt^2


i.e. when both of the variables have the same power (and this power is a number)

However, I am not able to simplify the expressions in which the powers are different. For example, I cannot simplify (i.e. make it equal to EXtC in this case),

EXt^2 EXtC^3


even with the use of FullSimplify. I tried to introduce the following tag

EXt /: EXt^n_ EXtC^m_ := EXtC^(m - n)


but soon learned (for example, from here) that the upvalue mechanism can only scan one level deep, so I expectedly get the error message

TagSetDelayed::tagpos: Tag EXt in EXt^n_ EXtC^m_ is too deep for an assigned rule to be found. >>


Any ideas on how to circumvent this restriction and implement this property?

Clear[ext, extc]
ext /: ext[n_] extc[m_] := extc[m - n]
ext /: ext[n_] ext[m_] := ext[m + n]
extc /: extc[n_] extc[m_] := extc[m + n]
ext /: Conjugate@ext[n_] := extc[n]
extc /: Conjugate@extc[n_] := ext[n]
extc[n_?Negative] := ext[-n]
ext[n_?Negative] := extc[-n]
extc = 1;

ext /: Power[ext[m_], n_] := ext[m n]
extc /: Power[extc[m_], n_] := extc[m n]

\$Pre = # &;
patt = Except[Clear | ClearAll | Remove];
ext /: (h : patt)[a___, ext, b___] := h[a, ext@1, b]
extc /: (h : patt)[a___, extc, b___] := h[a, extc@1, b]

Format@ext[n_] := EXt^n
Format@extc[n_] := EXtC^n


Example:

ext
(* EXt *)

ext^2 extc^3
(* EXtC *)

ext extc^n // Conjugate
(* EXt^(-1 + n) *)

• One fun thing you could always add is ext /: Power[ext, n] := ext[n] which would obviate the need for writing ext[n] for powers. Then all you'd need to do would be add some rules on ext so that when used in the appropriate context it expands to ext and then you'd get out the behavior the OP wanted. You could even do something like ext /: (h: Power|Times|...)[a___, ext, b___]:>h[a, ext, b]) and then things would be easy Oct 23, 2018 at 17:25
• @b3m2a1 Inspired by your comment, I recalled something interesting. Have a look. Oct 23, 2018 at 18:14
• Edge case that isn't handled: ext^2. Also, as usual, using Format has an evaluation leak, e.g., Hold[ext[1+1]]. Oct 23, 2018 at 18:48
• @CarlWoll Thanks for pointing out. Fixed. Oct 23, 2018 at 19:03
• Works perfectly! Thanks a lot! Oct 23, 2018 at 19:47

Here's a variation of @xzczd's idea, using only a single symbol and adding formatting:

Clear[ext]
ext[n_] ext[m_] ^:= ext[n+m]
ext[n_]^m_ ^:= ext[n m]
Conjugate[ext[n_]] ^:= ext[-n]
ext = 1;

MakeBoxes[ext[n_],StandardForm]:=Switch[Unevaluated @ n,
0, "1",
1, MakeBoxes[EXt],
-1, MakeBoxes[EXtC],
_Integer?Negative, With[{s=-n}, MakeBoxes[EXtC^s]],
_, MakeBoxes[EXt^n]
]


For example:

EXt = ext
EXtC = ext[-1]


EXt

EXtC

And:

EXt^2 EXtC^2
EXt^2 EXtC^3
EXt EXtC^n //Conjugate


1

EXtC

EXt^(-1 + n)

• Works perfectly! Thanks a lot! Oct 23, 2018 at 19:47