Как решить стохастические дифференциальные уравнения в Julia?

Я пытаюсь понять, как решать стохастические дифференциальные уравнения (СДУ) численно (у меня нет опыта в любом языке, но по некоторым причинам я выбрал Юлию). В качестве начальной модели я решил использовать уравнения Лотки-Вольтерры. Я прочитал руководство и руководство для DifferentialEquations.jl. Пока моя модель представляет собой простую систему ODE:

введите описание изображения здесь

все отлично работает:

using DifferentialEquations
using Plots
function lotka(du,u,p,t);
    ????, ????, ????, ???? = p; 
    du[1] = ????*u[1]-????*u[1]*u[2];
    du[2] = ????*u[1]*u[2]-????*u[2];
end
u0 = [15.0,1.0,0.0,0.0];
p = (0.3,0.05,0.7,0.1);
tspan = (0.0,50.0);
prob = ODEProblem(lotka,u0,tspan,p);
sol = solve(prob);
plot(sol,vars = (1,2))

Теперь я хочу добавить шум Орнштейна-Уленбека:

введите описание изображения здесь

Глупое простое решение:

using DifferentialEquations
using Plots
function lotka(du,u,p,t);
    ????, ????, ????, ????, ????, ???? = p; 
    du[1] = ????*u[1]-????*u[1]*u[2]+u[3];
    du[2] = ????*u[1]*u[2]-????*u[2]+u[4];
    du[3] = -u[3]/????+sqrt((2.0*????^2.0/????))*randn();
    du[4] =  -u[4]/????+sqrt((2.0*????^2.0/????))*randn();
end
u0 = [15.0,1.0,0.0,0.0];
p = (0.3,0.05,0.7,0.1,0.1,0.1);
tspan = (0.0,50.0);
prob = ODEProblem(lotka,u0,tspan,p);
sol = solve(prob);

Но, как и ожидалось, это не сработало, так как решатель не для такой задачи SDE.

┌ Warning: Interrupted. Larger maxiters is needed.
└ @ DiffEqBase /home/jrun/.julia/packages/DiffEqBase/ujEgN/src/integrator_interface.jl:116

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

ОБНОВИТЬ:

Наконец, у меня есть следующий код:

using DifferentialEquations,Plots;

function lotka(du,u,p,t);
    ????, ????, ????, ????, ????, ???? = p; 
    du[1] = ????*u[1]-????*u[1]*u[2];
    du[2] = ????*u[1]*u[2]-????*u[2];
end
function stoch(du,u,p,t)
  ????, ????, ????, ????, ????, ???? = p; 
  du[1] = 1 
  du[2] = 1
end
u0 = [15.0,1.0];
p = (0.3,0.05,0.7,0.1,0.9,0.1);
????, ????, ????, ????, ????, ???? = p; 
OU = OrnsteinUhlenbeckProcess(1/????, 0.0, ????, 0.0, 0.0);
tspan = (0.0,100.0);
prob = SDEProblem(lotka,stoch,u0,tspan,p,noise = OU);
sol = solve(prob,EM(),dt = 1e-3, adaptive=false);

Чтобы закрыть эту тему, у меня два последних вопроса:

  1. Это правильный код? (Боюсь, что мой шум в этом случае не диагональный)

  2. Могу ли я иметь различный начальный шум (W0) для каждого из двух уравнений?


person zlon    schedule 16.11.2018    source источник
comment
не получилось ... Что вы имеете в виду? Ваш скрипт выдает сообщения об ошибках или результат не соответствует вашим ожиданиям?   -  person Sven Krüger    schedule 16.11.2018
comment
@ SvenKrüger Я добавляю сообщение об ошибке в тему   -  person zlon    schedule 16.11.2018
comment
Это не ошибка, это просто предупреждение. Попробуйте предоставить больший временной интервал tspan = [0 t_max], где t_max > 50.   -  person Sven Krüger    schedule 16.11.2018
comment
Хорошо, это предупреждение, и я могу попробовать изменить параметр maxiter, но это не очень хорошее решение. Это специально разработанные решатели, которые я не понимаю, как использовать   -  person zlon    schedule 16.11.2018
comment
Должно быть prob = SDEProblem (lotka, u0, tspan, p);   -  person zlon    schedule 16.11.2018
comment
Почему это не должно быть хорошим решением? Алгоритм решения предлагает это ... Я должен признать, что у меня нет опыта работы с Julia или ее библиотеками, но мне это кажется очевидным ... Некоторое руководство   -  person Sven Krüger    schedule 16.11.2018
comment
Вам необходимо переформулировать исходные уравнения, поскольку вам нужны функции a,b в dX = a(t,X) dt + b(t,X) dW в качестве аргументов в конструкторе SDEProblem.   -  person Lutz Lehmann    schedule 16.11.2018


Ответы (1)


Кажется, у вас есть SDE, где первые два члена управляются вторыми двумя, которые являются стохастическими? В этом случае вы бы составили lotka детерминированные термины:

function lotka(du,u,p,t);
    ????, ????, ????, ????, ????, ???? = p; 
    du[1] = ????*u[1]-????*u[1]*u[2]+u[3];
    du[2] = ????*u[1]*u[2]-????*u[2]+u[4];
    du[3] = -u[3]/????
    du[4] = -u[4]/????
end

а затем stoch стохастическая часть:

function stoch(du,u,p,t)
  ????, ????, ????, ????, ????, ???? = p; 
  du[1] = 0 
  du[2] = 0
  du[3] = sqrt((2.0*????^2.0/????))
  du[4] = sqrt((2.0*????^2.0/????))
