Skip to content

Commit 6ee9f99

Browse files
committed
Added a variety of vector functions. Modified linear solver to use partial pivoting. Added a tridiagonal solver.
1 parent 9fc9837 commit 6ee9f99

File tree

13 files changed

+279
-51
lines changed

13 files changed

+279
-51
lines changed

GameMakerScripts.yyp

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,22 @@ Common array functions (such as searching and counting).
1212

1313
* [`_array_count`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_array_count/_array_count.gml): Counts the number of occurrences of a specified value in an array.
1414
* [`_array_index`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_array_index/_array_index.gml): Finds the first index at which a specified value occurs in an array (or -1 if not found). An optional argument allows the search to begin with a specified index.
15-
* [`_array_max`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_array_max/_array_max.gml): Returns the maximum value in an array.
16-
* [`_array_min`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_array_min/_array_min.gml): Returns the minimum value in an array.
17-
18-
## Computational Mathematics Functions
19-
20-
Algorithms from computational mathematics (such as regression and interpolation).
21-
22-
* `...`
15+
* [`_array_max`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_array_max/_array_max.gml): Returns the maximum value (or the index of the maximum value) in an array.
16+
* [`_array_min`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_array_min/_array_min.gml): Returns the minimum value (or the index of the minimum value) in an array.
17+
* [`_invert_permutation`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_invert_permutation/_invert_permutation.gml): Generates a permutation array to invert a given permutation array.
18+
* [`_linspace`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_linspace/_linspace.gml): Generates an array with a specified number of equally-spaced values that cover a specified range.
19+
* [`_permute`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_permute/_permute.gml): Permutes the elements of an array according to a given permutation array.
20+
* [`_range`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_range/_range.gml): Generates an array of equally-spaced values over a specified range with a specified step size.
2321

2422
## Linear Algebra Functions
2523

2624
Common linear algebra algorithms for dealing with matrices and vectors. In all functions, _vectors_ are considered to be 1D arrays while _matrices_ are 2D arrays.
2725

28-
* [`_linear_solve`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_linear_solve/_linear_solve.gml): Solves a linear system given a coefficient matrix and righthand vector.
26+
* [`_linear_solve`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_linear_solve/_linear_solve.gml): Solves a linear system given a coefficient matrix and righthand vector (using Gaussian elimination with partial pivoting).
2927
* [`_matrix_multiply`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_matrix_multiply/_matrix_multiply.gml): Performs matrix-matrix, matrix-vector, and vector-vector multiplication.
3028
* [`_matrix_transpose`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_matrix_transpose/_matrix_transpose.gml): Transposes a 2D matrix.
31-
* [`_triangular_solve`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_triangular_solve/_triangular_solve.gml): Solves an upper or lower triangular system.
29+
* [`_tridiagonal_solve`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_tridiagonal_solve/_tridiagonal_solve.gml): Solves a tridiagonal system (using the Thomas algorithm).
30+
* [`_triangular_solve`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_triangular_solve/_triangular_solve.gml): Solves an upper or lower triangular system (using forward or back substitution).
3231
* [`_unit_vector`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_unit_vector/_unit_vector.gml): Defines a unit direction vector between two coordinates.
3332
* [`_vector_angle`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_vector_angle/_vector_angle.gml): Calculates the acute angle between two vectors.
3433
* [`_vector_distance`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_vector_distance/_vector_distance.gml): Calculates the Lp-distance between two vectors.

scripts/_array_max/_array_max.gml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
1-
/// @func _array_max(arr)
2-
/// @desc Finds the maximum value in an array.
1+
/// @func _array_max(arr[, val=true])
2+
/// @desc Finds the maximum value (or its index) in an array.
33
/// @param {real[]} arr Array to search.
4-
/// @return {real} Maximum value in arr.
4+
/// @param {bool} [val=true] If true the maximum value is returned, if false the (first) index of the maximum value is returned.
5+
/// @return {real} Maximum value (or its index) in arr.
56

67
function _array_max(arr)
78
{
9+
// Check for optional index argument
10+
var val = (argument_count > 1 ? argument[1] : true);
11+
812
// Go through array to find largest value
9-
var val = -infinity;
13+
var mv = -infinity; // maximum value
14+
var mi = -1; // index of maximum value
1015
for (var i = 0; i < array_length(arr); i++)
1116
{
12-
if (arr[i] > val)
13-
val = arr[i];
17+
if (arr[i] > mv)
18+
{
19+
mv = arr[i];
20+
mi = i;
21+
}
1422
}
1523

16-
// Return largest value
17-
return val;
24+
// Return largest value or its index
25+
if (val == true)
26+
return mv;
27+
else
28+
return mi;
1829
}

