2

I recently ran into something that should be straight forward, but seems to be incredibly complex.

If I define some function,

f[x_,y_]:=x+y

I wish to take the derivative of the complex conjugate. I have found some workarounds, such as here.

excluded=OptionValue[SystemOptions[], "DifferentiationOptions"->"ExcludedFunctions"];
SetSystemOptions["DifferentiationOptions"->
"ExcludedFunctions"->Union[excluded,{Conjugate}]];

Unprotect[Conjugate];
Conjugate /: D[Conjugate[f_], x__] := Conjugate[D[f, x]]
Protect[Conjugate];

However, let's say I choose the variable to differentiate to be the complex conjugate. If I set y to some constant

D[Conjugate[f[x, 1]], Conjugate[x]] (*1*)

I get the desired result. However, if I set y as a variable

 D[Conjugate[f[x, y]], Conjugate[x]] (*0*)

I get the wrong result, while

  D[Conjugate[f[x, y]], x] (*1*)

It appears that when I have two or more variables, the result doesn't work because the conjugate isn't expanded.I have used the FunctionExpand function, which yields the correct results, but I am more interested in why the disconnect occurs

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
zalba19
  • 269
  • 2
  • 6
  • This is also (1) D[Conjugate[f[x, 2 y]], Conjugate[x]]. Have you considered something line f[x_, y_] := Cos[x] + Sin[y]? It looks like results are pretty much wrong anyways. – Vsevolod A. May 30 '18 at 20:51

2 Answers2

2

You could use my ComplexD function, which I repeat here (slightly modified):

ComplexD[expr_, z__] := With[
    {
    nc = NonConstants -> Union @ Cases[{z},
        s_Symbol | Conjugate[s_Symbol] | {s_Symbol | Conjugate[s_Symbol], _} :> s
    ],
    old = OptionValue[
        SystemOptions[],
        "DifferentiationOptions" -> "ExcludedFunctions"]
    },

    Internal`WithLocalSettings[
        With[{new = Join[old, {Abs, Conjugate}]},
            SetSystemOptions["DifferentiationOptions"->"ExcludedFunctions" -> new]
        ];
        Unprotect[Conjugate, Abs];
        Conjugate /: D[w_, Conjugate[w_], nc] := 0;
        Conjugate /: D[Conjugate[f_], w_, nc] := Conjugate[D[f, Conjugate[w], nc]];
        Abs /: D[Abs[f_], w_, nc] := D[Conjugate[f]f, w, nc]/(2 Abs[f]),

        D[expr, z, nc],

        SetSystemOptions["DifferentiationOptions" -> "ExcludedFunctions" -> old];
        Conjugate /: D[w_, Conjugate[w_], nc] =.;
        Conjugate /: D[Conjugate[f_], w_, nc] =.;
        Abs /: D[Abs[f_], w_, nc] =.;
        Protect[Conjugate, Abs];
    ]
]

Then:

ComplexD[Conjugate[x+y], Conjugate[x]]
ComplexD[Conjugate[Sin[x y]], Conjugate[x]]

1

Conjugate[y Cos[x y]]

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
1
f[x_, y_] := x + y

It just needs a look at the return value of

Conjugate[f[x, y]]

Conjugate[x + y]

to see why D[Conjugate[f[x, y]], Conjugate[x]] returns 0. There is no Conjugate[x] involved in the expression. When calling D[arg1, arg2], Mathematica has to look for literal occurrences of arg2 within arg1.

So, the problem is that Conjugate did propagate over Plus[x,y]. In this case, we can enforce that with Distribute:

Distribute@Conjugate[f[x, y]]
D[Distribute@Conjugate[f[x, y]], Conjugate[x]]

Conjugate[x] + Conjugate[y]

1

If you add the following rule to Conjugate, then it will always try to propagate into holomorphic functions

Unprotect[Conjugate];
Conjugate[f_[x__]] := f[Sequence @@ Conjugate /@ {x}] /; ComplexAnalysis`HolomorphicQ[f]
Protect[Conjugate];

Now we can even deal with the following:

D[Conjugate[Sin[x y]], Conjugate[x]]

Conjugate[y] Cos[Conjugate[x] Conjugate[y]]

Henrik Schumacher
  • 106,770
  • 7
  • 179
  • 309