繁体   English   中英

使用python的公切线

[英]Common tangent using python

我正在尝试使用 python 找到两条曲线的共同切线,但我无法解决它。
两条曲线的方程很复杂,涉及对数。

python中有没有一种方法可以计算两条曲线共同的切线的x坐标。 如果我有 2 条曲线 f(x) 和 g(x),我想在公共切线上找到 x 坐标 x1 和 x2,其中 x1 在 f(x) 上,x2 在 g(x) 上。 我正在尝试 f'(x1) = g'(x2) 和 f'(x1) = f(x1) - f(x2) / (x1 - x2) 来获得 x1 和 x2 但我无法使用nonlinsolve 因为方程太复杂了。

我只想找到公切线的 x 坐标

任何人都可以提出更好的方法吗?

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()

我正在尝试这个

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])

首先需要做的是减少公式

例如,第一个公式实际上是这样的:

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

这更干净,并且是带有对数项的二次方。 我希望您也可以在对数术语上做一些工作,但这是原始海报的练习

同样,第二个公式可以以相同的方式进行简化,这又是对原始海报的练习

由此,两个方程都需要对 x 进行微分才能找到切线。 然后将两个公式设置为彼此相等(对于公切线)。

这将彻底解决问题。

我真的想知道这到底是一个python问题还是一个纯数学问题......

需要注意的重要一点是,由于导数是单调的,因此对于fun1的任何导数值,都有fun2的解。 如果您绘制两个导数,则可以很容易地看到这一点。

因此,我们想要一个函数,给定一个x1 ,返回一个与之匹配的x2 我将使用数值解法,因为系统对于数值解法来说太麻烦了。

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]

我使用fmin作为上面的求解器,因为它有效,而且我知道如何使用它。 也许root_scalar可以给出更好的结果。

使用上面的函数,让我们得到一些导数相等的对(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)}')

这个结果是:

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

如果您想要几个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