JSpline+ API Specification

JSpline+: Spline Library for Java

See:
          Description

Core Packages
ru.sscc.util Collection of miscellaneous utility classes.
ru.sscc.util.data Collection of data access classes implementing such concepts as a data container, data vector, data pointer, and array of vectors.

 
Linear Algebra
ru.sscc.matrix Collection of classes describing algebraic matrices.
ru.sscc.matrix.solve Collection of Solvers intended for solving of Systems of Linear Algebraic Equations (SLAE).

 
Splines
ru.sscc.spline Basic spline approximation classes.
ru.sscc.spline.analytic Multivariate Duchon's splines.
ru.sscc.spline.creator The collection of auxiliary classes used in spline creation.
ru.sscc.spline.mesh The collection of 1D meshes and auxiliary classes.
ru.sscc.spline.polynomial One-dimensional polynomial splines.
ru.sscc.spline.reduction The collection of multi-D space transformations (reductions) and multi-D meshes.

 

JSpline+: Spline Library for Java

Version 1.25.

See also: JSpline+: Change List.

The samples and benchmarks are described in Samples for JSpline+



Contents

1  Aims and Historical Notes
2  Unified Data Access
3  Matrices
    3.1  Solving of Linear Algebraic Systems
4  Splines
    4.1  Polynomial Splines
        4.1.1  Interpolation with Splines of Odd Degree
        4.1.2  Interpolation on Uniform Mesh
        4.1.3  Fitting with Splines of Odd Degree
        4.1.4  Construction of Many Splines
    4.2  Multivariate Duchon's Splines



1  Aims and Historical Notes

The first and main aim of the development of this Library was an implementation of various splines to be constructed by function measurements on 1D or multi-dimensional mesh of scattered points. This job was originated on the spline software library LIDA-3 developed in 1985 at the Novosibirsk Computing Center under the leadership of Prof. Vladimir A. Vasilenko. The current job began at the middle of 1999. While developing, the initial scope of the Library was enlarged. So, the "plus" sign in the library name reflects the fact that the library contains other independent sections within. It now consists of 3 main sections:

The scope of the Library will be continuously enlarged to cover other fields of the Numerical Mathematics.



2  Unified Data Access

The ru.sscc.util.data package provides unified access to user's data vectors. The enumeration of vector's entries always starts from zero. All package classes support four primitive operations upon data entries:

get(...)
returns the value of entry;
set(...,value)
sets the entry to the specified value and returns the original value passed as the parameter;
add(...,value)
adds the value to the entry and returns the result;
mul(...,value)
multiplies the entry by the value and returns the result.

Four conceptual classes are introduced here:

RealContainer
is an array of double or float type entries. The class is used as a body of many objects of the library. For example, matrix entries and spline coefficients are stored in a RealContainer instance. To improve performance, vector operations on container's entries are introduced: inner products upon the subvectors of the container, Givens rotation of subvectors, and others. These operations are useful in the solving of Linear Algebraic Systems. The relativeAccuracy() method returns the relative accuracy of data type used in the container, e.g. the smallest value e such that 1+e isn't equal to 1 for the data type used. This constant is widely useful in numeric calculations, but it is absent in Java.

RealVector
is a vector of double or float type entries. The mathematical concept of vector of the length n is described as a set of indexed entries: a0, a1, ..., an-1. This set may be mapped to the memory by many ways. The subclasses of this class support 3 mapping schemes: the regular mapping means the storage of entries in a container regularly when the distance between any two neighbor vector entries is constant; the reference mapping provides an arbitrary mapping of vector entries to the container via a reference vector that contains indices of vector entries in the container; and the component reference mapping corresponds to the cutting a component out of a set of vectors mapped via reference vector (see the package description for more details). Some BLAS operations are implemented for this class: assign a vector or constant or vector multiplied by a constant, add a vector multiplied by a value, multiply by a value, inner product, weighted inner product, useful vector norms, and so on.

RealPointer
is a "pointer" to vector's entry. This class implements "like C access" to vector entries via a pointing object. The RealPointer may go up and down along vector's entries and get or modify its values. In contrast to Java iterator, the pointer never "knows" how many vector entries it can still get. Every RealVector subtype has corresponding RealPointer subtype. Special subtypes are added to point to a single double value, the SimplePointer, and to point to entries of the RealVectors instance, the RealPointers.

RealVectors
is a "table of vectors". The class was designed to support the concept of "set of points in multi-D space". Every vector occupies a continuous part of the underlying container. All the vectors have the same dimension, e.g. consist of the identical number of components. Two mapping schemes are supported: the simple mapping means the sequential storage of vectors in the container and the reference mapping provides an arbitrary mapping of vectors to the table via a reference vector that contains indices of vectors in the table. To calculate the squared Euclidian distance between a point belonging to the set of vectors and an arbitrary point of multi-D space, the squaredDistance(index,pointer) method is used.

All above mentioned classes are tied together: the RealContainer class allows to create a vector or pointer upon it; the RealVector class allows to create a subvector or pointer to a subvector in it; the RealVectors class provides getting of i-th vector from the set of vectors, creation of a vector consisting of j-th component of all vectors, creation of a pointer to i-th vector. All (sub)vector creation operations don't create a copy of entries. They create an instance that refers to the same underlying data container as the instance with the help of which the operation was performed.

Two special subclasses, ChainVector and ChainPointer, provide the access to the chain of vectors considered as one composite vector.

A container can move or shift the starting index of a vector created by it. This operation is useful in matrix calculations when a matrix is considered as a set of rows or columns, and the same operation must be produced on every element of the set.

To simplify conversions, a number of static by methods is introduced. For example, to create a RealContainer from a double[] or float[] array, you can write down the following:

     double[] array = new double[count];
     //... Fill the array in
     RealContainer container = RealContainer.by(array);

Finally, we notice the RealMath class. It contains many useful static methods that perform some BLAS operations upon double[], float[], and RealPointer instances. The calculation of factorial of n, integer power of x, and a polynomial value by the Gorner's algorithm is also implemented here.



3  Matrices

The ru.sscc.matrix package and its subpackages present the Numerical Linear Algebra Section of the Library. The root package describes matrices. Only real matrices are implemented now.

The Matrix interface describes the most common properties of any matrix: a matrix is a rectangular table consisting of a constant number of rows and columns and a matrix is serializable object.

The RealAlgebraicMatrix interface extends the Matrix by adding two algebraic methods: multiplication of the matrix by a vector and multiplication of the transposed matrix by a vector. In other words, the algebraic matrix is the operator that linearly maps a source vector to the target vector and it has the transposed operator acting analogously. In addition, the method relativeAccuracy() must return the relative accuracy of data type used for matrix entries.

When a matrix is used for solving of a linear algebraic system, the decomposition coefficients are stored in it. In this case, the matrix loses the algebraicity and the multiplication by a vector has no sense more. We say that the matrix becomes non-algebraic and the try to multiply it by a vector throws the IllegalStateException.

The TransposedMatrix class is the decorator class. It is used if you need to "transpose" an algebraic matrix. This is the logical transposing. It logically interchanges the columns and rows numbers and treats the matrix-by-vector multiplication as the transposed multiplication for the underlying matrix. Conversely, the multiplication of the transposed matrix by a vector is treated as the direct multiplication for the underlying matrix.

The RealMatrix class is the basic class for almost all real matrices. It is the abstract class. It partially implements the RealAlgebraicMatrix interface and adds four primitive operations for the access to matrix values, get(i,j), set(i,j,value), add(i,j,value), and mul(i,j,value).

The indices of matrix entries start from zero. So, if the matrix has m rows and n columns then i must belong to the set {0,1,...,m-1} and j must belong to the set {0,1,...,n-1}.

All real matrices store their coefficients in the body, an instance of the RealContainer type, e.g. the 1D array is used as the storage for matrix entries. This solution was selected by the efficiency reason. You can get the matrix body by the getContainer() method. The access to the matrix dimensions may be done in two way:

The RealMatrix class supports cloning. The clone is the matrix having the separate body copied from the body of the original matrix. The clone is the algebraic matrix, independently to the state of the original matrix. If the original matrix is a submatrix of a dense matrix, the clone will contain the submatrix entries only.

Three types of matrices are implemented in the current version of the Library:

DenseMatrix
is a rectangular dense matrix, e.g. all matrix entries are stored in the body and can be modified. This class supports the following algebraic operations: matrix assignment and creation of the transposed matrix upon the same body. The creation of a submatrix sharing their entries with the parent matrix is also possible.

SymBandedMatrix
is a symmetric banded matrix. Only the half of matrix band is stored in the body. This class also supports Toeplitz symmetric banded matrices. The Toeplitz matrix has identical values along main diagonals. So, much less memory is needed to store the Toeplitz matrix.

