NDSolve中的递归函数未更新

时间:2011-05-04 16:51:21

标签: wolfram-mathematica

下面的代码在Mathematica中建模了一个简单的SIR模型(用于疾病控制)。 (我直接从笔记本上复制了它。)

可以使用NDSolve求解方程式,并将解决方案插入到三个不同的函数中以供进一步使用。

可以看出,第一行的Beta术语取决于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 个答案:

答案 0 :(得分:3)

罪魁祸首是Sign []

我不知道为什么,但我将问题追溯到在NDSolve内部无法正常工作的Sign []函数!

删除它:

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知识的人可以解释代码中发生的事情。

HTH!

答案 1 :(得分:1)

在某些方面,您遇到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仍然未评估,Beta很可能仍会给出纯粹的结果象征性的输入。我会尝试三件事之一,

  1. 使用UpdateTransmission[Inf[t]]
  2. 替换方程式中每次出现的Beta
  3. 使用SetDelayed重新定义Beta := UpdateTransmission[Inf[t]] ,例如

    UpdateTransmission

    以便每次遇到它时都会重新评估,或者

  4. 重新定义UpdateTransmission[x_?(Head[#]=!=Symbol&)] := ... 不通过

    接受符号
    UpdateTransmission[x_] /; Head[x]=!= Symbol := ...
    

    UpdateTransmission[Inf[t]]
  5. 选项3的工作方式是强制Beta保持未评估状态,并有效地执行与选项1相同的操作。但是,它需要最少的更改。就个人而言,我赞成选项1或3,因为我不知道NDSolve需要重新评估多少次{{1}}。