Как найти минимум нелинейной многомерной функции с помощью метода Ньютона (код не линейной алгебры)

Я пытаюсь сделать некоторую оценку параметров и хочу выбрать оценки параметров, которые минимизируют квадратную ошибку в предсказанном уравнении более 30 переменных. Если бы уравнение было линейным, я бы просто вычислил 30 частных производных, установил бы их все в ноль и использовал бы решатель линейных уравнений. Но, к сожалению уравнение нелинейное и его производные.

Если бы уравнение было над одной переменной, я бы просто использовал метод Ньютона (также известный как Ньютона-Рафсона). Сеть богата примерами и кодом для реализации метода Ньютона для функций одной переменной.

учитывая, что у меня около 30 переменных,Как я могу запрограммировать численное решение этой проблемы с помощью метода? У меня есть уравнение в закрытой форме и я могу вычислить первую и вторую производные, но я не знаю, как из этого исходить. Я нашел большое количество процедуры в интернете, но они быстро попадают в тяжелые матричные обозначения. Я нашел что-то умеренно полезным в Википедии, но у меня возникли проблемы с переводом его в код.

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

вполне бетон:

  • Я хочу работать с таблицами, отображающими переменные в их значения. Я могу написать функцию такой таблицы, которая возвращает квадратную ошибку, заданную такой таблицей как аргумент. Я также могу создавать функции, возвращающие частичную производную по любой заданной переменной.

  • У меня есть разумная начальная оценка для значений в таблице, поэтому я не беспокоюсь о сходимости.

  • Я не уверен, как чтобы написать цикл, который использует оценку (таблицу значений для каждой переменной), функцию и таблицу функций с частичной производной для получения новой оценки.

Это последнее, с чем я хотел бы помочь. Любая прямая помощь или указатели на хорошие источники будут тепло оценены.


Edit: поскольку у меня есть первая и вторая производные в закрытой форме, я хотел бы воспользоваться ими и избежать более медленных сходящихся методов, таких как симплекс поиски.

4 ответов


вы можете найти то, что вам нужно, на числовых рецептах на веб-странице C. Есть бесплатная версия доступна онлайн. здесь (PDF)-это глава, содержащая метод Ньютона-Рафсона, реализованный в C. Вы также можете посмотреть, что доступно в библиотека netlib (LINPack, et. Эл.).


ссылка на числовые рецепты была наиболее полезной. Я закончил символически дифференцировать мою оценку ошибки, чтобы получить 30 частных производных, а затем использовал метод Ньютона, чтобы установить их все в ноль. Вот основные моменты кода:

__doc.findzero = [[function(functions, partials, point, [epsilon, steps]) returns table, boolean
Where
  point       is a table mapping variable names to real numbers 
              (a point in N-dimensional space)
  functions   is a list of functions, each of which takes a table like
              point as an argument
  partials    is a list of tables; partials[i].x is the partial derivative
              of functions[i] with respect to 'x'
  epilson     is a number that says how close to zero we're trying to get
  steps       is max number of steps to take (defaults to infinity)
  result      is a table like 'point', boolean that says 'converged'
]]

-- See Numerical Recipes in C, Section 9.6 [http://www.nrbook.com/a/bookcpdf.php]




function findzero(functions, partials, point, epsilon, steps)
  epsilon = epsilon or 1.0e-6
  steps = steps or 1/0
  assert(#functions > 0)
  assert(table.numpairs(partials[1]) == #functions,
         'number of functions not equal to number of variables')
  local equations = { }
  repeat
    if Linf(functions, point) <= epsilon then
      return point, true
    end
    for i = 1, #functions do
      local F = functions[i](point)
      local zero = F
      for x, partial in pairs(partials[i]) do
        zero = zero + lineq.var(x) * partial(point)
      end
      equations[i] = lineq.eqn(zero, 0)
    end
    local delta = table.map(lineq.tonumber, lineq.solve(equations, {}).answers)
    point = table.map(function(v, x) return v + delta[x] end, point)
    steps = steps - 1
  until steps <= 0
  return point, false
end


function Linf(functions, point)
  -- distance using L-infinity norm
  assert(#functions > 0)
  local max = 0
  for i = 1, #functions do
    local z = functions[i](point)
    max = math.max(max, math.abs(z))
  end
  return max
end

в качестве альтернативы использованию метода Ньютона Симплексный метод Nelder-Mead идеально подходит для этой проблемы и ссылается в числовых Recpies в C.

Роб