2
$\begingroup$

I've been trying to write some simple code to let me use physics vector notation: $\hat{x}$, $\hat{y}$, $\hat{r}$, and $\hat{\theta}$.

Unprotect[Plus, Times, Dot];
Plus[Vector[xhat1_, yhat1_, rhat1_, ϕhat1_], 
   Vector[xhat2_, yhat2_, rhat2_, ϕhat2_]] := 
  Vector[xhat1 + xhat2, yhat1 + yhat2, 
   rhat1 + rhat2, ϕhat1 + ϕhat2];

Times[c_, Vector[xhat_, yhat_, rhat_, ϕhat_]] := 
  Vector[c xhat, c yhat, c rhat, c ϕhat];
Dot[Vector[xhat1_, yhat1_, rhat1_, ϕhat1_], 
   Vector[xhat2_, yhat2_, rhat2_, ϕhat2_]] := 
  xhat1 xhat2 + yhat1 yhat2 + rhat1 rhat2 + ϕhat1 ϕhat2;

Dot[scalar1_ vector1_Vector, 
   scalar2_ vector2_Vector] := (scalar1 vector1).(scalar2 vector2);
Protect[Plus, Times, Dot];
Format[Vector[xhat_, yhat_, rhat_, ϕhat_]] := 
  DisplayForm[
   xhat OverscriptBox["x", "^"] + yhat OverscriptBox["y", "^"] + 
    rhat OverscriptBox["r", "^"] + ϕhat OverscriptBox["ϕ", 
      "^"]];

Overhat[x] = Vector[1, 0, 0, 0];
Overhat[y] = Vector[0, 1, 0, 0];
Overhat[r] = Vector[0, 0, 1, 0];
Overhat[θ] = Vector[0, 0, 0, 1];

I've been having trouble getting my dot product operation to work correctly. The source of the problem is that Dot has a higher precedence than Times so expressions such as Overhat[x].y Overhat[y] (that is $\hat{x}.y \hat{y}$) evaluates as Times[Dot[Overhat[x],y],Overhat[y]]. I don't want to evaluate Dot[Overhat[x],y] because that would be a vector dotted with a scalar. How can I prevent Mathematica from evaluating it in this way. If I could simply tell it to give precedence to Times over Dot then it would work, but this is probably impossible. Perhaps there is some clever pattern matching stuff I can to set how the expression evaluates before Mathematica can do anything with it. Such as

Times[Dot[v1_Vector, scalar_], v2_Vector] := scalar Dot[v1, v2];.

Unfortunately this doesn't work though.

This is the second post, the first one being How can I use a unit vector notation found in physic texts?, though it is somewhat unrelated.

**Edit: ** Mr. Wizard's solution is pretty much what I am looking for. But I found some unusual behavior that I couldn't find the explanation for. If we set $Pre twice, the second time seems to unset it:

