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?

up vote 6 down vote accepted

How about the following?:

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 at 17:25
  • @b3m2a1 Inspired by your comment, I recalled something interesting. Have a look. – xzczd Oct 23 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 at 18:48
  • @CarlWoll Thanks for pointing out. Fixed. – xzczd Oct 23 at 19:03
  • Works perfectly! Thanks a lot! – user43283 Oct 23 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 at 19:47

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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