4
$\begingroup$

I define a function with a condition like so.

ClearAll[foo];
foo[expr_] /; FreeQ[expr, bar] := expr

Such that foo[12] returns 12, and foo[12 bar] returns unevaluated as foo[12 bar].

Why is it that when I take the derivative D[foo[12 bar], x] or D[foo[12 bar], bar] it acts as if the condition were not present, returning 0 and 12 respectively?

The expected and desired behaviour is that the derivative is not able to be evaluated. I consider the result that Mathematica gives to be wrong. My function does not have that output when that condition is not met, and that is therefore not a valid derivative.

I've found that additionally specifying that catch all foo[_] := 0 means that D does take notice of the condition and uses that definition instead when appropriate, but without it the condition is ignored as shown above. Moving the condition to foo[expr_] /; FreeQ[expr, bar] := expr has no effect on the behaviour.

I guess that this line from the documentation may be relevant: "D returns generic results that may not account for discontinuities, cusps or other special points" Is my condition being treated as a special point? I don't want that, I just want it to behave like other functions that can't be evaluated for some input.

$\endgroup$
  • $\begingroup$ You are mixing programming constructs (/;) with mathematical constructs (D). In other words, the function you defined is not a function in the mathematical sense. It's a function in the programming sense. Trying to do math on it will lead to disaster sooner or later. $\endgroup$ – Szabolcs Feb 26 at 19:35
  • $\begingroup$ That's an interesting way to think about it @Szabolcs, but isn't that what many of the built in functions do? I'm thinking in particular of things like Integrate, which evaluate when they can and return unevaluated when they can't. The unevaluated forms are still valid for mathematical use. That's the style of function I was trying to create here. $\endgroup$ – Sam Feb 26 at 19:54
  • $\begingroup$ foo[12 bar] is returning unevaluated and then D performs the symbolic differentiation on the result. $\endgroup$ – Edmund Feb 26 at 21:49
4
$\begingroup$

Consider the calculation that Mathematica does internally, which is a chain rule:

D[foo[12 bar], bar] // Trace // TableForm

enter image description here

You can see that it needs to compute foo'[12 bar], and the way it does this is to create a special internal indexed variable

System`Private`DerivativeX[1]

and computes the derivative with respect to that. Because this doesn't have bar in it, it takes the derivative of the function

foo[System`Private`DerivativeX[1]]

which evaluates to

System`Private`DerivativeX[1]

whose derivative is just the function 1 &, i.e. the constant-1 function. This is then evaluated at the original input 12*bar, but of course 1 is returned, and so the final result is 12.

You can argue whether or not this is the right way to do things, but I think it is a sensical way to implement symbolic derivatives on nested functions internally. I don't really consider this a bug.


Now, to implement the desired behavior, we could short-circuit the evaluation of D by wrapping the expression in HoldForm at the appropriate step in the evaluation. For instance, one could add the following UpValue to foo:

foo /: HoldPattern[D[foo[expr_], bar]] := HoldForm[D[foo[expr], bar]]

Then,

D[foo[12 bar], bar] // FullForm
(* HoldForm[D[foo[Times[12, bar]], bar]] *)

This might or might not be the desired form: it might be clunky to work with if you want to do further evaluations. However, there are some set of evaluation rules associated with D, and I don't think there is a way for Mathematica to return the unevaluated expression

D[foo[12*bar], bar]
|improve this answer|||||
$\endgroup$
  • $\begingroup$ Ah, this makes sense in terms of the implementation, but I can't see why it's not considered broken when the result is not mathematically sensible. Your explanation looks like the explanation of a bug, not a feature. In my use case, foo is meant to be a wrapper that only evaluates its contents under specific conditions. Is there a way to make it behave as expected (returning D[foo[12 bar], x] unevaluated), perhaps by a Derivative[n_][foo][expr_] := style definition? Providing a work around as well as an explanation would make this an excellent answer. $\endgroup$ – Sam Feb 26 at 18:11
  • 1
    $\begingroup$ @Sam. I've added one possible solution with some commentary. I'm not sure I could or would do anything else! $\endgroup$ – march Feb 26 at 18:25
  • $\begingroup$ Thanks @march. I don't know whether the HoldForm approach will work for me because I do need to do further evaluation and manipulation, and as you say it's clunky. Inactive[D] might be a good alternative to HoldForm in some cases, although that's not very useful for me either. If anybody has any other ideas I'd like to see them, but this is an excellent answer to the question so I'm giving it the tick. $\endgroup$ – Sam Feb 26 at 18:42
  • 1
    $\begingroup$ @Sam It might be worth holding off on accepting the answer in order to attract other answers. There are pretty expert Mathematica users here, including many actual employees of Wolfram, and they might likely have a better response to both "Is it a bug?" and "What's a way to implement what I want?" If the question has an accepted answer, it's less likely to attract more answers. $\endgroup$ – march Feb 26 at 19:00
  • $\begingroup$ Fair enough @March, I've unaccepted for now. That's a very gracious thing for you to point out considering that the answer was yours. $\endgroup$ – Sam Feb 26 at 19: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.