(*First set*)
$Pre = Function[, Unevaluated[#] /. a_.b_ c_ :> a.(b c), HoldAll];
Overhat[x] = {1, 2, 3, 4, 5}; Overhat[y] = {a, b, c, d, e};
Overhat[x].y Overhat[y]
(*Evaluates as expected*)
a y + 2 b y + 3 c y + 4 d y + 5 e y
(*Second set*)
$Pre = Function[, Unevaluated[#] /. a_.b_ c_ :> a.(b c), HoldAll];
Overhat[x] = {1, 2, 3, 4, 5}; Overhat[y] = {a, b, c, d, e};
Overhat[x].y Overhat[y]
(*Evaluates as if $Pre had never been set*)
{a {1, 2, 3, 4, 5}.y, b {1, 2, 3, 4, 5}.y, c {1, 2, 3, 4, 5}.y, 
 d {1, 2, 3, 4, 5}.y, e {1, 2, 3, 4, 5}.y}

Even stranger is that $Pre doesn't appear to change between sets (now going into a new notebook):

$Pre

Outputs: $Pre Now if we set it:

$Pre = Function[, Unevaluated[#] /. a_.b_ c_ :> a.(b c), HoldAll];

Then: $Pre

Outputs: Function[Null, Unevaluated[#1] /. (a_).(b_) c_ :> a.(b c), HoldAll]

And doing the setting process again:

$Pre = Function[, Unevaluated[#] /. a_.b_ c_ :> a.(b c), HoldAll];

Then: $Pre

Outputs: Function[Null, Unevaluated[#1] /. (a_).(b_) c_ :> a.(b c), HoldAll]

So it appears to be set, but $Pre doesn't apply to this expression as (at least as I) would expect:

Overhat[x] = {1, 2, 3, 4, 5}; Overhat[y] = {a, b, c, d, e};
Overhat[x].y Overhat[y]

Outputs:

a {1, 2, 3, 4, 5}.y, b {1, 2, 3, 4, 5}.y, c {1, 2, 3, 4, 5}.y, d {1, 2, 3, 4, 5}.y, e {1, 2, 3, 4, 5}.y}

Is there some hidden feature of $Pre interacting with itself that makes it difficult to get these successive evaluations to work as expected?

**Edit 2: ** Following the advice of Mr. Wizard, here is the solution:

If[ValueQ[$Pre], , $Pre = 
   Function[, Unevaluated[#] /. a_. b_ . c_ d_ :> (a b).(c d), 
    HoldAll]];

Insert this anywhere in the above code to resolve the dot product problem.

$\endgroup$
  • $\begingroup$ you can always use () to control precedence. Can you not write Overhat[x].(y Overhat[y]) for example? $\endgroup$ – Nasser Dec 29 '19 at 20:03
  • $\begingroup$ @Nasser Ya your right. I could just use parentheses explicitly and maybe its a good idea to do that instead. But in typical usage that sort of thing isn't necessary because we understand immediately the expression y Overhat[y] to be a vector; unlike Mathematica and (my implementation of) Vector. Also (and this is a little lazy) I wanna avoid having to use parentheses with almost all applications of Dot. $\endgroup$ – Tanner Legvold Dec 29 '19 at 21:44
  • 1
    $\begingroup$ Messing with the definitions of basic functions such as Plus, Times and Dot is always a bad idea. $\endgroup$ – m_goldberg Dec 30 '19 at 1:42
  • $\begingroup$ @m_goldberg In this example I could change to CenterDot, CircleTimes, and CirclePlus and it would solve that problem, and I probably will in the long run. But I am restricted in what I can use as operators by the preferences, and I think the same problem will remain because I am still stuck using Times for multiplication by a scalar (unless I use something wacky as the dot product operator). I'm trying to avoid using something heavy duty like the Notation package. Theres got to be some way to tell MMA how to evaluate an expression of the listed form. $\endgroup$ – Tanner Legvold Dec 30 '19 at 7:01
  • $\begingroup$ Related: (19067) $\endgroup$ – Mr.Wizard Dec 30 '19 at 14:46
2
$\begingroup$

If this only has to work for manual input consider $Pre:

$Pre = Function[, Unevaluated[#] /. a_ . b_ c_ :> a.(b c), HoldAll];

Overhat[x] = {1, 2, 3, 4, 5}; Overhat[y] = {a, b, c, d, e};

Overhat[x].y Overhat[y]
a y + 2 b y + 3 c y + 4 d y + 5 e y
|improve this answer|||||
$\endgroup$
  • $\begingroup$ Thanks @Mr.Wizard this was the solution I was looking for. But I ran into some strange behavior that I described more in an edit to the original question (it took a lot of space) that I'm sure you know the explanation for. $\endgroup$ – Tanner Legvold Dec 30 '19 at 17:28
  • $\begingroup$ @Tanner Two points. (1) a_.b_ c_ is NOT the same as a_ . b_ c_ because a_. parses as Optional[Pattern[a, _]]. Perhaps I should have written Dot[a_, b_] c_ for robustness. (2) The second definition of $Pre is itself modified by the existing Function; here is a stand-alone example: Function[, Unevaluated[#] /. Dot[a_, b_] c_ :> a.(b c), HoldAll] /. Dot[a_, b_] c_ :> a.(b c) — within the result the left hand side of RuleDelayed is transformed into (a_).(b_ c_) which is the new precedence rather than the original one. $\endgroup$ – Mr.Wizard Dec 30 '19 at 22:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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