8
$\begingroup$

Is there a way I can redefine the || operator such that a||b will be 1/(1/a + 1/b)?

Is it possible to define it infix as above and prefix such that ||[a,b,c] is 1/(1/a+1/b+1/c)?

I'm working with circuit impedances and it's a much more natural way of describing the circuit to use + for series and something simple like || for parallel.

$\endgroup$
3
  • 5
    $\begingroup$ You could, but you're asking for a witches-brew of nastiness messing with it that way. Why not just define a single character function - perhaps using some preferred symbol with no built-in operation, e.g. ` p[a___] := 1/Tr@(1/{a})` $\endgroup$
    – ciao
    Commented Aug 1, 2015 at 22:57
  • $\begingroup$ Welcome to Mathematica.SE! I suggest the following: 1) As you receive help, try to give it too, by answering questions in your area of expertise. 2) Read the faq! 3) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! $\endgroup$
    – Michael E2
    Commented Aug 1, 2015 at 23:11
  • $\begingroup$ If you follow @ciao's suggestion, you can also use it in infix notation via a ~p~ b. $\endgroup$
    – user484
    Commented Aug 1, 2015 at 23:22

3 Answers 3

11
$\begingroup$

Use upvalues. You don't want || to change its behavior except when it's operating on impedances. So, use a wrapper (z[ ], say) around the quantities that represent impedances, and associate upvalues with the wrapper. This lets you redefine how standard operators work on the wrapped values:

z[a_] || z[b_] ^= z[1/(1/a + 1/b)];
z[a_] + z[b_] ^= z[a + b];
a_ z[b_] ^= z[a b];

2 z[2] || z[1] + z[3]
(* z[2] *)
$\endgroup$
3
  • $\begingroup$ This sounds very much like what I'd like. Time to go digging through the docs and figure out what upvalues are... $\endgroup$
    – Omegaman
    Commented Aug 1, 2015 at 23:50
  • $\begingroup$ I wound up going with the DoubleVerticalBar suggestions below, but this best answers the question I was asking in a safe way. Is the preferred assignment operator ^= or ^:=? Both seem to work, but I'm sure there must be a difference. $\endgroup$
    – Omegaman
    Commented Aug 2, 2015 at 20:15
  • $\begingroup$ @Omegaman There is exactly the same difference that there is between = and :=. The ^ just stands there to signal that you want to associate the whole definition to the symbol z and not ||. Define f1[g1[t_]] ^= Expand[t^2] and f2[g2[t_]] ^:= Expand[t^2] and run f1[g1[t+1]] and f2[g2[t+1]]. You can check why it does what it does by looking at ?g1 and ?g2. $\endgroup$
    – Federico
    Commented Aug 3, 2015 at 9:54
10
$\begingroup$

I don't like the idea of redefining Or (||). Rather, I would suggest defining a function with the name DoubleVerticalBar.

There is a special double vertical bar character which will be interpreted as the infix operator for DoubleVerticalBar and can be input with Esc+Space+|+|+Esc.

SetAttributes[
  DoubleVerticalBar, 
  {NumericFunction, Orderless, Flat, OneIdentity, Listable}]
DoubleVerticalBar[a_, 0] := a
DoubleVerticalBar[a_, b_] := 1/(1/a + 1/b)

Then you can do things like the following

DblVerBar

