Skip to content

Commit

Permalink
Broke the 2D splines into their own classes
Browse files Browse the repository at this point in the history
  • Loading branch information
StaticBeagle committed Dec 12, 2024
1 parent d530015 commit 7f31ca8
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.wildbitsfoundry.etk4j.math.interpolation;

import java.util.Arrays;

public class BiCubicSpline extends Spline2D {

protected BiCubicSpline(double[] y, Spline[] splines, int order) {
super(y, splines, order);
}

/**
* Construct a bicubic spline using not-a-knot conditions.
*
* @param x The x coordinates of the spline.
* @param y The y coordinates of the spline.
* @param z The values of the spline at each {@code (x, y)}. Notice that for each x and y combination there should
* be a value in {@code z}. For example, consider: <br>
*
* {@code x = [1, 2, 3, 4]}, {@code y = [1, 2, 3, 4]}, <br>and {@code z(x, y) = x<sup>2</sup> * y<sup>2</sup>}. <br>
* This means that the first row of {@code z} will be all the values obtained by fixing {@code x = 1} and
* iterating over all the values of {@code y}. <br>
* {@code z[0] = [z(1, 1), z(1, 2), z(1, 3), z(1, 4)}; <br>
* Similarly: <br>
* {@code z[1] = [z(2, 1), z(2, 2), z(2, 3), z(2, 4)}; <br>
* and so on. <br>
* Even though internally we iterate over {@code x} and {@code y} multiple times, only a single copy of
* each {@code (x, y)} is required while. Please refer to the example in {@link examples.Spline2DExample}.
*
* @return A bicubic spline.
*/
public static Spline2D newBicubicSpline(double[] x, double[] y, double[][] z) {
final int rows = y.length;
final int cols = x.length;
final int order = 4;

if (z.length != y.length) {
throw new IllegalArgumentException("The length of z has to be the same length as y.");
}

double[] yt = Arrays.copyOf(y, rows);
Spline[] splines = new Spline[rows];
for (int i = 0; i < rows; ++i) {
if (cols != z[i].length) {
throw new IllegalArgumentException("The length of each array in z has to be the same.");
}
splines[i] = CubicSpline.newCubicSplineInPlace(x, z[i]);
}
return new BiCubicSpline(yt, splines, order);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.wildbitsfoundry.etk4j.math.interpolation;

import examples.Spline2DExample;

import java.util.Arrays;

public class BiLinearSpline extends Spline2D {

protected BiLinearSpline(double[] y, Spline[] splines, int order) {
super(y, splines, order);
}

/**
* Construct a bilinear spline using not-a-knot conditions.
*
* @param x The x coordinates of the spline.
* @param y The y coordinates of the spline.
* @param z The values of the spline at each {@code (x, y)}. Notice that for each x and y combination there should
* be a value in {@code z}. For example, consider: <br>
*
* {@code x = [1, 2, 3, 4]}, {@code y = [1, 2, 3, 4]}, <br>and {@code z(x, y) = x<sup>2</sup> * y<sup>2</sup>}. <br>
* This means that the first row of {@code z} will be all the values obtained by fixing {@code x = 1} and
* iterating over all the values of {@code y}. <br>
* {@code z[0] = [z(1, 1), z(1, 2), z(1, 3), z(1, 4)}; <br>
* Similarly: <br>
* {@code z[1] = [z(2, 1), z(2, 2), z(2, 3), z(2, 4)}; <br>
* and so on. <br>
* Even though internally we iterate over {@code x} and {@code y} multiple times, only a single copy of
* each {@code (x, y)} is required while. Please refer to the example in {@link Spline2DExample}.
*
* @return A bilinear spline.
*/
public static Spline2D newBilinearSpline(double[] x, double[] y, double[][] z) {
final int rows = y.length;
final int cols = x.length;
final int order = 2;

if (z.length != y.length) {
throw new IllegalArgumentException("The length of z has to be the same length as y.");
}

double[] yt = Arrays.copyOf(y, rows);
Spline[] splines = new Spline[rows];
for (int i = 0; i < rows; ++i) {
if (cols != z[i].length) {
throw new IllegalArgumentException("The length of each array in z has to be the same.");
}
splines[i] = LinearSpline.newLinearSplineInPlace(x, z[i]);
}
return new BiLinearSpline(yt, splines, order);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
/**
* The {@code Spline2D} class represents bicubic and bilinear interpolation using cubic and linear splines respectively.
*/
public class Spline2D implements BivariateFunction {
public abstract class Spline2D implements BivariateFunction {

private double[] y;
private Spline[] splines;
Expand All @@ -21,86 +21,6 @@ protected Spline2D(double[] y, Spline[] splines, int order) {
this.splines = splines;
}

/**
* Construct a bicubic spline using not-a-knot conditions.
*
* @param x The x coordinates of the spline.
* @param y The y coordinates of the spline.
* @param z The values of the spline at each {@code (x, y)}. Notice that for each x and y combination there should
* be a value in {@code z}. For example, consider: <br>
*
* {@code x = [1, 2, 3, 4]}, {@code y = [1, 2, 3, 4]}, <br>and {@code z(x, y) = x<sup>2</sup> * y<sup>2</sup>}. <br>
* This means that the first row of {@code z} will be all the values obtained by fixing {@code x = 1} and
* iterating over all the values of {@code y}. <br>
* {@code z[0] = [z(1, 1), z(1, 2), z(1, 3), z(1, 4)}; <br>
* Similarly: <br>
* {@code z[1] = [z(2, 1), z(2, 2), z(2, 3), z(2, 4)}; <br>
* and so on. <br>
* Even though internally we iterate over {@code x} and {@code y} multiple times, only a single copy of
* each {@code (x, y)} is required while. Please refer to the example in {@link examples.Spline2DExample}.
*
* @return A bicubic spline.
*/
public static Spline2D newBicubicSpline(double[] x, double[] y, double[][] z) {
final int rows = y.length;
final int cols = x.length;
final int order = 4;

if (z.length != y.length) {
throw new IllegalArgumentException("The length of z has to be the same length as y.");
}

double[] yt = Arrays.copyOf(y, rows);
Spline[] splines = new Spline[rows];
for (int i = 0; i < rows; ++i) {
if (cols != z[i].length) {
throw new IllegalArgumentException("The length of each array in z has to be the same.");
}
splines[i] = CubicSpline.newCubicSplineInPlace(x, z[i]);
}
return new Spline2D(yt, splines, order);
}

/**
* Construct a bilinear spline using not-a-knot conditions.
*
* @param x The x coordinates of the spline.
* @param y The y coordinates of the spline.
* @param z The values of the spline at each {@code (x, y)}. Notice that for each x and y combination there should
* be a value in {@code z}. For example, consider: <br>
*
* {@code x = [1, 2, 3, 4]}, {@code y = [1, 2, 3, 4]}, <br>and {@code z(x, y) = x<sup>2</sup> * y<sup>2</sup>}. <br>
* This means that the first row of {@code z} will be all the values obtained by fixing {@code x = 1} and
* iterating over all the values of {@code y}. <br>
* {@code z[0] = [z(1, 1), z(1, 2), z(1, 3), z(1, 4)}; <br>
* Similarly: <br>
* {@code z[1] = [z(2, 1), z(2, 2), z(2, 3), z(2, 4)}; <br>
* and so on. <br>
* Even though internally we iterate over {@code x} and {@code y} multiple times, only a single copy of
* each {@code (x, y)} is required while. Please refer to the example in {@link Spline2DExample}.
*
* @return A bilinear spline.
*/
public static Spline2D newBilinearSpline(double[] x, double[] y, double[][] z) {
final int rows = y.length;
final int cols = x.length;
final int order = 2;

if (z.length != y.length) {
throw new IllegalArgumentException("The length of z has to be the same length as y.");
}

double[] yt = Arrays.copyOf(y, rows);
Spline[] splines = new Spline[rows];
for (int i = 0; i < rows; ++i) {
if (cols != z[i].length) {
throw new IllegalArgumentException("The length of each array in z has to be the same.");
}
splines[i] = LinearSpline.newLinearSplineInPlace(x, z[i]);
}
return new Spline2D(yt, splines, order);
}

/**
* Evaluate the spline.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ public static void main(String[] args) {
.solve(new ComplexMatrixDense(new Complex[][]{g, f}));
System.out.println("Solution to system");
System.out.println(sol);

ComplexMatrixDense AA = new ComplexMatrixDense(new Complex[][] {
{new Complex(1, 1), new Complex(2, 0)},
{new Complex(2, -1), new Complex(3, 0)}
});

ComplexQRDecompositionDense qrDecompositionDense = new ComplexQRDecompositionDense(AA);
System.out.println(qrDecompositionDense.getQ());
System.out.println(qrDecompositionDense.getR());
}

private static Complex sig(Complex u) {
Expand Down
9 changes: 4 additions & 5 deletions src/main/java/examples/Spline2DExample.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package examples;

import static com.wildbitsfoundry.etk4j.math.interpolation.Spline2D.newBicubicSpline;
import static com.wildbitsfoundry.etk4j.math.interpolation.Spline2D.newBilinearSpline;

import com.wildbitsfoundry.etk4j.math.functions.BivariateFunction;
import com.wildbitsfoundry.etk4j.math.interpolation.BiCubicSpline;
import com.wildbitsfoundry.etk4j.math.interpolation.BiLinearSpline;
import com.wildbitsfoundry.etk4j.math.interpolation.Spline2D;

public class Spline2DExample {
Expand All @@ -24,11 +23,11 @@ public static void createSurface() {
System.out.printf(":: Function z(x, y) = x^2 * y^2%n%n");

System.out.println(":: Test Bicubic spline");
Spline2D sp = newBicubicSpline(x, y, z);
Spline2D sp = BiCubicSpline.newBicubicSpline(x, y, z);
printSpline2D(sp, x, y);

System.out.printf("%n:: Test Bilinear spline%n");
sp = newBilinearSpline(x, y, z);
sp = BiLinearSpline.newBilinearSpline(x, y, z);
printSpline2D(sp, x, y);
}

Expand Down
5 changes: 2 additions & 3 deletions src/main/java/examples/Spline2DifferentDimensionsExample.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package examples;

import static com.wildbitsfoundry.etk4j.math.interpolation.Spline2D.newBilinearSpline;

import com.wildbitsfoundry.etk4j.math.interpolation.BiLinearSpline;
import com.wildbitsfoundry.etk4j.math.interpolation.Spline2D;

public class Spline2DifferentDimensionsExample {
Expand All @@ -17,7 +16,7 @@ public static void createPlane() {
double[][] z = { { 1, 2, 3, 4, 5, 6, 7, 8 }, { 2, 4, 6, 8, 10, 12, 14, 16 }, {3, 6, 9, 12, 15, 18, 21, 24} };

System.out.printf("%n:: Test Bilinear spline%n");
Spline2D sp = newBilinearSpline(x, y, z);
Spline2D sp = BiLinearSpline.newBilinearSpline(x, y, z);
Spline2DExample.printSpline2D(sp, x, y);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.wildbitsfoundry.etk4j.math.interpolation;

import static com.wildbitsfoundry.etk4j.math.interpolation.Spline2D.newBicubicSpline;
import static org.junit.Assert.assertEquals;

import com.wildbitsfoundry.etk4j.math.interpolation.Spline2D;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
Expand Down Expand Up @@ -33,7 +31,7 @@ public static void setArrays() {

@Test
public void testBicubicInterpolation() {
Spline2D sp = newBicubicSpline(x, y, z);
Spline2D sp = BiCubicSpline.newBicubicSpline(x, y, z);

double yi = sp.evaluateAt(xiyi[0][0], xiyi[0][1]);
assertEquals(5.0625, yi, 1e-12);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package com.wildbitsfoundry.etk4j.math.interpolation;

import static com.wildbitsfoundry.etk4j.math.interpolation.Spline2D.newBilinearSpline;
import static org.junit.Assert.assertEquals;

import com.wildbitsfoundry.etk4j.math.interpolation.Spline2D;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.junit.Assert.assertEquals;

public class BilinearSplineTest {
static double[] x;
static double[] y;
Expand All @@ -33,7 +31,7 @@ public static void setArrays() {

@Test
public void testBilinearSplineInterpolation() {
Spline2D sp = newBilinearSpline(x, y, z);
Spline2D sp = BiLinearSpline.newBilinearSpline(x, y, z);

double yi = sp.evaluateAt(xiyi[0][0], xiyi[0][1]);
assertEquals(6.2500, yi, 1e-12);
Expand Down

0 comments on commit 7f31ca8

Please sign in to comment.