5
$\begingroup$

I have a program where I deal with multiple complex variables and it is convenient to ouput all absolute values and complex conjugates as $|x|$ and $x^*$. To achieve this, I've added these lines to my code:

Unprotect[Conjugate];
Conjugate /: MakeBoxes[Conjugate[x_], StandardForm] := TemplateBox[{Parenthesize[x, StandardForm, Power]}, "Conjugate", DisplayFunction -> (SuperscriptBox[#1, "*"] &)]
Protect[Conjugate];

Unprotect[Abs];
Abs := StringForm["|``|", #1] &
Protect[Abs];

The lines for Conjugate work well, but the ones for Abs are problematic. Whenever I copy-paste the output of Abs[x], the in-line command looks like this:

StringForm["|``|", x]

instead of Abs[x] or |x|. Is there a better way to tell Mathematica how to format this absolute value?.

$\endgroup$
4
  • 1
    $\begingroup$ I assume wrapping the whole expression in TraditionalForm isn't what you want, and in fact you just want these to be formatted in place to make reading easier while still having computability? Also Format might be worth looking at. $\endgroup$ Commented Apr 30, 2022 at 20:15
  • 2
    $\begingroup$ Use Abs /: MakeBoxes[Abs[x_], StandardForm] := TemplateBox[{MakeBoxes[x, StandardForm]}, "Abs"] $\endgroup$
    – Carl Woll
    Commented Apr 30, 2022 at 20:43
  • $\begingroup$ Closely related: Is there a keybinding for absolute value? $\endgroup$
    – Jens
    Commented May 1, 2022 at 17:54
  • $\begingroup$ @CarlWoll Wow, I never noticed the relationship between TemplateBox and TraditionalForm! This should really be posted as an answer! $\endgroup$
    – xzczd
    Commented May 2, 2022 at 15:10

3 Answers 3

3
$\begingroup$
myFormat[f_] := (Unprotect@f;
  Format[f[x_], StandardForm] := Activate@TraditionalForm[Inactive@f[x]] (*Watch out for recursion!*);
 Protect@f)

myFormat /@ {Abs, Conjugate};

{Abs[x], Conjugate[x]}^2
% /. x -> I

Displayed output of the code

$\endgroup$
3
$\begingroup$

First off, I would strongly recommend you don't redefine Abs and Conjugate, but obviously that's your perogative.

Second, it's difficult to understand what you want. You say that you want the output of your re-defined Abs to be Abs[x] or |x|, but what would that even mean? It can't be Abs[x], because Abs is a function that you've redefined to produce a StringForm expression. As for |x|, that's not a valid Mathematica expression. Maybe you meant it to be string: "|x|". If you want that string, that can be accommodated, but I don't know what value that has for you.

Anyway, here are four alternatives for doing the formatting (each shows slightly different strategies):

Format[AbsHold1A[expr_]] := StringForm["|``|", expr];
Format[AbsHold1B[expr_]] := "|" <> ToString[expr] <> "|";

SetAttributes[{AbsHold2A, AbsHold2B}, HoldAll];
Format[AbsHold2A[expr_]] := StringForm["|``|", ToString@Unevaluated[expr]];
Format[AbsHold2B[expr_]] := "|" <> ToString[Unevaluated@expr] <> "|";

Now you can apply one of these new heads instead of Abs:

AbsHold1A[-5] (* displays as |-5| *)
(* the other three also display as |-5| *)

x = -5;
AbsHold1A[x] (* the 1 versions display as |-5| *)
AbsHold2A[x] (* the 2 versions display as |x| *)

With this approach, you still have a value that you can evaluate. One way would be to set UpValues with regard to Abs:

Abs[abs_AbsHold1A] ^:= Abs @@ abs
(* do the same for the other three *)

But, if you want the output of AbsForm to actually be the string, e.g. "|x|", then just define it directly rather than using Format:

AbsHold3A[expr_] := StringForm["|``|", expr];
AbsHold3B[expr_] := "|" <> ToString[expr] <> "|"
(* and so forth for the other two, making sure to set the necessary attributes *)

If you want to retrieve the value, you'll have to do something to destructure the string/stringform:

StringTake[ToString[AbsHold3A[x]], {2, -2}];
StringTake[AbsHold3B[x], {2, -2}];
$\endgroup$
1
  • 1
    $\begingroup$ hmm. Based on the other answers, maybe I misunderstood. If you're literally doing this with just pure symbols whose evaluation you don't need to suppress, then yeah, the other answers are simpler. I interpreted "variables" to mean things that might have assigned values. $\endgroup$
    – lericr
    Commented Apr 30, 2022 at 20:58
1
$\begingroup$

Turn the simple and surprising solution in Carl Woll's comment to an answer:

Unprotect[Abs];
Abs /: MakeBoxes[Abs[x_], StandardForm] := 
  TemplateBox[{MakeBoxes[x, StandardForm]}, "Abs"]
Protect[Abs];
$\endgroup$

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.