5
$\begingroup$

I would like to replace the derivative of a function by my own definition. For example I have the function a:

a[x_]:=Sin[x];

And I would like to assign now:

a'[x_]:=-Sin[x];

This gives me an error. What works for me is defining:

a[x_?NumberQ]:=Sin[x];

and then applying the above definition of a'. But this solution seems not right to me, since i would change the way Mathematica treats the both definitions of the function a.

  • Can someone explain why exactly the second solution works. What is inherently different between the two definitions?
  • How is the assignment of the derivative done properly when defining a without the ?NumberQ?
$\endgroup$
  • $\begingroup$ You have to Unprotect D/Derivative in order to overwrite pattern matching rules for built-in functions. That's because a'[x] actually evaluates to Derivative[1][a][x] which means it belongs to Derivative. $\endgroup$ – Thies Heidecke Nov 21 '17 at 17:00
  • 1
    $\begingroup$ Are you sure that what you are trying to do makes sense? The derivative of Sin[x] is not -Sin[x] and to try and define it this way would appear to be nonsense. You can define some other operator "myDerivative" that has this property, but it is not the (regular) derivative. $\endgroup$ – bill s Nov 21 '17 at 17:00
  • $\begingroup$ @ThiesHeidecke Then: Unprotect[Derivative]; a[x_] := Sin[x]; Derivative[1][a][x_] := -Sin[x]; should work? It somehow does not for me. $\endgroup$ – Mr Puh Nov 21 '17 at 17:03
  • $\begingroup$ @bills Its a dummy example to understand the concept. It make sense to provide the derivative of a function in order to not calculate the derivative each time when it is called. Also using approximate versions of derivatives which are algebraically simpler could be an application. $\endgroup$ – Mr Puh Nov 21 '17 at 17:11
  • 1
    $\begingroup$ You can avoid calculating the derivative each time it appears by defining using Set instead of SetDelayed. Unprotecting and redefining built-in functions (like Derivative) will lead you to grief sooner or later. $\endgroup$ – bill s Nov 21 '17 at 17:15
8
$\begingroup$

Derivative is not a protected symbol just so you can define derivatives for functions as you desire (although, I think it's a good idea to use UpValues for a anyways). The problem is that you are trying to define (sub)SubValues of Derivative, and you are running into a premature evaluation. In particular:

Clear[a]
a[x_] := Sin[x]
a'
a'[Pi]

Cos[#1] &

-1

Notice how a' already evaluates to Cos[#1]&. So, when you try to define:

a'[x_] := -Sin[x]

you are really trying to define:

(Cos[#1]&)[x_] := -Sin[x]

which is a definition for Function, a protected symbol. If you had instead done:

a /: a' = -Sin[#]&

-Sin[#1] &

then you would get the behavior you want:

a'[Pi]

0

Finally, your second definition of a doesn't run into this issue:

Clear[a]
a[x_?NumberQ] := Sin[x]
a'

Derivative[1][a]

Notice how Derivative[1][a] now doesn't have a definition. Mathematica only creates such definitions when the DownValues for a is not restricted.

$\endgroup$
4
$\begingroup$

I find it a really bad idea to re-define how D calculates derivatives; I'm pretty sure that in the majority of use-cases I have encountered, it has never been a good idea to 'overload' D in such a manner and I am stating this as a matter of personal fact.

It can conceivably be considered as an appropriate approach to pursue by really experienced users that know what they are doing but I definitely do not consider myself to be among their rank so I don't use it.

Having said that, a way around the issue of Unprotect-ing built-in symbols in general and D in particular might be defining a 'wrapper' function around the original built-in symbol.

Consider evaluating the following lines

 ClearAll[d]

 SetAttributes[d, HoldFirst]

 d[f_[x_]] := D[f[x], x]

We're using HoldFirst as a Attribute for our derivative operator d in order to not allow it to evaluate its input; this will come in handy later.

Symbol d now can be used to calculate simple first degree derivatives eg evaluating

f[x_]:=x^2

d[f[x]]

will return

2x

as expected.

Now, in order to address the theme of 'changing the derivative of a function', consider again the example of f[x_]:=x^2 above but let's set its derivative equal to 3 x + 1.

In order to accomplish this, we can evaluate the following

d[f[x_]] ^:= 3x+1

Note we are using UpSetDelayed (see UpSetDelayed).

Also note that, had we not used HoldFirst earlier in the attribute list of symbol d, we would not have been be able to use UpSetDelayed successfully; there would also be other unwanted side effects, such as the possibility that the definition of d might not have been able to identify its input correctly and would thus return unevaluated.

As an educational aside, we can clear all definitions made so far and attempt to evaluate everything again, with the exception of not using HoldFirst, this time. Doing that will produce two errors.

  1. evaluating d[f[x]] will return un-evaluated ie d[x^2]
  2. attempting to define our derivative operator will return an UpSetDelayed::write error message.

Issue no. 1 occurs because Mathematica evaluates f[x] before applying any rules to it. Evaluating f[x] produces x^2 and our new operator d does not match any rule of the form d[Power[x, 2]] hence it returns un-evaluated.

Issue no. 2 occurs because Power is a built-in symbol and it is Protected thus not allowing us to modify rules associated with it (that is partly the issue we are trying to avoid with defining the wrapper function d for D in the first place).

Returning from this brief detour, after clearing all definitions once more, and evaluating everything, including SetAttributes[f,HoldFirst], doing something like

 d[f[x]] 

would return

 1+3x

as expected.


I include the notebook code as one unified piece for ease of replication

Code block 1

ClearAll[f, d]

SetAttributes[d, HoldFirst]

d[f_[x_]] := D[f[x], x]

f[x_] := x^2

d[f[x]]

d[f[x_]] ^:= 3 x + 1

d[f[x]]

Code block 2 (to replicate errors)

ClearAll[f, d]

d[f_[x_]] := D[f[x], x]

f[x_] := x^2

d[f[x]]

d[f[x_]] ^:= 3 x + 1

d[f[x]]
$\endgroup$
1
$\begingroup$

Using the OPs code from the comments, and without re-defining any built-in symbols, we can define the desired derivatives directly by giving them another name.

int = Interpolation[Range[100]^(1/2)];
ader[x_]  = D[int[x], x];
bder[x_] := D[int[x], x]; 
{AbsoluteTiming[Null[Table[ader[i], {i, 1, 5, .01}, {j, 0, 5, 0.01}]];], 
 AbsoluteTiming[Null[Table[bder[i], {i, 1, 5, .01}, {j, 0, 5, 0.01}]];]}

{{2.96934, Null},{4.21217, Null}}

So the first method, which takes the derivative only once, is faster. Here I have just defined the desired derivative functions with the names ader and bder instead of messing with the definitions of built-in functions.

$\endgroup$

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.