6

This is a strange result with a function defined as "functionB" in this example. Can someone explain this? I want to plot functionB[x] and functionB[Sqrt[x]], they must be different, but this code shows that functionB[x] = functionB[Sqrt[x]], which is impossible.

model = 4/Sqrt[3] - a1/(x + b1) - a2/(x + b2)^2 - a3/(x + b3)^4;
fit = {a1 -> 0.27, a2 -> 0.335, a3 -> -0.347, b1 -> 4.29, b2 -> 0.435,
    b3 -> 0.712};
functionB[x_] := model /. fit

Show[
 ParametricPlot[{x, functionB[x]}, {x, 0, 1}],
 ParametricPlot[{x, functionB[Sqrt[x]]}, {x, 0, 1}]
 ]

functionB[x] must different from functionB[Sqrt[x]], but in this case, the 2 lines are the same (which is incorrect).

Mr.Wizard
  • 24,179
  • 5
  • 44
  • 125
Nam Nguyen
  • 165
  • 5
  • 1
    It's definitely not a bug... See my answer below (and doubtless numerous others that will appear soon) – acl May 18 '11 at 14:57
  • 1
    I will try to remember this example to confuse/challenge my students the next time I teach with MMA. :) Some suggestions: I'd highly recommend you get a copy of 'Mathematica Navigator' (3rd). It's available for cheap and contains lots of examples to clear up your programming thought process. Next, get Sal's 'Mathematica Cookbook'--you should be able to find an eBook deal online for $9.99. Once comfortable with those, download Leonid Shifrin's 'Mathematica Programming - An Advanced Introduction' (it's free!) WARNING: do not dive into Leonid's book until you're ready! He's a smart dude. – telefunkenvf14 May 18 '11 at 19:28
  • 2
    `ParametricPlot` is a bit overkill here given that the first coordinate is a plain x. `Plot[functionB[x], {x, 0, 1}]` suffices. – Sjoerd C. de Vries May 18 '11 at 20:10
  • @telefunken Please abstain to comment like that about Leonid's book. He is lurking around here and your effusiveness may cause him to have second thoughts about giving away his book! :D – Dr. belisarius May 18 '11 at 21:31
  • 1
    @belisarius, @telefunkenvf14 The good thing about Creative Commons License is that it is irrelevant whether or not I change my mind after releasing under it, at least for whatever version was released under it - that particular version will always be free :). But the issue in question is beyond its scope anyway (pun intended). Apart from the excellent answer of @acl, this thread is possibly relevant (due to its format, you'll need to track replies to see them all - unlike google groups where google does this for you) http://forums.wolfram.com/mathgroup/archive/2010/May/msg00102.html – Leonid Shifrin May 18 '11 at 22:10
  • @user759342, do either of the answers answer your question? If so, then you should accept that answer by using the checkmark. This has three effects, both you and the poster get a reputation boost, and it allows others know that that answer seems to be the correct one. – rcollyer May 19 '11 at 14:43
  • @Leonid Shifrin: Thank you for your solution. – Nam Nguyen May 20 '11 at 12:51
  • DaoTRINH, who is the cutie in your profile picture? – Mr.Wizard May 22 '11 at 00:12

2 Answers2

10

If you try ?functionB, you'll see that it is stored as functionB[x_]:=model/.fit. Thus, whenever you now have functionB[y], for any y, Mathematica evaluates model/.fit, obtaining 4/Sqrt[3] - 0.335/(0.435 + x)^2 + 0.347/(0.712 + x)^4 - 0.27/(4.29 + x).

This has to do with using SetDelayed (i.e., :=). The rhs of functionB[x_]:=model/.fit is evaluated anew each time Mathematica sees the pattern f[_]. That you have named the pattern x is irrelevant.

What you want could be achieved by e.g. functionC[x_] = model /. fit. That is, by using Set (=) rather than SetDelayed (:=), so as to evaluate the rhs.

Hope this is clear enough (it probably isn't)...

Sjoerd C. de Vries
  • 16,122
  • 3
  • 42
  • 94
acl
  • 6,490
  • 1
  • 27
  • 33
  • Thank you, I understand. Vote for you ! – Nam Nguyen May 18 '11 at 15:05
  • if it answers your question, you can "Accept" it as the answer. or you can wait to see if other, better answers turn up – acl May 18 '11 at 15:31
  • 1
    @acl, at one point, I don't think that would have worked, and you'd have to `Evaluate` the RHS first and use `SetDelayed`. But, according to the [docs](http://reference.wolfram.com/mathematica/ref/Set.html) under Scope, it works correctly (in v.7, also). I wonder when the change was. So, you get a +1 for teaching me something new about an old function. – rcollyer May 18 '11 at 16:55
  • 2
    @rcollyer I know for certain that Mma versions 4 through 8 all support using `Set` in this way. I suspect this behaviour goes all the way back to v1, but perhaps an old(er) timer can set me straight. – WReach May 18 '11 at 18:09
  • @WReach, I seem to remember it not working for me, but it has been a long time since I tried it. (Although, if something is buggy, and I've accidentally done this, it is the first thing I change.) I could be remembering behavior from v.3, as that when I first actively used mma. – rcollyer May 18 '11 at 18:27
  • @rcollyer I suspect that you are referring to the pitfalls described by @Leonid in one of his comments to a [follow-up question](http://stackoverflow.com/questions/6058281/about-plotting-process-a-further-question-about-a-problem-in-mathematica-8-wi/6060078#6060078) -- namely that symbols in the context of the RHS of `Set` do not play well with nested scoping constructs. – WReach May 19 '11 at 17:40
3

You might want to try defining the model inside functionB so x in both places are related:

fit = {a1 -> 0.27, a2 -> 0.335, a3 -> -0.347, b1 -> 4.29, b2 -> 0.435, b3 -> 0.712};
functionB[x_] := Module[
  {model = 4/Sqrt[3] - a1/(x + b1) - a2/(x + b2)^2 - a3/(x + b3)^4},
  model /. fit
]
Meng Lu
  • 13,726
  • 12
  • 39
  • 47
  • 1
    dev, prior to re-reading the docs, I'd agree that this would work where acl's solution involving `Set` would not. But, apparently you can use a pattern rule with `Set`, also, and get the answer you expect. – rcollyer May 18 '11 at 16:57