$\endgroup$
4
  • $\begingroup$ If need be, the function can of course be redefined to handle an argument of $0$, without it spitting out a warning message. $\endgroup$ Commented Aug 2, 2015 at 5:36
  • $\begingroup$ @Guesswhoitis. Good idea. I have acted on it. $\endgroup$
    – m_goldberg
    Commented Aug 2, 2015 at 5:48
  • $\begingroup$ This was suggested by @Karsten7 as a comment to another answer, and is what I'm currently implementing. The SetAttributes call is quite helpful. I'd also point out that if one argument is 0, the result should be zero in order to be consistent with the full definition (and, in this case, true parallel impedances). You have my gratitude and upvote, but I think selecting this answer probably will confuse people in the future that search on the question as I (too) narrowly asked it. Thank you though, you got me closer to my solution. $\endgroup$
    – Omegaman
    Commented Aug 2, 2015 at 20:09
  • $\begingroup$ @Omegaman. I interpreted one argument being zero an meaning only one impedance was present rather than as a short circuit. But defining that case to be a short circuit makes a lot sense and is a trivial change the function: DoubleVerticalBar[a_, 0] := 0 $\endgroup$
    – m_goldberg
    Commented Aug 2, 2015 at 21:16
7
$\begingroup$

(I would love to hear from someone more knowledgeable about how to improve this answer.)

It is possible to redefine the || operator if you're willing to redefine the built-in Or, but I would certainly not recommend that because Or is a very common function upon which Mathematica probably relies internally all over the place.

Possibly more robust but still really scary is redefining the notation itself, using the Notation package. (This will look much nicer when pasted into Mathematica.)

mean[l___] := HarmonicMean[l]/Length[l]

<< Notation`

Notation[ParsedBoxWrapper[
RowBox[{"x_", "||", " ", "y_", " "}]] \[DoubleLongLeftRightArrow] 
  ParsedBoxWrapper[
   RowBox[List[" ", 
    RowBox[List["mean", "[", 
     RowBox[List["{", RowBox[List["x_", ",", "y_"]], "}"]], "]"]]]]]]

This will cause Mathematica to evaluate mean[{a,b}] instead of Or[a,b] when you type a || b.

A similar trick will let you use ||[a,b,c]. It's extremely odd, I have no idea how robust it is, and Mathematica's syntax highlighting will have a fit, but it works. It also doesn't interfere with Or, that I can see.

Notation[ParsedBoxWrapper[
  RowBox[{"||", 
  RowBox[{"[", 
  RowBox[{"a_", ",", "b_", ",", "c_"}], 
   "]"}]}]] \[DoubleLongLeftRightArrow]
 ParsedBoxWrapper[
  RowBox[{" ", 
  RowBox[{"mean", "[", 
  RowBox[{"{", 
  RowBox[{"a_", ",", "b_", ",", "c_"}], "}"}], "]"}]}]]]

Then || [a, b, c] will output 1/(1/a + 1/b + 1/c).

As I see ciao has commented above, it is really much better to define your own symbol.

$\endgroup$
5
  • 3
    $\begingroup$ In the words of the G-Man "...prepare for unforeseen consequences" - +1 on the answer and the appropriate cautions. $\endgroup$
    – ciao
    Commented Aug 1, 2015 at 23:08
  • $\begingroup$ I guess I don't understand how Mathematica is implemented under the hood. If I redefine the top-level symbol ||, it will redefine Or the behavior as used by other built-ins? I figured I'd lose the ability to use || at the top level but would retain access to Or and certainly wouldn't be able to disrupt internal implementations... $\endgroup$
    – Omegaman
    Commented Aug 1, 2015 at 23:46
  • $\begingroup$ It's because the symbol || is translated immediately into Or before evaluation even takes place. It's just syntactic sugar. Either you have to change Or, or you have to change the mapping between || and Or. (It's the latter which I fleshed out above, using Notation.) EDIT: I mean "symbol" as distinct from Symbol - in the typographical sense rather than the Mathematica-construct sense. $\endgroup$ Commented Aug 1, 2015 at 23:51
  • 2
    $\begingroup$ One could avoid all the potential trouble by using \[DoubleVerticalBar], which is displayed as , instead of ||. $\endgroup$
    – Karsten7
    Commented Aug 2, 2015 at 0:22
  • $\begingroup$ @Karsten7, that's the solution I went with. Didn't actually answer the question I'd asked, but solved the problem I had. Thanks! $\endgroup$
    – Omegaman
    Commented Aug 2, 2015 at 5:01

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.