RectBandedMatrix
is a rectangular banded matrix. This is the very special matrix. It was implemented because the Spline Section of the Library uses it. Toeplitz rectangular banded matrices are also supported.

The switching between algebraic and non-algebraic state of matrices is implemented by the lock and reuse methods: the lock method changes the matrix state to be non-algebraic and the reuse method allows the reusing of the matrix as the algebraic matrix.

The package supports matrix-by-matrix multiplication operations as static methods of the RealMatrix class.



3.1  Solving of Linear Algebraic Systems

The ru.sscc.matrix.solve package is devoted to the solving of a System of Linear Algebraic Equations (SLAE)

Ax = b
and consists of various solvers. We consider now only real solvers that solve SLAE with a real matrix A and real right hand side b.

Every real solver implements the RealSolver interface, containing the solve(b,x) method that receives the right hand side vector b and calculates the solution vector x. Two auxiliary methods are also described in the interface: sourceSize() and targetSize().

The RealSolver interfaces supports serialization.

We distinct two main types of real solvers: direct solvers and iterative solvers. Only direct solvers are implemented yet. The basic abstract class for all direct solvers is the RealDirectSolver. It implements the basic interface for all direct solvers and adds the abstract method factorize() that provides the matrix decomposition by factors (e.g. factorization). The matrix to be factorized is attached to the solver. A direct solver can have two states: before the factorization and after it. If the matrix is nonfactorized yet, the solve method is inaccessible. When the matrix is factorized, it becomes non-algebraic, and all algebraic operations with it are blocked. The reuse method implemented in all subclasses changes the state of the solver and the attached matrix to the initial state: the factorization tag is cleared and the matrix becomes algebraic again. So, after that, you can fill in the attached matrix again.

The basic principal for all direct solvers is: "Once factorize, many times solve". So, if you need to solve many SLAEs that differ in the right hand sides only, you should factorize the matrix only once, and then can find the solution many times for different right hand sides.

To improve the solution accuracy, use the iterative refinement algorithm implemented in the RealDirectSolver. It is most efficient if the attached matrix is constructed on the base of the float[] type vector. The construction of the inverse matrix is also implemented in this class.

The RealDirectSolver class supports cloning. A clone is always clear solver without attached matrix.

The hierarchy of the classes based on the RealDirectSolver is the following:



4  Splines

The ru.sscc.spline package contains basic spline approximation classes. We use the term spline for a function

s(x) = s(x0,¼,xm-1)
in the multi-D space Rm of points x = (x0,¼,xm-1) if it is constructed as a linear combination
s(x) = M-1
å
i = 0 
aisi(x)
of some basic functions si(x), called the spline base. The vector a = (a0,¼,aM-1) is called by the spline coefficients vector.

A spline instance consists of 3 parts:

The BaseSpline class is the basic class for all splines. It implements common operations for all splines: the dimension() operation returns the dimension m of the space of points Rm for which the spline was constructed; the clone() operation creates a clone of the spline (the clone shares the body and coefficients with the parent instance, but has its own workspace); and the flush() operation removes the workspace from a spline. You can also use the getBody() and getContainer() operations for the access to the spline body and coefficients.

All splines are serializable objects.

The BaseSpline instance cannot be created directly. But it has two subclasses having public constructors: the Spline and Splines. The first class performs operations with a unique spline, and the last class performs operations with many splines constructed on the same spline body.

The Spline class has a number of value() operations. For 1D spline, you can use any of them, but, for multivariate spline, you must use only the multi-D variant of the operation. If 1D spline allows to calculate a spline derivative, the value(point,derivative) operation may be used. For the multivariate spline, you can calculate a spline value only. If the calculation cannot be done for the parameters specified, the IllegalArgumentException is thrown.

The Splines class has more value() operations: as individual spline value calculation so as vector operations for all splines of the instance.



4.1  Polynomial Splines

The ru.sscc.spline.polynomial package is intended for the construction of 1D piecewise polynomial splines. The polynomial splines differ by the spline degree and spline representation. The construction of polynomial splines of odd degree with polynomial representation in mesh nodes is available now. We plan to add the construction of even degree splines and also implement the B-spline representation for all splines in future releases.



4.1.1  Interpolation with Splines of Odd Degree

The POddSplineCreator class allows to construct polynomial splines of odd degree. To describe its features, we introduce the notation on the example of cubic splines.

Let x0 < x1 < ¼ < xn-1 be mesh nodes on the real axis and fi = f(xi) be the values of the function to be interpolated. The well-known cubic spline is the function constructed with the cubic polynomials defined at mesh cells (xi,xi+1), i = 0,¼,n-2, in such a way to provide its second derivative to be continuous function at mesh nodes. The interpolating cubic spline satisfies the interpolation conditions

