I am recently doing some studies on numerical algorithms in C#. Therefore I did some experiments in search for the most suitable math library for .NET. One thing I do very often is to evaluate objective functions, which usually are functions that take a vector as input and returns a vector as output. I compared the implementations of the same objective function in ILNumerics, system array and Math.NET. The syntax of ILNumerics really makes it stand out because it resembles that of MatLab and R for lengthy mathematical formulas. However, I discovered that for the same number of evaluations, ILNumerics seems to be taking much longer than either system array of Math.NET. Below is the code I used to compare. I'm not doing any linear algebra here, just purely applying math formulas over long vectors.
[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);
}
Unfortunately, the test shows that ILNumerics is taking too long to do something so simple.
315 | System array took 0.7117623 seconds.
323 | ILNumerics took 14.5100766 seconds.
330 | Math.Net took 5.3917536 seconds.
I really liked the way it made the code look so much like mathematical formulas. However, taking many more times the time taken by system array or Math.NET to evaluate functions such as the above means I have to choose other alternatives instead of ILNumerics even though this will lead to longer and harder to interpret functions.
Am I using ILNumerics in the wrong way? Or is it by design slower in this kind of scenarios. Maybe I'm not using it for the most suitable purpose. Can someone explain?
ILNumerics 3.2.2.0 and Math.NET.Numerics 2.6.1.30 are used in the test.