# 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