common tangent of double-well function
32 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
Mateusz Brzezinski
am 9 Sep. 2020
Kommentiert: John D'Errico
am 15 Feb. 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 Kommentar
Matt J
am 9 Sep. 2020
Bearbeitet: Matt J
am 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.
Akzeptierte Antwort
Matt J
am 9 Sep. 2020
Bearbeitet: Matt J
am 9 Sep. 2020
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 Kommentare
Matt J
am 22 Jan. 2022
I would try narrowing the range of x.
x=linspace(-0.25,2,10000);
Weitere Antworten (1)
John D'Errico
am 22 Jan. 2022
Bearbeitet: John D'Errico
am 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))
(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)
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)
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)
Now we can just try using solve on the problem.
uvsol = solve(eq)
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),:) = []
That leaves 6 distinct solutions. We can plot them simply enough, as
UV = double(uv')
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 Kommentare
将实
am 15 Feb. 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
am 15 Feb. 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.
Siehe auch
Kategorien
Mehr zu Calculus finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!