数组的建构

现在我们知道了如何将变量声明为向量。下一步则是填充在这些数组中的元素。有许多不同的方式可以构造的Modelica数组。

常值符

向量

用于构建数组最简单的方法是枚举每一个单独的元素。例如,下面的参数声明表明变量x为向量:

parameter Real x[3];

我们在此使用“向量”这个术语时,其指代的是仅有一个维度下标的数组。如果想要为向量赋值,我们可以这样做:

parameter Real x[3] = {1.0, 0.0, -1.0};

显然,变量x是(被声明为)有三个实值分量的向量。为了保持一致性,等式的右侧也必须是具有三个实值分量的向量。幸运的是,它确实是。表达式{1.0, 0.0, -1.0}是Modelica里用于创建向量的一种特殊语法。用这种由包含着以逗号分隔的一系列表达式的一对{},我们可以用这种语法来构任何大小的向量。如:

parameter Real x[5] = {1.0, 0.0, -1.0, 2.0, 0.0};

尽管可以使用{}表示法来构建任何维度的数组,如

parameter Real B[2,3] = {{1.0, 2.0, 3.0}, {5.0, 6.0, 7.0}};

范围表示法

Modelica语言包含速记表示法,用以构建有连续或者等差的数列组成的向量。例如,为了构建一个由1到5之间整数组成的向量,可以使用如下的语法:

1:5       // {1, 2, 3, 4, 5}

相同的语法可以用以构建一个由1到5之间整数组成的向量:

1.0:5.0   // {1.0, 2.0, 3.0, 4.0, 5.0}

应当注意,在用此形式表示实数向量时,浮点精度问题可能会导致终值不包括在向量内的情况。也可以使用另外一种方法(而且可能更安全):

1.0*(1:5)             // {1.0, 2.0, 3.0, 4.0, 5.0}
{1.0*i for i in 1:5}  // {1.0, 2.0, 3.0, 4.0, 5.0}

此外,也可以通过在初始值以及终值之间加入“步长”值,以构建一个元素间间隔不为1的范围值。例如,3和9之间的所有奇数可以表示为:

3:2:9   // {3, 5, 7, 9}

另外,在处理浮点数字时也插入一个步长值。范围表示法还可以应用在enumeration类里(但在此情况下不能使用步长值)。

矩阵的构造

但值得注意的是,有另一种用于构成矩阵(正好有两个下标维度的数组)的特殊语法。请考虑以下带有初始化语句的参数声明:

parameter Real B[2,3] = [1.0, 2.0, 3.0; 5.0, 6.0, 7.0];

在这种情况下,参数B相当于如下的数学记号:

\[\begin{split}B = \left[ \begin{array}{ccc} 1.0 & 2.0 & 3.0 \\ 5.0 & 6.0 & 7.0 \end{array} \right]\end{split}\]

正如我们可以从Modelica代码里或其更数学的表示形式里得知,矩阵B有两行三列。使用这种方式构建矩阵的语法比仅仅构建向量时更为复杂。从表面上我们看到,向量的两旁是{},而矩阵两旁则为[]。但更重要的是,逗号和分号混在一起用作分隔符。分号用来分隔行,逗号则用来分隔列。

这个矩阵构建方法的一个很好的特性在于,在其中可以嵌入向量或子矩阵。

向量

当嵌入向量时,值得注意的是向量均为列向量。还句话说,在建构矩阵时,大小为\(n\)的向量被看作\(n\)行1列的矩阵。

为了演示嵌入的流程,可以考虑在这里我们希望构建以下矩阵的情况:

\[\begin{split}C = \left[ \begin{array}{ccc} \left| \begin{array}{cc} 2 & 1 \\ 1 & 2 \end{array} \right| & \left| \begin{array}{cc} 0 & 0 \\ 0 & 0 \end{array} \right| & \left| \begin{array}{cc} 0 & 0 \\ 0 & 0 \end{array} \right| \\ \left| \begin{array}{cc} 0 & 0 \\ 0 & 0 \end{array} \right| & \left| \begin{array}{cc} 2 & 1 \\ 1 & 2 \end{array} \right| & \left| \begin{array}{cc} 0 & 0 \\ 0 & 0 \end{array} \right| \\ \left| \begin{array}{cc} 0 & 0 \\ 0 & 0 \end{array} \right| & \left| \begin{array}{cc} 0 & 0 \\ 0 & 0 \end{array} \right| & \left| \begin{array}{cc} 2 & 1 \\ 1 & 2 \end{array} \right| \end{array} \right]\end{split}\]

我们可以用Modelica简洁地构建这个矩阵:先创建每个子矩阵,继而如下将子矩阵填入\(C\)

parameter D[2,2] = [2, 1; 1, 2];
parameter Z[2,2] = [0, 0; 0, 0];
parameter C[6,6] = [D, Z, Z;
                    Z, D, Z;
                    Z, Z, D];

换句话说,,;分隔符可以用于标量或子矩阵。

正如我们将看到的,对于上述矩阵构建有数个不同的数据建构函数是很有用的。

任意大小的数组

到目前为止,我们已经讨论了向量和矩阵。但是,利用一系列嵌套向量,你可以构造任意维数的数组(包括向量和矩阵)。例如,为了构建一个三维矩阵,我们可以简单地嵌套向量,如下:

parameter Real A[2,3,4] = { { {1, 2, 3, 4},
                              {5, 6, 7, 8},
                              {9, 8, 7, 6} },
                            { {4, 3, 2, 1},
                              {8, 7, 6, 5},
                              {4, 3, 2, 1} } };

如在此示例中可以看出,在此嵌套结构的最内层元素对应于声明内最右的维度。换句话说,此数组为包含两个元素的向量。而这两个元素则均为含有三个元素的向量。进而,上述的三个元素则各为含有4个标量的向量。

数组解析

到目前为止,我们已经展示了如何通过枚举数组中的元素来构造向量、矩阵以及高维数组。正如我们在高维数组的情况下看到,构造语句会变得非常复杂。幸运的是,Modelica语言包括数组解析这个方便的语法,让我们可以编程构建数组。这种方法有两个主要优点。首先,这是一个更为紧凑的表示法。其次,这种方法可以让我们轻松地表达数组中的值是如何与指标联系在一起。

为了演示数组解析,请考虑数组内元素与其索引的关系。

\[a_{ijk} = i\ x_j\ y_k\]

其中\(x\)\(y\)均为向量。我们已经看到了如何递归地使用一系列嵌套向量去定义这样的数组。但是,我们也看到了表达式可能会变得多长,而读写这样的表达式会变得如何的费力。使用数组解析我们可以容易地建构数组\(a\)

parameter Real a[10,12,15] = {i*x[j]*y[k] for k in 1:15,
                                              j in 1:12,
                                              i in 1:10};

这个代码以区区数行Modelica代码生成了有1800个元素的数组。