# common tangent of double-well function

29 views (last 30 days)
Mateusz Brzezinski on 9 Sep 2020
Commented: Haiying Yang on 22 Jan 2022
Hello,
I have a complex problem and I am looking for a way to solve it using existing functions.
Let say that I have a double-well function y=f(x). Both y and x are stored in arrays. What I would like to do is to find a common tangent of two points near the local minima (red line). From a mathematical point of view, there are only two-point existing that can have a common tangent (red line). Others crossing function with more than 2 points (secants), they are touching only one point (unique tangent) or they are inside part of the function (common secants). Those two points are not necessarily local minimus in extremal cases this can be a descending function in most of its range and have only one minimum but still, there is only one line that touches only two-point without crossing others. Is there any function that can give me both coordinates or just y or x values of these two and only two points. I was thinking of a function that will create those lines and check if only two points are touched. I will appreciate any idea, tip link, or anything that can help build such a piece of code.
Matt J on 9 Sep 2020
From a mathematical point of view, there are only two-point existing that can have a common tangent (red line).
That would be true if you had f() in functional form, but since you only have samples x,y there is an infinite spectrum of different functions passing through the points, and a correspondingly infinite spectrum of tangents. You need to define some sort of interpolation model to connect the points continuously.

Matt J on 9 Sep 2020
Edited: Matt J on 9 Sep 2020
This might give you an acceptable discrete approximation, but note my comment.
p=polyfit([0,1,2,3,0.5, 2.5],[0 0 0 0 -1, -10],4); %fake data
x=linspace(-1,4,10000);
y=polyval(p,x);
%% Calculation begins here %%%
k=convhull(x,y);
[xk,yk]=deal(x(k),y(k));
j = diff(xk)>0;
[xk,yk]=deal(xk(j),yk(j));
interDist=vecnorm( diff([xk(:),yk(:)],1,1) ,2,2);
[~,imax]=max(interDist);
x1=xk(imax); y1=yk(imax); %the two tangent points (x1,y1) and (x2,y2)
x2=xk(imax+1); y2=yk(imax+1);
%% Plot the results %%%
close all
hold on
plot(x,polyval(p,x))
pl=polyfit([x1,x2],[y1,y2],1);
plot(x,polyval(pl,x))
xlim([0,3])
hold off Haiying Yang on 22 Jan 2022
Thank you Matt, it works.

John D'Errico on 22 Jan 2022
Edited: John D'Errico on 22 Jan 2022
This is actually not a difficult problem to solve, IF you think about what a tangent line means.
For example, consider the polynomial
syms x
y(x) = expand((x-1)*(x+1)*(x+2)*(x-2)*(x-2.5)*(x+2.5))
y(x) = (I don't do homework problems for people. Sorry. So this is my own function. Feel free to look at what I wrote and to use it. But that would force you to think about what I wrote, and how to modify it to solve a different problem.)
fplot(y,[-4,4]),ylim([-40,30]) The goal is to find lines that are doubly tangent to the curve. How would we define that in terms of mathematics? First, we need the derivative of the function y.
dy = diff(y,x)
dy(x) = What do points of common tangency have in common? The slope MUST be the same at both points. Can we write that in mathematics? Assume the x xoordinates of the points of common tangency are at the locations u and v.
syms u v
eq(1) = dy(u) == dy(v)
eq = That just says the slope of the curve at x=u mst be the same as the slope at x=v. But we need more than that. We can define a line by two points along the line. Think of them as (u,y(u)) and (v,y(v)). If the tngent line connects tose two points, then we must have this simple relation (THINK ABOUT WHAT IT MEANS!)
eq(2) = y(u) + (v - u)*dy(u) == y(v)
eq = Now we can just try using solve on the problem.
uvsol = solve(eq)
uvsol = struct with fields:
u: [13×1 sym] v: [13×1 sym]
And that must fail (if you look at it, because we are effectively trying to solve an implicit polynomial of degree 13), so we must convert those results to floating point numbers to resolve them. Actually, we should be happy that solve finds these solutions.
uv = vpa([uvsol.u,uvsol.v]);
Again, 13 solutions were found overall. We want to exclude the cases where we have u==v. We also want to worry only about the cases where v > u, since we seem to have duplicates. That is, if we found the solution (u,v), then the solution (v,u) should be excluded, as it would be the same line. We can resolve both issues by including only those sets where u < v (thus excluding those where u>=v).
uv(uv(:,1) >= uv(:,2),:) = []
uv = That leaves 6 distinct solutions. We can plot them simply enough, as
UV = double(uv')
UV = 2×6
-1.4931 -2.2958 -2.3373 -2.2754 -1.4469 0.1251 1.4931 2.2958 -0.1251 1.4469 2.2754 2.3373
yfun = matlabFunction(y);
yUV = yfun(UV);
fplot(y,[-3,3]),ylim([-30,20])
hold on
plot(UV,yUV,'o-')
grid on Those are the 6 lines of double tangency for this specific function. (At least for MY choice of function.) Change the function, and the solutions will be different. There may be different numbers of doubly tangent lines.
A nice feature of this solution is these lines are indeed the exact solutions to the problem, and they effectively encompass all possible solutions. (Exact to within floating point trash, that is.)
Haiying Yang on 22 Jan 2022
Hi John,
Thank you very much for your detailed explaination of the code and how you did. I got the common tangents for my function. The following is the figure. Best,

R2020a

### Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!