加快对称矩阵的 Math.NET 声明

Speeding up Math.NET declaration for symmetric matrices

我正在用 this constructor:

构建一个相当大的矩阵
var M = Matrix<double>.Build.Dense(N, N, (i, j) => SomeRoutine(i, j));

N 很大,而 SomeRoutine 很慢,所以我尝试在这里和那里进行优化。我注意到对于任何 i, j 保持 SomeRoutine(i, j) == SomeRoutine(j, i),即 M 是对称的,因此可以只定义一个上(或下)三角形,减少对 SomeRoutine 的调用次数从 N^2N(N+1)/2,很好。

这是我的优化方法。

var arr = new double[N, N];
for (int i = 0; i < N; i++)
{
  for (int j = 0; j < N; j++)
  {
    arr[i, j] = (i <= j) ? SomeRoutine(i, j) : arr[j, i];
  }
}
var M = Matrix<double>.Build.DenseOfArray(arr);

我觉得不太优雅。有什么方法可以在保留 lambda 样式声明的同时采用相同的优化想法?或者也许我应该编写某种包装器来屏蔽 for 循环?

我认为最好把它分成两部分:首先,计算下三角,然后在一个单独的循环中将下三角的值分配给上三角。它可能会更高效。您也可以在外循环(计算期间)使用 Parallel.For 来加快速度。

像这样:

public static void Main()
{
    var test = CreateLowerMatrix(5);
    CopyLowerToUpperMatrix(test, 5);
}

public static double[,] CreateLowerMatrix(int n)
{
    var result = new double[n,n];

    Parallel.For(0, n, r => {
        for (int c = r; c < n; ++c)
            result[r, c] = calc(r, c); });

    return result;
}

public static void CopyLowerToUpperMatrix(double[,] matrix, int n)
{
    for (int r = 1; r < n; ++r)
        for (int c = r + 1; c < n; ++c)
            matrix[c, r] = matrix[r, c];
}

public static double calc(int x, int y)
{
    return x * y;
}

我怀疑将 CopyLowerToUpperMatrix() 并联起来是否有用。

如果您想要简短的内容,可以使用它。请注意,它并不真正被推荐,因为它不是真正可读的,而且具有副作用的 lambda 表达式通常不受欢迎。试想一下,如果矩阵构建函数决定并行执行操作,将会出现竞争条件。

我建议从数组构建矩阵,就像在问题或其他答案中一样,但如果您决定使用它,请确保它有很好的评论。

var cache = new double?[N, N];
Func<int, int, double> WrapAndCacheSomeRoutine = (i, j) => 
    cache[i,j] ?? cache[j,i] ?? (cache[i,j] = SomeRoutine(i, j));
var M = Matrix<double>.Build.Dense(N, N, WrapAndCacheSomeRoutine);