简体   繁体   中英

Common tangent function

I have an interesting problem in Python where I have two functions (arbitrary), and I'd like to find the common tangent between them, and the points on the x-axis where the common tangent touches each function. Ideally there would be a function that gives all the coordinates (imagine a very curvy set of functions with multiple solutions).

So, I have something that works, but it's very crude. What I've done is put each function into a matrix so M[h,0] contains the x-values, M[h,1] is function1 y values, M[h,2] is function2 y values. I then find the derivative and place this in a new matrix D[h,1] and D[h,2] (span is one less than M[h,:] . My idea was to essentially "plot" the slopes on the x-axis, and the intercepts on the y-axis, and search all these points for the closest pair, then give the values.

Two problems here:

  1. program doesn't know if the closest pair is a solution or not and

  2. it's painfully slow (numb_of_points^2 search). I realize some optimization libraries may help out, but I worry they will hone in on one solution and ignore the rest.

Anyone think of the best way to do this? My "code" is here:

def common_tangent(T):
    x_points = 600
    x_start = 0.0001 
    x_end = 0.9999
    M = zeros(((x_points+1),5) )
    for h in range(M.shape[0]):
        M[h,0] = x_start + ((x_end-x_start)/x_points)*(h) # populate matrix
        """ Some function 1 """
        M[h,1] = T*M[h,0]**2 + 56 + log(M[h,0])
        """ Some function 2 """
        M[h,2] = 5*T*M[h,0]**3 + T*M[h,0]**2 - log(M[h,0])
    der1 = ediff1d(M[:,1])*x_points # derivative of the first function
    der2 = ediff1d(M[:,2])*x_points # derivative of the second function
    D = zeros(((x_points),9) )
    for h in range(D.shape[0]):
        D[h,0] = (M[h,0]+M[h+1,0])/2 # for the der matric, find the point between
        D[h,1] = der1[h] # slope m_1 at this point
        D[h,2] = der2[h] # slope m_2 at this point
        D[h,3] = (M[h,1]+M[h+1,1])/2# average y_1 here
        D[h,4] = (M[h,2]+M[h+1,2])/2# average y_2 here
        D[h,5] = D[h,3] - D[h,1]*D[h,0] # y-intercept 1
        D[h,6] = D[h,4] - D[h,2]*D[h,0] # y-intercept 2
    monitor_distance = 5000 # some starting number
    for h in range(D.shape[0]):
        for w in range(D.shape[0]):
            distance = sqrt( #in "slope intercept space" find distance
                (D[w,6] - D[h,5])**2 +
                (D[w,2] - D[h,1])**2
                )
            if distance < monitor_distance: # do until the closest is found
                monitor_distance = distance
                fraction1 = D[h,0]
                fraction2 = D[w,0]
                slope_02 = D[w,2]
                slope_01 = D[h,1]
                intercept_01 = D[h,5]
                intercept_02 = D[w,6]
    return (fraction1, fraction2)

This has plenty of applications in materials science, in finding the common tangents between multiple Gibb's functions for the calculation of phase diagrams. It'd be nice to get a robust function out there for all to use...

You could go through the points of curve A, and at each point, draw the tangent line and calculate how many times it crosses curve B. If the number of crossings jumps up or down by two, then you know that you just passed a mutual tangent. This is still pretty crude but I imagine it would be somewhat faster than your original proposal, just because you don't need very many sample points on curve B to compute the number of times that the curve crosses a given tangent line. (Just count the number of times curve B switches between being above versus below the line.)

(Sure, if you have too few samples, you might miss a pair of crossings near the double-tangent, but that's fine, you're still going to be close to the double-tangent. You can and should add a separate estimate-refinement algorithm once you're very close to a true double-tangent. You can use something analogous to Newton's method, recursive bisections, etc.)

If you're more serious, I found this more sophisticated discussion .

Instead of solving the common tangent problem, you can just use a Legendre transform to convert the problem into solving the intersection of two curves. Once you do that, you can get the "common tangent region" by using the equality you found as the condition that the two original functions must satisfy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM