From 2375abdb425f9c031be01271648bced1d58cf214 Mon Sep 17 00:00:00 2001 From: imgolem Date: Tue, 24 Oct 2023 14:06:22 +0300 Subject: [PATCH 1/5] feat(): simple math classes --- lib/src/main/java/de/edux/math/Entity.java | 16 ++ lib/src/main/java/de/edux/math/MathUtil.java | 19 ++ .../main/java/de/edux/math/Validations.java | 20 +++ .../main/java/de/edux/math/entity/Matrix.java | 167 ++++++++++++++++++ .../main/java/de/edux/math/entity/Vector.java | 166 +++++++++++++++++ 5 files changed, 388 insertions(+) create mode 100644 lib/src/main/java/de/edux/math/Entity.java create mode 100644 lib/src/main/java/de/edux/math/MathUtil.java create mode 100644 lib/src/main/java/de/edux/math/Validations.java create mode 100644 lib/src/main/java/de/edux/math/entity/Matrix.java create mode 100644 lib/src/main/java/de/edux/math/entity/Vector.java diff --git a/lib/src/main/java/de/edux/math/Entity.java b/lib/src/main/java/de/edux/math/Entity.java new file mode 100644 index 0000000..0fb37a7 --- /dev/null +++ b/lib/src/main/java/de/edux/math/Entity.java @@ -0,0 +1,16 @@ +package de.edux.math; + +/** + * @author ImGolem? + */ +public interface Entity { + + T add(T another); + + T subtract(T another); + + T multiply(T another); + + T scalarMultiply(double n); + +} diff --git a/lib/src/main/java/de/edux/math/MathUtil.java b/lib/src/main/java/de/edux/math/MathUtil.java new file mode 100644 index 0000000..2809010 --- /dev/null +++ b/lib/src/main/java/de/edux/math/MathUtil.java @@ -0,0 +1,19 @@ +package de.edux.math; + +/** + * @author ImGolem? + */ +public final class MathUtil { + + public static double[] unwrap(double[][] matrix) { + double[] result = new double[matrix.length * matrix[0].length]; + int i = 0; + for (double[] arr : matrix) { + for (double val : arr) { + result[i++] = val; + } + } + return result; + } + +} diff --git a/lib/src/main/java/de/edux/math/Validations.java b/lib/src/main/java/de/edux/math/Validations.java new file mode 100644 index 0000000..7db237d --- /dev/null +++ b/lib/src/main/java/de/edux/math/Validations.java @@ -0,0 +1,20 @@ +package de.edux.math; + +/** + * @author ImGolem? + */ +public final class Validations { + + public static void size(double[] f, double[] s) { + if (f.length != s.length) { + throw new IllegalArgumentException("sizes mismatch"); + } + } + + public static void sizeMatrix(double[][] f, double[][] s) { + if (f.length != s.length || f[0].length != s[0].length) { + throw new IllegalArgumentException("sizes mismatch"); + } + } + +} diff --git a/lib/src/main/java/de/edux/math/entity/Matrix.java b/lib/src/main/java/de/edux/math/entity/Matrix.java new file mode 100644 index 0000000..dce31e1 --- /dev/null +++ b/lib/src/main/java/de/edux/math/entity/Matrix.java @@ -0,0 +1,167 @@ +package de.edux.math.entity; + +import de.edux.math.Entity; +import de.edux.math.MathUtil; +import de.edux.math.Validations; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * @author ImGolem? + */ +public class Matrix implements Entity, Iterable { + + /** + * Represents a raw matrix as a default two-dimension array + */ + private final double[][] raw; + + public Matrix(double[][] matrix) { + this.raw = matrix; + } + + @Override + public Matrix add(Matrix another) { + return add(another.raw()); + } + + public Matrix add(double[][] another) { + Validations.sizeMatrix(raw, another); + + double[][] result = new double[raw.length][raw[0].length]; + + for (int i = 0; i < result.length; i++) { + for (int a = 0; a < result[0].length; a++) { + result[i][a] = raw[i][a] + another[i][a]; + } + } + + return new Matrix(result); + } + + @Override + public Matrix subtract(Matrix another) { + return subtract(another.raw()); + } + + @Override + public Matrix multiply(Matrix another) { + return multiply(another.raw()); + } + + public Matrix multiply(double[][] another) { + return null; // TODO optimized algorithm for matrix multiplication + } + + @Override + public Matrix scalarMultiply(double n) { + double[][] result = new double[raw.length][raw[0].length]; + + for (int i = 0; i < result.length; i++) { + for (int a = 0; a < result[0].length; a++) { + result[i][a] = raw[i][a] * n; + } + } + + return new Matrix(result); + } + + public Matrix subtract(double[][] another) { + Validations.sizeMatrix(raw, another); + + double[][] result = new double[raw.length][raw[0].length]; + + for (int i = 0; i < result.length; i++) { + for (int a = 0; a < result[0].length; a++) { + result[i][a] = raw[i][a] - another[i][a]; + } + } + + return new Matrix(result); + } + + public boolean isSquare() { + return rows() == columns(); + } + + public int rows() { + return raw.length; + } + + public int columns() { + return raw[0].length; + } + + public double[][] raw() { + return raw; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Matrix matrix) { + if (matrix.rows() != rows() || matrix.columns() != columns()) { + return false; + } + for (int i = 0; i < raw.length; i++) { + for (int a = 0; a < raw[i].length; a++) { + if (matrix.raw()[i][a] != raw[i][a]) { + return false; + } + } + } + return true; + } + return false; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("[").append("\n"); + for (int i = 0; i < raw.length; i++) { + builder.append(" ").append("["); + for (int a = 0; a < raw[i].length; a++) { + builder.append(raw[i][a]); + if (a != raw[i].length - 1) { + builder.append(", "); + } + } + builder.append("]"); + if (i != raw.length - 1) { + builder.append(","); + } + builder.append("\n"); + } + return builder.append("]").toString(); + } + + @Override + public Iterator iterator() { + return new MatrixIterator(raw); + } + + public static class MatrixIterator implements Iterator { + + private final double[] data; + private int current; + + public MatrixIterator(double[][] data) { + this.data = MathUtil.unwrap(data); + this.current = 0; + } + + @Override + public boolean hasNext() { + return current < data.length; + } + + @Override + public Double next() { + if (!hasNext()) + throw new NoSuchElementException(); + return data[current++]; + } + + } + +} diff --git a/lib/src/main/java/de/edux/math/entity/Vector.java b/lib/src/main/java/de/edux/math/entity/Vector.java new file mode 100644 index 0000000..b51a33d --- /dev/null +++ b/lib/src/main/java/de/edux/math/entity/Vector.java @@ -0,0 +1,166 @@ +package de.edux.math.entity; + +import de.edux.math.Entity; +import de.edux.math.Validations; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * @author ImGolem? + */ +public class Vector implements Entity, Iterable { + + /** + * Represents a raw vector as a default array + */ + private final double[] raw; + + public Vector(double[] vector) { + this.raw = vector; + } + + @Override + public Vector add(Vector another) { + return add(another.raw()); + } + + public Vector add(double[] another) { + Validations.size(raw, another); + + double[] result = new double[length()]; + for (int i = 0; i < result.length; i++) { + result[i] = raw[i] + another[i]; + } + + return new Vector(result); + } + + @Override + public Vector subtract(Vector another) { + return subtract(another.raw()); + } + + public Vector subtract(double[] another) { + Validations.size(raw, another); + + double[] result = new double[length()]; + for (int i = 0; i < result.length; i++) { + result[i] = raw[i] - another[i]; + } + + return new Vector(result); + } + + @Override + public Vector multiply(Vector another) { + return multiply(another.raw()); + } + + public Vector multiply(double[] another) { + Validations.size(raw, another); + + double[] result = new double[length()]; + for (int i = 0; i < result.length; i++) { + result[i] = raw[i] * another[i]; + if (result[i] == 0) { // Avoiding -0 result + result[i] = 0; + } + } + + return new Vector(result); + } + + @Override + public Vector scalarMultiply(double n) { + double[] result = new double[length()]; + for (int i = 0; i < result.length; i++) { + result[i] = raw[i] * n; + if (result[i] == 0) { // Avoiding -0 result + result[i] = 0; + } + } + + return new Vector(result); + } + + public double dot(Vector another) { + return dot(another.raw()); + } + + public double dot(double[] another) { + Validations.size(raw, another); + + double result = 0; + for (int i = 0; i < raw.length; i++) { + result += raw[i] * another[i]; + } + + return result; + } + + /** + * @return length of the vector + */ + public int length() { + return raw.length; + } + + /** + * @return raw vector (array) + */ + public double[] raw() { + return raw.clone(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Vector) { + return Arrays.equals(raw, ((Vector) obj).raw()); + } + return false; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder("["); + for (int i = 0; i < raw.length; i++) { + builder.append(raw[i]); + if (i != raw.length - 1) { + builder.append(", "); + } + } + return builder.append("]").toString(); + } + + @Override + public Iterator iterator() { + return new VectorIterator(raw); + } + + public static class VectorIterator implements Iterator { + + private final double[] data; + private int current; + + public VectorIterator(double[] data) { + this.data = data; + this.current = 0; + } + + @Override + public boolean hasNext() { + return current < data.length; + } + + @Override + public Double next() { + if (!hasNext()) + throw new NoSuchElementException(); + return data[current++]; + } + + } + +} From 5174aaee28b4a9b4f98f13b1c36af3cdf52ca3ba Mon Sep 17 00:00:00 2001 From: imgolem Date: Tue, 24 Oct 2023 14:06:30 +0300 Subject: [PATCH 2/5] test(): math classes --- .../test/java/de/edux/math/EntityTest.java | 13 ++++ .../java/de/edux/math/entity/MatrixTest.java | 69 +++++++++++++++++++ .../java/de/edux/math/entity/VectorTest.java | 50 ++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 lib/src/test/java/de/edux/math/EntityTest.java create mode 100644 lib/src/test/java/de/edux/math/entity/MatrixTest.java create mode 100644 lib/src/test/java/de/edux/math/entity/VectorTest.java diff --git a/lib/src/test/java/de/edux/math/EntityTest.java b/lib/src/test/java/de/edux/math/EntityTest.java new file mode 100644 index 0000000..e89340d --- /dev/null +++ b/lib/src/test/java/de/edux/math/EntityTest.java @@ -0,0 +1,13 @@ +package de.edux.math; + +public interface EntityTest { + + void testAdd(); + + void testSubtract(); + + void testMultiply(); + + void testScalarMultiply(); + +} diff --git a/lib/src/test/java/de/edux/math/entity/MatrixTest.java b/lib/src/test/java/de/edux/math/entity/MatrixTest.java new file mode 100644 index 0000000..3b4df00 --- /dev/null +++ b/lib/src/test/java/de/edux/math/entity/MatrixTest.java @@ -0,0 +1,69 @@ +package de.edux.math.entity; + +import de.edux.math.EntityTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MatrixTest implements EntityTest { + + static Matrix first; + static Matrix second; + + @BeforeEach + public void init() { + first = new Matrix(new double[][] { + {5, 3, -1}, + {-2, 0, 6}, + {5, 1, -9} + }); + second = new Matrix(new double[][] { + {8, 7, 4}, + {1, -5, 2}, + {0, 3, 0} + }); + } + + @Override + @Test + public void testAdd() { + assertEquals(new Matrix(new double[][] { + {13, 10, 3}, + {-1, -5, 8}, + {5, 4, -9} + }), first.add(second)); + } + + @Override + @Test + public void testSubtract() { + assertEquals(new Matrix(new double[][] { + {-3, -4, -5}, + {-3, 5, 4}, + {5, -2, -9} + }), first.subtract(second)); + } + + @Override + @Test + public void testMultiply() { + // TODO other matrices + } + + @Override + @Test + public void testScalarMultiply() { + assertEquals(new Matrix(new double[][] { + {20, 12, -4}, + {-8, 0, 24}, + {20, 4, -36} + }), first.scalarMultiply(4)); + assertEquals(new Matrix(new double[][] { + {-48, -42, -24}, + {-6, 30, -12}, + {0, -18, 0} + }), second.scalarMultiply(-6)); + } + +} diff --git a/lib/src/test/java/de/edux/math/entity/VectorTest.java b/lib/src/test/java/de/edux/math/entity/VectorTest.java new file mode 100644 index 0000000..2d31d7a --- /dev/null +++ b/lib/src/test/java/de/edux/math/entity/VectorTest.java @@ -0,0 +1,50 @@ +package de.edux.math.entity; + +import de.edux.math.EntityTest; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class VectorTest implements EntityTest { + + static Vector first; + static Vector second; + + @BeforeAll + public static void init() { + first = new Vector(new double[] {1, 5, 4}); + second = new Vector(new double[] {3, 8, 0}); + } + + @Test + @Override + public void testAdd() { + assertEquals(new Vector(new double[] {4, 13, 4}), first.add(second)); + } + + @Test + @Override + public void testSubtract() { + assertEquals(new Vector(new double[] {-2, -3, 4}), first.subtract(second)); + } + + @Test + @Override + public void testMultiply() { + assertEquals(new Vector(new double[] {3, 40, 0}), first.multiply(second)); + } + + @Test + @Override + public void testScalarMultiply() { + assertEquals(new Vector(new double[] {3, 15, 12}), first.scalarMultiply(3)); // first by 3 + assertEquals(new Vector(new double[] {-6, -16, 0}), second.scalarMultiply(-2)); // second by -2 + } + + @Test + public void testDot() { + assertEquals(43, first.dot(second)); + } + +} From 7d1ec40f7c39be08656d55b6cbbbda0f017231e1 Mon Sep 17 00:00:00 2001 From: imgolem Date: Wed, 25 Oct 2023 23:00:46 +0300 Subject: [PATCH 3/5] chore(): update javadoc; change names --- lib/src/main/java/de/edux/math/Entity.java | 3 --- lib/src/main/java/de/edux/math/MathUtil.java | 3 --- lib/src/main/java/de/edux/math/Validations.java | 11 ++++------- lib/src/main/java/de/edux/math/entity/Matrix.java | 6 ------ lib/src/main/java/de/edux/math/entity/Vector.java | 6 ------ 5 files changed, 4 insertions(+), 25 deletions(-) diff --git a/lib/src/main/java/de/edux/math/Entity.java b/lib/src/main/java/de/edux/math/Entity.java index 0fb37a7..2f1ceb0 100644 --- a/lib/src/main/java/de/edux/math/Entity.java +++ b/lib/src/main/java/de/edux/math/Entity.java @@ -1,8 +1,5 @@ package de.edux.math; -/** - * @author ImGolem? - */ public interface Entity { T add(T another); diff --git a/lib/src/main/java/de/edux/math/MathUtil.java b/lib/src/main/java/de/edux/math/MathUtil.java index 2809010..162c1fc 100644 --- a/lib/src/main/java/de/edux/math/MathUtil.java +++ b/lib/src/main/java/de/edux/math/MathUtil.java @@ -1,8 +1,5 @@ package de.edux.math; -/** - * @author ImGolem? - */ public final class MathUtil { public static double[] unwrap(double[][] matrix) { diff --git a/lib/src/main/java/de/edux/math/Validations.java b/lib/src/main/java/de/edux/math/Validations.java index 7db237d..7fbc8e8 100644 --- a/lib/src/main/java/de/edux/math/Validations.java +++ b/lib/src/main/java/de/edux/math/Validations.java @@ -1,18 +1,15 @@ package de.edux.math; -/** - * @author ImGolem? - */ public final class Validations { - public static void size(double[] f, double[] s) { - if (f.length != s.length) { + public static void size(double[] first, double[] second) { + if (first.length != second.length) { throw new IllegalArgumentException("sizes mismatch"); } } - public static void sizeMatrix(double[][] f, double[][] s) { - if (f.length != s.length || f[0].length != s[0].length) { + public static void sizeMatrix(double[][] first, double[][] second) { + if (first.length != second.length || first[0].length != second[0].length) { throw new IllegalArgumentException("sizes mismatch"); } } diff --git a/lib/src/main/java/de/edux/math/entity/Matrix.java b/lib/src/main/java/de/edux/math/entity/Matrix.java index dce31e1..c643a39 100644 --- a/lib/src/main/java/de/edux/math/entity/Matrix.java +++ b/lib/src/main/java/de/edux/math/entity/Matrix.java @@ -7,14 +7,8 @@ import java.util.Iterator; import java.util.NoSuchElementException; -/** - * @author ImGolem? - */ public class Matrix implements Entity, Iterable { - /** - * Represents a raw matrix as a default two-dimension array - */ private final double[][] raw; public Matrix(double[][] matrix) { diff --git a/lib/src/main/java/de/edux/math/entity/Vector.java b/lib/src/main/java/de/edux/math/entity/Vector.java index b51a33d..ee99b83 100644 --- a/lib/src/main/java/de/edux/math/entity/Vector.java +++ b/lib/src/main/java/de/edux/math/entity/Vector.java @@ -7,14 +7,8 @@ import java.util.Iterator; import java.util.NoSuchElementException; -/** - * @author ImGolem? - */ public class Vector implements Entity, Iterable { - /** - * Represents a raw vector as a default array - */ private final double[] raw; public Vector(double[] vector) { From 608420718a3bcdc6cf8944e181a04c5c2f26a96f Mon Sep 17 00:00:00 2001 From: imgolem Date: Wed, 25 Oct 2023 23:41:26 +0300 Subject: [PATCH 4/5] chore(): remove javadoc --- lib/src/main/java/de/edux/math/entity/Vector.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/src/main/java/de/edux/math/entity/Vector.java b/lib/src/main/java/de/edux/math/entity/Vector.java index ee99b83..a7cf59d 100644 --- a/lib/src/main/java/de/edux/math/entity/Vector.java +++ b/lib/src/main/java/de/edux/math/entity/Vector.java @@ -94,16 +94,10 @@ public double dot(double[] another) { return result; } - /** - * @return length of the vector - */ public int length() { return raw.length; } - /** - * @return raw vector (array) - */ public double[] raw() { return raw.clone(); } From 6374b1e278fcd04124868eee834190271a1d731a Mon Sep 17 00:00:00 2001 From: imgolem Date: Wed, 25 Oct 2023 23:41:53 +0300 Subject: [PATCH 5/5] test(): remove entity interface --- lib/src/test/java/de/edux/math/EntityTest.java | 13 ------------- .../test/java/de/edux/math/entity/MatrixTest.java | 12 +----------- .../test/java/de/edux/math/entity/VectorTest.java | 7 +------ 3 files changed, 2 insertions(+), 30 deletions(-) delete mode 100644 lib/src/test/java/de/edux/math/EntityTest.java diff --git a/lib/src/test/java/de/edux/math/EntityTest.java b/lib/src/test/java/de/edux/math/EntityTest.java deleted file mode 100644 index e89340d..0000000 --- a/lib/src/test/java/de/edux/math/EntityTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.edux.math; - -public interface EntityTest { - - void testAdd(); - - void testSubtract(); - - void testMultiply(); - - void testScalarMultiply(); - -} diff --git a/lib/src/test/java/de/edux/math/entity/MatrixTest.java b/lib/src/test/java/de/edux/math/entity/MatrixTest.java index 3b4df00..ed590df 100644 --- a/lib/src/test/java/de/edux/math/entity/MatrixTest.java +++ b/lib/src/test/java/de/edux/math/entity/MatrixTest.java @@ -1,12 +1,11 @@ package de.edux.math.entity; -import de.edux.math.EntityTest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -public class MatrixTest implements EntityTest { +public class MatrixTest { static Matrix first; static Matrix second; @@ -25,7 +24,6 @@ public void init() { }); } - @Override @Test public void testAdd() { assertEquals(new Matrix(new double[][] { @@ -35,7 +33,6 @@ public void testAdd() { }), first.add(second)); } - @Override @Test public void testSubtract() { assertEquals(new Matrix(new double[][] { @@ -45,13 +42,6 @@ public void testSubtract() { }), first.subtract(second)); } - @Override - @Test - public void testMultiply() { - // TODO other matrices - } - - @Override @Test public void testScalarMultiply() { assertEquals(new Matrix(new double[][] { diff --git a/lib/src/test/java/de/edux/math/entity/VectorTest.java b/lib/src/test/java/de/edux/math/entity/VectorTest.java index 2d31d7a..f4fc013 100644 --- a/lib/src/test/java/de/edux/math/entity/VectorTest.java +++ b/lib/src/test/java/de/edux/math/entity/VectorTest.java @@ -1,12 +1,11 @@ package de.edux.math.entity; -import de.edux.math.EntityTest; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -public class VectorTest implements EntityTest { +public class VectorTest { static Vector first; static Vector second; @@ -18,25 +17,21 @@ public static void init() { } @Test - @Override public void testAdd() { assertEquals(new Vector(new double[] {4, 13, 4}), first.add(second)); } @Test - @Override public void testSubtract() { assertEquals(new Vector(new double[] {-2, -3, 4}), first.subtract(second)); } @Test - @Override public void testMultiply() { assertEquals(new Vector(new double[] {3, 40, 0}), first.multiply(second)); } @Test - @Override public void testScalarMultiply() { assertEquals(new Vector(new double[] {3, 15, 12}), first.scalarMultiply(3)); // first by 3 assertEquals(new Vector(new double[] {-6, -16, 0}), second.scalarMultiply(-2)); // second by -2