s(xi) = fi,    i = 0,¼,n-1.
The cubic spline is called the natural if it satisfies the boundary conditions
s¢¢(x0) = s¢¢(xn-1) = 0.

To construct and use the natural interpolating cubic spline, write the following code:

     // Create a mesh array. It may be a double[], float[], or RealContainer instance.
     // For example:
     double[] mesh = new double[n];
     // ... fill the mesh

     // Create an array of interpolation values at mesh nodes. For example:
     double[] values = new double[n];
     // ... fill the array

     // Create the natural interpolating cubic spline
     Spline spl = POddSplineCreator.createSpline(2, mesh, values);

     // Use the spline in calculations: x - a point on the real axis, f - the spline value
     f = spl.value(x);

The first parameter of all createSpline methods in the POddSplineCreator class is the difference order that is tied with the spline degree by the following rule: degree=2*order-1. So, to create the cubic spline, the order must be equal to 2. If order=1, the piecewise linear spline will be constructed. For order=3,4,..., the quintic spline, 7th degree spline, etc. will be constructed. The more order is used, the higher spline derivative is continuous. Exactly, the (2*order-2)-th spline derivative is the continuous function. The extrapolation (e.g. calculation of the spline values for x < x0 and x > xn-1) is provided by the polynomials of (order-1)-th degree. So, the cubic spline is extended by linear functions, the quintic spline is extended by quadratic functions and so on.

The number of mesh nodes must satisfy the inequality n>=order. The mesh nodes must be ordered in increasing or decreasing order and must be different. If the mesh is incorrect, or some mesh nodes are very closed, or the difference order is too large, the CalculatingException will be thrown while the spline construction. This means that the spline cannot be constructed. You must catch this exception anywhere.



4.1.2  Interpolation on Uniform Mesh

If the distance between mesh nodes is constant, you need not fill in the mesh array. Use the following method instead:

     Spline spl = POddSplineCreator.createSpline(order, x0, step, n, values);
Here x0 is the first mesh node, step is the distance between neighbour mesh nodes, n is the number of mesh nodes, and values is the array of interpolating values at mesh nodes.



4.1.3  Fitting with Splines of Odd Degree

When the function measurements are non-strict, the constructing of smoothing spline is more preferable than the interpolation. The smoothing spline goes "near" the function measurements. It is more smooth and may suppress unexpected overshoots in the measurements. The degree of smoothing is controlled by the smoothing parameter a > 0. When a tends to zero, the smoothing spline converges to the interpolation spline. When a tends to the positive infinity, the smoothing spline converges to the polynomial of the degree order-1 (this is the linear function for cubic spline). The problem is to select proper a providing the "best" smoothing results.

We select the smoothing parameter to satisfy the residual criterion

n-1
å
i = 0 
(fi-s(xi))2 = e2,
where e is the residual level wanted. The solution of the residual criterion equation may be found if e isn't greater than the emax-the residual for a = ¥.

It isn't necessary to solve this equation with high accuracy. It is usually enough to construct the spline, such that the residual belongs to the segment [e(1-d),e(1+delta)]. Here d is the accuracy level. The default accuracy level is set to 0.1. It may be changed by the SmoothingPreparator.setAccuracy(delta) method.

To construct a smoothing spline satisfying the residual criterion, the following methods are used:

     // For arbitrary mesh:
     Spline spl = POddSplineCreator.createSpline(order, mesh, values, epsilon);
     // For uniform mesh:
     Spline spl = POddSplineCreator.createSpline(order, x0, step, n, values, epsilon);
If epsilon isn't less than emax, the spline will coincide with the polynomial of the (order-1)-th degree-the solution to the smoothing problem for a = ¥.

If you know the function measurement error for every mesh node, you'll want to construct the smoothing spline that may strongly deviate from the function measurements in "bad" nodes, and weekly deviate in the "good" nodes. To provide this, use the weighted residual criterion

n-1
å
i = 0 
wi-1(fi-s(xi))2 = e2,
where wi are positive weights. The more weight is used in a node, the greater deviation in it will be received.

To construct a smoothing spline satisfying the weighted residual criterion, the following methods are used:

     // For arbitrary mesh:
     Spline spl = POddSplineCreator.createSpline(order, mesh, values, epsilon, weights);
     // For uniform mesh:
     Spline spl = POddSplineCreator.createSpline(order, x0, step, n, values, epsilon, weights);
