Как я могу построить полиномиальную лямбда-функцию из списка коэффициентов?

У меня есть список коэффициентов, которые соответствуют полиномиальному выражению, то есть: [1,2,0] соответствует x^2 + 2x + 0. Я хотел бы поместить массив произвольной длины этих коэффициентов в лямбда-функцию.

В частности, я использую mpmath, и у меня есть список, используемый для модуль polyval, то есть:

polyval(ctx, coeffs, x, derivative=False)

Учитывая коэффициенты и число, polyval() оценивает многочлен.

И мне нужно использовать модуль findroot, который принимает одномерная функция, т.е.:

findroot(lambda x: x**3 + 2*x + 1, 2)

Как я могу построить лямбда-функцию из списка коэффициентов?


person Chris    schedule 01.02.2011    source источник
comment
Что вы имеете в виду, поместив массив произвольной длины этих коэффициентов в лямбда-функцию?   -  person Phil    schedule 01.02.2011


Ответы (4)


Вам действительно нужна лямбда-функция? Использование «нормальной» функции должно быть проще:

def poly(coeffs):
   def calc(x):
      result = 0
      for c in coeffs:
         result = result*x + c
      return result
   return calc

findroot(poly([1,2,0]))

И с помощью упомянутой вами функции polyval() должно работать что-то вроде этого:

findroot(lambda x: polyval(ctx, [1,2,0], x))

(Для соответствующего значения ctx)

person sth    schedule 01.02.2011
comment
Это в корне правильно. Только две настройки: (1) ctx просто замаскирован (polyval - это метод), и его не нужно передавать; и (2) findroot нужен интервал или начальная точка. Итак, findroot(lambda x: polyval([1,2,0], x), [-3, -1]) возвращает mpf('-2.0'), как и должно быть. - person DSM; 01.02.2011

Подход, основанный на polyval() sth, выглядит как лучший ответ (поскольку у вас уже есть доступ к этой функции), но если вы хотите реализовать свой собственный эквивалент, функция будет выглядеть больше как:

def poly(coeffs):
  def calc(x)
    result = 0
    for i,c in enumerate(reversed(coeffs)):
      result += c*(x**i)
    return result
  return calc

findroot(poly([1,2,0]))
person ncoghlan    schedule 01.02.2011

Если вам действительно нужно лямбда-выражение, проще всего использовать reduce():

coeffs = [1, 2, 0]
f = lambda x: reduce(lambda y, a: x*y + a, coeffs, 0.0)
findroot(f, 2)

Поскольку это также помечено numpy, вы также можете использовать numpy.poly1d:

coeffs = [1, 2, 0]
f = numpy.poly1d(coeffs)
findroot(f, 2)
person Sven Marnach    schedule 01.02.2011
comment
Прекрасное использование функции reduce! - person Emmanuel; 02.02.2011

Лямбда-выражение возможно благодаря отличным базовым функциям Python! Во-первых, нужно получить пары (коэффициент, показатель степени) с помощью мощной функции zip:

>>> l = [3, 0, 4, -9]
>>> range(len(l) - 1, -1, -1)
[3, 2, 1, 0]
>>> zip(l, range(len(l) - 1, -1, -1))
[(3, 3), (0, 2), (4, 1), (-9, 0)]

Я использую перевернутую range, так как большие показатели находятся в начале списка. Теперь многочлен — это сумма... вычисленная благодаря функции sum!

>>> f = lambda x: sum([coef*x**exp for (coef, exp) in zip(l, range(len(l) - 1, -1, -1))])
>>> f(3)
84

и действительно 3*3^3 + 0*3^2 + 4*3^1 - 9*3^0 = 3*27 + 0 + 4*3 - 9*1 = 81 + 12 - 9 = 84. Это выражение f верно для всего списка коэффициентов l, независимо от его длины, благодаря использованию len(l).

person Emmanuel    schedule 01.02.2011
comment
Я думаю, что вариант суммы ответа ncoghlan проще: def f(cfs, x): return sum(cx*i for i, c in enumerate(reversed(cfs))) - person DSM; 01.02.2011