# 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[0] = 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[1] 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[1], b]) and then things would be easy – b3m2a1 Oct 23 '18 at 17:25
• @b3m2a1 Inspired by your comment, I recalled something interesting. Have a look. – xzczd Oct 23 '18 at 18:14
• Edge case that isn't handled: ext[2]^2. Also, as usual, using Format has an evaluation leak, e.g., Hold[ext[1+1]]. – Carl Woll Oct 23 '18 at 18:48
• @CarlWoll Thanks for pointing out. Fixed. – xzczd Oct 23 '18 at 19:03
• Works perfectly! Thanks a lot! – user43283 Oct 23 '18 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[0] = 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[1]
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! – user43283 Oct 23 '18 at 19:47