Дифференциальные уравнения в Java - PullRequest
10 голосов
/ 05 декабря 2010

Я пытаюсь создать простую имитационную программу для модели SIR-эпидемий в Java.

По существу, SIR определяется системой трех дифференциальных уравнений:
S '(t) = - l (t) * S (t)
I '(t) = 1 (t) * S (t) - g (t) * I (t)
R '(t) = g (t) * I (t)

S - восприимчивые люди, I - зараженные люди, R - выздоровевшие люди.

l (t) = [c * x * I (t)] / N (T)

c - количество контактов, x - инфекционность (вероятность заболеть после контакта с больным человеком), N (t) - общая численность населения (которая постоянна).

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

public class Main {
public static void main(String[] args) {
    int tppl = 100;
    double sppl = 1;
    double hppl = 99;
    double rppl = 0;
    int numContacts = 50;
    double infectiveness = 0.5;
    double lamda = 0;
    double duration = 0.5;
    double gamma = 1 / duration;
    for (int i = 0; i < 40; i++) {
        lamda = (numContacts * infectiveness * sppl) / tppl;
        hppl = hppl - lamda * hppl;
        sppl = sppl + lamda * hppl - gamma * sppl;
        rppl = rppl + gamma * sppl;
        System.out.println (i + " " + tppl + " " + hppl + " " + sppl + " " + rppl); 
    }
}

}

Буду очень признателен за любую помощь, большое спасибо заранее!

1 Ответ

15 голосов
/ 05 декабря 2010

Дифференциальные уравнения временного ряда можно численно моделировать, взяв dt = небольшое число и используя один из нескольких методов численного интегрирования , например. метод Эйлера или Рунге-Кутта . Метод Эйлера может быть примитивным, но он работает хорошо для некоторых уравнений, и он достаточно прост, чтобы вы могли попробовать. e.g.:

S '(t) = - l (t) * S (t)

I '(t) = 1 (t) * S (t) - g (t) * I (t)

R '(т) = г (т) * I (т)

int N = 100;
double[] S = new double[N+1];
double[] I = new double[N+1];
double[] R = new double[N+1];

S[0] = /* initial value */
I[0] = /* initial value */
R[0] = /* initial value */

double dt = total_time / N;

for (int i = 0; i < 100; ++i)
{
   double t = i*dt;
   double l = /* compute l here */
   double g = /* compute g here */

   /* calculate derivatives */
   double dSdt = - I[i] * S[i];
   double dIdt = I[i] * S[i] - g * I[i];
   double dRdt = g * I[i];

   /* now integrate using Euler */
   S[i+1] = S[i] + dSdt * dt;
   I[i+1] = I[i] + dIdt * dt;
   R[i+1] = R[i] + dRdt * dt;
}

Самое сложное - выяснить, сколько шагов нужно использовать. Вы должны прочитать одну из статей, на которые я ссылался. Более сложные средства решения дифференциальных уравнений используют переменные размеры шагов, которые адаптируются к точности / стабильности для каждого шага.

Я бы порекомендовал использовать числовое программное обеспечение, такое как R или Mathematica, MATLAB или Octave, так как они включают решатели ODE, и вам не придется заниматься всеми проблемами самостоятельно. Но если вам нужно сделать это как часть более крупного Java-приложения, по крайней мере, сначала попробуйте это с математическим программным обеспечением, а затем получите представление о том, каковы размеры шагов и какие решатели работают.

Удачи!

...