Add ol.math.solveLinearSystem
This commit is contained in:
@@ -78,6 +78,69 @@ ol.math.squaredDistance = function(x1, y1, x2, y2) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Solves system of linear equations using Gaussian elimination method.
|
||||
*
|
||||
* @param {Array.<Array.<number>>} A Augmented matrix (n x n + 1 column)
|
||||
* in row-major order.
|
||||
* @return {Array.<number>} The resulting vector.
|
||||
*/
|
||||
ol.math.solveLinearSystem = function(A) {
|
||||
var n = A.length;
|
||||
|
||||
if (goog.asserts.ENABLE_ASSERTS) {
|
||||
for (var row = 0; row < n; row++) {
|
||||
goog.asserts.assert(A[row].length == n + 1,
|
||||
'every row should have correct number of columns');
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < n; i++) {
|
||||
// Find max in the i-th column (ignoring i - 1 first rows)
|
||||
var maxRow = i;
|
||||
var maxEl = Math.abs(A[i][i]);
|
||||
for (var r = i + 1; r < n; r++) {
|
||||
var absValue = Math.abs(A[r][i]);
|
||||
if (absValue > maxEl) {
|
||||
maxEl = absValue;
|
||||
maxRow = r;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxEl === 0) {
|
||||
return null; // matrix is singular
|
||||
}
|
||||
|
||||
// Swap max row with i-th (current) row
|
||||
var tmp = A[maxRow];
|
||||
A[maxRow] = A[i];
|
||||
A[i] = tmp;
|
||||
|
||||
// Subtract the i-th row to make all the remaining rows 0 in the i-th column
|
||||
for (var j = i + 1; j < n; j++) {
|
||||
var coef = -A[j][i] / A[i][i];
|
||||
for (var k = i; k < n + 1; k++) {
|
||||
if (i == k) {
|
||||
A[j][k] = 0;
|
||||
} else {
|
||||
A[j][k] += coef * A[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Solve Ax=b for upper triangular matrix A
|
||||
var x = new Array(n);
|
||||
for (var l = n - 1; l >= 0; l--) {
|
||||
x[l] = A[l][n] / A[l][l];
|
||||
for (var m = l - 1; m >= 0; m--) {
|
||||
A[m][n] -= A[m][l] * x[l];
|
||||
}
|
||||
}
|
||||
return x;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Converts radians to to degrees.
|
||||
*
|
||||
|
||||
@@ -91,6 +91,45 @@ describe('ol.math.roundUpToPowerOfTwo', function() {
|
||||
});
|
||||
|
||||
|
||||
describe('ol.math.solveLinearSystem', function() {
|
||||
it('calculates correctly', function() {
|
||||
var result = ol.math.solveLinearSystem([
|
||||
[2, 1, 3, 1],
|
||||
[2, 6, 8, 3],
|
||||
[6, 8, 18, 5]
|
||||
]);
|
||||
expect(result[0]).to.roughlyEqual(0.3, 1e-9);
|
||||
expect(result[1]).to.roughlyEqual(0.4, 1e-9);
|
||||
expect(result[2]).to.roughlyEqual(0, 1e-9);
|
||||
});
|
||||
it('can handle singular matrix', function() {
|
||||
var result = ol.math.solveLinearSystem([
|
||||
[2, 1, 3, 1],
|
||||
[2, 6, 8, 3],
|
||||
[2, 1, 3, 1]
|
||||
]);
|
||||
expect(result).to.be(null);
|
||||
});
|
||||
it('raises an exception when the matrix is malformed', function() {
|
||||
expect(function() {
|
||||
ol.math.solveLinearSystem([
|
||||
[2, 1, 3, 1],
|
||||
[2, 6, 8, 3],
|
||||
[6, 8, 18]
|
||||
]);
|
||||
}).to.throwException();
|
||||
|
||||
expect(function() {
|
||||
ol.math.solveLinearSystem([
|
||||
[2, 1, 3, 1],
|
||||
[2, 6, 8, 3],
|
||||
[6, 8, 18, 5, 0]
|
||||
]);
|
||||
}).to.throwException();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('ol.math.toDegrees', function() {
|
||||
it('returns the correct value at -π', function() {
|
||||
expect(ol.math.toDegrees(-Math.PI)).to.be(-180);
|
||||
|
||||
Reference in New Issue
Block a user