最简单的示例#

现在我们已经准备好使用modelx进行练习,并且理解了modelx对象的基础知识,接下来我们将以斐波那契数列作为第一个建模示例。

斐波那契数列是一个整数序列,从0、1开始,后续的每个数字都是前两个数字相加得到的。

斐波那契数列可以用以下递归公式表示。

\[\begin{split}&F(n) = F(n-1) + F(n-2) \quad (n > 1)\\ &F(1) = 1\\ &F(0) = 0\end{split}\]

以下是n=10以内的斐波那契数列。

n

0

1

2

3

4

5

6

7

8

9

10

F(n)

0

1

1

2

3

5

8

13

21

34

55

在modelx术语中,我们将n称为参数,0, 1, 2, 3...称为实参, 而0, 1, 1, 2, 3, ...则是公式的返回值。

通过这个练习,我们将学习如何在modelx中执行基本操作。

创建单元格并定义其公式#

在您的Spyder IDE中找到MxExplorer小部件。

../_images/BlankMxExplorer1.png

空白MxExplorer#

在右上角附近有一个标题为Model的下拉框。 这个下拉框用于选择要在下方窗格中显示的模型。 由于我们目前还没有模型,所以显示的是Current Model - None

左侧的空白窗格用于显示所选模型中对象的树状结构。

在MxExplorer的空白处右键点击,会显示上下文菜单。选择菜单中的创建新单元格项。

../_images/MxExplorerContextMenu.png

MxExplorer中的上下文菜单#

弹出一个用于创建新Cells的对话框。

../_images/NewCellsDialogBox.png

新建单元格对话框#

对话框包含3个标有ParentCells NameImport As的文本框,在Import As前还有一个复选框,底部则是一个标题为Formula的代码编辑器框。默认情况下,所有文本框均为空白,且复选框处于勾选状态。

父级框用于选择我们将要创建的单元格的父级空间。单元格的父级空间是包含该单元格的空间。由于我们目前还没有任何模型或空间,因此该框中未列出任何项目。在本练习中,您可以保持该框不变,因为当单元格创建时,包含该单元格的模型和空间将自动创建,并使用它们的默认名称Model1Space1

单元格名称框用于指定单元格名称。 如果该框留空,则单元格名称将从公式框中输入的函数定义中获取。 您可以暂时留空单元格名称框,因为 稍后我们将在公式框中编写一个名为Fibo的函数定义, 因此该单元格也将被命名为Fibo

导入为标签前的复选框用于指示是否要将新单元格导入关联MxConsole中IPython会话的全局命名空间,而导入为标签旁边的文本框用于指定全局变量的名称。如果留空,则变量名称将设置为单元格名称。

如果勾选此复选框,那么要在MxConsole中获取单元格Fibo,只需输入:

>>> Fibo

如果不勾选此框,要获取单元格 Fibo,您需要输入:

>>> mx.Model1.Space1.Fibo

因此勾选该复选框的效果等同于执行以下赋值语句:

>>> Fibo = mx.Model1.Space1.Fibo

在本示例中,您无需编辑这些内容,保持原样即可。 您只需要编辑公式框。

有几种方法可以编写返回斐波那契数列的函数。 在这个示例中,我们使用以下定义。 在公式框中编写以下代码,然后点击确定

def Fibo(n):
    if n > 1:
        return Fibo(n-1) + Fibo(n-2)
    else:
        return n
../_images/NewCellsDialogBoxWithFormula.png

新建单元格对话框#

现在你可以看到模型框中的选中文本已更改为当前模型 - Model1。 在MxExplorer的左侧,你会看到一个名为Space1的项目。 这意味着modelx创建了一个名为Model1的新模型,并在Model1模型中创建了一个名为Space1的UserSpace对象。 双击Space1项目,你将在Space1下看到一个名为Fibo的项目。

选择Fibo并右键点击调出上下文菜单。 从上下文菜单中选择显示属性, 然后您将在右下方面板中看到公式。

../_images/MxExplorerWithFormula.png

MxExplorer#

获取计算结果#

单元格 Fibo 在刚创建时还没有值。

我们使用MxConsole来访问Cells对象Fibo。 记得在创建CellsFibo时,我们在对话框中勾选了Import AS旁边的复选框, 同时将Import As的文本框留空。 这意味着创建的Cells对象Fibo会以相同的名称Fibo导入到MxConsole的命名空间中。

在MxConsole中输入Fibo[10]Fibo(10)同样有效):

>>> Fibo[10]
55

55,输出了第10个斐波那契数。

其值由关联的Formula自动计算, 当访问单元格值时。 请注意,不仅会为指定参数计算值, 还会为公式递归引用的参数计算值, 以获取指定参数的值。

由于Fibo[10]引用了Fibo[9]Fibo[8]Fibo[9]又引用了Fibo[8]Fibo[7], 这种递归引用会一直持续直到在Fibo[1]Fibo[0]处停止, 只需调用fibo[10]就能计算出从010参数的Fibo值。

要查看计算斐波那契数列使用了哪些参数, 您可以将单元格中的参数和值对作为字典获取:

>>> dict(Fibo)
{1: 1, 0: 0, 2: 1, 3: 2, 4: 3, 5: 5, 6: 8, 7: 13, 8: 21, 9: 34, 10: 55}