scripts/_array_min/_array_min.gml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
1-
/// @func _array_min(arr)
2-
/// @desc Finds the minimum value in an array.
1+
/// @func _array_min(arr[, val=true])
2+
/// @desc Finds the minimum value (or its index) in an array.
33
/// @param {real[]} arr Array to search.
4-
/// @return {real} Minimum value in arr.
4+
/// @param {bool} [val=true] If true the minimum value is returned, if false the (first) index of the minimum value is returned.
5+
/// @return {real} Minimum value (or its index) in arr.
56

67
function _array_min(arr)
78
{
9+
// Check for optional index argument
10+
var val = (argument_count > 1 ? argument[1] : true);
11+
812
// Go through array to find smallest value
9-
var val = infinity;
13+
var mv = infinity; // minimum value
14+
var mi = -1; // index of minimum value
1015
for (var i = 0; i < array_length(arr); i++)
1116
{
12-
if (arr[i] < val)
13-
val = arr[i];
17+
if (arr[i] < mv)
18+
{
19+
mv = arr[i];
20+
mi = i;
21+
}
1422
}
1523

16-
// Return smallest value
17-
return val;
24+
// Return smallest value or its index
25+
if (val == true)
26+
return mv;
27+
else
28+
return mi;
1829
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// @func _invert_permutation(perm)
2+
/// @desc Creates the inverse of a given permutation array.
3+
/// @param {int[]} perm Permutation array, consisting of a sequence of indices 0, 1, 2, ...
4+
/// @return {int[]} Permutation array which inverts the permutation defined by perm (undefined in case of error).
5+
6+
function _invert_permutation(perm)
7+
{
8+
// Get array length
9+
var n = array_length(perm);
10+
11+
// Initialize inverse
12+
var inv = array_create(n);
13+
14+
// Determine values of inverse array
15+
for (var i = 0; i < n; i++)
16+
{
17+
// Verify that index is within bounds
18+
if ((perm[i] < 0) || (perm[i] >= n))
19+
return undefined;
20+
21+
// Reverse mapping
22+
inv[perm[i]] = i;
23+
}
24+
25+
return inv;
26+
}
Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/// @func _linear_solve(a, b)
2-
/// @desc Solves a linear system of the form Ax = b (via Gaussian elimination) for a given coefficient matrix and constant vector.
3-
/// @requires _triangular_solve
4-
/// @param {real[]} a Square coefficient matrix (as a 2D array).
5-
/// @param {real[]} b Constraint vector (as a 1D array whose length matches a).
2+
/// @desc Solves a linear system of the form Ax = b (via Gaussian elimination with partial pivoting) for a given coefficient matrix and constant vector.
3+
/// @param {real[][]} a Square coefficient matrix.
4+
/// @param {real[]} b Constant vector (as an array whose length matches a).
65
/// @return {real[]} Solution vector x of the linear system Ax = b (undefined in case of inconsistent dimensions or singular matrix).
76

87
function _linear_solve(a, b)
@@ -12,31 +11,60 @@ function _linear_solve(a, b)
1211
return undefined;
1312

1413
// Initialize system
15-
var n, l, u;
14+
var n, aa, bb, xx, perm;
1615
n = array_length(b); // size of system
17-
l = array_create(n, array_create(n, 0)); // lower triangular matrix
16+
aa = a; // diagonalized matrix
17+
bb = b; // constant vector
18+
xx = array_create(n); // solution vector
19+
perm = array_create(n); // row permutation array
1820
for (var i = 0; i < n; i++)
19-
l[i][i] = 1; // initialize as identity matrix
20-
u = a; // upper triangular matrix
21+
perm[i] = i;
2122

22-
// Perform Gaussian elimination to obtain LU decomposition
23-
for (var i = 0; i < n-1; i++)
23+
// Perform Gaussian elimination with partial pivoting
24+
for (var i = 0; i < n; i++)
2425
{
26+
// Find maximum absolute value in current column's subdiagonal
27+
var p = i; // pivot row index
2528
for (var j = i+1; j < n; j++)
2629
{
27-
// Verify that we are not dividing by zero
28-
if (u[i][i] == 0)
29-
return undefined;
30+
if (abs(aa[perm[j]][i]) > abs(aa[perm[p]][i]))
31+
p = j;
32+
}
33+
34+
// Verify that the element is nonzero
35+
if (aa[perm[p]][i] == 0)
36+
return undefined;
37+
38+
// Set permutation array to exchange the current row and the pivot row
39+
if (i != p)
40+
{
41+
var temp = perm[i];
42+
perm[i] = perm[p];
43+
perm[p] = temp;
44+
}
45+
46+
// Perform elimination using pivot element
47+
for (var j = 0; j < n; j++)
48+
{
49+
// Ignore pivot row
50+
if (j == i)
51+
continue;
52+
53+
// Calculate multiplicative factor
54+
var multi = aa[perm[j]][i]/aa[perm[i]][i];
3055

31-
l[j][i] = u[j][i]/u[i][i];
56+
// Eliminate row
3257
for (var k = i; k < n; k++)
33-
u[j][k] = u[j][k] - l[j][i]*u[i][k];
58+
aa[perm[j]][k] -= multi*aa[perm[i]][k];
59+
60+
// Transform constant vector
61+
bb[perm[j]] -= multi*bb[perm[i]];
3462
}
3563
}
3664

37-
// Solve Ly = b
38-
var yy = _triangular_solve(l, b, false);
65+
// Solve diagonalized system
66+
for (var i = 0; i < n; i++)
67+
xx[i] = bb[perm[i]]/aa[perm[i]][i];
3968

40-
// Solve Ux = y
41-
return _triangular_solve(u, yy, true);
69+
return xx;
4270
}

