General::ivar is not a valid variable when plotting - what actually causes this and how to avoid it?

I was just evaluating a couple of expressions and started to get errors like this:

General::ivar: -1.49994 is not a valid variable. >>
General::ivar: -1.43871 is not a valid variable. >>
General::ivar: -1.37749 is not a valid variable. >>
General::stop: Further output of General::ivar will be
suppressed during this calculation. >>


I'm doing nothing complicated - currently, I simply did this:

f[x_]:=x^2 + 2x + 1
Plot[f[x], {x, -4, 4}]
Solve[f[x] == 4]
g[x_]:=D[f[x], x]
Plot[g[x], {x, -2, 2}]
// ^ errors caused by this


Actually, this isn't the exact quadratic I am investigating, but it is a quadratic and I expected this to work. I googled, as you'd expect, and found this Stack Overflow question which suggested:

Plot[Evaluate[g[x]], {x, -2, 2}]


As a workaround.

It works - my question is, why doesn't that set of instructions generate that error (I can see it is something to do with replacing, but why is one plot different from the other?) and how can I avoid it? Is there something I should specifically have done in forming g?

-
Or you could do g[x_] = D[f[x], x] (note that I changed SetDelayed to Set) before plotting... – J. M. Feb 4 '12 at 14:01
@J.M. that works - got an explanation as to why? Would make a nice answer :) – user236 Feb 4 '12 at 14:07
Related question: stackoverflow.com/questions/5320330/… – Leonid Shifrin Feb 4 '12 at 15:02

The problem lies in g[x_] := D[f[x], x]; remember that what SetDelayed (that is, :=) does is to replace stuff on the right corresponding to patterns on the left before evaluating. Thus, when one does something like g[2] (and something like this happens within Plot[]), you are in fact evaluating D[f[2], 2], and since one cannot differentiate with respect to a constant ;), you get the General::ivar error message.

If you use Set instead (that is, g[x_] = D[f[x], x]), f[x] is differentiated first before the result of D[] is assigned to g[x_]. Since what's on the right of g[x_] is now an actual function, Plot[] no longer has a reason to complain.

-

J. M. has already given you a good answer to your question on the General::ivar error and how to avoid it. I wanted to demonstrate another example in the same spirit, where the difference between Set and SetDelayed is important, but you don't have the luxury of getting an error message like you did in this case, because it isn't semantically/syntactically incorrect. This is a common pitfall to watch out for, and is often the cause of "slow" plotting.

Consider a function that's the result of an expensive (however slight) calculation defined using Set and SetDelayed, as:

f[x_] := (Pause[0.05]; Integrate[y^2, {y, 0, 1}] x)
g[x_] = (Pause[0.05]; Integrate[y^2, {y, 0, 1}] x);


Now let's monitor the time taken in plotting the two functions and the points plotted in each case with:

Module[{i = 0, t},
t = (Plot[f[x], {x, 0, 1}, EvaluationMonitor :> i++]; // AbsoluteTiming // First);
Print["Timing = ", t, ", Points = ", i, ", Time/Point = ",  t/i]
]


and replace f[x] with g[x] for the latter. I get the following for f[x] and g[x] respectively:

(*
f[x] — Timing = 4.289333, Points = 77, Time/Point = 0.05570562
g[x] — Timing = 0.001735, Points = 77, Time/Point = 0.00002253
*)


What's happening here is that Plot is evaluating f[x] for each plot point (time/point ≈ 0.05), which can result in a tremendous slow down in cases where the evaluation takes considerable time. On the other hand, if you use Set as in g[x], the expensive calculation is computed only once and only the result is stored as the definition for g[x], and hence Plot doesn't have to re-evaluate it. The alternative is to force evaluation of f[x] and pass the result to Plot and this can also be done by wrapping an Evaluate around f[x].

-
I like this example. :) – J. M. Feb 4 '12 at 15:21
How come plotting Evaluate[f[x]] is still much slower then plotting g[x] (for a factor of six on my system)? – BoLe Jul 5 at 4:49

As has already been explained by J. M., you need to evaluate the derivative.

When using the format g[x_] = D[f[x], x] I highly recommend either localizing x or using \[FormalX] (enter with Esc \$x Esc) in its place:

Module[{x},
g[x_] = D[f[x], x]
]


Or:

-