或者作为Pandas的Series或DataFrame对象:

>>> Fibo.series
n
1      1
0      0
2      1
3      2
4      3
5      5
6      8
7     13
8     21
9     34
10    55
Name: Fibo, dtype: int64

>>> Fibo.frame
    Fibo
n
1      1
0      0
2      1
3      2
4      3
5      5
6      8
7     13
8     21
9     34
10    55

追踪计算#

追踪计算用于检查计算依赖关系。 例如,当您想要调试计算并检查计算是否正确基于预期值时,它非常有用。

要追踪Fibo[10]的计算过程, 打开MxAnalyzer小部件,选择Precedents标签页, 在Object框中输入Fibo, 在Args框中输入10。 你将看到代表Fibo[10]的条目出现在小部件中。 点击箭头展开该条目,你会看到 Fibo[9]Fibo[8]Fibo[10]分支出来。 通过递归展开前置条目,你可以回溯 Fibo[10]的计算过程,直到 追溯到Fibo[1]Fibo[0]

../_images/PrecedentsFibo.png

MxAnalyzer 前置条件选项卡#

同样地,你也可以在依赖项标签页中追踪Fibo某个元素的依赖项, 例如Fibo[5]。 依赖项是指那些直接或间接使用Fibo[5]值进行计算的其他元素。

../_images/DependentsFibo.png

MxAnalyzer 依赖项标签页#

通过输入覆盖计算#

单元格的值可以由用户指定。当用户为某些参数赋值时,这些指定的值将优先于公式计算结果。让我们看看这是如何运作的。

现在单元格 Fibo 中已有 n=0, ... ,10 的值。 我们将通过给 Fibo[0] 赋值为 1,来把 n=0 的值从 0 替换为 1

>>> Fibo[0] = 1

然后检查Fibo中保存的所有值:

>>> dict(Fibo)
{1: 1, 0: 1}

可以看到,对于n=2, ..., 10的值被清除了。 这是因为n=2, ..., 10的值是通过递归计算得出的, 最终引用了Fibo[1]Fibo[0]。 由于Fibo[0]被你的输入更新了, 所有依赖的值都被清除了。 再次获取Fibo直到n=10的值:

>>> Fibo[10]
89

>> dict(Fibo)
{1: 1, 0: 1, 2: 2, 3: 3, 4: 5, 5: 8, 6: 13, 7: 21, 8: 34, 9: 55, 10: 89}

现在你可以看到,当n=10时的值是89,这个值在修改Fibo[0]之前是n=11对应的值。

保存工作#

最后一步是保存我们创建的Model。在MxExplorer中右键点击部件调出上下文菜单,然后选择Write Model项。

../_images/WriteModel.png

编写模型对话框#

顶部的线条框用于选择放置模型文件夹的位置。 点击文件夹按钮并选择您想要放置模型的文件夹。模型将被保存为多个文件, 存放在所选位置下的一个文件夹中。 在文件夹名称框中输入文件夹名称。 这里我们将文件夹命名为FiboModel,但您可以根据喜好自由命名。

../_images/WriteModelFibo.png

写入模型对话框#

如果勾选了标有备份旧文件夹的复选框,并且存在同名文件夹时,系统会在创建新文件夹前,将原文件夹重命名为带有_BAK后缀加数字的形式,例如FiboModel_BAK1。 由于该路径下不存在名为FiboModel的文件夹,因此该复选框不会产生任何效果。 点击确定保存模型。

现在让我们检查保存的模型是否可以重新加载。 在MxExplorer的上下文菜单中,选择Read Model, 然后会出现Read Model对话框。

从文件夹按钮中选择模型文件夹。 模型名称框用于指定模型名称,如果您希望 将新模型命名为与保存名称不同的名称。 导入为复选框用于指示是否要为 模型定义一个全局名称,并指定变量名。 如果留空,变量名将设置为与模型名称相同。

在这个练习中,我们将模型名称留空并保持导入为勾选且空白,看看会发生什么。

../_images/ReadModelFibo.png

读取模型对话框#

新模型将作为Model1可用,而旧模型 会被重命名为Model1_BAK1,您可以在 MxExplorer中的Model框中查看。

../_images/SelectModelBackup.png

模型列表#

请注意,MxConsole中的全局变量Fibo仍然指向旧模型Model1_BAK1中的Cells:

>>> Fibo
<Cells Fibo(n) in Model1_BAK1.Space1>

新Model中的Fibo单元格可以通过Model1.Space1.Fibo访问, 因此重新定义Fibo指向新的单元格:

>>> Model1.Space1.Fibo
<Cells Fibo(n) in Model1.Space1>

>>> Fibo = Model1.Space1.Fibo

现在,让我们检查一下 Fiob 在计算前的值。

>>> dict(Fibo)
{0: 1}

您可以看到只有您输入的值被记住,而计算出的值并未保存。您可以检查是否获得了与旧模型相同的值:

>>> Fibo[10]
89

>>> dict(Fibo)
{0: 1, 1: 1, 2: 2, 3: 3, 4: 5, 5: 8, 6: 13, 7: 21, 8: 34, 9: 55, 10: 89}