当导数的值受到约束时如何拟合多项式?
How to fit a polynomial when the values of derivatives are constrained?
对于 x
的特定值范围,是否有一种简单的方法来获得对多项式函数 f(x)
的导数的最大值有约束的解决方案?
就像对 的回答一样,scipy.optimize
中的 curve_fit
可以处理对各个系数的约束,如下例所示:
def func(x, a, b, c, d):
return a + b * x + c * x ** 2 + d * x ** 3
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0])
popt_cons, _ = curve_fit(func, x, y, bounds=([-np.inf, 2, -np.inf, -np.inf], [np.inf, 2.001, np.inf, np.inf]))
print(popt_cons)
>>> [-0.14331349 2. -0.95913556 0.10494372]
但是,如果我想要最适合的多项式,例如在一定范围内的 x
值的加速度最大值(二阶导数)有限制,该怎么办?
这意味着,通过对函数进行两次积分,可以说 2*c + 6*d*x
的值在 0
到 10
之间存在约束。
有没有办法做到这一点,还是我必须从头开始构建它?
curve_fit
方法不支持附加约束。但是,您可以实现非线性最小二乘问题
min ||f(x, coeffs) - y||^2
s.t. lb <= coeffs <= ub
f''(x, coeffs) <= max_val for all x_lb <= x <= x_ub
有额外的约束并用minimize
. Here's an example of how it could be done by means of np.polyval
and np.polyder
解决它:
import numpy as np
from scipy.optimize import minimize
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0])
def objective(coeffs):
return np.linalg.norm(np.polyval(coeffs, x) - y)
def constraint(coeffs, deriv_order, x_lb, x_ub, max_val):
deriv_coeffs = np.polyder(coeffs, deriv_order)
# Evaluate the derivative for all x_lb <= x <= x_ub
deriv_value = np.polyval(deriv_coeffs, x[(x >= x_lb) & (x <= x_ub)])
return -1.0*deriv_value + max_val
# Each inequality constraint has the form fun(x) >= 0
cons = [{'type': 'ineq', 'fun': lambda coeffs: constraint(coeffs, 2, 0.0, 3.0, 20)}]
bnds = [(-np.inf, np.inf), (2, 5.001), (-np.inf, np.inf), (-np.inf, np.inf)]
poly_degree = 3
res = minimize(objective, x0=2.0*np.ones(poly_degree+1), bounds=bnds, constraints=cons)
请注意,每个不等式约束的形式为 fun(x) >= 0
,即我们有 -f''(x, coeffs) + max_val >= 0
,第二个我们使用 x_lb = 0.0
、x_ub = 3.0
和 max_val = 20
衍生物。最后,res.x
包含多项式系数。
对于 x
的特定值范围,是否有一种简单的方法来获得对多项式函数 f(x)
的导数的最大值有约束的解决方案?
就像对 scipy.optimize
中的 curve_fit
可以处理对各个系数的约束,如下例所示:
def func(x, a, b, c, d):
return a + b * x + c * x ** 2 + d * x ** 3
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0])
popt_cons, _ = curve_fit(func, x, y, bounds=([-np.inf, 2, -np.inf, -np.inf], [np.inf, 2.001, np.inf, np.inf]))
print(popt_cons)
>>> [-0.14331349 2. -0.95913556 0.10494372]
但是,如果我想要最适合的多项式,例如在一定范围内的 x
值的加速度最大值(二阶导数)有限制,该怎么办?
这意味着,通过对函数进行两次积分,可以说 2*c + 6*d*x
的值在 0
到 10
之间存在约束。
有没有办法做到这一点,还是我必须从头开始构建它?
curve_fit
方法不支持附加约束。但是,您可以实现非线性最小二乘问题
min ||f(x, coeffs) - y||^2
s.t. lb <= coeffs <= ub
f''(x, coeffs) <= max_val for all x_lb <= x <= x_ub
有额外的约束并用minimize
. Here's an example of how it could be done by means of np.polyval
and np.polyder
解决它:
import numpy as np
from scipy.optimize import minimize
x = np.array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
y = np.array([0.0, 0.8, 0.9, 0.1, -0.8, -1.0])
def objective(coeffs):
return np.linalg.norm(np.polyval(coeffs, x) - y)
def constraint(coeffs, deriv_order, x_lb, x_ub, max_val):
deriv_coeffs = np.polyder(coeffs, deriv_order)
# Evaluate the derivative for all x_lb <= x <= x_ub
deriv_value = np.polyval(deriv_coeffs, x[(x >= x_lb) & (x <= x_ub)])
return -1.0*deriv_value + max_val
# Each inequality constraint has the form fun(x) >= 0
cons = [{'type': 'ineq', 'fun': lambda coeffs: constraint(coeffs, 2, 0.0, 3.0, 20)}]
bnds = [(-np.inf, np.inf), (2, 5.001), (-np.inf, np.inf), (-np.inf, np.inf)]
poly_degree = 3
res = minimize(objective, x0=2.0*np.ones(poly_degree+1), bounds=bnds, constraints=cons)
请注意,每个不等式约束的形式为 fun(x) >= 0
,即我们有 -f''(x, coeffs) + max_val >= 0
,第二个我们使用 x_lb = 0.0
、x_ub = 3.0
和 max_val = 20
衍生物。最后,res.x
包含多项式系数。