Рекурсивная функция в NDSolve не обновляется - PullRequest
2 голосов
/ 04 мая 2011

Приведенный ниже код моделирует простую модель SIR (используется для контроля заболеваний) в Mathematica. (Я скопировал его прямо из блокнота).

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

Как видно, термин Бета в первой строке изменяется в зависимости от значения Inf [t], которое является одним из трех решений функции NDSolve.

Этот код работает нормально, и я включил его, чтобы лучше объяснить мой вопрос ниже.

Beta = Piecewise[{{0.01, Inf[t] > 20}, {.06, Inf[t] <= 20}}];
Mu = 0.1;
Pop = 100;
ans = NDSolve[{S'[t] == -Beta S[t] Inf[t], 
    Inf'[t] == Beta S[t] Inf[t] - Mu Inf[t], 
    R'[t] == Mu Inf[t], 
    S[0] == Pop - 1, Inf[0] == 1, 
    R[0] == 0}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. ans[[1, 1]];
Infected[t_] = Inf[t] /. ans[[1, 2]];
Rec[t_] = R[t] /. ans[[1, 3]];

Теперь я хотел обновить код таким образом, чтобы вместо наличия либо / или значения для параметра Beta на основе значения Inf[t], у меня было бы значение Beta, равное выходу функции где Inf[t] является входом. Это можно увидеть ниже, где UpdateTransmission[] - функция.

Когда я пытаюсь запустить приведенный ниже код, значение Beta остается равным 0 и не увеличивается. Проблема не в функции UpdateTransmission, поскольку я проверил это независимо.

Beta = UpdateTransmission[SpinMatrix, ThresholdMatrix, Inf[t]];
Mu = 0.1;
Pop = 100;
ans = NDSolve[{S'[t] == -Beta S[t] Inf[t], 
    Inf'[t] == Beta S[t] Inf[t] - Mu Inf[t], 
    R'[t] == Mu Inf[t], S[0] == Pop - 1, Inf[0] == 1, 
    R[0] == 0}, 
    {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. ans[[1, 1]];
Infected[t_] = Inf[t] /. ans[[1, 2]];
Rec[t_] = R[t] /. ans[[1, 3]];

Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 5}]

Может кто-нибудь пролить свет на то, почему это может работать неправильно?

Редактировать: вот обновленная функция

UpdateTransmission[S_, Th_, Infect_] := Module[{BetaOverall},
 P = S;
 For[i = 1, i <= Pop, i++,
    P[[i]] = Sign[Infect - Th[[i]]];];
   BetaOverall = ((Count[P, 1]*.02) + (Count[P, -1]*.5))/Pop
]

Вот два списка, которые упоминаются в приведенном выше коде:

SpinMatrix = Table[-1, {Pop}]

val := RandomReal[NormalDistribution[.5, .1]]
ThresholdMatrix = Table[Pop*val, {Pop}]

Редактировать Редактировать

Хорошо, я собрал все вместе и попытался построить три кривые. Теперь, как видно здесь, все они плоские. Линия Sus [t] остается на уровне 100, в то время как две другие, похоже, остаются ниже 1. Что здесь должно произойти, так это то, что линия Sus [t] должна значительно упасть, а две другие линии должны увеличиться.

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

 Pop = 100;
SpinMatrix = Table[-1, {Pop}];
val := RandomReal[NormalDistribution[.5, .1]];
ThresholdMatrix = Table[Pop*val, {Pop}];

updateTransmission[S_, Th_, Infect_] := Module[{}, P = S;
   For[i = 1, i <= Pop, i++, P[[i]] = Sign[Infect - Th[[i]]];];
   Return[((Count[P, 1]*.02) + (Count[P, -1]*.5))/Pop]];

beta[t_] := updateTransmission[SpinMatrix, ThresholdMatrix, Inf[t]];
mu = 0.1;
ans = NDSolve[{S'[t] == -beta[t] S[t] Inf[t], 
    Inf'[t] == beta[t] S[t] Inf[t] -
      mu Inf[t], R'[t] == mu Inf[t], S[0] == Pop - 1, Inf[0] == 1, 
    R[0] == 0}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. First@ans;
Infected[t_] = Inf[t] /. First@ans;
Rec[t_] = R[t] /. First@ans;
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 10}]

Вывод, который я ожидаю, должен выглядеть примерно так, как показано в приведенном ниже коде:

