10
$\begingroup$

I have my own version of Dot called mydot, and it behaves quite similar to the built-in version in that it represents the non-commutative product of a string of objects. Also, mydot is supposed to support differentiation that behaves in the same way as Dot. But I am unable to get D to operate on mydot the same way D works on built-in Dot:

D[Dot[x, (x + a y), z], y]

enter image description here

But

D[mydot[x, (x + a y), z], y]

enter image description here

I tried:

Derivative[ndiff__][mydot][x__] := 
  ReplaceAll[Derivative[ndiff][Dot][x], Dot :> mydot];
D[mydot[x, (x + a y), z], y]

enter image description here

As you can see, the serious problem I'm having is that it is pulling the factor a outside of mydot, which is incorrect.

Trying to get this to behave properly by making definitions of Derivative fails, because the chain rule has already been applied:

Derivative[ndiff__][mydot][x__] := stuff;
D[mydot[x, (x + a y), z], y]

How do I program D and Derivative to apply chain rule to the symbol mydot correctly?

enter image description here

$\endgroup$
  • $\begingroup$ I strongly prefer against injecting code into a built-in function like this: ClearAttributes[D, Protected]; D[expr_, args__] := Block[{$inD = True, result}, result = (D[expr /. mydot[seq___] :> NonCommutativeMultiply[seq], args]) /. NonCommutativeMultiply[seq___] :> mydot[seq]; result ] /; ! TrueQ[$inD] SetAttributes[D, Protected]; $\endgroup$ – QuantumDot Jan 10 '16 at 13:26
  • $\begingroup$ What about defining the UpValues of built-in symbol D[]. $\endgroup$ – xyz Jan 10 '16 at 13:33
  • $\begingroup$ @ShutaoTANG How do you define UpValues when mydot can be arbitrarily deep inside of an expression? $\endgroup$ – QuantumDot Jan 10 '16 at 14:19
  • $\begingroup$ Why not define a myD function? Something like myD[expr_, args__] := (D[expr /. mydot -> NonCommutativeMultiply, args]) /. NonCommutativeMultiply -> mydot. $\endgroup$ – Virgil Jan 12 '16 at 19:04
6
$\begingroup$

By default, Mathematica always differentiates function heads that contain the independent differentiation variables, unless the function head is listed in the "DifferentiationOptions"->"ExcludedFunctions" system options. So, we can get the behavior you want by adding mydot to this list:

SetSystemOptions[
    "DifferentiationOptions" -> 
    "ExcludedFunctions"-> DeleteDuplicates[
        Append[
            OptionValue[SystemOptions[], "DifferentiationOptions"->"ExcludedFunctions"],
            mydot
        ]
    ]
];

and then adding a custom differentiation rule for mydot:

mydot /: D[mydot[a__], y_] := D[Dot[a], y] /. Dot->mydot

Then, we have:

D[mydot[x, (x+a y), z], y]

mydot[x, a, z]

as desired. Here are the rest of @Jens' tests:

D[y^2 + 2 mydot[x + b y, (x + a y), z], y]
D[y^2 + 2 mydot[x, f[x + a y], z], y]
D[mydot[x, (x + a y^2), z], y, y]

2 y + 2 (mydot[b, x + a y, z] + mydot[x + b y, a, z])

2 y + 2 mydot[x, a f'[x + a y], z]

mydot[x, 2 a, z]

$\endgroup$
7
$\begingroup$

Maybe you can use the following:

ClearAll[dmydot, mydot]

Derivative[ndiff__][mydot][x__] := dmydot[ndiff][x];

dmydot /: Times[f__, dmydot[n1___, 1, n2___][x__]] := 
 mydot @@ MapAt[Times[f] &, {x}, Length[{n1}] + 1]

All I'm doing here is pull the inner derivative that came from the chain rule back into the mydot to replace the original entry at that position. This is done by defining the derivative as dmydot and giving it a rule that acts when something multiplies it. Now it can of course happen that this "something" also contains factors that were there even before the chain rule kicked in. But at least the operation of pulling such additional factors into the mydot product can never be incorrect. Whether you are willing to live with this possibility, I'm not sure...

Here are some tests:

D[y^2 + 2 mydot[x + b y, (x + a y), z], y]

(* ==> 2 y + 2 (mydot[b, x + a y, z] + mydot[x + b y, a, z]) *)

This now behaves exactly like Dot:

D[y^2 + 2 Dot[x + b y, (x + a y), z], y]

(* ==> 2 y + 2 (b.(x + a y).z + (x + b y).a.z) *)

Here is a more general function f inside mydot:

D[y^2 + 2 mydot[x, f[x + a y], z], y]

(* ==> 2 y + mydot[x, 2 a Derivative[1][f][x + a y], z] *)

I think this is all mathematically correct, and the main issue of unwanted inner derivatives in front of the product has been fixed. In addition, it also works with higher derivatives:

D[mydot[x, (x + a y^2), z], y, y]

(* ==> mydot[x, 2 a, z] *)
$\endgroup$
  • $\begingroup$ I'm assuming that the differentiation variables (y) is a scalar. Differentiation with respect to matrices or operators would require additional rules. $\endgroup$ – Jens Jan 11 '16 at 5:59
  • $\begingroup$ Yes, differentials are w.r.t scalar. Also, so that it works with Series we need to define Derivative for higher order derivatives. My proposal is to replace your first line with the following two: Derivative[ndiff__][mydot][x__] /; And @@ Thread[Less[{ndiff},2]] := dmydot[ndiff][x]; and Derivative[ndiff__][mydot][x__] /; Or @@ Thread[GreaterEqual[{ndiff},2]] := 0;. Any thoughts? $\endgroup$ – QuantumDot Jan 11 '16 at 14:48
  • $\begingroup$ Yes, that seems to work with Series, too. I guess Series doesn't do the same internal simplifications that happen when a higher-order D is encountered. By the way, I also had an idea based on using Dt instead of D... but I guessed you prefer sticking with D. $\endgroup$ – Jens Jan 11 '16 at 20:13
  • $\begingroup$ Any ideas with Dt are welcome too! Thanks $\endgroup$ – QuantumDot Jan 11 '16 at 21:14
  • $\begingroup$ But with Dt, you'd have to give up using Series - so I think it's of more limited usefulness. The good thing about Dt is that it allows you to identify what the differentiation variables is "after the fact," because there will always be Dt[_,y] terms that give it away. Then you can reverse the chain rule without affecting other prefactors. $\endgroup$ – Jens Jan 12 '16 at 19:05

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.