Заставить numy fsolve работать над кусочно-постоянными функциями

Я пытаюсь использовать fsolve, чтобы найти точки пересечения различных параметрических кусочно-определенных функций:

max_price = 20.0
b = 0.5
consumption_func = lambda x,b : max_price if x <= b else max_price - (x-b)
func = lambda x: consumption_func(x,b)

bid_start, _, ier, msg = fsolve(lambda x: func(x) - 5.0, 0.0, xtol=0.0001, full_output=True)

Однако решатель не может найти пересечение даже для этой очень простой функции, если начальная точка находится в диапазоне, где функция постоянна:

bid_start, _, ier, msg = fsolve(lambda x: func(x) - 5.0, b-0.1, full_output=True)

Out: array([0.4]) #starting point
msg='The iteration is not making good progress, as measured by the 
  improvement from the last ten iterations.'

и успешно, если он находится в непостоянном диапазоне:

bid_start, _, ier, msg = fsolve(lambda x: func(x) - 5.0, b-0.1, full_output=True)

Out: array([15.5]) #correct answer

Я предполагаю, что это как-то связано с алгоритмом MINPACK, который использует fsolve (возможно, на основе градиента). В этом простом случае мне удается обойти это, передав b в качестве параметра, но в будущем я планирую работать с более сложными функциями; Любая идея о том, как я могу заставить fsolve работать здесь?

1 ответ

Решение

Ты можешь получить fsolve отклеить, добавив в уравнение случайную линейную функцию. Используйте решение рандомизированного уравнения в качестве отправной точки для исходного уравнения. Решение рандомизированного уравнения иногда будет близко к оригиналу реального уравнения, что приведет к сходимости. Если это не так; попробуйте еще раз с другим случайным.

Увидеть while цикл ниже, который работает до флага ier из fsolve равен 1 для исходного уравнения, что указывает на успех.

from scipy.optimize import fsolve
import random
max_price = 20.0
b = 0.5
consumption_func = lambda x,b : max_price if x <= b else max_price - (x-b)
func = lambda x: consumption_func(x,b)

ier = 0
while ier != 1:
    k = random.uniform(-0.01, 0.01)
    func_random = lambda x: func(x) + k*x
    x_prelim = fsolve(lambda x: func_random(x) - 5.0, 0.0, xtol=0.01)
    bid_start, _, ier, msg = fsolve(lambda x: func(x) - 5.0, x_prelim, xtol=0.0001, full_output=True)

print(bid_start)
Другие вопросы по тегам