Beta = Piecewise[{{0.5, Inf[t] > 20}, {.02, Inf[t] <= 20}}];
Mu = 0.1;
Pop = 100;
ans = NDSolve[{S'[t] == -Beta S[t] Inf[t], 
    Inf'[t] == Beta S[t] Inf[t] - Mu Inf[t], 
    R'[t] == Mu Inf[t], S[0] == Pop - 1, Inf[0] == 1, 
    R[0] == 0}, {S[t], Inf[t], R[t]}, {t, 0, 10}];
Sus[t_] = S[t] /. ans[[1, 1]];
Infected[t_] = Inf[t] /. ans[[1, 2]];
Rec[t_] = R[t] /. ans[[1, 3]];
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 10}]

Ответы [ 2 ]

3 голосов
/ 04 мая 2011

Виновником является Знак []

Не знаю почему, но я проследил проблему до функции Sign [], которая не работает должным образом в NDSolve!

Снятие:

Pop = 100;
SpinMatrix = Table[-1, {Pop}];
val := RandomReal[NormalDistribution[.5, .1]];

ThresholdMatrix = Table[Pop*val, {Pop}];

updateTransmission[Th_, Inf_] :=
  Total[Table[If[Inf >= Th[[i]], 2/100, 1/2]/Pop , {i, Pop}]];

beta[t_] := updateTransmission[ThresholdMatrix, Inf[t]];
mu = 0.1;

ans = NDSolve[{
    S'[t] == -beta[t] S[t] Inf[t],
    Inf'[t] == beta[t] S[t] Inf[t] - mu Inf[t],
    R'[t] == mu Inf[t],
    S[0] == Pop - 1,
    R[0] == 0,
    Inf[0] == 1}, {S[t], Inf[t], R[t]}, {t, 0, 10}];

Sus[t_] = S[t] /. First@ans;
Infected[t_] = Inf[t] /. First@ans;
Rec[t_] := R[t] /. First@ans;
Plot[{Sus[t], Infected[t], Rec[t]}, {t, 0, 10}]  

Дает:

enter image description here

Возможно, кто-то, кто лучше знает Mma, сможет объяснить, что происходит в вашем коде.

НТН!

1 голос
/ 04 мая 2011

В некоторых случаях вы сталкиваетесь с разницей между Set (=) и SetDelayed (:=).Например, если вы написали f = 7, f становится 7 во всех случаях f после его инициализации.Но если вы вместо этого напишите f = 7 t и попытаетесь использовать ее как функцию, то есть f[8], вы получите (7 t)[8], потому что Set говорит, что значение f не меняется.SetDelayed, однако, подразумевает, что значение f изменится и должно пересматриваться каждый раз, когда это происходит.Ваш первоначальный случай, тем не менее, является особым.

Когда вы писали

Beta = Piecewise[{{0.01, Inf[t] > 20}, {.06, Inf[t] <= 20}}]

Inf[t], он был неопределенным, так что он оставался неоцененным.Но каждый случай Beta в ваших дифференциальных уравнениях был заменен приведенной выше формулой, любезно предоставленной Set, поэтому NDSolve видел только функции Piecewise.Во втором случае вы написали

Beta = UpdateTransmission[Inf[t]]

Здесь проблема заключается в том, что UpdateTransmission выполняется только тогда, когда Beta изначально определено, и в то время как Piecewise остается неоцененным, UpdateTransmission, скорее всего, все еще даетрезультат для чисто символического ввода.Я бы попробовал одну из трех вещей:

  1. заменить каждое вхождение Beta в ваших уравнениях на UpdateTransmission[Inf[t]],
  2. переопределить Beta, используя SetDelayedнапример,

    Beta := UpdateTransmission[Inf[t]]
    

    , так что он будет переоцениваться при каждом обнаружении, или

  3. переопределять UpdateTransmission, чтобы не принимать символы через

    UpdateTransmission[x_?(Head[#]=!=Symbol&)] := ...
    

    или

    UpdateTransmission[x_] /; Head[x]=!= Symbol := ...
    

Вариант 3 работает, заставляя UpdateTransmission[Inf[t]] оставаться неоцененным, и фактически делает то же самое, что и вариант 1. Но для этого требуется минимумменять.Лично я за варианты 1 или 3, так как я не знаю, сколько раз Beta нужно будет переоценить для работы NDSolve.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...