common tangent of double-well function

28 vues (au cours des 30 derniers jours)
Mateusz Brzezinski
Mateusz Brzezinski le 9 Sep 2020
Commenté : John D'Errico le 15 Fév 2024
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.
  1 commentaire
Matt J
Matt J le 9 Sep 2020
Modifié(e) : Matt J le 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.

Connectez-vous pour commenter.

Réponse acceptée

Matt J
Matt J le 9 Sep 2020
Modifié(e) : Matt J le 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
  13 commentaires
Matt J
Matt J le 22 Jan 2022
I would try narrowing the range of x.
x=linspace(-0.25,2,10000);
Haiying Yang
Haiying Yang le 22 Jan 2022
Thank you Matt, it works.

Connectez-vous pour commenter.

Plus de réponses (1)

John D'Errico
John D'Errico le 22 Jan 2022
Modifié(e) : John D'Errico le 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.)
  5 commentaires
将实
将实 le 15 Fév 2024
Hi John,
Thank you for such detailed explanation. This is very helpful to me. But I still want to ask why the solution I found using ''fsolve''' without using toolbox is that u and v are very close, that is to say, it can find the solutions but the solution it finds is not what I want.
John D'Errico
John D'Errico le 15 Fév 2024
Think about it. Suppose in my example, I had chosen u==v. Is that a solution to that set of equations?
Now look at the starting values I chose. They were far apart. AND they were close to the solution I knew to exist.
Do you understand that a nonlinear system of equations can have multiple sets of solutions? That is not at all unusual. Some of those solutions may be trivial ones. In fact, I would expect this system of equations will have infinitely many pairs of trivial solutions, all where u==v. So if you started the solver with u near v, then you will get u==v, probably to within the convergence tolerance.
When you use a nonlinear solver, it is imperative that you choose starting values that are at least reasonable, else you will likely get garbage for a solution. That is possibly why your attempt failed.

Connectez-vous pour commenter.

Catégories

En savoir plus sur Programming dans Help Center et File Exchange

Produits


Version

R2020a

Community Treasure Hunt

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

Start Hunting!

Translated by