rank method

  1. @override
int rank()
override

The rank of a matrix A is the dimension of the vector space generated by its columns. This corresponds to the maximal number of linearly independent columns of A.

The rank is generally denoted by rank(A) or rk(A).

Implementation

@override
int rank() {
  if (isSquareMatrix && rowCount == 1) {
    return this(0, 0) == 0 ? 0 : 1;
  }

  // If it's a square matrix, we can use the LU decomposition which is faster
  if (isSquareMatrix) {
    final lower = luDecomposition().first;

    // Linearly independent columns
    var independentCols = 0;

    for (var i = 0; i < lower.rowCount; ++i) {
      for (var j = 0; j < lower.columnCount; ++j) {
        if ((i == j) && (lower(i, j) != 0)) {
          ++independentCols;
        }
      }
    }

    return independentCols;
  }

  // If the matrix is rectangular and it's not 1x1, then use the "traditional"
  // algorithm
  var rank = 0;
  final matrix = toListOfList();

  const precision = 1.0e-12;
  final selectedRow = List<bool>.generate(rowCount, (_) => false);

  for (var i = 0; i < columnCount; ++i) {
    var j = 0;
    for (j = 0; j < rowCount; ++j) {
      if (!selectedRow[j] && matrix[j][i].abs() > precision) {
        break;
      }
    }

    if (j != rowCount) {
      ++rank;
      selectedRow[j] = true;

      for (var p = i + 1; p < columnCount; ++p) {
        matrix[j][p] /= matrix[j][i];
      }

      for (var k = 0; k < rowCount; ++k) {
        if (k != j && matrix[k][i].abs() > precision) {
          for (var p = i + 1; p < columnCount; ++p) {
            matrix[k][p] -= matrix[j][p] * matrix[k][i];
          }
        }
      }
    }
  }

  return rank;
}