2
$\begingroup$

I would like to find the root of the third component of an interpolating function, here e.g. a BezierFunction p:

tab = Table[{Tan[u], Cos[u], Sin[u]}, {u, 0., 2. Pi}]
p = BezierFunction[tab]
Plot[p[x][[3]], {x, 0, 2 Pi}]

enter image description here

Now I would like to extract the root of the third component of the function like so:

FindRoot[p[u][[3]], {u, .2}]

However, differently to the Plot function before, this does not work:

Part::partw: Part 3 of BezierFunction[{{0.,1.}},<>][u] does not exist.

  • Why is Mathematica treating Plot and FindRoot in this regard differently? Both have the Attribute HoldAll.
  • How do i modify the line FindRoot[p[u][[3]], {u, .2}], so I am getting the right result for u?
$\endgroup$
  • $\begingroup$ Have you seen Indexed? The attribute HoldAll means that evaluation is held until it gets inside the function. After that, it's up to the function when the expression gets evaluated. Many functions in Mathematica evaluate the expression symbolically for various reasons (to find out if the derivatve/Jacobian can be computed, for instance). $\endgroup$ – Michael E2 Apr 15 at 11:40
1
$\begingroup$

1. The attribute HoldAll means that evaluation is held until the arguments get inside the function. After that, it's up to the function when the expressions are evaluated. Many functions in Mathematica evaluate the expression symbolically for various reasons (to find out if the derivative/Jacobian can be computed, for instance, which FindRoot might do). Plot also turns off a lot of messages, so the Part::partw error might be happening inside Plot without your knowing it. For Plot, a function not evaluating to a real number is not considered a serious problem. It usually just creates a gap in the graph that is drawn.

2. I get three messages, the second and third ones being the telling ones, not the first message that was quoted in the OP:

FindRoot[p[u][[3]], {u, .2}]

Part::partw: Part 3 of BezierFunction[{{0.,1.}},<>][u] does not exist.

Part::partw: Part 3 of BezierFunction[{{0.,1.}},<>][-0.729293] does not exist.

FindRoot::nlnum: The function value {BezierFunction[{{0.,1.}},<>][-0.729293][[3]]} is not a list of numbers with dimensions {1} at {u} = {-0.729293}.

{u -> 0.2}

The input -0.729293 lies outside the domain and the Bezier function does not extrapolate. This is an error that FindRoot does not recover from. The first message is only a warning.

To get a solution, add the domain as search boundaries:

FindRoot[p[u][[3]], {u, .2, 0, 1}]

Part::partw: Part 3 of BezierFunction[{{0.,1.}},<>][u] does not exist.

{u -> 0.}

Another root:

FindRoot[p[u][[3]], {u, .5, 0, 1}]

Part::partw: Part 3 of BezierFunction[{{0.,1.}},<>][u] does not exist.

{u -> 0.521603}

If you want to get rid of the warning, an alternative to defining a NumericQ-protected objective function is to use Indexed:

FindRoot[Indexed[p[u], 3], {u, .5, 0, 1}]
{u -> 0.521603}
| improve this answer | |
$\endgroup$
0
$\begingroup$

Here my workaround for your second question:

eq[u_?NumericQ] := p[u][[3]]
opt=NMinimize[{1, 0 == eq[u], 0 < u < 1} , u]
(* {1., {u -> 0.521603}} *)
| improve this answer | |
$\endgroup$
  • $\begingroup$ With more appropriate initial guess FindRoot can also be used: FindRoot[eq[u]==0,{u,0.5}]. $\endgroup$ – Alx Apr 15 at 15:25
  • $\begingroup$ Yes but you have to know the right starting value! For example FindRoot[eq[u] == 0, {u, .85 }]fails! $\endgroup$ – Ulrich Neumann Apr 15 at 18:45
  • $\begingroup$ Of course, using FindRoot obviously means one knows good starting values, without that FindRoot is useless. I only wrote that comment to show that OP can make use FindRoot as he wants/needs. $\endgroup$ – Alx Apr 16 at 0:23

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.