function RBF(points, values, distanceFunction, epsilon) {
var distance = distanceThinPlate;
var M = numeric.identity(points.length);
for(var j=0; j<points.length; j++) {
for(var i=0; i<points.length; i++) {
M[j][i] = norm(points[i], points[j]);
}
}
if(epsilon === undefined) {
epsilon = numeric.sum(M) / (Math.pow(points.length, 2) - points.length);
}
for(var j=0; j<points.length; j++) {
for(var i=0; i<points.length; i++) {
M[j][i] = distance(M[j][i], epsilon);
}
}
var sample = values[0];
var D = typeof sample === 'number'
? 1
: sample.length;
if(D === 1) {
values = values.map(function(value) {
return [value];
});
}
var tmp = new Array(D);
for(var i=0; i<D; i++) {
tmp[i] = values.map(function(value) {
return value[i];
});
}
values = tmp;
var w = new Array(D);
var LU = numeric.LU(M);
for(var i=0; i<D; i++) {
w[i] = numeric.LUsolve(LU, values[i]);
}
function interpolant(p) {
var distances = new Array(points.length);
for(var i=0; i<points.length; i++) {
distances[i] = distance(norm(p, points[i]), epsilon);
}
var sums = new Array(D);
for(var i=0; i<D; i++) {
sums[i] = numeric.sum(numeric.mul(distances, w[i]));
}
return sums;
}
return interpolant;
}