Skip to main content

equation solving - How to find a tangent line with 2 points of tangency for a curve?


Say I have a function like this:


f[x_] := 4 x^4 - 9 x^3 - x^2 + 10;
Plot[f[x], {x, -1, 2}]


enter image description here


It's obvious that there's a tangent line with 2 points of tangency here:


enter image description here


The problem is, how can I find this line programmatically for any such curve given?




UPDATE: Sorry, I lied. My function is actually f[\[CurlyPhi]_] := 1.100955 \[CurlyPhi] (1 - \[CurlyPhi]) + \[CurlyPhi]/9.99968* Log[\[CurlyPhi]] + (1 - \[CurlyPhi]) Log[1 - \[CurlyPhi]], which, even with a "Rationalize" at the head, yields a error message as follows:



This system cannot be solved with the methods available to Reduce.




What can I do about this?



Answer



Introduction:


We are looking for two distinct values of $x$ for which a generic line and your function have 1) the same $y$ value (i.e. the line touches the curve) and 2) the same derivative (i.e. the line is tangent to the curve).


We can set up the following system of equations spelling out these conditions:


y[x_] := a x + b                      (* a generic line *)
f[x_] := 4 x^4 - 9 x^3 - x^2 + 10; (* your function *)

sol = List@ToRules@Reduce[
{y[x1] == f[x1],

y'[x1] == f'[x1],
y[x2] == f[x2],
y'[x2] == f'[x2],
x2 != x1},
{x1, x2}
]

solutions


Notice that Solve wouldn't work here, because there are no general solutions valid for all values of the parameters (indeed, Solve will return the empty set). Reduce will generate conditions valid for some values of the parameters $a$ and $b$, which is what we are looking for. Reduce returns equations as results, but I converted those to substitution rules for plotting.


