HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Linear algebra, reduced row echelon form

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
linearalgebraformrowechelonreduced

Problem

The code that I am sharing here for you to review today, is a segment of a JavaScript library that I am going to write as time goes by for fun. It is only the two functions in the following code:

```
/jslint browser: true, indent: 8 /
/global console /

/*
Sorts matrix like from something like this:
[
[0, 0, 0],
[0, 0, 0],
[0, 2, 1],
[0, 1, 3],
[1, 2, 3],
[0, 0, 3]
]
to this:
[
[1, 2, 3],
[0, 1, 3],
[0, 2, 1],
[0, 0, 0],
[0, 0, 0],
[0, 0, 3]
]

The reason why the [0, 0, 3] is last is because
the vector has the length of 3, so only
3 vectors are sorted and the rest (irrelevent vectors) are appended
later.
*/
function sort_reduced_matrix(matrix) {
'use strict';
var i, j, len, has_pivot, irrelevant, positions, new_matrix, count;

len = {};
len.i = matrix.length; // matrix length (row)
len.j = matrix[0].length; // vector length (column)
positions = [];

has_pivot = [];

// Find pivot positions
for (j = 0; j < len.j; j += 1) {
for (i = 0; i < len.i; i += 1) {
if (matrix[i][j] === 1 && has_pivot[i] !== i) {
has_pivot[i] = i;
positions[positions.length] = i;
break;
}
}
}

irrelevant = [];
count = 0;

// Find irrelevant vectors positions
for (i = 0; i < len.i; i += 1) {
if (has_pivot[i] === undefined) {
irrelevant[count] = i;

Solution

Partial answer. Wait around and I'm sure someone will do the actual reduction function justice. It's a bit much for me to digest right now.

From a cursory glance, though, I'd suggest breaking things out into functions where possible. But again, I haven't delved too deep.

Overall stuff:

  • You misspelled echelon in the function name ("echolon")



  • Conventionally, names in JavaScript are camelCased, not under_scored



  • You have a lot of really short variable names. Yes, there are comments explaining them where they're declared, but that doesn't help much, when you're in the middle of a dense line later, having to refer back to the comments again and again. Yes, lines will get longer with longer variable names, but they'll also become a lot more readable!



-
There's no need to first assign an empty object to a variable, and then add properties to that object. It'd be clearer to define the object's initial state in one go:

len = {
  i: matrix.length,    // matrix length (rows)
  j: matrix[0].length  // vector length (columns)
};


Looking at the above code, the object should perhaps be called simply size, and i and j could well be called rows and columns - it's what the comments say, so you might as well just call them that.

The above things are fixable without changed to the actual logic. What's more troublesome to me is that your reduced_row_echelon_form function produces side effects: It alters the matrix you pass it, rather than returning a new one. After calling it, you have the answer, but you've lost the question.

I'd suggest making a lot more use of map(). Again, I haven't had the courage to dive into the reduced_row_echelon_form function, but - for instance - the sorting function can be cleaned up rather nicely using it:

function sortRows(matrix) {
  // map rows to arrays with the structure
  // [, , ]
  // which makes them easily sortable
  var pivots = matrix.map(function (row, r) {
    for(var c = 0, l = row.length ; c < l ; c++) {
      if(row[c]) {
        return [c, row[c], r]; // found a non-zero coefficient at matrix[r][c]
      }
    }
    return [Infinity, null, r]; // row is all-zero
  });

  // sort the pivots array, and use it to (re)build
  // the matrix with the rows in the correct order
  return pivots.sort().map(function (pivot) {
    return matrix[pivot[2]];
  });
}


Which will do something like (in some sort of ascii-notation)

[ 0, 0, 0 ] [ 1, 2, 3 ]
[ 0, 0, 0 ] [ 0, 1, 3 ]
[ 0, 2, 1 ] => [ 0, 2, 1 ]
[ 0, 1, 3 ] [ 0, 0, 3 ]
[ 1, 2, 3 ] [ 0, 0, 0 ]
[ 0, 0, 3 ] [ 0, 0, 0 ]

Code Snippets

len = {
  i: matrix.length,    // matrix length (rows)
  j: matrix[0].length  // vector length (columns)
};
function sortRows(matrix) {
  // map rows to arrays with the structure
  // [<column index>, <pivot coefficient>, <row index>]
  // which makes them easily sortable
  var pivots = matrix.map(function (row, r) {
    for(var c = 0, l = row.length ; c < l ; c++) {
      if(row[c]) {
        return [c, row[c], r]; // found a non-zero coefficient at matrix[r][c]
      }
    }
    return [Infinity, null, r]; // row is all-zero
  });

  // sort the pivots array, and use it to (re)build
  // the matrix with the rows in the correct order
  return pivots.sort().map(function (pivot) {
    return matrix[pivot[2]];
  });
}

Context

StackExchange Code Review Q#54539, answer score: 2

Revisions (0)

No revisions yet.