SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
SmoothingCubicSpline.java
1/*
2 * Class: SmoothingCubicSpline
3 * Description: smoothing cubic spline algorithm of Schoenberg
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.functionfit;
26
27import umontreal.ssj.functions.*;
28import umontreal.ssj.functions.Polynomial;
29import umontreal.ssj.functions.MathFunctionWithFirstDerivative;
30import umontreal.ssj.functions.MathFunctionWithDerivative;
31import umontreal.ssj.functions.MathFunctionWithIntegral;
32import umontreal.ssj.functions.SquareMathFunction;
33import umontreal.ssj.functions.MathFunctionUtil;
34
90
91 private Polynomial[] splineVector;
92 private double[] x, y, weight;
93 private double rho;
94
108 public SmoothingCubicSpline(double[] x, double[] y, double[] w, double rho) {
109 if (x.length != y.length)
110 throw new IllegalArgumentException("x.length != y.length");
111 if (w != null && x.length != w.length)
112 throw new IllegalArgumentException("x.length != w.length");
113 if (rho < 0 || rho > 1)
114 throw new IllegalArgumentException("rho not in [0, 1]");
115
116 splineVector = new Polynomial[x.length + 1];
117 this.rho = rho;
118 this.x = x.clone();
119 this.y = y.clone();
120
121 weight = new double[x.length];
122 if (w == null) {
123 for (int i = 0; i < weight.length; i++)
124 weight[i] = 1.0;
125 } else {
126 for (int i = 0; i < weight.length; i++)
127 weight[i] = w[i];
128 }
129
130 resolve();
131 }
132
145 public SmoothingCubicSpline(double[] x, double[] y, double rho) {
146 this(x, y, null, rho);
147 }
148
155 public double evaluate(double z) {
156 int i = getFitPolynomialIndex(z);
157 if (i == 0)
158 return splineVector[i].evaluate(z - x[0]);
159 else
160 return splineVector[i].evaluate(z - x[i - 1]);
161 }
162
171 public double integral(double a, double b) {
172 int iA = getFitPolynomialIndex(a);
173 int iB = getFitPolynomialIndex(b);
174 double retour;
175 int i = 1;
176
177 // Calcule l'integrale
178 if (iA == iB) { // les deux valeurs sont sur le meme polynome
179 retour = splineVector[iB].integral(a - x[iB], b - x[iB]);
180 } else {
181 if (iA == 0)
182 retour = splineVector[iA].integral(a - x[iA], 0);
183 else
184 retour = splineVector[iA].integral(a - x[iA], x[iA + 1] - x[iA]);
185 for (i = iA + 1; i < iB; i++) {
186 retour += splineVector[i].integral(0, x[i + 1] - x[i]);
187 }
188 retour += splineVector[iB].integral(0, b - x[iB]);
189 }
190 return retour;
191 }
192
200 public double derivative(double z) {
201 int i = getFitPolynomialIndex(z);
202 if (i == 0)
203 return splineVector[i].derivative(z - x[0]);
204 else
205 return splineVector[i].derivative(z - x[i - 1]);
206 }
207
216 public double derivative(double z, int n) {
217 int i = getFitPolynomialIndex(z);
218 if (i == 0)
219 return splineVector[i].derivative(z - x[0], n);
220 else
221 return splineVector[i].derivative(z - x[i - 1], n);
222 }
223
229 public double[] getX() {
230 return x.clone();
231 }
232
238 public double[] getY() {
239 return y.clone();
240 }
241
247 public double[] getWeights() {
248 return weight;
249 }
250
256 public double getRho() {
257 return rho;
258 }
259
266 return splineVector.clone();
267 }
268
280 public int getFitPolynomialIndex(double x) {
281 // Algorithme de recherche binaire legerement modifie
282 int j = this.x.length - 1;
283 if (x > this.x[j])
284 return j + 1;
285 int tmp = 0;
286 int i = 0;
287
288 while (i + 1 != j) {
289 if (x > this.x[tmp]) {
290 i = tmp;
291 tmp = i + (j - i) / 2;
292 } else {
293 j = tmp;
294 tmp = i + (j - i) / 2;
295 }
296 if (j == 0) // le point est < a x_0, on sort
297 i--;
298 }
299 return i + 1;
300 }
301
302 private void resolve() {
303 /*
304 * taken from D.S.G Pollock's paper, "Smoothing with Cubic Splines", Queen Mary,
305 * University of London (1993) http://www.qmw.ac.uk/~ugte133/PAPERS/SPLINES.PDF
306 */
307
308 double[] h = new double[x.length];
309 double[] r = new double[x.length];
310 double[] u = new double[x.length];
311 double[] v = new double[x.length];
312 double[] w = new double[x.length];
313 double[] q = new double[x.length + 1];
314 double[] sigma = new double[weight.length];
315
316 for (int i = 0; i < weight.length; i++) {
317 if (weight[i] <= 0.0)
318 sigma[i] = 1.0e100;
319 else
320 sigma[i] = 1.0 / Math.sqrt(weight[i]);
321 }
322
323 double mu;
324 int n = x.length - 1;
325
326 if (rho <= 0)
327 mu = 1.0e100; // arbitrary large number to avoid 1/0
328 else
329 mu = 2 * (1 - rho) / (3 * rho);
330
331 h[0] = x[1] - x[0];
332 r[0] = 3 / h[0];
333 for (int i = 1; i < n; i++) {
334 h[i] = x[i + 1] - x[i];
335 r[i] = 3 / h[i];
336 q[i] = 3 * (y[i + 1] - y[i]) / h[i] - 3 * (y[i] - y[i - 1]) / h[i - 1];
337 }
338
339 for (int i = 1; i < n; i++) {
340 u[i] = r[i - 1] * r[i - 1] * sigma[i - 1] + (r[i - 1] + r[i]) * (r[i - 1] + r[i]) * sigma[i]
341 + r[i] * r[i] * sigma[i + 1];
342 u[i] = mu * u[i] + 2 * (x[i + 1] - x[i - 1]);
343 v[i] = -(r[i - 1] + r[i]) * r[i] * sigma[i] - r[i] * (r[i] + r[i + 1]) * sigma[i + 1];
344 v[i] = mu * v[i] + h[i];
345 w[i] = mu * r[i] * r[i + 1] * sigma[i + 1];
346 }
347 q = Quincunx(u, v, w, q);
348
349 // extrapolation a gauche
350 double[] params = new double[4];
351 double dd;
352 params[0] = y[0] - mu * r[0] * q[1] * sigma[0];
353 dd = y[1] - mu * ((-r[0] - r[1]) * q[1] + r[1] * q[2]) * sigma[1];
354 params[1] = (dd - params[0]) / h[0] - q[1] * h[0] / 3;
355 splineVector[0] = new Polynomial(params);
356
357 // premier polynome
358 params[0] = y[0] - mu * r[0] * q[1] * sigma[0];
359 dd = y[1] - mu * ((-r[0] - r[1]) * q[1] + r[1] * q[2]) * sigma[1];
360 params[3] = q[1] / (3 * h[0]);
361 params[2] = 0;
362 params[1] = (dd - params[0]) / h[0] - q[1] * h[0] / 3;
363 splineVector[1] = new Polynomial(params);
364
365 // les polynomes suivants
366 int j;
367 for (j = 1; j < n; j++) {
368 params[3] = (q[j + 1] - q[j]) / (3 * h[j]);
369 params[2] = q[j];
370 params[1] = (q[j] + q[j - 1]) * h[j - 1] + splineVector[j].getCoefficient(1);
371 params[0] = r[j - 1] * q[j - 1] + (-r[j - 1] - r[j]) * q[j] + r[j] * q[j + 1];
372 params[0] = y[j] - mu * params[0] * sigma[j];
373 splineVector[j + 1] = new Polynomial(params);
374 }
375
376 // extrapolation a droite
377 j = n;
378 params[3] = 0;
379 params[2] = 0;
380 params[1] = splineVector[j].derivative(x[x.length - 1] - x[x.length - 2]);
381 params[0] = splineVector[j].evaluate(x[x.length - 1] - x[x.length - 2]);
382 splineVector[n + 1] = new Polynomial(params);
383 }
384
385 private static double[] Quincunx(double[] u, double[] v, double[] w, double[] q) {
386 u[0] = 0;
387 v[1] = v[1] / u[1];
388 w[1] = w[1] / u[1];
389 int j;
390
391 for (j = 2; j < u.length - 1; j++) {
392 u[j] = u[j] - u[j - 2] * w[j - 2] * w[j - 2] - u[j - 1] * v[j - 1] * v[j - 1];
393 v[j] = (v[j] - u[j - 1] * v[j - 1] * w[j - 1]) / u[j];
394 w[j] = w[j] / u[j];
395 }
396
397 // forward substitution
398 q[1] = q[1] - v[0] * q[0];
399 for (j = 2; j < u.length - 1; j++) {
400 q[j] = q[j] - v[j - 1] * q[j - 1] - w[j - 2] * q[j - 2];
401 }
402 for (j = 1; j < u.length - 1; j++) {
403 q[j] = q[j] / u[j];
404 }
405
406 // back substitution
407 q[u.length - 1] = 0;
408 for (j = u.length - 3; j > 0; j--) {
409 q[j] = q[j] - v[j] * q[j + 1] - w[j] * q[j + 2];
410 }
411 return q;
412 }
413}
double evaluate(double z)
Evaluates and returns the value of the spline at .
double integral(double a, double b)
Evaluates and returns the value of the integral of the spline from.
SmoothingCubicSpline(double[] x, double[] y, double[] w, double rho)
Constructs a spline with nodes at , with weights.
double getRho()
Returns the smoothing factor used to construct the spline.
double[] getWeights()
Returns the weights of the points.
double[] getY()
Returns the coordinates for this spline.
int getFitPolynomialIndex(double x)
Returns the index of , the.
double derivative(double z)
Evaluates and returns the value of the first derivative of the spline at .
SmoothingCubicSpline(double[] x, double[] y, double rho)
Constructs a spline with nodes at , with weights and smoothing factor = rho.
Polynomial[] getSplinePolynomials()
Returns a table containing all fitting polynomials.
double derivative(double z, int n)
Evaluates and returns the value of the n-th derivative of the spline at .
double[] getX()
Returns the coordinates for this spline.
Represents a polynomial of degree in power form.
Represents a mathematical function whose th derivative can be computed using derivative(double,...
Represents a mathematical function whose derivative can be computed using derivative(double).
Represents a mathematical function whose integral can be computed by the integral(double,...
This interface should be implemented by classes which represent univariate mathematical functions.