简体   繁体   English

使用python的公切线

[英]Common tangent using python

I am trying to find a common tangent to two curves using python but I am not able to solve it.我正在尝试使用 python 找到两条曲线的共同切线,但我无法解决它。
The equations to the two curves are complicated that involve logarithms.两条曲线的方程很复杂,涉及对数。

Is there a way in python to compute the x coordinates of a tangent that is common to both the curves in general. python中有没有一种方法可以计算两条曲线共同的切线的x坐标。 If I have 2 curves f(x) and g(x), I want to find the x-coordinates x1 and x2 on a common tangent where x1 lies on f(x) and x2 on g(x).如果我有 2 条曲线 f(x) 和 g(x),我想在公共切线上找到 x 坐标 x1 和 x2,其中 x1 在 f(x) 上,x2 在 g(x) 上。 I am trying f'(x1) = g'(x2) and f'(x1) = f(x1) - f(x2) / (x1 - x2) to get x1 and x2 but I am not able to get values using nonlinsolve as the equations are too complicated.我正在尝试 f'(x1) = g'(x2) 和 f'(x1) = f(x1) - f(x2) / (x1 - x2) 来获得 x1 和 x2 但我无法使用nonlinsolve 因为方程太复杂了。

I want to just find x-coordinates of the common tangent我只想找到公切线的 x 坐标

Can anyone suggest a better way?任何人都可以提出更好的方法吗?

import numpy as np
import sympy
from sympy import *
from matplotlib import pyplot as plt


x = symbols('x')
a, b, c, d, e, f = -99322.50019502985, -86864.87072433547, -96876.05627516498, -89703.35055202093, -3390.863799999999, -20942.518


def func(x):
    y1_1 = a - a*x + b*x
    y1_2 = c - c*x + d*x

    c1 = (1 - x) ** (1 - x)
    c2 = (x ** x)
    y2 = 12471 * (sympy.log((c1*c2)))

    y3 = 2*f*x**3 - x**2*(e + 3*f) + x*(e + f)
    eqn1 = y1_1 + y2 + y3
    eqn2 = y1_2 + y2 + y3
    return eqn1, eqn2


val = np.linspace(0, 1)
f1 = sympy.lambdify(x, func(x)[0])(val)
f2 = sympy.lambdify(x, func(x)[1])(val)

plt.plot(val, f1)
plt.plot(val, f2)
plt.show()

I am trying this我正在尝试这个

x1, x2 = sympy.symbols('x1 x2')

fun1 = func(x1)[0]
fun2 = func(x2)[0]
diff1 = diff(fun1,x1)
diff2 = diff(fun2,x2)
eq1 = diff1 - diff2
eq2 = diff1 - ((fun1 - fun2) / (x1 - x2))

sol = nonlinsolve([eq1, eq2], [x1, x2])

the first thing that needs to be done is to reduce the formulas首先需要做的是减少公式

for example the first formula is actually this:例如,第一个公式实际上是这样的:

formula = x*(1 - x)*(17551.6542 - 41885.036*x) + x*(1 - x)*(41885.036*x - 24333.3818) + 12457.6294706944*x + log((x/(1 - x))**(12000*x)*(1 - x)**12000) - 99322.5001950298
formula = (x-x^2)*(17551.6542 - 41885.036*x) + (x-x^2)*(41885.036*x - 24333.3818) + 12457.6294706944*x + log((x/(1 - x))**(12000*x)*(1 - x)**12000) - 99322.5001950298

# constants
a = 41885.036
b = 17551.6542
c = 24333.3818
d = 12457.6294706944
e = 99322.5001950298
f = 12000

formula = (x-x^2)*(b - a*x) + (x-x^2)*(a*x - c) + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
formula = (ax^3 -bx^2 + bx - ax^2) + (x-x^2)*(a*x - c) + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e
formula = ax^3 -bx^2 + bx - ax^2 -ax^3 + ax^2 + cx^2 -cx + d*x + log((x/(1 - x))**(f*x)*(1 - x)**f) - e

# collect x terms by power (note how the x^3 tern drops out, so its easier).
formula =  (c-b)*x^2 + (b-c+d)*x  + log((x/(1 - x))**(f*x)*(1 - x)**f) - e

which is much cleaner and is a quadratic with a log term.这更干净,并且是带有对数项的二次方。 i expect that you can do some work on the log term too, but this is an excercise for the original poster .我希望您也可以在对数术语上做一些工作,但这是原始海报的练习

likewise the second formula can be reduced in the same way, which is again an excercise for the original poster .同样,第二个公式可以以相同的方式进行简化,这又是对原始海报的练习

From this, both equations need to be differentiated with respect to x to find the tangent.由此,两个方程都需要对 x 进行微分才能找到切线。 Then set both formulas to be equal to each other (for a common tangent).然后将两个公式设置为彼此相等(对于公切线)。

This would completely solve the question.这将彻底解决问题。

I actually wonder if this is a python question at all or actually a pure maths question.....我真的想知道这到底是一个python问题还是一个纯数学问题......

The important point to note is that, since the derivatives are monotonic, for any value of derivative of fun1 , there is a solution for fun2 .需要注意的重要一点是,由于导数是单调的,因此对于fun1的任何导数值,都有fun2的解。 This can be easily seen if you plot both derivatives.如果您绘制两个导数,则可以很容易地看到这一点。

Thus, we want a function that, given an x1 , returns an x2 that matches it.因此,我们想要一个函数,给定一个x1 ,返回一个与之匹配的x2 I'll use numerical solution because the system is too cumbersome for numerical solution.我将使用数值解法,因为系统对于数值解法来说太麻烦了。

import scipy.optimize

def find_equal_value(f1, f2, x, x1):
    goal = f1.subs(x, x1)
    to_solve = sympy.lambdify(x, (f2 - goal)**2)  # Quadratic functions tend to be better behaved, and the result is the same
    sol = scipy.optimize.fmin(func=to_solve, x0=x1, ftol=1e-8, disp=False)  # The value for f1 is a good starting guess
    return sol[0]

I used fmin as the solver above because it worked and I knew how to use it by heart.我使用fmin作为上面的求解器,因为它有效,而且我知道如何使用它。 Maybe root_scalar can give better results.也许root_scalar可以给出更好的结果。

Using the function above, let's get some pairs (x1, x2) where the derivatives are equal:使用上面的函数,让我们得到一些导数相等的对(x1, x2)

df1 = sympy.diff(func(x)[0])
df2 = sympy.diff(func(x)[1])

x1 = 0.25236537  # Close to the zero derivative
x2 = find_equal_value(df1, df2, x, x1)
print(f'Derivative of f1 in x1: {df1.subs(x, x1)}')
print(f'Derivative of f2 in x2: {df2.subs(x, x2)}')
print(f'Error: {df1.subs(x, x1) - df2.subs(x, x2)}')

This results is:这个结果是:

Derivative of f1 in x1: 0.0000768765858083498
Derivative of f2 in x2: 0.0000681969431752805
Error: 0.00000867964263306931

If you want a x2 for several x1 s (beware that in some cases the solver hits a value where the logs are invalid. Always check your result for validity):如果您想要几个x1x2 (请注意,在某些情况下,求解器会遇到日志无效的值。始终检查您的结果是否有效):

x1s = np.linspace(0.2, 0.8, 50)
x2s = [find_equal_value(df1, df2, x, x1) for x1 in x1s]
plt.plot(x1s, x2s); plt.grid(); plt.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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