我最近正在研究 C# 中的数值算法。因此,我做了一些实验来寻找最适合 .NET 的数学库。我经常做的一件事是评估目标函数,这些函数通常是将向量作为输入并返回向量作为输出的函数。我比较了 ILNumerics、系统数组和 Math.NET 中相同目标函数的实现。ILNumerics 的语法确实使它脱颖而出,因为它类似于 MatLab 和 R 的冗长数学公式。但是,我发现对于相同数量的评估,ILNumerics 似乎比 Math.NET 的任一系统数组花费的时间要长得多。下面是我用来比较的代码。我在这里没有做任何线性代数,只是纯粹将数学公式应用于长向量。
[Test]
public void TestFunctionEval()
{
int numObj = 2;
int m = 100000;
Func<double[], double[]> fun1 = (x) =>
{
double[] z = new double[numObj];
z[0] = x[0];
double g = 1.0;
for (int i = 1; i < x.Length; i++)
g = g + 9.0 * x[i] / (m - 1);
double h = 1.0 - Math.Sqrt(z[0] / g);
z[1] = g * h;
return z;
};
Func<ILArray<double>, ILArray<double>> fun2 = (x) =>
{
ILArray<double> z = zeros(numObj);
z[0] = x[0];
ILArray<double> g = 1.0 + 9.0 * sum(x[r(1, end)]) / (m - 1);
ILArray<double> h = 1.0 - sqrt(z[0] / g);
z[1] = g * h;
return z;
};
Func<Vector<double>, Vector<double>> fun3 = (x) =>
{
DenseVector z = DenseVector.Create(numObj, (i) => 0);
z[0] = x[0];
double g = 1.0 + 9.0*(x.SubVector(1, x.Count - 1) / (m - 1)).Sum();
double h = 1.0 - Math.Sqrt(z[0] / g);
z[1] = g * h;
return z;
};
int n = 1000;
ILArray<double> xs = rand(n, m);
IList<double[]> xRaw = new List<double[]>();
for (int i = 0; i < n; i++)
{
double[] row = xs[i, full].ToArray();
xRaw.Add(row);
}
DenseMatrix xDen = DenseMatrix.OfRows(n, m, xRaw);
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < n; i++)
{
ILArray<double> ret = fun1(xRaw[i]);
}
watch.Stop();
log.InfoFormat("System array took {0} seconds.", watch.Elapsed.TotalSeconds);
watch.Reset();
watch.Start();
for (int i = 0; i < n; i++)
{
ILArray<double> ret = fun2(xs[i, full]);
}
watch.Stop();
log.InfoFormat("ILNumerics took {0} seconds.", watch.Elapsed.TotalSeconds);
watch.Reset();
watch.Start();
for (int i = 0; i < n; i++)
{
var ret = fun3(xDen.Row(i));
}
watch.Stop();
log.InfoFormat("Math.Net took {0} seconds.", watch.Elapsed.TotalSeconds);
}
不幸的是,测试表明 ILNumerics 花费了太长时间来完成如此简单的事情。
315 | System array took 0.7117623 seconds.
323 | ILNumerics took 14.5100766 seconds.
330 | Math.Net took 5.3917536 seconds.
我真的很喜欢它让代码看起来很像数学公式的方式。但是,系统数组或 Math.NET 花费更多时间来评估上述函数意味着我必须选择其他替代方案而不是 ILNumerics,即使这会导致函数的解释时间更长、更难。
我是否以错误的方式使用 ILNumerics?还是在这种情况下设计速度较慢。也许我没有将它用于最合适的目的。有人可以解释吗?
测试中使用 ILNumerics 3.2.2.0 和 Math.NET.Numerics 2.6.1.30。