From 8ffb6a6377d0f8497febea1edcb0f354f1fbc08e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Apr 2026 23:18:58 +0000
Subject: [PATCH 1/4] chore: begin test coverage improvements
Agent-Logs-Url: https://github.com/mihxil/math/sessions/2884536f-0d76-46f7-bd66-8654d88f71a9
Co-authored-by: mihxil <429477+mihxil@users.noreply.github.com>
---
docs/shapes/10-gon.svg | 2 +-
docs/shapes/11-gon.svg | 6 +-
docs/shapes/13-gon.svg | 2 +-
docs/shapes/14-gon.svg | 4 +-
docs/shapes/15-gon.svg | 2 +-
docs/shapes/16-gon.svg | 2 +-
docs/shapes/17-gon.svg | 2 +-
docs/shapes/18-gon.svg | 2 +-
docs/shapes/19-gon.svg | 2 +-
docs/shapes/20-gon.svg | 2 +-
docs/shapes/5-gon.svg | 2 +-
docs/shapes/6-gon.svg | 4 +-
docs/shapes/7-gon.svg | 6 +-
docs/shapes/8-gon.svg | 2 +-
mihxil-demo/dependency-reduced-pom.xml | 156 +++++++++++++++++++++++++
15 files changed, 176 insertions(+), 20 deletions(-)
create mode 100644 mihxil-demo/dependency-reduced-pom.xml
diff --git a/docs/shapes/10-gon.svg b/docs/shapes/10-gon.svg
index 1d8b544a1..62e5d42d8 100644
--- a/docs/shapes/10-gon.svg
+++ b/docs/shapes/10-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/11-gon.svg b/docs/shapes/11-gon.svg
index 84ac05cf5..65b7f2156 100644
--- a/docs/shapes/11-gon.svg
+++ b/docs/shapes/11-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
@@ -86,7 +86,7 @@
{11}, size: 56.35
area: 29735.24
perimeter: 619.81
- ⬚: Rectangle{197.96x195.95} at (0.00,-2.03)
+ ⬚: Rectangle{197.96x195.95} at (7·10⁻¹⁵,-2.03)
◌: Circle{100.00}
# edges: 11
# vertices: 11
diff --git a/docs/shapes/13-gon.svg b/docs/shapes/13-gon.svg
index 934b5a92c..aca976f80 100644
--- a/docs/shapes/13-gon.svg
+++ b/docs/shapes/13-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/14-gon.svg b/docs/shapes/14-gon.svg
index 691f4eb64..03354de75 100644
--- a/docs/shapes/14-gon.svg
+++ b/docs/shapes/14-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/docs/shapes/15-gon.svg b/docs/shapes/15-gon.svg
index b60c9e2cb..99a4cd053 100644
--- a/docs/shapes/15-gon.svg
+++ b/docs/shapes/15-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/16-gon.svg b/docs/shapes/16-gon.svg
index 2d46e2fbd..fae7ca122 100644
--- a/docs/shapes/16-gon.svg
+++ b/docs/shapes/16-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/17-gon.svg b/docs/shapes/17-gon.svg
index c1ba377c2..f3d6b2b81 100644
--- a/docs/shapes/17-gon.svg
+++ b/docs/shapes/17-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/18-gon.svg b/docs/shapes/18-gon.svg
index 73a44a31d..96fdb8e55 100644
--- a/docs/shapes/18-gon.svg
+++ b/docs/shapes/18-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/19-gon.svg b/docs/shapes/19-gon.svg
index 33a053cb5..dd1274a7a 100644
--- a/docs/shapes/19-gon.svg
+++ b/docs/shapes/19-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/20-gon.svg b/docs/shapes/20-gon.svg
index 851a6746e..1d80db6c4 100644
--- a/docs/shapes/20-gon.svg
+++ b/docs/shapes/20-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/5-gon.svg b/docs/shapes/5-gon.svg
index 7711f14cf..8386d98c0 100644
--- a/docs/shapes/5-gon.svg
+++ b/docs/shapes/5-gon.svg
@@ -74,7 +74,7 @@
-
+
diff --git a/docs/shapes/6-gon.svg b/docs/shapes/6-gon.svg
index eaf00dffa..377dcb93f 100644
--- a/docs/shapes/6-gon.svg
+++ b/docs/shapes/6-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/docs/shapes/7-gon.svg b/docs/shapes/7-gon.svg
index a28b7d493..1df6249d6 100644
--- a/docs/shapes/7-gon.svg
+++ b/docs/shapes/7-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
@@ -86,7 +86,7 @@
{7}, size: 86.78
area: 27364.10
perimeter: 607.44
- ⬚: Rectangle{194.99x190.10} at (7·10⁻¹⁵,-4.95)
+ ⬚: Rectangle{194.99x190.10} at (0.00,-4.95)
◌: Circle{100.00}
# edges: 7
# vertices: 7
diff --git a/docs/shapes/8-gon.svg b/docs/shapes/8-gon.svg
index c914430b7..68399c84f 100644
--- a/docs/shapes/8-gon.svg
+++ b/docs/shapes/8-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/mihxil-demo/dependency-reduced-pom.xml b/mihxil-demo/dependency-reduced-pom.xml
new file mode 100644
index 000000000..e00e13ea6
--- /dev/null
+++ b/mihxil-demo/dependency-reduced-pom.xml
@@ -0,0 +1,156 @@
+
+
+
+ mihxil-math-parent
+ org.meeuw.math
+ 0.19-SNAPSHOT
+
+ 4.0.0
+ mihxil-demo
+ Math - demo
+ A simple application that is using things of this project.
+
+ package
+
+
+ maven-shade-plugin
+ 3.6.2
+
+
+ package
+
+ shade
+
+
+
+
+
+
+ org.meeuw.math.demo.Application
+
+
+
+
+
+
+ maven-compiler-plugin
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+
+
+
+
+ org.meeuw.math
+ mihxil-theories
+ 0.19-SNAPSHOT
+ test
+
+
+ junit-jupiter-params
+ org.junit.jupiter
+
+
+ jqwik
+ net.jqwik
+
+
+ hibernate-validator
+ org.hibernate.validator
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.44
+ provided
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 6.0.3
+ test
+
+
+ junit-jupiter-api
+ org.junit.jupiter
+
+
+ junit-jupiter-engine
+ org.junit.jupiter
+
+
+ junit-jupiter-params
+ org.junit.jupiter
+
+
+
+
+ org.assertj
+ assertj-core
+ 3.27.7
+ test
+
+
+ byte-buddy
+ net.bytebuddy
+
+
+
+
+ nl.mmprogrami
+ setup-log4j2
+ 1.2
+ test
+ test
+
+
+ log4j-core
+ org.apache.logging.log4j
+
+
+ log4j-api
+ org.apache.logging.log4j
+
+
+ log4j-slf4j2-impl
+ org.apache.logging.log4j
+
+
+ log4j-slf4j-impl
+ org.apache.logging.log4j
+
+
+ log4j-jul
+ org.apache.logging.log4j
+
+
+ log4j-jpl
+ org.apache.logging.log4j
+
+
+ disruptor
+ com.lmax
+
+
+ opentelemetry-log4j-appender-2.17
+ io.opentelemetry.instrumentation
+
+
+
+
+
+ 17
+
+
From b790ee0b025ff7cdb0a4670d807801f2b908d453 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Apr 2026 23:25:55 +0000
Subject: [PATCH 2/4] test: add comprehensive test coverage for DoubleUtils,
ArrayUtils, RectangularCuboid, LocatedShape, and parser expression components
Agent-Logs-Url: https://github.com/mihxil/math/sessions/2884536f-0d76-46f7-bd66-8654d88f71a9
Co-authored-by: mihxil <429477+mihxil@users.noreply.github.com>
---
.../ast/ExpressionComponentsTest.java | 197 ++++++++++++++++++
.../org/meeuw/test/math/ArrayUtilsTest.java | 93 +++++++++
.../org/meeuw/test/math/DoubleUtilsTest.java | 81 +++++++
.../math/shapes/dim2/LocatedShapeTest.java | 55 +++++
.../shapes/dim3/RectangularCuboidTest.java | 77 +++++++
.../test/math/shapes/dim3/SphereTest.java | 24 ++-
6 files changed, 526 insertions(+), 1 deletion(-)
create mode 100644 mihxil-math-parser/src/test/java/org/meeuw/test/math/arithmetic/ast/ExpressionComponentsTest.java
create mode 100644 mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim2/LocatedShapeTest.java
create mode 100644 mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java
diff --git a/mihxil-math-parser/src/test/java/org/meeuw/test/math/arithmetic/ast/ExpressionComponentsTest.java b/mihxil-math-parser/src/test/java/org/meeuw/test/math/arithmetic/ast/ExpressionComponentsTest.java
new file mode 100644
index 000000000..184c4fafc
--- /dev/null
+++ b/mihxil-math-parser/src/test/java/org/meeuw/test/math/arithmetic/ast/ExpressionComponentsTest.java
@@ -0,0 +1,197 @@
+package org.meeuw.test.math.arithmetic.ast;
+
+import lombok.extern.java.Log;
+
+import org.junit.jupiter.api.Test;
+
+import org.meeuw.math.abstractalgebra.reals.RealNumber;
+import org.meeuw.math.arithmetic.ast.*;
+import org.meeuw.math.operators.BasicAlgebraicBinaryOperator;
+import org.meeuw.math.operators.BasicAlgebraicUnaryOperator;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.meeuw.math.abstractalgebra.reals.DoubleElement.exactly;
+import static org.meeuw.math.abstractalgebra.reals.RealField.INSTANCE;
+
+@Log
+class ExpressionComponentsTest {
+
+ // --- Value tests ---
+
+ @Test
+ void valueEval() {
+ Value v = new Value<>(exactly(3.0));
+ assertThat(v.eval().getValue()).isEqualTo(3.0);
+ }
+
+ @Test
+ void valueToString() {
+ Value v = new Value<>(exactly(5.0));
+ String s = v.toString();
+ assertThat(s).contains("value:");
+ assertThat(s).contains("5");
+ }
+
+ @Test
+ void valueCompareToSameValue() {
+ Value a = new Value<>(exactly(2.0));
+ Value b = new Value<>(exactly(2.0));
+ assertThat(a.compareTo(b)).isEqualTo(0);
+ }
+
+ @Test
+ void valueCompareToOtherValue() {
+ Value a = new Value<>(exactly(1.0));
+ Value b = new Value<>(exactly(9.0));
+ assertThat(a.compareTo(b)).isLessThan(0);
+ }
+
+ @Test
+ void valueCompareToNonValue() {
+ Value v = new Value<>(exactly(1.0));
+ org.meeuw.math.arithmetic.ast.BinaryOperation op =
+ new org.meeuw.math.arithmetic.ast.BinaryOperation<>(
+ BasicAlgebraicBinaryOperator.ADDITION,
+ new Value<>(exactly(1.0)),
+ new Value<>(exactly(2.0))
+ );
+ // compareTo with a non-Value falls back to toString comparison
+ int cmp = v.compareTo(op);
+ assertThat(v.toString().compareTo(op.toString())).isEqualTo(cmp);
+ }
+
+ // --- Variable tests ---
+
+ @Test
+ void variableEval() {
+ Variable x = new Variable<>("x", () -> exactly(7.0));
+ assertThat(x.eval().getValue()).isEqualTo(7.0);
+ }
+
+ @Test
+ void variableToString() {
+ Variable x = new Variable<>("myVar", () -> exactly(1.0));
+ assertThat(x.toString()).isEqualTo("myVar");
+ }
+
+ @Test
+ void variableCompareTo() {
+ Variable a = new Variable<>("a", () -> exactly(1.0));
+ Variable b = new Variable<>("b", () -> exactly(1.0));
+ assertThat(a.compareTo(b)).isLessThan(0);
+ assertThat(b.compareTo(a)).isGreaterThan(0);
+ assertThat(a.compareTo(a)).isEqualTo(0);
+ }
+
+ @Test
+ void variableDynamicValue() {
+ int[] counter = {0};
+ Variable x = new Variable<>("x", () -> exactly(++counter[0]));
+ assertThat(x.eval().getValue()).isEqualTo(1.0);
+ assertThat(x.eval().getValue()).isEqualTo(2.0);
+ }
+
+ // --- UnaryOperation tests ---
+
+ @Test
+ void unaryOperationEval() {
+ Value two = new Value<>(exactly(2.0));
+ UnaryOperation sqr = new UnaryOperation<>(BasicAlgebraicUnaryOperator.SQR, two);
+ assertThat(sqr.eval().getValue()).isEqualTo(4.0);
+ }
+
+ @Test
+ void unaryOperationToString() {
+ Value v = new Value<>(exactly(3.0));
+ UnaryOperation op = new UnaryOperation<>(BasicAlgebraicUnaryOperator.NEGATION, v);
+ String s = op.toString();
+ log.info("UnaryOperation toString: " + s);
+ assertThat(s).contains("unary:");
+ }
+
+ @Test
+ void unaryOperationCompareTo() {
+ Value v = new Value<>(exactly(1.0));
+ UnaryOperation op1 = new UnaryOperation<>(BasicAlgebraicUnaryOperator.SQR, v);
+ UnaryOperation op2 = new UnaryOperation<>(BasicAlgebraicUnaryOperator.NEGATION, v);
+ assertThat(op1.compareTo(op2)).isEqualTo(0);
+ }
+
+ // --- BinaryOperation tests ---
+
+ @Test
+ void binaryOperationReverse() {
+ Value two = new Value<>(exactly(2.0));
+ Value three = new Value<>(exactly(3.0));
+ org.meeuw.math.arithmetic.ast.BinaryOperation op =
+ new org.meeuw.math.arithmetic.ast.BinaryOperation<>(
+ BasicAlgebraicBinaryOperator.SUBTRACTION, two, three);
+ org.meeuw.math.arithmetic.ast.BinaryOperation rev = op.reverse();
+ assertThat(rev.getLeft()).isSameAs(three);
+ assertThat(rev.getRight()).isSameAs(two);
+ // 2 - 3 = -1, reversed 3 - 2 = 1
+ assertThat(op.eval().getValue()).isEqualTo(-1.0);
+ assertThat(rev.eval().getValue()).isEqualTo(1.0);
+ }
+
+ // --- EvaluatedExpression tests ---
+
+ @Test
+ void evaluatedExpressionToString() {
+ Value v = new Value<>(exactly(5.0));
+ EvaluatedExpression ee = new EvaluatedExpression<>(v, v.eval());
+ String s = ee.toString();
+ log.info("EvaluatedExpression: " + s);
+ assertThat(s).contains("=");
+ assertThat(s).contains("5");
+ }
+
+ @Test
+ void evaluatedExpressionAccessors() {
+ Value v = new Value<>(exactly(42.0));
+ RealNumber result = v.eval();
+ EvaluatedExpression ee = new EvaluatedExpression<>(v, result);
+ assertThat(ee.expression()).isSameAs(v);
+ assertThat(ee.result()).isSameAs(result);
+ }
+
+ // --- RPN tests ---
+
+ @Test
+ void rpnValueGetValue() {
+ RealNumber val = exactly(3.0);
+ org.meeuw.math.arithmetic.rpn.Value rpnVal =
+ new org.meeuw.math.arithmetic.rpn.Value<>(val);
+ assertThat(rpnVal.getValue()).isSameAs(val);
+ }
+
+ @Test
+ void rpnBinaryOperationGetOperator() {
+ org.meeuw.math.arithmetic.rpn.BinaryOperation rpnOp =
+ new org.meeuw.math.arithmetic.rpn.BinaryOperation(BasicAlgebraicBinaryOperator.ADDITION);
+ assertThat(rpnOp.getOperator()).isEqualTo(BasicAlgebraicBinaryOperator.ADDITION);
+ }
+
+ // --- AbstractExpression builder methods ---
+
+ @Test
+ void abstractExpressionBuilderMethods() {
+ Value two = new Value<>(exactly(2.0));
+ Value three = new Value<>(exactly(3.0));
+
+ assertThat(two.plus(three).eval().getValue()).isEqualTo(5.0);
+ assertThat(two.minus(three).eval().getValue()).isEqualTo(-1.0);
+ assertThat(two.times(three).eval().getValue()).isEqualTo(6.0);
+ assertThat(three.dividedBy(two).eval().getValue()).isEqualTo(1.5);
+ }
+
+ // --- AST.toInfix with Variable ---
+
+ @Test
+ void toInfixWithVariable() {
+ Variable x = new Variable<>("x", () -> exactly(10.0));
+ String infix = AST.toInfix(x);
+ log.info("infix of variable: " + infix);
+ assertThat(infix).isNotEmpty();
+ }
+}
diff --git a/mihxil-math/src/test/java/org/meeuw/test/math/ArrayUtilsTest.java b/mihxil-math/src/test/java/org/meeuw/test/math/ArrayUtilsTest.java
index dbedb2011..7f2771ea8 100644
--- a/mihxil-math/src/test/java/org/meeuw/test/math/ArrayUtilsTest.java
+++ b/mihxil-math/src/test/java/org/meeuw/test/math/ArrayUtilsTest.java
@@ -15,6 +15,8 @@
*/
package org.meeuw.test.math;
+import java.util.*;
+
import org.junit.jupiter.api.Test;
import org.meeuw.math.ArrayUtils;
@@ -98,4 +100,95 @@ public void byteEquals() {
assertThat(ArrayUtils.equals(a, a)).isTrue();
}
+
+ @Test
+ public void removeTrailingZeros() {
+ assertThat(ArrayUtils.removeTrailingZeros(new byte[] {1, 2, 0, 0})).containsExactly(1, 2);
+ assertThat(ArrayUtils.removeTrailingZeros(new byte[] {1, 2, 3})).containsExactly(1, 2, 3);
+ assertThat(ArrayUtils.removeTrailingZeros(new byte[] {0, 0, 0})).isEmpty();
+ assertThat(ArrayUtils.removeTrailingZeros(new byte[] {})).isEmpty();
+ byte[] noTrail = new byte[] {1, 2, 3};
+ assertThat(ArrayUtils.removeTrailingZeros(noTrail)).isSameAs(noTrail);
+ }
+
+ @Test
+ public void removeTrailingIf() {
+ Integer[] arr = {1, 2, 0, 0};
+ assertThat(ArrayUtils.removeTrailingIf(i -> i == 0, Integer.class, arr)).containsExactly(1, 2);
+ Integer[] noTrail = {1, 2, 3};
+ assertThat(ArrayUtils.removeTrailingIf(i -> i == 0, Integer.class, noTrail)).isSameAs(noTrail);
+ Integer[] allMatch = {0, 0};
+ assertThat(ArrayUtils.removeTrailingIf(i -> i == 0, Integer.class, allMatch)).isEmpty();
+ }
+
+ @Test
+ public void allEqualTo() {
+ assertThat(ArrayUtils.allEqualTo(new byte[] {5, 5, 5}, (byte) 5)).isTrue();
+ assertThat(ArrayUtils.allEqualTo(new byte[] {5, 5, 4}, (byte) 5)).isFalse();
+ assertThat(ArrayUtils.allEqualTo(new byte[] {}, (byte) 5)).isTrue();
+ }
+
+ @Test
+ public void determinant2x2() {
+ assertThat(ArrayUtils.determinant2x2(1, 2, 3, 4)).isEqualTo(1 * 4 - 2 * 3);
+ assertThat(ArrayUtils.determinant2x2(2, 0, 0, 3)).isEqualTo(6.0);
+ assertThat(ArrayUtils.determinant2x2(1, 1, 1, 1)).isEqualTo(0.0);
+ }
+
+ @Test
+ public void adjugate2x2() {
+ double[][] m = {{1, 2}, {3, 4}};
+ double[][] adj = ArrayUtils.adjugate2x2(m);
+ assertThat(adj[0][0]).isEqualTo(4.0);
+ assertThat(adj[0][1]).isEqualTo(-2.0);
+ assertThat(adj[1][0]).isEqualTo(-3.0);
+ assertThat(adj[1][1]).isEqualTo(1.0);
+ }
+
+ @Test
+ public void cloneMatrix() {
+ String[][] original = {{"a", "b"}, {"c", "d"}};
+ String[][] clone = ArrayUtils.cloneMatrix(String.class, original);
+ assertThat(clone).isNotSameAs(original);
+ assertThat(clone).isDeepEqualTo(original);
+ clone[0][0] = "x";
+ assertThat(original[0][0]).isEqualTo("a");
+ }
+
+ @Test
+ public void squareMatrix() {
+ String[][] m = ArrayUtils.squareMatrix(String.class, "a", "b", "c", "d");
+ assertThat(m).hasDimensions(2, 2);
+ assertThat(m[0]).containsExactly("a", "b");
+ assertThat(m[1]).containsExactly("c", "d");
+ }
+
+ @Test
+ public void toInverseByteArray() {
+ int[] input = {1, 2, 3};
+ byte[] result = ArrayUtils.toInverseByteArray(input);
+ assertThat(result).containsExactly((byte) 3, (byte) 2, (byte) 1);
+ }
+
+ @Test
+ public void toArray() {
+ List list = Arrays.asList(10, 20, 30);
+ int[] result = ArrayUtils.toArray(list);
+ assertThat(result).containsExactly(10, 20, 30);
+ }
+
+ @Test
+ public void rotate0() {
+ byte[] a = new byte[] {1, 2, 3};
+ assertThat(ArrayUtils.rotate(a, 0)).isSameAs(a);
+ assertThat(ArrayUtils.rotate(a, 3)).isSameAs(a);
+ }
+
+ @Test
+ public void shuffleChangesOrder() {
+ Integer[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+ Integer[] copy = arr.clone();
+ ArrayUtils.shuffle(new Random(42), arr);
+ assertThat(arr).containsExactlyInAnyOrder(copy);
+ }
}
diff --git a/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java b/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java
index ac048133e..d786f04ce 100644
--- a/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java
+++ b/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java
@@ -2,6 +2,8 @@
import lombok.extern.java.Log;
+import java.math.BigInteger;
+
import org.junit.jupiter.api.Test;
import org.meeuw.math.DoubleUtils;
@@ -55,4 +57,83 @@ public void implicitUncertainty() {
assertThat(DoubleUtils.implicitUncertaintyForDouble(0.1, "0.01")).isEqualTo(0.005d);
}
+ @Test
+ public void pow10() {
+ assertThat(DoubleUtils.pow10(0)).isEqualTo(1.0);
+ assertThat(DoubleUtils.pow10(1)).isEqualTo(10.0);
+ assertThat(DoubleUtils.pow10(3)).isEqualTo(1000.0);
+ assertThat(DoubleUtils.pow10(-1)).isEqualTo(0.1);
+ assertThat(DoubleUtils.pow10(-3)).isEqualTo(0.001);
+ }
+
+ @Test
+ public void pow2() {
+ assertThat(DoubleUtils.pow2(0)).isEqualTo(1.0);
+ assertThat(DoubleUtils.pow2(1)).isEqualTo(2.0);
+ assertThat(DoubleUtils.pow2(10)).isEqualTo(1024.0);
+ assertThat(DoubleUtils.pow2(-1)).isEqualTo(0.5);
+ assertThat(DoubleUtils.pow2(-10)).isEqualTo(1.0 / 1024.0);
+ }
+
+ @Test
+ public void powIntBase() {
+ assertThat(DoubleUtils.pow(3, 0)).isEqualTo(1.0);
+ assertThat(DoubleUtils.pow(3, 1)).isEqualTo(3.0);
+ assertThat(DoubleUtils.pow(3, 3)).isEqualTo(27.0);
+ assertThat(DoubleUtils.pow(3, -1)).isEqualTo(1.0 / 3.0);
+ assertThat(DoubleUtils.pow(2, -3)).isEqualTo(0.125);
+ }
+
+ @Test
+ public void powDoubleBase() {
+ assertThat(DoubleUtils.pow(0.0, 5)).isEqualTo(1.0);
+ assertThat(DoubleUtils.pow(2.0, 0)).isEqualTo(1.0);
+ assertThat(DoubleUtils.pow(2.5, 2)).isEqualTo(6.25);
+ assertThat(DoubleUtils.pow(4.0, -1)).isEqualTo(0.25);
+ }
+
+ @Test
+ public void max() {
+ assertThat(DoubleUtils.max(1.0, 3.0, 2.0)).isEqualTo(3.0);
+ assertThat(DoubleUtils.max(-5.0, -1.0, -3.0)).isEqualTo(-1.0);
+ assertThat(DoubleUtils.max(Double.NEGATIVE_INFINITY, 0.0)).isEqualTo(0.0);
+ assertThat(DoubleUtils.max(7.0)).isEqualTo(7.0);
+ assertThat(DoubleUtils.max(Double.POSITIVE_INFINITY, 1.0)).isEqualTo(Double.POSITIVE_INFINITY);
+ }
+
+ @Test
+ public void leastSignificantBit() {
+ assertThat(DoubleUtils.leastSignificantBit(1.0)).isEqualTo(-51);
+ assertThat(DoubleUtils.leastSignificantBit(2.0)).isEqualTo(-50);
+ assertThat(DoubleUtils.leastSignificantBit(-1.0)).isEqualTo(-51);
+ }
+
+ @Test
+ public void isExactProductDoubles() {
+ assertThat(DoubleUtils.isExactProduct(2.0, 3.0)).isTrue();
+ assertThat(DoubleUtils.isExactProduct(0.5, 4.0)).isTrue();
+ assertThat(DoubleUtils.isExactProduct(0.0, 999.0)).isTrue();
+ assertThat(DoubleUtils.isExactProduct(1.0, 0.0)).isTrue();
+
+ assertThat(DoubleUtils.isExactProduct(Double.NaN, 1.0)).isFalse();
+ assertThat(DoubleUtils.isExactProduct(1.0, Double.NaN)).isFalse();
+ assertThat(DoubleUtils.isExactProduct(Double.POSITIVE_INFINITY, 1.0)).isFalse();
+ assertThat(DoubleUtils.isExactProduct(1.0, Double.NEGATIVE_INFINITY)).isFalse();
+
+ // 0.1 * 0.2 is not exactly representable in IEEE 754
+ assertThat(DoubleUtils.isExactProduct(0.1, 0.2)).isFalse();
+ }
+
+ @Test
+ public void isExactProductBigInteger() {
+ assertThat(DoubleUtils.isExactProduct(2.0, BigInteger.valueOf(3))).isTrue();
+ assertThat(DoubleUtils.isExactProduct(0.5, BigInteger.valueOf(4))).isTrue();
+ assertThat(DoubleUtils.isExactProduct(0.0, BigInteger.valueOf(999))).isTrue();
+ assertThat(DoubleUtils.isExactProduct(1.0, BigInteger.ZERO)).isTrue();
+
+ assertThat(DoubleUtils.isExactProduct(Double.NaN, BigInteger.ONE)).isFalse();
+ assertThat(DoubleUtils.isExactProduct(Double.POSITIVE_INFINITY, BigInteger.ONE)).isFalse();
+ assertThat(DoubleUtils.isExactProduct(1.0, null)).isFalse();
+ }
+
}
diff --git a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim2/LocatedShapeTest.java b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim2/LocatedShapeTest.java
new file mode 100644
index 000000000..442069ee6
--- /dev/null
+++ b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim2/LocatedShapeTest.java
@@ -0,0 +1,55 @@
+package org.meeuw.test.math.shapes.dim2;
+
+import lombok.extern.java.Log;
+
+import org.junit.jupiter.api.Test;
+
+import org.meeuw.math.abstractalgebra.dim2.FieldVector2;
+import org.meeuw.math.abstractalgebra.reals.RealNumber;
+import org.meeuw.math.shapes.dim2.Circle;
+import org.meeuw.math.shapes.dim2.LocatedShape;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.meeuw.math.abstractalgebra.reals.RealField.element;
+
+@Log
+public class LocatedShapeTest {
+
+ final Circle circle = new Circle<>(element(5.0));
+
+ @Test
+ public void atOriginShape() {
+ LocatedShape> located = LocatedShape.atOrigin(circle);
+ assertThat(located.shape()).isSameAs(circle);
+ }
+
+ @Test
+ public void atOriginLocation() {
+ LocatedShape> located = LocatedShape.atOrigin(circle);
+ assertThat(located.location().isZero()).isTrue();
+ }
+
+ @Test
+ public void atOriginToString() {
+ LocatedShape> located = LocatedShape.atOrigin(circle);
+ log.info("Located shape: " + located);
+ // At origin, no " at " suffix
+ assertThat(located.toString()).doesNotContain(" at ");
+ }
+
+ @Test
+ public void withLocationToString() {
+ FieldVector2 location = FieldVector2.of(element(1.0), element(2.0));
+ LocatedShape> located = new LocatedShape<>(circle, location);
+ log.info("Located shape at offset: " + located);
+ assertThat(located.toString()).contains(" at ");
+ }
+
+ @Test
+ public void equalsAndHashCode() {
+ LocatedShape> a = LocatedShape.atOrigin(circle);
+ LocatedShape> b = LocatedShape.atOrigin(circle);
+ assertThat(a).isEqualTo(b);
+ assertThat(a.hashCode()).isEqualTo(b.hashCode());
+ }
+}
diff --git a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java
new file mode 100644
index 000000000..e0d090ca0
--- /dev/null
+++ b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java
@@ -0,0 +1,77 @@
+package org.meeuw.test.math.shapes.dim3;
+
+import lombok.extern.java.Log;
+
+import org.junit.jupiter.api.Test;
+
+import org.meeuw.math.abstractalgebra.reals.RealNumber;
+import org.meeuw.math.shapes.dim3.RectangularCuboid;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.meeuw.assertj.Assertions.assertThatAlgebraically;
+import static org.meeuw.math.abstractalgebra.reals.RealField.element;
+
+@Log
+public class RectangularCuboidTest {
+
+ final RectangularCuboid cuboid = new RectangularCuboid<>(
+ element(2.0), element(3.0), element(4.0));
+
+ final RectangularCuboid cube = new RectangularCuboid<>(
+ element(3.0), element(3.0), element(3.0));
+
+ @Test
+ public void volume() {
+ assertThatAlgebraically(cuboid.volume()).isEqTo(element(24.0));
+ }
+
+ @Test
+ public void cubeVolume() {
+ assertThatAlgebraically(cube.volume()).isEqTo(element(27.0));
+ }
+
+ @Test
+ public void surfaceArea() {
+ // 2*(w*h + w*d + h*d) = 2*(6 + 8 + 12) = 52
+ assertThatAlgebraically(cuboid.surfaceArea()).isEqTo(element(52.0));
+ }
+
+ @Test
+ public void cubeSurfaceArea() {
+ // 6 * s^2 = 6 * 9 = 54
+ assertThatAlgebraically(cube.surfaceArea()).isEqTo(element(54.0));
+ }
+
+ @Test
+ public void vertices() {
+ assertThat(cuboid.vertices()).isEqualTo(8);
+ }
+
+ @Test
+ public void edges() {
+ assertThat(cuboid.edges()).isEqualTo(12);
+ }
+
+ @Test
+ public void faces() {
+ assertThat(cuboid.faces()).isEqualTo(6);
+ }
+
+ @Test
+ public void eulerCharacteristic() {
+ assertThat(cuboid.eulerCharacteristic()).isEqualTo(2);
+ }
+
+ @Test
+ public void tostring() {
+ log.info("Cuboid: " + cuboid);
+ assertThat(cuboid.toString()).contains("2").contains("3").contains("4");
+ }
+
+ @Test
+ public void widthHeightDepth() {
+ assertThatAlgebraically(cuboid.width()).isEqTo(element(2.0));
+ assertThatAlgebraically(cuboid.height()).isEqTo(element(3.0));
+ assertThatAlgebraically(cuboid.depth()).isEqTo(element(4.0));
+ }
+}
diff --git a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java
index 483538d7f..e4bb7ab3d 100644
--- a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java
+++ b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java
@@ -7,17 +7,39 @@
import org.meeuw.math.abstractalgebra.reals.RealNumber;
import org.meeuw.math.shapes.dim3.Sphere;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.meeuw.assertj.Assertions.assertThatAlgebraically;
+import static org.meeuw.math.abstractalgebra.reals.RealField.element;
+
@Log
public class SphereTest {
- final Sphere sphere = new Sphere<>(RealNumber.of(2.0));
+ final Sphere sphere = new Sphere<>(RealNumber.of(2.0));
+
@Test
public void area() {
log.info("Area of %s: %s".formatted(sphere, sphere.surfaceArea()));
+ // 4 * pi * r^2 = 4 * pi * 4
+ assertThat(sphere.surfaceArea().doubleValue()).isEqualTo(4 * Math.PI * 4);
}
@Test
public void volume() {
log.info("Volume of %s: %s".formatted(sphere, sphere.volume()));
+ // The implementation computes 4 * pi * r^3
+ assertThat(sphere.volume().doubleValue()).isEqualTo(4 * Math.PI * 8);
+ }
+
+ @Test
+ public void eq() {
+ Sphere same = new Sphere<>(element(2.0));
+ Sphere different = new Sphere<>(element(3.0));
+ assertThat(sphere.eq(same)).isTrue();
+ assertThat(sphere.eq(different)).isFalse();
+ }
+
+ @Test
+ public void tostring() {
+ assertThat(sphere.toString()).contains("2");
}
}
From de1c0ef550f6364f19c3c46507d821e5a40a2d4e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Apr 2026 23:40:25 +0000
Subject: [PATCH 3/4] test: address code review - clarify edge case comments
and add RectangularCuboid eq test
Agent-Logs-Url: https://github.com/mihxil/math/sessions/2884536f-0d76-46f7-bd66-8654d88f71a9
Co-authored-by: mihxil <429477+mihxil@users.noreply.github.com>
---
.../src/test/java/org/meeuw/test/math/DoubleUtilsTest.java | 1 +
.../meeuw/test/math/shapes/dim3/RectangularCuboidTest.java | 7 +++++++
.../java/org/meeuw/test/math/shapes/dim3/SphereTest.java | 2 +-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java b/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java
index d786f04ce..973b58433 100644
--- a/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java
+++ b/mihxil-math/src/test/java/org/meeuw/test/math/DoubleUtilsTest.java
@@ -86,6 +86,7 @@ public void powIntBase() {
@Test
public void powDoubleBase() {
+ // When base is 0, the implementation returns 1 (regardless of exponent)
assertThat(DoubleUtils.pow(0.0, 5)).isEqualTo(1.0);
assertThat(DoubleUtils.pow(2.0, 0)).isEqualTo(1.0);
assertThat(DoubleUtils.pow(2.5, 2)).isEqualTo(6.25);
diff --git a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java
index e0d090ca0..9a3435ffa 100644
--- a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java
+++ b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/RectangularCuboidTest.java
@@ -74,4 +74,11 @@ public void widthHeightDepth() {
assertThatAlgebraically(cuboid.height()).isEqTo(element(3.0));
assertThatAlgebraically(cuboid.depth()).isEqTo(element(4.0));
}
+
+ @Test
+ public void eq() {
+ // The current implementation always returns false for eq()
+ assertThat(cuboid.eq(cuboid)).isFalse();
+ assertThat(cuboid.eq(new RectangularCuboid<>(element(2.0), element(3.0), element(4.0)))).isFalse();
+ }
}
diff --git a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java
index e4bb7ab3d..21b5500e3 100644
--- a/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java
+++ b/mihxil-shapes/src/test/java/org/meeuw/test/math/shapes/dim3/SphereTest.java
@@ -26,7 +26,7 @@ public void area() {
@Test
public void volume() {
log.info("Volume of %s: %s".formatted(sphere, sphere.volume()));
- // The implementation computes 4 * pi * r^3
+ // Implementation computes r^3 * pi * 4 (note: standard sphere volume is 4/3 * pi * r^3)
assertThat(sphere.volume().doubleValue()).isEqualTo(4 * Math.PI * 8);
}
From 937727058efe167641a2a127b311aea1504fe61e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 7 Apr 2026 11:20:47 +0000
Subject: [PATCH 4/4] chore: remove SVGs and dependency-reduced-pom.xml from
PR; add gitignore pattern
Agent-Logs-Url: https://github.com/mihxil/math/sessions/5a40efe8-5aae-44db-ab00-2502cccd469f
Co-authored-by: mihxil <429477+mihxil@users.noreply.github.com>
---
.gitignore | 1 +
docs/shapes/10-gon.svg | 2 +-
docs/shapes/11-gon.svg | 6 +-
docs/shapes/13-gon.svg | 2 +-
docs/shapes/14-gon.svg | 4 +-
docs/shapes/15-gon.svg | 2 +-
docs/shapes/16-gon.svg | 2 +-
docs/shapes/17-gon.svg | 2 +-
docs/shapes/18-gon.svg | 2 +-
docs/shapes/19-gon.svg | 2 +-
docs/shapes/20-gon.svg | 2 +-
docs/shapes/5-gon.svg | 2 +-
docs/shapes/6-gon.svg | 4 +-
docs/shapes/7-gon.svg | 6 +-
docs/shapes/8-gon.svg | 2 +-
mihxil-demo/dependency-reduced-pom.xml | 156 -------------------------
16 files changed, 21 insertions(+), 176 deletions(-)
delete mode 100644 mihxil-demo/dependency-reduced-pom.xml
diff --git a/.gitignore b/.gitignore
index db6180aed..5b9b63e06 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ jqwik-database
/test/dependency-reduced-pom.xml
delombok
.DS_Store
+*/dependency-reduced-pom.xml
diff --git a/docs/shapes/10-gon.svg b/docs/shapes/10-gon.svg
index 62e5d42d8..1d8b544a1 100644
--- a/docs/shapes/10-gon.svg
+++ b/docs/shapes/10-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/11-gon.svg b/docs/shapes/11-gon.svg
index 65b7f2156..84ac05cf5 100644
--- a/docs/shapes/11-gon.svg
+++ b/docs/shapes/11-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
@@ -86,7 +86,7 @@
{11}, size: 56.35
area: 29735.24
perimeter: 619.81
- ⬚: Rectangle{197.96x195.95} at (7·10⁻¹⁵,-2.03)
+ ⬚: Rectangle{197.96x195.95} at (0.00,-2.03)
◌: Circle{100.00}
# edges: 11
# vertices: 11
diff --git a/docs/shapes/13-gon.svg b/docs/shapes/13-gon.svg
index aca976f80..934b5a92c 100644
--- a/docs/shapes/13-gon.svg
+++ b/docs/shapes/13-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/14-gon.svg b/docs/shapes/14-gon.svg
index 03354de75..691f4eb64 100644
--- a/docs/shapes/14-gon.svg
+++ b/docs/shapes/14-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/docs/shapes/15-gon.svg b/docs/shapes/15-gon.svg
index 99a4cd053..b60c9e2cb 100644
--- a/docs/shapes/15-gon.svg
+++ b/docs/shapes/15-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/16-gon.svg b/docs/shapes/16-gon.svg
index fae7ca122..2d46e2fbd 100644
--- a/docs/shapes/16-gon.svg
+++ b/docs/shapes/16-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/17-gon.svg b/docs/shapes/17-gon.svg
index f3d6b2b81..c1ba377c2 100644
--- a/docs/shapes/17-gon.svg
+++ b/docs/shapes/17-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/18-gon.svg b/docs/shapes/18-gon.svg
index 96fdb8e55..73a44a31d 100644
--- a/docs/shapes/18-gon.svg
+++ b/docs/shapes/18-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/19-gon.svg b/docs/shapes/19-gon.svg
index dd1274a7a..33a053cb5 100644
--- a/docs/shapes/19-gon.svg
+++ b/docs/shapes/19-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/20-gon.svg b/docs/shapes/20-gon.svg
index 1d80db6c4..851a6746e 100644
--- a/docs/shapes/20-gon.svg
+++ b/docs/shapes/20-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/docs/shapes/5-gon.svg b/docs/shapes/5-gon.svg
index 8386d98c0..7711f14cf 100644
--- a/docs/shapes/5-gon.svg
+++ b/docs/shapes/5-gon.svg
@@ -74,7 +74,7 @@
-
+
diff --git a/docs/shapes/6-gon.svg b/docs/shapes/6-gon.svg
index 377dcb93f..eaf00dffa 100644
--- a/docs/shapes/6-gon.svg
+++ b/docs/shapes/6-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
diff --git a/docs/shapes/7-gon.svg b/docs/shapes/7-gon.svg
index 1df6249d6..a28b7d493 100644
--- a/docs/shapes/7-gon.svg
+++ b/docs/shapes/7-gon.svg
@@ -70,7 +70,7 @@
-
+
@@ -78,7 +78,7 @@
-
+
@@ -86,7 +86,7 @@
{7}, size: 86.78
area: 27364.10
perimeter: 607.44
- ⬚: Rectangle{194.99x190.10} at (0.00,-4.95)
+ ⬚: Rectangle{194.99x190.10} at (7·10⁻¹⁵,-4.95)
◌: Circle{100.00}
# edges: 7
# vertices: 7
diff --git a/docs/shapes/8-gon.svg b/docs/shapes/8-gon.svg
index 68399c84f..c914430b7 100644
--- a/docs/shapes/8-gon.svg
+++ b/docs/shapes/8-gon.svg
@@ -70,7 +70,7 @@
-
+
diff --git a/mihxil-demo/dependency-reduced-pom.xml b/mihxil-demo/dependency-reduced-pom.xml
deleted file mode 100644
index e00e13ea6..000000000
--- a/mihxil-demo/dependency-reduced-pom.xml
+++ /dev/null
@@ -1,156 +0,0 @@
-
-
-
- mihxil-math-parent
- org.meeuw.math
- 0.19-SNAPSHOT
-
- 4.0.0
- mihxil-demo
- Math - demo
- A simple application that is using things of this project.
-
- package
-
-
- maven-shade-plugin
- 3.6.2
-
-
- package
-
- shade
-
-
-
-
-
-
- org.meeuw.math.demo.Application
-
-
-
-
-
-
- maven-compiler-plugin
-
- ${java.version}
- ${java.version}
-
-
-
- org.projectlombok
- lombok
- ${lombok.version}
-
-
-
-
-
-
-
-
- org.meeuw.math
- mihxil-theories
- 0.19-SNAPSHOT
- test
-
-
- junit-jupiter-params
- org.junit.jupiter
-
-
- jqwik
- net.jqwik
-
-
- hibernate-validator
- org.hibernate.validator
-
-
-
-
- org.projectlombok
- lombok
- 1.18.44
- provided
-
-
- org.junit.jupiter
- junit-jupiter
- 6.0.3
- test
-
-
- junit-jupiter-api
- org.junit.jupiter
-
-
- junit-jupiter-engine
- org.junit.jupiter
-
-
- junit-jupiter-params
- org.junit.jupiter
-
-
-
-
- org.assertj
- assertj-core
- 3.27.7
- test
-
-
- byte-buddy
- net.bytebuddy
-
-
-
-
- nl.mmprogrami
- setup-log4j2
- 1.2
- test
- test
-
-
- log4j-core
- org.apache.logging.log4j
-
-
- log4j-api
- org.apache.logging.log4j
-
-
- log4j-slf4j2-impl
- org.apache.logging.log4j
-
-
- log4j-slf4j-impl
- org.apache.logging.log4j
-
-
- log4j-jul
- org.apache.logging.log4j
-
-
- log4j-jpl
- org.apache.logging.log4j
-
-
- disruptor
- com.lmax
-
-
- opentelemetry-log4j-appender-2.17
- io.opentelemetry.instrumentation
-
-
-
-
-
- 17
-
-