Here the weights array contains positive weights assigned to mesh nodes.



4.1.4  Construction of Many Splines

If you want to construct many splines distinct in function measurements only, you must do the following:

  1. Construct the spline creator instance using a constructor of the POddSplineCreator class.

  2. Prepare the creator's solver. You may set weights before the preparation of the solver.

  3. Construct a spline or many splines simultaneously by one of construct... methods of the class.

The Step 3 may be repeated many times.

Example 1  To construct a number of interpolating splines on an arbitrary mesh, write down the following:

     double[] mesh = new double[n];
     // ... fill the mesh

     OddSplineCreator creator = new POddSplineCreator(order, RealVector.by(mesh));
     creator.prepareSolver(0); // Prepare solver for alpha=0

     // Create array for the measurements
     double[] values = new double[n];
     // ... prepare function measurements in the array

     // Construct the first spline:
     Spline spl1 = creator.constructSpline(RealVector.by(values));

     // ... prepare function measurements in the same array

     // Construct the second spline:
     Spline spl2 = creator.constructSpline(RealVector.by(values));
     // And so on ...
The POddSplineCreator class is the implementation of the abstract OddSplineCreator class. The conversion of the creator instance to its superclass is preferable in this case, because the superclass has just the same interface.

Example 2  To construct the weighted smoothing splines with the same smoothing parameter a (1 in this example), write down the following:

     OddSplineCreator creator = new POddSplineCreator(order, RealVector.by(mesh));
     double[] weights = new double[n];
     // ... fill the weight vector

     creator.prepareWeights(weights);
     creator.prepareSolver(1); // Prepare solver for alpha=1

     // ... construct splines by the same manner as in the previous example

Example 3  To construct the smoothing spline with selection of a from the residual criterion, you need not prepare the solver. Instead of the preparation of the solver you can immediately use the constructing method:

     Spline spl1 = creator.constructSpline(RealVector.by(values), epsilon);
After that, the solver will be prepared. So, to construct other splines with the same parameter a, you can call:
     Spline spl2 = creator.constructSpline(RealVector.by(values));
     // ...

Example 4  When many splines must be constructed in one Splines instance, you should prepare the RealVectors instance containing all functions measurements and use one of the following methods:

     RealVectors measurements;
     // ... prepare the measurements

     // Construct splines by the rows of the measurements array:
     Splines spls = creator.constructSplinesByRows(measurements);
     // or construct splines by the columns of the measurements array:
     Splines spls = creator.constructSplinesByColumns(measurements);

Example 5  If you want to create the Splines instance with sequential calculation the splines' coefficients, do the following. Manually construct the Splines instance:

     Splines spls = new Splines(creator.getSplineBody(), count);
Here count is a number of splines to be calculated. After that, call the calculate method in a cycle:
     for(int i=0; i<count; i++) {
       // ... prepare i-th measurements in the values array ...

       // Calculate the coefficients of i-th spline
       creator.calculate(RealVector.by(values), spls.getVector(i));
     }



4.2  Multivariate Duchon's Splines

The ru.sscc.spline.analytic package is intended for the construction of multivariate analytic Duchon's splines. The Duchon's spline is the generalization of so-called 2D thin plate spline to multi-D case. It allows to construct spline for arbitrary number of independent variables on a scattered mesh of interpolating nodes. The Duchon's spline is constructed with the help of especial multivariate radial basic function g(x). The range of possible basic functions is wide, but we use 3 of them only:

The Duchon's spline has the form

s(x) = n-1
å
i = 0 
aig(x-xi)+p(x),
where xi are mesh nodes and p(x) is a polynomial. We call the function p(x) as the polynomial kernel of Duchon's approximation.

The type of spline to be constructed is defined by the mode parameter. Four different modes may be used:

mode=0
pseudo-linear spline with constant kernel;
mode=1
pseudo-linear spline with linear kernel;
mode=2
pseudo-quadratic spline with linear kernel;
mode=3
pseudo-cubic spline with linear kernel.

The more mode is used, the smoother spline is constructed.

The GSplineCreator class allows to construct Duchon's splines. The use of this class is quite similar to the use of the polynomial spline creator on a nonuniform mesh (see Section 4.1) except two essential distinctions:

The interpolation, fitting, and residual criterion fitting (weighted or not) are possible.


File translated from TEX by TTH, version 2.25.
On 08 Feb 2001, 16:40.