Plot[

{f[x], y[x] /. sol}, {x, -1, 2},
Epilog -> {PointSize[0.015], Point[{{x1, f[x1]}, {x2, f[x2]}}] //. sol}
]

plot


A self-contained function:


We can package this in a function:


Clear[doubleTangent]
doubleTangent[f_, range_ /; VectorQ[range, NumericQ] && Dimensions[range] == {2}] :=
Module[

{x1, x2, a, b, y, sol},
y[x_] := a x + b;
sol = Solve[{
f[x1] == y[x1], f[x2] == y[x2],
f'[x1] == y'[x1], f'[x2] == y'[x2], x1 != x2},
{x1, x2, a, b}, Reals
];
Plot[
{f[x], y[x] /. sol},
Evaluate@Flatten@{x, range},

PlotLegends -> {"function", "tangent"},
Epilog -> {
ReplaceRepeated[
{
PointSize[0.02],
Tooltip[Point[{#, f[#]}], Round[{#, f[#]}, 0.01]] & /@ {x1, x2}
},
N@sol
],
Inset[

"a = " <> ToString[N[a /. First@sol]] <> "\nb = " <> ToString[N[b /. First@sol]],
Scaled[{0.9, 0.9}], Alignment -> Left
]
}
]
]

This function will return the same result found above, with annotations, when used as follows:


doubleTangent[4 #^4 - 9 #^3 - #^2 + 10 &, {-1, 2}]


old example with doubleTangent


Yet another case:


doubleTangent[3 #^4 - 12 #^2 + 5 # + 9 &, {-3, 3}]

another example


Using a numerical solver for non-polynomial functions:


Here is a version relying on a numerical solver (FindRoot) to solve the system of equations in those cases in which Solve or Reduce are unable to provide a solution. Of course, the method is quite a bit more brittle, and initial (even rough) estimates must be provided of the positions of the points of tangency. It is fiddly, but it works nonetheless :-)


Clear[doubleTangentNumeric]

doubleTangentNumeric[

f_,
range_ /; VectorQ[range, NumericQ] && Dimensions[range] == {2},
initval_ /; VectorQ[initval, NumericQ] && Dimensions[initval] == {2}
] := Module[
{x1, x2, a, b, y, sol},
y[x_] := a x + b;
(* This is the BIG CHANGE; using a numerical solver rather than Solve or Reduce *)
sol = FindRoot[
{f[x1] == y[x1],
f[x2] == y[x2],

f'[x1] == y'[x1],
f'[x2] == y'[x2]},
{{x1, initval[[1]]},
{x2, initval[[2]]},
{a, 1}, {b, 1}},
WorkingPrecision -> 30, MaxIterations -> 1000
];
Plot[
{f[x], y[x] /. sol},
Evaluate@Flatten@{x, range},

PlotLegends -> {"function", "tangent"},

(* Replaced First@sol with sol, since only one solution is returned by FindRoot *)
Epilog -> {
ReplaceRepeated[{PointSize[0.02],
Tooltip[Point[{#, f[#]}], Round[{#, f[#]}, 0.01]] & /@ {x1, x2}}, N@sol],
Inset[
"a = " <> ToString[N[a /. sol]] <> "\nb = " <> ToString[N[b /. sol]],
Scaled[{0.8, 0.8}], Alignment -> Left]
}

]
]

We can now try it on the function from your comment:


f = Log[1 - #1] (1 - #1) + (3125 Log[#1] #1)/31249 + (73666 (1 - #1) #1)/66911 &;

doubleTangentNumeric[f, {0, 1}, {0.1, 0.9}]

numerical results


Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

calculus and analysis - Integral of the Sinc product

Let us consider the following integral $$ B_n = \int_0^\infty \prod_{k=1,3,5,\dots}^n\frac{\sin (x/k)}{x/k}dx $$ By definition, Sinc[x] == Sin[x]/x , therefore B[n_?OddQ] := Integrate[Product[Sinc[x/k], {k, 1, n, 2}], {x, 0, Infinity}] B /@ Range[1, 13, 2] {Pi/2, Pi/2, Pi/2, Pi/2, Pi/2, Pi/2, Pi/2} OK, everything is fine. But... B[15] 467807924713440738696537864469 Pi/935615849440640907310521750000 What's going on? Answer As Eckhard wrote in comments B[n] is the n-th Borwein integral . (The letter B was not accidental :) ) This funny properties of Borwein integrals is related to the Fourier transform of Sinc function FourierTransform[Sinc[x], x, k] 1/2 Sqrt[Pi/2] (Sign[1 - k] + Sign[1 + k]) Plot[%, {k, -2, 2}, Filling -> 0] which is the box function. The result is $\pi/2$ while the sum $$ 1/3+1/5+\dots+1/n $$ B_n = \frac{\pi}{2} - \pi \bigg(\sum_{k=3,5,\ldots}^n\frac{1}{k} -1\biggr)^\frac{n-1}{2}\prod_{k=3,5,\dots}^n\frac{k}{k-1}. $$ For $n=15$ it is equal to $$ \frac{46780...

list manipulation - Selecting multiple columns from a matrix?

Sample data: data = { {{2013, 1, 1}, 24.13, 167.67, 231.82}, {{2013, 1, 2}, 32.15, 170.92, 225.99}, {{2013, 1, 3}, 35.43, 172.68, 221.67}, {{2013, 1, 4}, 36.73, 173.05, 218.32}, {{2013, 1, 5}, 58.19, 165.96, 197.05}, {{2013, 1, 6}, 69.99, 163.50, 187.52}, {{2013, 1, 7}, 71.37, 154.21, 175.58}, {{2013, 1, 8}, 72.51, 149.66, 163.25}}; I want a DateListPlot with three graphs, so for a matrix formed by columns 1 and 2, one for columns 1 and 3, and 1 for columns 1 and 4. At the moment I'm using this code: data2 = Transpose[{data[[All, 1]], data[[All, 2]]}]; data3 = Transpose[{data[[All, 1]], data[[All, 3]]}]; data4 = Transpose[{data[[All, 1]], data[[All, 4]]}]; DateListPlot[{data2, data3, data4}, Joined -> True, Filling -> {3 -> {1}}] but I have a hunch that this can be done more efficiently. I don't like the Transpose s in particular. Any ideas? edit (for extra credit) What if I need to multiply the second column by 2, which in my solution is simp...