return (1 + a) * np.sin(a + b - x) - x

For (a, b) == (0, 0) I want to the root at 0, for (2, 0) I want the one near 1.5 and Для (2, 1) я хочу, чтобы один около 2.2 .
Теперь эта проблема кажется такой, которая может быть достаточно общей, чтобы иметь подготовленный, быстрый решатель в Scipy или другой стандартный пакет (или инструменты для легко и эффективно построить один). Тем не менее, я не знаю, какие термины искать, чтобы найти его (или убедиться, что его не существует). есть готовый инструмент для этого? Как называется такая проблема? Конечно, это не очень быстро, что в некоторой степени ограничивает меня в моем реальном приложении. < /P>
import functools
import numpy as np
from scipy.optimize import root_scalar
from matplotlib import pyplot as plt
def foo(x, a, b):
return (1 + a) * np.sin(a + b - x) - x
fig, ax = plt.subplots()
ax.grid()
ax.set_xlabel("x")
ax.set_ylabel("foo")
x = np.linspace(-np.pi, np.pi, 201)
ax.plot(x, foo(x, 0, 0), label="(a, b) = (0, 0)")
ax.plot(x, foo(x, 2, 0), label="(a, b) = (2, 0)")
ax.plot(x, foo(x, 2, 1), label="(a, b) = (2, 1)")
ax.legend()
plt.show()
# Semi-bodged solver for reference:
def _dfoo(x, a, b):
return -(1 + a) * np.cos(a + b - x) - 1
def _solve_fooroot(guess, a, b):
# Determine limits for finding the root.
# Allow for slightly larger limits to account for numerical imprecision.
maxlim = 1.1 * (1 + a)
y0 = foo(guess, a, b)
if y0 == 0:
return guess
dy0 = _dfoo(guess, a, b)
estimate = -y0 / dy0
# Too small estimates are no good.
if np.abs(estimate) < 1e-2 * maxlim:
estimate = np.sign(estimate) * 1e-2 * maxlim
for lim in np.arange(guess, guess + 10 * estimate, 1e-1 * estimate):
if np.sign(foo(lim, a, b)) != np.sign(y0):
bracket = sorted([guess, lim])
break
else:
return np.nan
sol = root_scalar(foo, (a, b), bracket=bracket)
return sol.root
@functools.cache
def _fooroot(an, astep, bn, bstep):
if an == 0:
if bn == 0:
return 0
guessan, guessbn = an, bn - 1
else:
guessan, guessbn = an - 1, bn
# Avoid reaching maximum recursion depth.
for thisbn in range(0, guessbn, 100):
_fooroot(0, astep, thisbn, bstep)
for thisan in range(0, guessan, 100):
_fooroot(thisan, astep, guessbn, bstep)
guess = _fooroot(guessan, astep, guessbn, bstep)
return _solve_fooroot(guess, an * astep, bn * bstep)
@np.vectorize(excluded=[2, 3, 4, 5])
@functools.cache
def fooroot(a, b):
astep = (-1 if a < 0 else 1) * 1e-2
bstep = (-1 if b < 0 else 1) * 1e-2
guess = _fooroot(int(a / astep), astep, int(b / bstep), bstep)
return _solve_fooroot(guess, a, b)
print(fooroot(0, 0))
print(fooroot(2, 0))
print(fooroot(2, 1))
Подробнее здесь: https://stackoverflow.com/questions/795 ... of-paramet