scripts/_linspace/_linspace.gml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// @func _linspace(start, stop, n)
2+
/// @desc Generates a specified number of equally-spaced values within a specified range.
3+
/// @param {real} start First value of array.
4+
/// @param {real} stop Last value of array.
5+
/// @param {int} n Number of values in array. Must be at least 2 (unless the endpoints are equal).
6+
/// @return {real[]} An array with first value start, final value stop, and a total of n elements (or empty array in case of error).
7+
8+
function _linspace(start, stop, n)
9+
{
10+
// Verify that number of elements is valid
11+
if (n < 2)
12+
{
13+
// n=1 is allowed only if the endpoints are equal
14+
if ((start == stop) && (n == 1))
15+
return [start];
16+
17+
// Otherwise we return an empty array
18+
return [];
19+
}
20+
21+
// Determine step size
22+
var step = (stop - start)/(n - 1);
23+
24+
// Generate array
25+
var arr = array_create(n);
26+
for (var i = 0; i < n-1; i++)
27+
arr[i] = start + i*step;
28+
arr[n-1] = stop; // ensure that final value is exact
29+
30+
return arr;
31+
}

scripts/_matrix_multiply/_matrix_multiply.gml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// @func _matrix_multiply(a, b)
22
/// @desc Multiplies two matrices and/or vectors of compatible dimensions.
3-
/// @param {real[]} a 1D or 2D array to use as the left factor of the product.
4-
/// @param {real[]} b 1D or 2D array to use as the right factor of the product.
3+
/// @param {real[]*} a 1D or 2D array to use as the left factor of the product.
4+
/// @param {real[]*} b 1D or 2D array to use as the right factor of the product.
55
/// @return {real[]} Product of matrix multiplication (undefiend if dimensions not compatible; scalar for vector-vector products).
66

77
function _matrix_multiply(a, b)

scripts/_matrix_transpose/_matrix_transpose.gml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// @func _matrix_transpose(a)
22
/// @desc Transposes a 2D array.
3-
/// @param {*[]} a Matrix to transpose.
4-
/// @return {*[]} The transpose of the input array a.
3+
/// @param {*[][]} a Matrix to transpose.
4+
/// @return {*[][]} The transpose of the input array a.
55

66
function _matrix_transpose(a)
77
{

scripts/_permute/_permute.gml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// @func _permute(arr, perm)
2+
/// @desc Permutes a given array according to a given permutation array.
3+
/// @param {*[]} arr Array to be permuted.
4+
/// @param {int[]} perm Permutation array (length must match arr and consist of consecutive integers 0, 1, 2, ...).
5+
/// @return {*[]} Array consisting of values in arr permutated according to perm (or original array if lengths mismatch).
6+
7+
function _permute(arr, perm)
8+
{
9+
// Verify that array lengths match
10+
if (array_length(arr) != array_length(perm))
11+
return arr;
12+
13+
// Get array length
14+
var n = array_length(arr);
15+
16+
// Apply permutation
17+
var arrp = array_create(n); // permuted array
18+
for (var i = 0; i < n; i++)
19+
{
20+
// Verify that index is within bounds
21+
if ((perm[i] < 0) || (perm[i] >= n))
22+
return arr;
23+
24+
arrp[i] = arr[perm[i]];
25+
}
26+
27+
return arrp;
28+
}

0 commit comments

Comments
 (0)