# Natural cubic spline representation of given data.
spline = function (A; B)
{
local (n; x; y; s; d; u; w; i; c);
# If `B' is given, then we take it that the user wants
# to evaluate the spline `A' at the points in `B'.
if (B != NULL)
{
if (A.class != "spline") { A = self (A); }
return self.eval (A; B);
}
# Otherwise, we're to take data in `A' and return a spline.
s = {class = "spline"};
A = vector (A); # Make sure input is a vector.
n = A.ne;
if (n < 2)
{
message ("run time error: At least two data points are required.");
exception ();
}
# Generate abscissa, if necessary.
if (A.eid == NULL)
{
A.eid = 1:n;
elseif (A.eid.type == "character")
A.eid = 1:n;
}
# Switch data and labels.
x = A.eid;
A.eid = NULL;
x.eid = A;
# Sort by abscissa values. (Require them to be unique.)
x = set (x);
if (n != x.ne)
{
message ("run time error: Abscissa values must be unique.");
exception ();
}
# Get ordinate values.
y = x.eid;
x.eid = NULL;
# Go for it.
c = dense (zero (n));
if (n > 3)
{
d = 2.0*(x[3:n]-x[1:n-2]);
u = x[2:n]-x[1:n-1];
w = 6.0*((y[3:n]-y[2:n-1])/u[2:n-1]-(y[2:n-1]-y[1:n-2])/u[1:n-2]);
for (i in 2:n-2)
{
w[i] = w[i] - w[i-1]*u[i]/d[i-1];
d[i] = d[i] - u[i]*u[i]/d[i-1];
}
for (i in n-1:2)
{
c[i] = (w[i-1]-u[i]*c[i+1])/d[i-1];
}
}
s.knots = label (y; x);
s.curvatures = c;
return s;
};
spline.eval = function (s; v)
{
local (x; y; t; i; u; sp; p; r; n);
v = vector (v);
y = s.knots;
x = y.eid;
x.eid = y.eid = NULL;
n = x.ne;
p = s.curvatures;
r = vector ();
for (u in v)
{
if (u < x[1])
{
sp = ( (y[2]-y[1])/(x[2]-x[1]) - (x[2]-x[1])*p[2]/6.0 );
r = r, y[1]-sp*(x[1]-u);
elseif (u >= x[n])
sp = ( (y[n]-y[n-1])/(x[n]-x[n-1]) - (x[n]-x[n-1])*p[n-1]/6.0 );
r = r, y[n]+sp*(u-x[n]);
else
i = find (1; u < x)[1] - 1;
t = (u-x[i])/(x[i+1]-x[i]);
r = r, ( t*y[i+1] + (1-t)*y[i] +
(x[i+1]-x[i])^2*((t^3-t)*p[i+1]+((1-t)^3-(1-t))*p[i])/6.0 );
}
}
r.eid = v;
return r;
};
syntax highlighted by Code2HTML, v. 0.9.1