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 - -