Skip to content

Commit f29ca1e

Browse files
committed
Added computational methods, including root finding methods and cubic spline interpolation.
1 parent 90d812c commit f29ca1e

File tree

8 files changed

+118
-3
lines changed

8 files changed

+118
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
_resources/
12
datafiles/
23
objects/
34
options/

GameMakerScripts.yyp

Lines changed: 2 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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Common array functions (such as searching and counting).
2323

2424
Numerical algorithms for computational mathematics.
2525

26+
* [`_cubic_spline_coefficients`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_cubic_spline_coefficients/_cubic_spline_coefficients.gml): Calculates vectors of coefficients for the natural cubic polynomial interpolating a given data set.
27+
* [`_cubic_spline_evaluate`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_cubic_spline_evaluate/_cubic_spline_evaluate.gml): Evaluates a piecewise cubic polynomial at a specific value given a given set of coefficient vectors and intervals.
2628
* [`_root_bisection`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_root_bisection/_root_bisection.gml): Finds a function root on a specified interval using the bisection method.
2729
* [`_root_newton`](https://github.com/adam-rumpf/game-maker-scripts/blob/master/scripts/_root_newton/_root_newton.gml): Finds a function root given a derivative and an initial guess using Newton's method.
2830

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/// @func _cubic_spline_coefficients(x, y)
2+
/// @desc Calculates the coefficients for a natural cubic spline interpolating a set of points.
3+
/// @requires _tridiagonal_solve
4+
/// @param {real[]} x Sample inputs, as a 1D array in ascending order.
5+
/// @param {real[]} y Sample outputs, as a 1D array the same length as the input array.
6+
/// @return {real[][]} Set of coefficients to define each segment of the natural cubic spline (see documentation for details), undefined in case of error.
7+
/**
8+
* For a data set of the form [x0, x1, ..., xn], [y0, y1, ..., yn], the natural cubic spline
9+
* consists of n-1 piecewise polynomials of the form:
10+
* si(x) = ai (x-xi)^3 + bi (x-xi)^2 + ci (x-xi) + di
11+
* on interval (xi, x(i+1)). The spline is twice differentiable with a second derivative
12+
* that vanishes at x0 and xn.
13+
*
14+
* The return value of this function is a list of 4 lists, each of length n-1 and consisting
15+
* of the coefficients of the form:
16+
* [
17+
* [a0, a1, ..., a(n-1)],
18+
* [b0, b1, ..., b(n-1)],
19+
* [c0, c1, ..., c(n-1)],
20+
* [d0, d1, ..., d(n-1)]
21+
* ]
22+
*/
23+
24+
function _cubic_spline_coefficients(xx, yy)
25+
{
26+
// Verify that argument lists have equal length
27+
if (array_length(xx) != array_length(yy))
28+
return undefined;
29+
30+
// Get length of data lists
31+
var n = array_length(xx);
32+
33+
// Calculate interval differences in x and y
34+
var dx, dy;
35+
dx = array_create(n-1);
36+
dy = array_create(n-1);
37+
for (var i = 0; i < n-1; i++)
38+
{
39+
dx[i] = xx[i+1] - xx[i];
40+
dy[i] = yy[i+1] - yy[i];
41+
}
42+
43+
// Define a tridiagonal system to calculate the quadratic coefficients
44+
var upper, lower, diag, rhs;
45+
upper = array_create(n-1, 0); // upper diagonal
46+
lower = array_create(n-1, 0); // lower diagonal
47+
diag = array_create(n, 1); // main diagonal
48+
rhs = array_create(n, 0); // constant vector
49+
for (var i = 1; i < n-1; i++)
50+
{
51+
lower[i-1] = dx[i-1];
52+
upper[i] = dx[i];
53+
diag[i] = 2*(dx[i-1] + dx[i]);
54+
rhs[i] = 3*((dy[i]/dx[i]) - (dy[i-1]/dx[i-1]));
55+
}
56+
57+
// Solve for quadratic coefficients
58+
var bb = _tridiagonal_solve(lower, diag, upper, rhs);
59+
60+
// Substitute to solve for remaining coefficients, and trim long coefficient arrays
61+
var a, b, c, d;
62+
a = array_create(n-1);
63+
b = array_create(n-1);
64+
c = array_create(n-1);
65+
d = array_create(n-1);
66+
for (var i = 0; i < n-1; i++)
67+
{
68+
// Calculate cubic and linear coefficients
69+
a[i] = (bb[i+1] - bb[i])/(3*dx[i]);
70+
c[i] = (dy[i]/dx[i]) - (dx[i]/3)*(2*bb[i] + bb[i+1]);
71+
72+
// Trim quadratic and constant coefficients (constants come directly from data)
73+
b[i] = bb[i];
74+
d[i] = yy[i];
75+
}
76+
77+
// Return all coefficient arrays
78+
return [a, b, c, d];
79+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// @func _cubic_spline_evaluate(a, b, c, d, x, t)
2+
/// @desc Evaluate a natural cubic spline at point t for coefficient vectors a, b, c, and d and input data vector x.
3+
/// @param {real[]} a Vector of cubic coefficients [a0, a1, ..., a(n-1)].
4+
/// @param {real[]} b Vector of quadratic coefficients [b0, b1, ..., b(n-1)].
5+
/// @param {real[]} c Vector of linear coefficients [c0, c1, ..., c(n-1)].
6+
/// @param {real[]} d Vector of contant coefficients [d0, d1, ..., d(n-1)].
7+
/// @param {real[]} x Vector of sample input values [x0, x1, ..., xn], in ascending order.
8+
/// @param {real} t Value at which to evaluate the spline.
9+
/// @return {real} Value of spline function evaluated at point t, depending on which interval if falls into, undefined in case of array size mismatch.
10+
/**
11+
* For a data set of the form [x0, x1, ..., xn], [y0, y1, ..., yn], the cubic spline consists of a
12+
* consists of n-1 piecewise polynomials of the form:
13+
* si(x) = ai (x-xi)^3 + bi (x-xi)^2 + ci (x-xi) + di
14+
* on interval (xi, x(i+1)).
15+
*/
16+
17+
function _cubic_spline_evaluate(a, b, c, d, xx, t)
18+
{
19+
// Verify that all arguments have the appropriate length
20+
var n = array_length(xx);
21+
if ((array_length(a) != n-1) || (array_length(b) != n-1) || (array_length(c) != n-1) || (array_length(d) != n-1))
22+
return undefined;
23+
24+
// Find which subinterval the input value belongs to
25+
var ii = 0; // index of subinterval
26+
while ((t >= xx[ii+1]) && (ii < n-2))
27+
ii++;
28+
29+
// Evaluate the function using the corresponding coefficients
30+
return a[ii]*power((t-xx[ii]), 3) + b[ii]*sqr(t-xx[ii]) + c[ii]*(t-xx[ii]) + d[ii];
31+
}

scripts/_range/_range.gml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
/// @desc Generates an array of equally-spaced values over a specified range with a specified step size.
33
/// @param {real} start First value of array.
44
/// @param {real} stop Final value of array (if the step size evenly divides the array; otherwise gives an upper bound to the final value).
5-
/// @param {real} [step=1] Step size. May be positive if start <= stop and negative if start >= stop.
5+
/// @param {real} [step=1] Step size. May be positive if start <= stop and negative otherwise.
66
/// @return {real[]} Array of values beginning with start, incrementing by step, and ending with the last value that does not extend beyond stop.
77

88
function _range(start, stop)

scripts/_root_bisection/_root_bisection.gml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// @func _root_bisection(f, a, b[, err[, cutoff]])
2-
/// @func Finds the root of a real-valued function on a specified interval using the bisection method.
2+
/// @func Finds the root of a real-valued, continuous function on a specified interval using the bisection method.
33
/// @param {function} f Function (which maps reals to reals) to find the root of. The signs of f(a) and f(b) must be opposite.
44
/// @param {real} a Lower bound of search interval.
55
/// @param {real} b Upper bound of search interval.

scripts/_root_newton/_root_newton.gml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/// @func _root_newton(f, fp, x0[, err[, cutoff]])
2-
/// @func Finds the root of a real-valued, differentiable function for an initial guess using Newton's method.
2+
/// @func Finds the root of a real-valued, differentiable function from an initial guess using Newton's method.
33
/// @param {function} f Differentiable function (which maps reals to reals) to find the root of.
44
/// @param {function} fp First derivative of function.
55
/// @param {real} x0 Initial guess.

0 commit comments

Comments
 (0)