# 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 – 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. 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 = 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! – user43283 Oct 23 '18 at 19:47