end

Теперь это записывается в форме du = f(u,p,t)dt + g(u,p,t)dW. Заметьте, что точно так же, как вы не пишете dt, вы не пишете randn(), поскольку это обрабатывается (более сложно) в решателе. Используя их, вы определяете проблему SDEP и решаете:

u0 = [15.0,1.0,0.0,0.0];
p = (0.3,0.05,0.7,0.1,0.1,0.1);
tspan = (0.0,50.0);
prob = SDEProblem(lotka,stoch,u0,tspan,p);
sol = solve(prob);

(Вы должны быть осторожны с этой моделью, хотя, поскольку она не гарантированно будет оставаться положительной, поэтому она может работать нестабильно, если будет слишком много шума. Не только интегратор, но и само решение)

Краткое объяснение того, почему использование решающей программы ODE не работает

Просто для ясности, причина того, что то, что вы делали выше, не работает, состоит в двух причинах. Во-первых, адаптивность делает предположения, основанные на свойствах решения. Например, стандартный интегратор 5-го порядка предполагает, что решение дифференцируемо в 5 раз, и использует это в своих оценках ошибок для выбора размеров шага. SDE дифференцируем в 0 раз: он дифференцируется только по эпсилону для каждого эпсилона ‹1/2. Итак, оценки ошибок и выбор временного шага будут сильно отключены при прямом использовании метода ODE для SDE.

Но, во-вторых, решатели ODE адаптируются с использованием отбраковочной выборки. Они выберут dt, попробуют, а если это не поможет, уменьшат dt. Здесь вы берете случайное число в своей производной, и интегратор 5-го порядка будет вызывать вашу производную функцию 7 раз, получая 7 разных значений для того, что, по его мнению, является производной, вычисляет оценку ошибки, понимает, что это дико не работает (поскольку это даже не дифференцируемым, поэтому весь алгоритм сделал неверные предположения), уменьшите временной шаг, а затем возьмите совершенно разные случайные числа, чтобы меньшее dt оказалось совершенно другой траекторией. Как вы понимаете, все это дико нестабильно и на самом деле не решает настоящую SDE, которая у нас была изначально.

Вы можете обойти это, будучи намного умнее с тем, как вы берете упомянутые случайные числа, как вы определяете оценки ошибок, и используя методы высокого порядка, которые предполагают «дифференцируемость Ито» (то есть «дифференцируемость» в терминах компонентов SDE). Это описано в документе, который является основой нынешнего поколения адаптивных решателей SDE .

Отвечая на обновления

Для кода у вас есть

using DifferentialEquations,Plots;

function lotka(du,u,p,t);
    ????, ????, ????, ????, ????, ???? = p; 
    du[1] = ????*u[1]-????*u[1]*u[2];
    du[2] = ????*u[1]*u[2]-????*u[2];
end
function stoch(du,u,p,t)
  ????, ????, ????, ????, ????, ???? = p; 
  du[1] = 1 
  du[2] = 1
end
u0 = [15.0,1.0];
p = (0.3,0.05,0.7,0.1,0.9,0.1);
????, ????, ????, ????, ????, ???? = p; 
OU = OrnsteinUhlenbeckProcess(1/????, 0.0, ????, 0.0, 0.0);
tspan = (0.0,100.0);
prob = SDEProblem(lotka,stoch,u0,tspan,p,noise = OU);
sol = solve(prob,EM(),dt = 1e-3, adaptive=false);

К обеим переменным добавлен процесс 1 OU. Если вы хотите, чтобы они были диагональными, то есть двумя независимыми процессами OU, вы используете:

OU = OrnsteinUhlenbeckProcess(1/????, 0.0, ????, 0.0, [0.0,0.0]);

В более общем плане [0.0,0.0] являются отправными точками, и вы меняете их, чтобы решить (2). Для небольшой оптимизации производительности вы можете выбрать:

OU = OrnsteinUhlenbeckProcess!(1/????, 0.0, ????, 0.0, [0.0,0.0]);

И эта формулировка, и формулировка с использованием броуновских СДУ работают. Формулировка SDE работает с адаптивными методами, но представляет собой более крупную систему, в то время как формулировка OUProcess представляет собой меньшую систему, но будет хорошо работать только с EM() и фиксированными временными шагами. Что лучше, будет зависеть от проблемы, но в большинстве случаев я бы предпочел SDE. Однако форма OUProcess будет намного лучше на RODE.

person Chris Rackauckas    schedule 17.11.2018
comment
Спасибо за столь подробный ответ. Не могли бы вы объяснить последние 2 пункта: (1) независимы ли u [3] и u [4]? (2) Я хотел использовать noise = OrnsteinUhlenbeckProcess () с заданной постоянной времени, сигмой и нулевым средним. То есть я пытаюсь моделировать с 3 и 4 уравнениями, но в документации я нашел только параметр Theta, но не tau. - person zlon; 18.11.2018
comment
в моих параметрах тета в канонической форме равна 1 / тау, сигма такая же. mu равняется нулю. - person zlon; 19.11.2018
comment
ну ладно, тогда есть какие-нибудь проблемы с кодом, который я дал? Параметры взяты только что из p. - person Chris Rackauckas; 19.11.2018
comment
Я обновил ответ. Обычно это запрещено в StackOverflow, и если вы хотите продолжить обсуждение, мы должны перенести его в Slack / Discourse. - person Chris Rackauckas; 19.11.2018