Skip to content

Commit 968f9de

Browse files
authored
Merge pull request #25 from StaticBeagle/romberg-integral
Added Romberg integrals, Jacobi solver, added release profile and clean-up
2 parents 386a373 + 1a81a97 commit 968f9de

File tree

13 files changed

+231
-49
lines changed

13 files changed

+231
-49
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,4 @@ jobs:
2626
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
2727
gpg-passphrase: GPG_PASSPHRASE
2828
- name: Publish package
29-
run: mvn -B deploy
29+
run: mvn -B deploy -P release

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
[![Java CI with Maven](https://github.com/StaticBeagle/ETK4J/actions/workflows/maven.yml/badge.svg)](https://github.com/StaticBeagle/ETK4J/actions/workflows/maven.yml)
44

5-
---------------------------------------------------------------------------
65
## Engineering Toolkit for Java
76

87
The purpose of this project is to create a library that can be used to prototype solutions to engineering problems. One
@@ -27,15 +26,22 @@ can be found in:
2726

2827
src/main/java
2928

30-
---------------------------------------------------------------------------
3129
## Maven Central
3230

33-
ETK4J can be included from Maven Central
31+
ETK4J can be included from Maven Central.
32+
33+
Maven
3434

3535
```xml
36-
<groupId>com.wildbitsfoundry</groupId>
37-
<artifactId>etk4j</artifactId>
38-
<version>2.0.0</version>
36+
<dependency>
37+
<groupId>com.wildbitsfoundry</groupId>
38+
<artifactId>etk4j</artifactId>
39+
<version>2.0.0</version>
40+
</dependency>
41+
```
42+
Gradle
43+
```bash
44+
implementation 'com.wildbitsfoundry:etk4j:2.0.0'
3945
```
4046

4147
Requirements

pom.xml

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>com.wildbitsfoundry</groupId>
44
<artifactId>etk4j</artifactId>
5-
<version>2.0.0</version>
5+
<version>2.1.0</version>
66
<name>Engineering Toolkit for Java</name>
77
<description>Tools and implementation of mathematical methods or backing math for engineering problems and
88
applications.
@@ -12,7 +12,7 @@
1212
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1313
</properties>
1414
<url>
15-
https://github.com/StaticBeagle/ETK4J
15+
https://wildbitsfoundry.com/etk4j
1616
</url>
1717

1818
<developers>
@@ -32,9 +32,8 @@
3232
</licenses>
3333

3434
<scm>
35-
<url>
36-
scm:git:git@github.com:StaticBeagle/ETK4J.git
37-
</url>
35+
<connection>scm:git:https://github.com/StaticBeagle/ETK4J.git</connection>
36+
<url>https://github.com/StaticBeagle/ETK4J</url>
3837
</scm>
3938

4039
<dependencies>
@@ -47,6 +46,30 @@
4746
</dependency>
4847
</dependencies>
4948

49+
<profiles>
50+
<profile>
51+
<id>release</id>
52+
<build>
53+
<plugins>
54+
<plugin>
55+
<groupId>org.apache.maven.plugins</groupId>
56+
<artifactId>maven-gpg-plugin</artifactId>
57+
<version>3.2.7</version>
58+
<executions>
59+
<execution>
60+
<id>sign-artifacts</id>
61+
<phase>verify</phase>
62+
<goals>
63+
<goal>sign</goal>
64+
</goals>
65+
</execution>
66+
</executions>
67+
</plugin>
68+
</plugins>
69+
</build>
70+
</profile>
71+
</profiles>
72+
5073
<build>
5174
<plugins>
5275
<plugin>
@@ -100,20 +123,6 @@
100123
</execution>
101124
</executions>
102125
</plugin>
103-
<plugin>
104-
<groupId>org.apache.maven.plugins</groupId>
105-
<artifactId>maven-gpg-plugin</artifactId>
106-
<version>3.2.7</version>
107-
<executions>
108-
<execution>
109-
<id>sign-artifacts</id>
110-
<phase>verify</phase>
111-
<goals>
112-
<goal>sign</goal>
113-
</goals>
114-
</execution>
115-
</executions>
116-
</plugin>
117126
</plugins>
118127
</build>
119128
</project>

src/main/java/com/wildbitsfoundry/etk4j/math/calculus/Integrals.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,56 @@ public static double simpson(UnivariateFunction func, double a, double b, int n)
119119
return simpson((x, o) -> func.evaluateAt(x), a, b, n);
120120
}
121121

122+
/**
123+
* Computes the approximate definite integral from a to b using the Romberg and Richardson extrapolation.
124+
*
125+
* @param func The function to be integrated.
126+
* @param a The lower limit of the integral.
127+
* @param b The upper limit of the integral.
128+
* @param maxIterations The maximum number of iterations
129+
* @param params Optional parameters passed to {@code func}.
130+
* @return The approximate definite integral of {@code func} from a to b.
131+
*/
132+
public static double romberg(BiFunction<Double, Object[], Double> func, double a, double b, int maxIterations, Object... params) {
133+
double[][] R = new double[maxIterations + 1][maxIterations + 1];
134+
135+
R[0][0] = trapz(func, a, b, 1, params);
136+
for(int i = 0; i <= maxIterations; i++) {
137+
int n = (int) Math.pow(2, i);
138+
R[i][0] = trapz(func, a, b, n, params);
139+
140+
for(int j = 1; j <= i; j++) {
141+
R[i][j] = (Math.pow(4, j) * R[i][j - 1] - R[i - 1][j - 1]) / (Math.pow(4, j) - 1);
142+
}
143+
}
144+
return R[maxIterations][maxIterations];
145+
}
146+
147+
/**
148+
* Computes the approximate definite integral from a to b using the Romberg and Richardson extrapolation.
149+
*
150+
* @param func The function to be integrated.
151+
* @param a The lower limit of the integral.
152+
* @param b The upper limit of the integral.
153+
* @param maxIterations The maximum number of iterations
154+
* @return The approximate definite integral of {@code func} from a to b.
155+
*/
156+
public static double romberg(UnivariateFunction func, double a, double b, int maxIterations) {
157+
return romberg((x, o) -> func.evaluateAt(x), a, b, maxIterations);
158+
}
159+
160+
/**
161+
* Computes the approximate definite integral from a to b using the Romberg and Richardson extrapolation.
162+
*
163+
* @param func The function to be integrated.
164+
* @param a The lower limit of the integral.
165+
* @param b The upper limit of the integral.
166+
* @return The approximate definite integral of {@code func} from a to b.
167+
*/
168+
public static double romberg(UnivariateFunction func, double a, double b) {
169+
return romberg((x, o) -> func.evaluateAt(x), a, b, 10);
170+
}
171+
122172
/**
123173
* Computes the approximate definite integral from a to b using 5 point Gaussian quadrature.
124174
*

src/main/java/com/wildbitsfoundry/etk4j/math/interpolation/QuadraticSpline.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.wildbitsfoundry.etk4j.math.interpolation;
22

3-
import com.wildbitsfoundry.etk4j.math.linearalgebra.GaussianElimination;
3+
import com.wildbitsfoundry.etk4j.math.linearalgebra.GaussianEliminationSolver;
44
import com.wildbitsfoundry.etk4j.math.linearalgebra.MatrixDense;
55

66
import java.util.Arrays;
@@ -41,7 +41,7 @@ public static QuadraticSpline newNaturalSplineInPlace(double[] x, double[] y) {
4141
A.set(2 * n - 4, n - 1, 1); // c[0] = 0
4242
A.set(2 * n - 3, 2 * n - 3, 1); // c[n - 1] = 0
4343

44-
double[] solution = GaussianElimination.solve(A, b);
44+
double[] solution = GaussianEliminationSolver.solve(A, b);
4545
// compute coefficients
4646
double[] coefficients = new double[(n - 1) * 3];
4747
for (int i = 0, j = 0; i < n - 1; ++i, ++j) {
@@ -83,7 +83,7 @@ public static QuadraticSpline newClampedSplineInPlace(double[] x, double[] y, do
8383
A.set(2 * n - 3, 2 * n - 3, 2 * (x[n - 1] - x[n - 2]));
8484
b[2 * n - 3] = mn; // derivative at the end
8585

86-
double[] solution = GaussianElimination.solve(A, b);
86+
double[] solution = GaussianEliminationSolver.solve(A, b);
8787
// compute coefficients
8888
double[] coefficients = new double[(n - 1) * 3];
8989
for (int i = 0, j = 0; i < n - 1; ++i, ++j) {

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/GaussSeidel.java

Lines changed: 0 additions & 8 deletions
This file was deleted.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.wildbitsfoundry.etk4j.math.linearalgebra;
2+
// TODO javadocs
3+
public class GaussSeidelSolver extends SuccessiveOverRelaxationSolver {
4+
5+
public GaussSeidelSolver(MatrixDense A, double[] b) {
6+
super(A, b, 1.0);
7+
}
8+
}

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/GaussianElimination.java renamed to src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/GaussianEliminationSolver.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.wildbitsfoundry.etk4j.math.linearalgebra;
2+
// TODO javadocs
3+
public final class GaussianEliminationSolver {
24

3-
public final class GaussianElimination {
4-
5-
private GaussianElimination() {}
5+
private GaussianEliminationSolver() {}
66

77
public static double[] solve(MatrixDense A, double[] b) {
88
return solve(A, b, 1e-10);
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package com.wildbitsfoundry.etk4j.math.linearalgebra;
2+
3+
import com.wildbitsfoundry.etk4j.util.DoubleArrays;
4+
// TODO javadocs
5+
public class JacobiMethodSolver {
6+
7+
private double[] b;
8+
private MatrixDense A;
9+
private int iterationLimit = 100;
10+
private double tol = 1e-9;
11+
private double[] x0 = null;
12+
13+
public JacobiMethodSolver(MatrixDense A, double[] b) {
14+
this.A = A;
15+
this.b = b;
16+
}
17+
18+
public JacobiMethodSolver iterationLimit(int iterationLimit) {
19+
this.iterationLimit = iterationLimit;
20+
return this;
21+
}
22+
23+
public JacobiMethodSolver tolerance(double tolerance) {
24+
this.tol = tolerance;
25+
return this;
26+
}
27+
28+
public JacobiMethodSolver initialGuess(double[] x0) {
29+
this.x0 = x0;
30+
return this;
31+
}
32+
33+
public IterativeSolverResults<double[]> solve() {
34+
double[] x = x0 == null ? new double[b.length] : x0;
35+
int n = A.getRowCount();
36+
double[] xNew = new double[n];
37+
int k;
38+
double error = Double.NaN;
39+
for (k = 0; k < iterationLimit; k++) {
40+
for (int i = 0; i < n; i++) {
41+
double sum = 0;
42+
for (int j = 0; j < n; j++) {
43+
if (j != i) {
44+
sum += A.unsafeGet(i, j) * x[j];
45+
}
46+
}
47+
xNew[i] = (b[i] - sum) / A.unsafeGet(i, i);
48+
}
49+
// Check for convergence
50+
error = DoubleArrays.norm2(DoubleArrays.subtractElementWise(xNew, x));
51+
if(error < tol) {
52+
IterativeSolverResults<double[]> solverResults = new IterativeSolverResults<>();
53+
solverResults.setSolverStatus("Converged");
54+
solverResults.setHasConverged(true);
55+
solverResults.setError(error);
56+
solverResults.setValue(xNew);
57+
solverResults.setNumberOfIterations(k + 1);
58+
return solverResults;
59+
}
60+
System.arraycopy(xNew, 0, x, 0, xNew.length);
61+
}
62+
IterativeSolverResults<double[]> solverResults = new IterativeSolverResults<>();
63+
solverResults.setSolverStatus("Maximum number of iterations exceeded");
64+
solverResults.setHasConverged(false);
65+
solverResults.setError(error);
66+
solverResults.setValue(x);
67+
solverResults.setNumberOfIterations(k + 1);
68+
return solverResults;
69+
70+
}
71+
public static void main(String[] args) {
72+
double[][] A = {{2, -1, 0}, {-1, 2, -1}, {0, -1, 2}};
73+
double[] b = {1, 0, 1};
74+
double[] x = {0, 0, 0}; // Initial guess
75+
int maxIterations = 100;
76+
double tolerance = 0.0001;
77+
double[] solution = new JacobiMethodSolver(new MatrixDense(A), b)
78+
.initialGuess(x).iterationLimit(maxIterations).tolerance(tolerance).solve().getValue();
79+
System.out.println("Solution:");
80+
for (double val : solution) {
81+
System.out.println(val);
82+
}
83+
}
84+
}

src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/SuccessiveOverRelaxation.java renamed to src/main/java/com/wildbitsfoundry/etk4j/math/linearalgebra/SuccessiveOverRelaxationSolver.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
package com.wildbitsfoundry.etk4j.math.linearalgebra;
22

3-
import java.util.Arrays;
43
// TODO javadocs
5-
public class SuccessiveOverRelaxation {
4+
public class SuccessiveOverRelaxationSolver {
65
private double w;
76
private double[] b;
87
private MatrixDense A;
98
private int iterationLimit = 100;
109
private double tol = 1e-9;
1110
private double[] x0 = null;
1211

13-
public SuccessiveOverRelaxation(MatrixDense A, double[] b, double w) {
12+
public SuccessiveOverRelaxationSolver(MatrixDense A, double[] b, double w) {
1413
this.A = A;
1514
this.b = b;
1615
this.w = w;
1716
}
1817

19-
public SuccessiveOverRelaxation iterationLimit(int iterationLimit) {
18+
public SuccessiveOverRelaxationSolver iterationLimit(int iterationLimit) {
2019
this.iterationLimit = iterationLimit;
2120
return this;
2221
}
2322

24-
public SuccessiveOverRelaxation tolerance(double tolerance) {
23+
public SuccessiveOverRelaxationSolver tolerance(double tolerance) {
2524
this.tol = tolerance;
2625
return this;
2726
}
2827

29-
public SuccessiveOverRelaxation initialConditions(double[] x0) {
28+
public SuccessiveOverRelaxationSolver initialGuess(double[] x0) {
3029
this.x0 = x0;
3130
return this;
3231
}

src/test/java/com/wildbitsfoundry/etk4j/math/calculus/IntegralsTest.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ public void testSimpson() {
3535
assertEquals(0.8281163288433171, simp, 1e-12);
3636
}
3737

38+
@Test
39+
public void testRomberg() {
40+
UnivariateFunction fx = x -> Math.sin(x * x);
41+
double romb = Integrals.romberg(fx, 0, Math.PI / 2.0);
42+
assertEquals(0.8281163288428953, romb, 1e-12);
43+
}
44+
3845
@Test
3946
public void testGaussianQuadrature() {
4047
UnivariateFunction fx = x -> Math.sin(x * x);
@@ -45,7 +52,7 @@ public void testGaussianQuadrature() {
4552
qadrat = Integrals.gaussianQuadrature(fx, Math.PI / 4.0, Math.PI / 2.0);
4653
assertEquals(0.5832680904501192, qadrat, 1e-12);
4754
}
48-
55+
4956
@Test
5057
public void testAdaptiveGaussianQuadrature() {
5158
double[] e = new double[2];

0 commit comments

Comments
 (0)