diff --git a/src/commandui/curtest.java b/src/commandui/curtest.java new file mode 100644 index 00000000..f4f1734b --- /dev/null +++ b/src/commandui/curtest.java @@ -0,0 +1,320 @@ +package commandui; + +import core.functions.GeneralFunction; +import core.functions.endpoint.Placeholder; +import core.functions.unitary.specialcases.Exp; +import static core.tools.defaults.DefaultFunctions.*; +import tensors.*; +import static tensors.TensorTools.prettyString; +import static tensors.TensorTools.product; +import static tensors.TensorTools.wrap; + +public class curtest { + public static void main(String[] args) { + System.out.println("hi"); + String[] genericVariables = new String[10]; + for (int i = 0; i < 3; ++i) { + genericVariables[i] = ((char) ('x' + i)) + ""; + } + for (int i = 3; i < genericVariables.length; ++i) { + genericVariables[i] = ((char) ('z' - i)) + ""; + } + + { + String[] vars = new String[2]; + for (int i = 0; i < vars.length; ++i) { + vars[i] = genericVariables[i]; + } + // var genericMetrics = TensorTools.placeholderMetrics(vars); + var genericMetrics = TensorTools.placeholderDiagonalMetrics(vars); + Tensor genericMetric = genericMetrics.getFirst(); + Tensor genericInverseMetric = genericMetrics.getSecond(); + // GeneralFunction conformalScale = new Placeholder("M", vars); + GeneralFunction conformalScale = new Exp(new Placeholder("w", vars)); + Tensor conformalMetric = TensorTools + .magicTensor(product(wrap(conformalScale), genericMetric.index("a", "b"))); + Tensor conformalInverseMetric = TensorTools + .magicTensor(product(wrap(reciprocal(conformalScale)), genericInverseMetric.index("a", "b"))); + Space conformalSpace = new Space(vars, conformalMetric, conformalInverseMetric); + System.out.println("Conformal Space: " + conformalSpace + + "\nConformal Metric: " + prettyString(conformalMetric, conformalSpace, "a", "b") + + "\nConformal Inverse Metric: " + prettyString(conformalInverseMetric, conformalSpace, "a", "b")); + System.out.println("Conformal Christoffel: " + + prettyString(conformalSpace.christoffel, conformalSpace, "a", "b", "c")); + // System.out.println("Conformal Riemann Tensor: " + // + prettyString(conformalSpace.riemannTensor, conformalSpace, vars)); + System.out.println("Conformal Ricci Tensor: " + + prettyString(conformalSpace.ricciTensor, conformalSpace, "a", "b")); + // System.out.println("Conformal Ricci Scalar: " + // + prettyString(conformalSpace.ricciScalar, conformalSpace, vars)); + } + // { + // String[] vars = { "t", "r", "h", "f", "s" }; + // GeneralFunction[] diag = { + // NEGATIVE_ONE, + // new Pow(TWO, new Placeholder("a", "t")), + // new Pow(TWO, new Sinh(new Variable(vars[1]))), + // new Pow(TWO, new Sin(new Variable(vars[2]))), + // new Pow(TWO, new Sin(new Variable(vars[3]))), + + // }; + // for (int i = 2; i < diag.length; ++i) { + // diag[i] = new Product(diag[i], diag[i]).simplifyPull(); + // } + + // System.out.println(Space.fromDiagonalMetric(vars, diag).ricciScalar); + // } + + // // { + // String[] vars = { "t", "r", "h", "f" }; + // Variable[] variables = + // Arrays.stream(vars).map(Variable::new).toArray(Variable[]::new); + // var radial = new Variable("r"); + // // var integration_constant = new Variable("C"); + // // var placeholder_f = new Placeholder("f", "r"); + // var integration_constant = ONE; + // var mass = new Variable("M"); + // var charge = new Variable("q"); + // var placeholder_f = new Sum(ONE, new Product(NEGATIVE_TWO, mass, + // reciprocal(radial)), + // square(new Product(charge, reciprocal(radial)))); + // GeneralFunction[] diag = { + // negative(placeholder_f), + // new Product(integration_constant, reciprocal(placeholder_f)), + // square(radial), + // new Product(square(radial), square(new Sin(new Variable(vars[2])))) + // }; + + // Space space = Space.fromDiagonalMetric(vars, diag); + // System.out.println(prettyString(space.christoffel, space, new String[] { "a", + // "b", "c" })); + // // System.out.println(prettyString(space.riemannTensor, space, new String[] { + // // "a", "b", "c", "d" })); + // // System.out.println(prettyString(space.einsteinTensor, space, new String[] + // { + // // "a", "b" })); + // Tensor einsteinDownUp = magicTensor( + // product(space.einsteinTensor.index("\\alpha", "\\beta"), + // space.inverseMetric.index("\\gamma", "\\beta"))); + // System.out.println(prettyString(einsteinDownUp, space, new String[] { + // "a", "b" })); + // // } + + // var curt = DefaultSpaces.s3.ricciTensor; + // var curtm = curt.modifyWithTensor(MiscTools::trigForSinners); + // System.out.println( + // TensorTools.prettyString(curtm, + // DefaultSpaces.s3, new String[] { "a", "b" })); + + } + /** + * @BeforeAll + * static void beforeAll() { + * DefaultSpaces.initialize(); + * } + * + * @Test + * void undirectedTest() { + * NestedArray test = NestedArray.nest(new Object[][] { + * { 1, 2 }, + * { 3, 4 } + * }); + * System.out.println(test); + * assertEquals(2, test.getAtIndex(0, 1)); + * assertEquals(2, test.getRank()); + * test.setAtIndex(-1, 0, 0); + * assertEquals(-1, test.getAtIndex(0, 0)); + * Nested test2 = test.modifyWith(i -> -2 * i); + * assertEquals(-4, test2.getAtIndex(0, 1)); + * } + * + * @Test + * void directedTest() { + * DirectedNested test = DirectedNestedArray.direct( + * new Object[][] { + * { 1, 2 }, + * { 3, 4 } + * }, new boolean[] { true, false }); + * System.out.println(test); + * assertEquals(2, test.getAtIndex(0, 1)); + * assertTrue(test.getDirection()); + * } + * + * @Test + * void tensorTest() { + * Tensor test = ArrayTensor.tensor( + * new Object[][] { + * { ONE, TWO }, + * { new Constant(3), new Product(TWO, E) } + * }, + * true, false); + * System.out.println(test); + * assertEquals(TWO, test.getAtIndex(0, 1)); + * assertTrue(test.getDirection()); + * DirectedNested test2d = + * DirectedNestedArray.direct(NestedArray.nest( + * new Object[][] { + * { ONE, ONE }, + * { ONE, TWO } + * }), new boolean[] { true, false }); + * Tensor test2 = ArrayTensor.tensor(test2d); + * DirectedNested sum = TensorTools.createFrom( + * List.of("a", "b"), + * new boolean[] { true, false }, + * 2, + * new ElementSum(indexTensor(test, "a", "b"), indexTensor(test2, "a", + * "b"))); + * assertEquals(sum.getAtIndex(1, 0), new Constant(4)); + * System.out.println(sum); + * } + * + * @Test + * void elementTest() { + * Tensor id2u = ArrayTensor.tensor( + * new Object[][] { + * { ZERO, ONE }, + * { ONE, ZERO } + * }, + * false, false); + * Tensor id2d = ArrayTensor.tensor( + * new Object[][] { + * { ZERO, ONE }, + * { ONE, ZERO } + * }, + * true, true); + * System.out.println(createFrom(List.of("a", "b"), new boolean[] { true, + * false }, 2, + * new ElementProduct(new ElementWrapper(id2u, "a", "m"), new + * ElementWrapper(id2d, "m", "b")))); + * } + * + * @Test + * void scalarTest1() { + * Tensor C = ArrayTensor.tensor( + * new Object[] { + * ONE, + * TWO + * }, + * true); + * Tensor R = ArrayTensor.tensor( + * new Object[] { + * TEN, ONE + * }, + * false); + * System.out.println(createFrom(List.of(), new boolean[] {}, 2, + * new ElementProduct(new ElementWrapper(R, "\\mu"), new ElementWrapper(C, + * "\\mu")))); + * } + * + * @Test + * void scalarTest2() { + * Tensor C = ArrayTensor.tensor( + * new Object[] { + * TEN, ONE + * }, + * true); + * Tensor metric = ArrayTensor.tensor( + * new Object[][] { + * { NEGATIVE_ONE, ZERO }, + * { ZERO, ONE } + * }, + * false, false); + * System.out.println(createFrom(List.of("\\nu"), new boolean[] { false }, + * 2, + * new ElementProduct(new ElementWrapper(C, "\\mu"), new + * ElementWrapper(metric, "\\mu", "\\nu")))); + * } + * + * @Test + * void christoffel() { + * Space space = DefaultSpaces.s2; + * System.out.println(space.christoffel); + * } + * + * @Test + * void cov1() { + * Space space = DefaultSpaces.cartesian2d; + * Tensor tensor = ArrayTensor.tensor( + * new Object[] { square(new Variable("x")), new Product(TWO, new + * Variable("y")) }, + * true); + * assertEquals(space.covariantDerivative("a", tensor, "b"), + * ArrayTensor.tensor( + * new Object[][] { + * { new Product(TWO, new Variable("x")), ZERO }, + * { ZERO, TWO } + * }, + * false, true)); + * + * } + * + * @Test + * void cov2() { + * Space space = DefaultSpaces.spherical; + * Tensor tensor = ArrayTensor.tensor( + * new Object[] { + * new Product(new Variable("k"), new Variable("q"), new Pow(NEGATIVE_TWO, + * new Variable("r"))), + * ZERO, ZERO }, + * true); + * Tensor expected = ArrayTensor.tensor( + * new Object[][] { + * { new Product(NEGATIVE_TWO, new Variable("k"), new Variable("q"), + * new Pow(new Constant(-3), new Variable("r"))), ZERO, ZERO }, + * { ZERO, new Product(new Variable("k"), new Variable("q"), + * new Pow(new Constant(-3), new Variable("r"))), ZERO }, + * { ZERO, ZERO, + * new Product(new Variable("k"), new Variable("q"), + * new Pow(new Constant(-3), new Variable("r"))) } + * }, + * false, true); + * assertEquals(expected, space.covariantDerivative("\\mu", tensor, + * "\\nu")); + * } + * + * @Test + * void cov3() { + * Space space = DefaultSpaces.cartesian2d; + * Tensor tensor = ArrayTensor.tensor( + * new Object[][] { + * { square(new Variable("x")), new Product(TWO, new Variable("y")) }, + * { ZERO, new Sin(new Variable("x")) } + * }, + * true, false); + * assertEquals(space.covariantDerivative("a", tensor, "b", "c"), + * ArrayTensor.tensor( + * new Object[][][] { + * { + * { new Product(TWO, new Variable("x")), ZERO }, + * { ZERO, new Cos(new Variable("x")) } + * }, + * { + * { ZERO, TWO }, + * { ZERO, ZERO } + * } + * }, + * false, true, false)); + * + * } + * + * @Test + * void access1() { + * Tensor vector = ArrayTensor.tensor( + * new Object[] { + * new Product(new Variable("k"), new Variable("q"), new Pow(NEGATIVE_TWO, + * new Variable("r"))), + * ZERO, ZERO }, + * true); + * System.out.println(TensorTools.createFrom( + * List.of("\\beta", "a"), + * new boolean[] { false, true }, + * 3, + * new ElementProduct( + * TensorTools.indexTensor(vector, "\\alpha"), + * TensorTools.indexTensor(DefaultSpaces.spherical.christoffel, "\\alpha", + * "a", "\\beta")))); + * } + * + **/ + +} diff --git a/src/core/functions/GeneralFunction.java b/src/core/functions/GeneralFunction.java index 5110bb5a..ec7928da 100644 --- a/src/core/functions/GeneralFunction.java +++ b/src/core/functions/GeneralFunction.java @@ -8,6 +8,7 @@ import core.functions.commutative.Sum; import core.functions.commutative.integer.IntegerCommutativeFunction; import core.functions.endpoint.Constant; +import core.functions.endpoint.Placeholder; import core.functions.endpoint.Variable; import core.functions.unitary.integer.IntegerUnitaryFunction; import core.functions.unitary.piecewise.PiecewiseFunction; @@ -25,18 +26,24 @@ import java.util.function.Predicate; /** - * A {@link GeneralFunction} is the generalized abstract function used throughout the CAS. - * It is critical to note that ALL FUNCTIONS ARE IMMUTABLE: as a consequence, methods such as {@link #simplify()} return a function that has been simplified rather than simplifying the caller in place. + * A {@link GeneralFunction} is the generalized abstract function used + * throughout the CAS. + * It is critical to note that ALL FUNCTIONS ARE IMMUTABLE: as a consequence, + * methods such as {@link #simplify()} return a function that has been + * simplified rather than simplifying the caller in place. */ -public abstract class GeneralFunction implements Evaluable, Differentiable, Simplifiable, Comparable, Iterable, Outputable { +public abstract class GeneralFunction implements Evaluable, Differentiable, Simplifiable, Comparable, + Iterable, Outputable { /** - * Describes the order that a {@link GeneralFunction} should appear in a sorted array (used in {@link #compareTo(GeneralFunction)}) + * Describes the order that a {@link GeneralFunction} should appear in a sorted + * array (used in {@link #compareTo(GeneralFunction)}) */ @SuppressWarnings("ClassReferencesSubclass") public static final Class[] sortOrder = { Constant.class, // Must always be first Variable.class, + Placeholder.class, Product.class, Pow.class, Logb.class, @@ -52,25 +59,29 @@ public abstract class GeneralFunction implements Evaluable, Differentiable, Simp }; /** - * Caches derivatives with the key corresponding to the {@code varID} of the derivative + * Caches derivatives with the key corresponding to the {@code varID} of the + * derivative */ protected final Map derivatives = new HashMap<>(); /** * Returns a String representation of this {@link GeneralFunction} + * * @return String representation of this function */ public abstract String toString(); /** * Returns a clone of this {@link GeneralFunction} + * * @return a clone of this function */ public abstract GeneralFunction clone(); - /** - * Overloads {@link Evaluable#evaluate(Map)} with no arguments, passing a {@code Collections#EMPTY_MAP} by default + * Overloads {@link Evaluable#evaluate(Map)} with no arguments, passing a + * {@code Collections#EMPTY_MAP} by default + * * @return the function evaluated with no arguments */ @SuppressWarnings("unchecked") @@ -78,7 +89,6 @@ public double evaluate() { return evaluate(Collections.EMPTY_MAP); } - public GeneralFunction getSimplifiedDerivative(String varID) { if (Settings.cacheDerivatives && derivatives.containsKey(varID)) return derivatives.get(varID); @@ -98,6 +108,7 @@ public GeneralFunction getNthDerivative(String varID, int N) { /** * Returns the value of the derivative at {@code point} + * * @param varID the variable being differentiated against * @param point the point to find the derivative at * @return the value of the derivative at {@code point} @@ -108,32 +119,41 @@ public double derivativeAt(String varID, Map point) { } /** - * Replaces every {@link GeneralFunction} that satisfies the {@code test} using the action specified by {@code replacer} - * @param test checks if the function should be replaced + * Replaces every {@link GeneralFunction} that satisfies the {@code test} using + * the action specified by {@code replacer} + * + * @param test checks if the function should be replaced * @param replacer replaces the function * @return a new {@link GeneralFunction} with all replacements made */ - public abstract GeneralFunction substituteAll(Predicate test, Function replacer); + public abstract GeneralFunction substituteAll(Predicate test, + Function replacer); /** * Substitutes variables with functions as specified in a map - * @param toSubstitute the map between {@link Variable} strings and {@link GeneralFunction}s + * + * @param toSubstitute the map between {@link Variable} strings and + * {@link GeneralFunction}s * @return the new {@link GeneralFunction} after all substitutions are preformed */ public GeneralFunction substituteVariables(Map toSubstitute) { - return substituteAll(f -> (f instanceof Variable v && toSubstitute.containsKey(v.varID)), f -> toSubstitute.get(((Variable) f).varID)); + return substituteAll(f -> (f instanceof Variable v && toSubstitute.containsKey(v.varID)), + f -> toSubstitute.get(((Variable) f).varID)); } - /** * Returns true when the two fully-simplified functions are equal - * @param that The {@link GeneralFunction} that the current function is being checked against + * + * @param that The {@link GeneralFunction} that the current function is being + * checked against * @return true if the two functions are equal */ public abstract boolean equalsFunction(GeneralFunction that); /** - * Simplifies the two functions, then compares them with {@link #equalsFunction(GeneralFunction)} + * Simplifies the two functions, then compares them with + * {@link #equalsFunction(GeneralFunction)} + * * @param that the function to be compared against * @return true if they're equal when simplified */ @@ -143,6 +163,7 @@ public boolean equalsSimplified(GeneralFunction that) { /** * Compares two functions with {@link #equalsFunction(GeneralFunction)} + * * @param that the object to be compared against * @return true if they're equal */ @@ -154,13 +175,18 @@ public boolean equals(Object that) { /** * Used internally for comparing two functions of the same exact type + * * @param that the {@link GeneralFunction} that this is compared against * @return the comparison */ protected abstract int compareSelf(GeneralFunction that); /** - * {@link GeneralFunction}s of different types are sorted according to {@link #sortOrder} and {@link MiscTools#findClassValue(GeneralFunction)}, and functions of the same exact type are sorted using {@link #compareSelf(GeneralFunction)} + * {@link GeneralFunction}s of different types are sorted according to + * {@link #sortOrder} and {@link MiscTools#findClassValue(GeneralFunction)}, and + * functions of the same exact type are sorted using + * {@link #compareSelf(GeneralFunction)} + * * @param that the {@link GeneralFunction} that this is compared against * @return the comparison */ @@ -180,12 +206,14 @@ else if (this.getClass().equals(that.getClass())) /** * Returns a hash code value for this object + * * @return a hash code value for this object */ public abstract int hashCode(); /** * Returns an iterator over the operands of this {@link GeneralFunction} + * * @return an iterator over the operands of this {@link GeneralFunction} */ public abstract Iterator iterator(); diff --git a/src/core/functions/endpoint/Placeholder.java b/src/core/functions/endpoint/Placeholder.java new file mode 100644 index 00000000..70880c03 --- /dev/null +++ b/src/core/functions/endpoint/Placeholder.java @@ -0,0 +1,118 @@ +package core.functions.endpoint; + +import core.functions.GeneralFunction; +import core.tools.exceptions.IllegalNameException; +import java.util.Arrays; +import java.util.Map; +import java.util.function.Function; +import java.util.function.Predicate; + +public class Placeholder extends EndpointFunction { + + public final String label; + public final String[] variables; + public final int[] derivatives; + public final boolean printVariables; + + public Placeholder(String label, String... variables) { + this(label, true, variables, new int[variables.length]); + } + + public Placeholder(String label, boolean printVariables, String... variables) { + this(label, printVariables, variables, new int[variables.length]); + } + + public Placeholder(String label, boolean printVariables, String[] variables, int[] derivatives) { + if (label == null || label.isEmpty()) + throw new IllegalNameException("Placeholder label cannot be null or empty"); + if (variables == null || variables.length == 0) + throw new IllegalArgumentException("Placeholder variables cannot be null or empty"); + this.label = label; + this.printVariables = printVariables; + this.variables = variables; + this.derivatives = derivatives; + } + + public double evaluate(Map variableValues) { + return Double.NaN; + } + + public String toString() { + // return label + "(" + String.join(", ", variables) + ")"; + StringBuilder sb = new StringBuilder(); + sb.append(label); + if (Arrays.stream(derivatives).sum() > 0) { + if (sb.charAt(sb.length() - 1) == '}') { + sb.deleteCharAt(sb.length() - 1); + sb.append(","); + } else { + sb.append("_{"); + } + for (int i = 0; i < variables.length; i++) { + for (int j = 0; j < derivatives[i]; j++) { + sb.append(variables[i]); + } + } + sb.append("}"); + } + if (printVariables && variables.length > 0) { + sb.append("("); + for (int i = 0; i < variables.length; i++) { + sb.append(variables[i]); + if (i != variables.length - 1) + sb.append(", "); + } + sb.append(")"); + } + return sb.toString(); + } + + public Placeholder incrementDerivative(int index) { + int[] newDerivatives = Arrays.copyOf(derivatives, derivatives.length); + newDerivatives[index]++; + return new Placeholder(label, printVariables, variables, newDerivatives); + } + + public GeneralFunction getDerivative(String varID) { + for (int i = 0; i < variables.length; i++) { + if (variables[i].equals(varID)) { + return incrementDerivative(i); + } + } + return new Constant(0); + } + + public GeneralFunction clone() { + return new Placeholder(label, printVariables, variables, derivatives); + } + + public GeneralFunction simplify() { + return this; + } + + public GeneralFunction substituteAll(Predicate test, + Function replacer) { + return this; + } + + public boolean equalsFunction(GeneralFunction that) { + if (that instanceof Placeholder other) { + return this.label.equals(other.label) + && Arrays.equals(this.variables, other.variables) + && Arrays.equals(this.derivatives, other.derivatives); + } + return false; + } + + @SuppressWarnings({ "ConstantConditions" }) + public int compareSelf(GeneralFunction that) { + if (that instanceof Placeholder other) + return (this.label + this.variables.toString() + this.derivatives.toString()) + .compareTo(other.label + other.variables.toString() + other.derivatives.toString()); + return -1; + } + + public int hashCode() { + return label.hashCode() + Arrays.hashCode(variables) + Arrays.hashCode(derivatives); + } +} diff --git a/src/core/tools/Cosine.java b/src/core/tools/Cosine.java new file mode 100644 index 00000000..f37055cb --- /dev/null +++ b/src/core/tools/Cosine.java @@ -0,0 +1,5 @@ +package core.tools; + +public class Cosine { + +} diff --git a/src/core/tools/MiscTools.java b/src/core/tools/MiscTools.java index a3f91881..0e892d78 100644 --- a/src/core/tools/MiscTools.java +++ b/src/core/tools/MiscTools.java @@ -6,7 +6,10 @@ import core.functions.commutative.Product; import core.functions.commutative.Sum; import core.functions.endpoint.Constant; +import core.functions.unitary.trig.normal.*; +import core.functions.binary.Pow; import core.tools.helperclasses.Pair; +import core.tools.defaults.DefaultFunctions; import java.util.LinkedList; import java.util.List; @@ -17,10 +20,12 @@ */ public class MiscTools { - private MiscTools(){} + private MiscTools() { + } /** * Returns n factorial (n!) + * * @param n the number * @return n! */ @@ -34,7 +39,9 @@ else if (n <= 1) } /** - * Computes the GCD of the inputs. It is preferred to input {@code a > b}, but this is not explicitly necessary. + * Computes the GCD of the inputs. It is preferred to input {@code a > b}, but + * this is not explicitly necessary. + * * @param a the first input * @param b the second input * @return the GCD of the inputs @@ -44,7 +51,9 @@ public static int gcd(int a, int b) { } /** - * Returns the location of a {@link GeneralFunction} in its class-based sort order (see {@link GeneralFunction#sortOrder}) + * Returns the location of a {@link GeneralFunction} in its class-based sort + * order (see {@link GeneralFunction#sortOrder}) + * * @param function the function whose location in the class order is to be found * @return location in {@link GeneralFunction#sortOrder} */ @@ -58,18 +67,22 @@ public static int findClassValue(GeneralFunction function) { } /** - * Returns a list of the elements in this {@link Sum} with the constants stripped as a pair. Ex: {@code x^2+2sin(x)} becomes {@code [<1.0, x^2>, <2.0, sin(x)>]} + * Returns a list of the elements in this {@link Sum} with the constants + * stripped as a pair. Ex: {@code x^2+2sin(x)} becomes + * {@code [<1.0, x^2>, <2.0, sin(x)>]} + * * @param sum the sum whose constants should be stripped * @return the list of pairs as specified above */ public static List> stripConstantsOfSum(Sum sum) { GeneralFunction[] sumArray = sum.getFunctions(); List> strippedPairsArray = new LinkedList<>(); - for (GeneralFunction function: sumArray) { + for (GeneralFunction function : sumArray) { if (function instanceof Product multiply) { GeneralFunction[] terms = multiply.getFunctions(); if (terms[0] instanceof Constant constant) - strippedPairsArray.add(new Pair<>(constant.constant, new Product(ArrayTools.removeFunctionAt(terms, 0)).simplifyTrivialElement())); + strippedPairsArray.add(new Pair<>(constant.constant, + new Product(ArrayTools.removeFunctionAt(terms, 0)).simplifyTrivialElement())); else strippedPairsArray.add(new Pair<>(1.0, multiply)); } else { @@ -80,7 +93,10 @@ public static List> stripConstantsOfSum(Sum sum) { } /** - * Executes {@link CommutativeFunction#simplifyTrivialElement()} until the function is not a {@code CommutativeFunction} or has a argument count greater than one. Ex: {@code (((2*x)))} becomes {@code 2*x} + * Executes {@link CommutativeFunction#simplifyTrivialElement()} until the + * function is not a {@code CommutativeFunction} or has a argument count greater + * than one. Ex: {@code (((2*x)))} becomes {@code 2*x} + * * @param function the function to be simplified * @return the function with all layers removed */ @@ -91,7 +107,9 @@ public static GeneralFunction toFirstNonTrivial(GeneralFunction function) { } /** - * Prints a message, sleeping for {@link Settings#defaultSleep} between newlines, but not at the end + * Prints a message, sleeping for {@link Settings#defaultSleep} between + * newlines, but not at the end + * * @param message the message to print */ public static void printWithSleep(String message) { @@ -99,9 +117,11 @@ public static void printWithSleep(String message) { } /** - * Prints a message, sleeping for {@code time} seconds between newlines, but not at the end + * Prints a message, sleeping for {@code time} seconds between newlines, but not + * at the end + * * @param message the message to print - * @param time amount of seconds to sleep + * @param time amount of seconds to sleep */ public static void printWithSleep(String message, double time) { String[] lines = ParsingTools.newline.split(message); @@ -113,9 +133,13 @@ public static void printWithSleep(String message, double time) { } /** - * Prints a message, sleeping for {@link Settings#defaultSleep} between newlines, then sleeps that same amount at the end if {@code sleepAtEnd} is true. - * @param message the message to print - * @param sleepAtEnd denotes whether the message should end with a {@code sleep()} + * Prints a message, sleeping for {@link Settings#defaultSleep} between + * newlines, then sleeps that same amount at the end if {@code sleepAtEnd} is + * true. + * + * @param message the message to print + * @param sleepAtEnd denotes whether the message should end with a + * {@code sleep()} */ public static void printWithSleep(String message, boolean sleepAtEnd) { printWithSleep(message, Settings.defaultSleep); @@ -128,7 +152,7 @@ public static void printWithSleep(String message, boolean sleepAtEnd) { */ public static void sleep() { try { - TimeUnit.MILLISECONDS.sleep((long) (Settings.defaultSleep*1000)); + TimeUnit.MILLISECONDS.sleep((long) (Settings.defaultSleep * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } @@ -136,18 +160,21 @@ public static void sleep() { /** * Sleeps for {@code seconds} seconds + * * @param seconds the amount of seconds to sleep for */ public static void sleep(double seconds) { try { - TimeUnit.MILLISECONDS.sleep((long) (seconds*1000)); + TimeUnit.MILLISECONDS.sleep((long) (seconds * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } } /** - * Simplifies the input without executing any of the optional simplifications steps enabled and disabled in {@link Settings} + * Simplifies the input without executing any of the optional simplifications + * steps enabled and disabled in {@link Settings} + * * @param function the function to be minimally simplified * @return the minimally simplified version of the function */ @@ -158,4 +185,45 @@ public static GeneralFunction minimalSimplify(GeneralFunction function) { Settings.distributeFunctions = dF; return simplified; } + + public static GeneralFunction trigForSinners(GeneralFunction function) { + return function.substituteAll(f -> f instanceof TrigFunction, + f -> { + if (f instanceof Cos c) + return DefaultFunctions + .sqrt(DefaultFunctions.subtract(DefaultFunctions.ONE, + DefaultFunctions.square(new Sin(c.operand)))); + else if (f instanceof Tan t) + return DefaultFunctions.frac(new Sin(t.operand), DefaultFunctions + .sqrt(DefaultFunctions.subtract(DefaultFunctions.ONE, + DefaultFunctions.square(new Sin(t.operand))))); + else if (f instanceof Cot c) + return DefaultFunctions.frac(DefaultFunctions + .sqrt(DefaultFunctions.subtract(DefaultFunctions.ONE, + DefaultFunctions.square(new Sin(c.operand)))), + new Sin(c.operand)); + else if (f instanceof Sec s) + return DefaultFunctions.reciprocal(DefaultFunctions + .sqrt(DefaultFunctions.subtract(DefaultFunctions.ONE, + DefaultFunctions.square(new Sin(s.operand))))); + else if (f instanceof Cosh c) + return DefaultFunctions.sqrt(new Sum(DefaultFunctions.ONE, + DefaultFunctions.square(new Sinh(c.operand)))); + else if (f instanceof Tanh t) + return DefaultFunctions.frac(new Sinh(t.operand), DefaultFunctions + .sqrt(new Sum(DefaultFunctions.ONE, + DefaultFunctions.square(new Sinh(t.operand))))); + else if (f instanceof Coth c) + return DefaultFunctions.frac(DefaultFunctions + .sqrt(new Sum(DefaultFunctions.ONE, + DefaultFunctions.square(new Sinh(c.operand)))), + new Sinh(c.operand)); + else if (f instanceof Sech s) + return DefaultFunctions.reciprocal(DefaultFunctions + .sqrt(new Sum(DefaultFunctions.ONE, + DefaultFunctions.square(new Sinh(s.operand))))); + else + return f; + }).simplify(); + } } diff --git a/src/parsing/InfixTokenizer.java b/src/parsing/InfixTokenizer.java index db3a9959..8762bd0f 100644 --- a/src/parsing/InfixTokenizer.java +++ b/src/parsing/InfixTokenizer.java @@ -86,7 +86,7 @@ public static List tokenizeInfix(String infix) { infix = infix.replace("[", "(").replace("]", ")"); // Insert multiplication in expressions like 2x and 7(x*y+1)sin(3y) infix = adjacentMultiplier.matcher(infix).replaceAll(" * "); - // Turns expressions like x-y into x+-y, and turns expressions like x*y into x*/y (the '/' operator represents reciprocals) + // Turns expressions like x-y into x+-y, and turns expressions like x/y into x*/y (the '/' operator represents reciprocals) infix = subtractionFinder.matcher(division.matcher(infix).replaceAll("*/")).replaceAll("+-"); // Turns differentials like `dx` and `d x` into `\d x` infix = differential.matcher(infix).replaceAll("\\\\difn "); diff --git a/src/tensors/ArrayTensor.java b/src/tensors/ArrayTensor.java new file mode 100644 index 00000000..cb743680 --- /dev/null +++ b/src/tensors/ArrayTensor.java @@ -0,0 +1,52 @@ +package tensors; + +import core.functions.GeneralFunction; + +import java.util.List; +import java.util.stream.Collectors; + +public class ArrayTensor extends DirectedNestedArray implements Tensor { + + @SuppressWarnings("unchecked") + public static Tensor tensor(DirectedNested directedNestedArray) { + if (directedNestedArray instanceof DirectedEndpoint) + return new TensorEndpoint(((DirectedEndpoint) directedNestedArray).contained); + else if (directedNestedArray.getElements().get(0) instanceof DirectedEndpoint) + return new ArrayTensor( + directedNestedArray.getDirection(), + directedNestedArray.getElements().stream() + .map(e -> (DirectedEndpoint) e) + .map(e -> new TensorEndpoint(e.contained)) + .collect(Collectors.toList())); + else + return new ArrayTensor( + directedNestedArray.getDirection(), + directedNestedArray.getElements().stream() + .map(ArrayTensor::tensor) + .collect(Collectors.toList())); + } + + public static Tensor tensor(Nested nestedArray, boolean... directions) { + assert directions.length == nestedArray.getRank() + 1; + return tensor(direct(nestedArray, directions)); + } + + public static Tensor tensor(Object[] elements, boolean... directions) { + return tensor(direct(nest(elements), directions)); + } + + protected ArrayTensor(boolean isUpper, List elements) { + super(isUpper, elements); + } + + @Override + public void setAtIndex(GeneralFunction toSet, int... index) { + throw new UnsupportedOperationException("Tensors are final, and their elements should never be changed."); + } + + public static class TensorEndpoint extends DirectedEndpoint implements Tensor { + public TensorEndpoint(GeneralFunction contained) { + super(contained); + } + } +} diff --git a/src/tensors/DefaultSpaces.java b/src/tensors/DefaultSpaces.java new file mode 100644 index 00000000..97fd4de7 --- /dev/null +++ b/src/tensors/DefaultSpaces.java @@ -0,0 +1,84 @@ +package tensors; + +import core.functions.commutative.Product; +import core.functions.endpoint.Variable; +import core.functions.unitary.trig.normal.Sin; + +import static core.tools.defaults.DefaultFunctions.*; + +@SuppressWarnings("NonAsciiCharacters") +public class DefaultSpaces { + + public static final Variable G = new Variable("G"); + public static final Variable M = new Variable("M"); + public static final Variable t = new Variable("t"); + public static final Variable x = new Variable("x"); + public static final Variable y = new Variable("y"); + public static final Variable z = new Variable("z"); + public static final Variable r = new Variable("r"); + public static final Variable r_s = new Variable("\\r_s"); + public static final Variable θ = new Variable("θ"); + public static final Variable φ = new Variable("φ"); + public static final Variable ψ = new Variable("ψ"); + + public static final Space cartesian2d = Space.fromDiagonalMetric(new String[] { "x", "y" }, + ONE, + ONE); + + public static final Space cartesian3d = Space.fromDiagonalMetric(new String[] { "x", "y", "z" }, + ONE, + ONE, + ONE); + + public static final Space polar = Space.fromDiagonalMetric(new String[] { "r", "θ" }, + ONE, + square(r)); + + public static final Space cylindrical = Space.fromDiagonalMetric(new String[] { "r", "θ", "z" }, + ONE, + square(r), + ONE); + + public static final Space spherical = Space.fromDiagonalMetric(new String[] { "r", "θ", "φ" }, + ONE, + square(r), + square(new Product(r, new Sin(θ)))); + + public static final Space minkowski1d = Space.fromDiagonalMetric(new String[] { "t", "x" }, + NEGATIVE_ONE, + ONE); + + public static final Space minkowski2d = Space.fromDiagonalMetric(new String[] { "t", "x", "y" }, + NEGATIVE_ONE, + ONE, + ONE); + + public static final Space minkowski = Space.fromDiagonalMetric(new String[] { "t", "x", "y", "z" }, + NEGATIVE_ONE, + ONE, + ONE, + ONE); + + public static final Space s2 = Space.fromDiagonalMetric(new String[] { "θ", "φ" }, + ONE, + square(new Sin(θ))); + + public static final Space s3 = Space.fromDiagonalMetric(new String[] { "ψ", "θ", "φ" }, + ONE, + square(new Sin(ψ)), + square(new Product(new Sin(ψ), new Sin(θ)))); + + public static final Space schwarzschild = Space.fromDiagonalMetric(new String[] { "t", "r", "θ", "φ" }, + negative(subtract(ONE, new Product(r_s, reciprocal(r)))), + reciprocal(subtract(ONE, new Product(r_s, reciprocal(r)))), + square(r), + square(new Product(r, new Sin(θ)))); + + private DefaultSpaces() { + } + + public static void initialize() { + // Method does nothing, and serves to force the JVM to initialize the class + } + +} diff --git a/src/tensors/DirectedNested.java b/src/tensors/DirectedNested.java new file mode 100644 index 00000000..4291ac63 --- /dev/null +++ b/src/tensors/DirectedNested.java @@ -0,0 +1,13 @@ +package tensors; + +import java.util.function.UnaryOperator; + +public interface DirectedNested, T> extends Nested { + + boolean matches(DirectedNested other); // TODO test if deepMatches accounts for direction + + boolean getDirection(); + + boolean[] getDirections(); + +} diff --git a/src/tensors/DirectedNestedArray.java b/src/tensors/DirectedNestedArray.java new file mode 100644 index 00000000..9b25e49e --- /dev/null +++ b/src/tensors/DirectedNestedArray.java @@ -0,0 +1,93 @@ +package tensors; + +import java.util.List; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; + +public class DirectedNestedArray, T> extends NestedArray + implements DirectedNested { + + private final boolean isUpper; + private final boolean[] directions; + + @SuppressWarnings({ "unchecked" }) + public static , T> DirectedNested direct(Nested nestedArray, + boolean... directions) { + if (nestedArray instanceof NestedEndpoint) + return new DirectedEndpoint<>(((NestedEndpoint) nestedArray).contained); + else if (nestedArray.getElements().get(0) instanceof NestedEndpoint) + return new DirectedNestedArray<>( + directions[directions.length - nestedArray.getRank()], + nestedArray.getElements().stream() + .map(e -> (NestedEndpoint) e) + .map(e -> (I) new DirectedEndpoint(e.contained)) + .collect(Collectors.toList())); + else + return new DirectedNestedArray<>( + directions[directions.length - nestedArray.getRank()], + nestedArray.getElements().stream() + .map(e -> (I) direct(e, directions)) + .collect(Collectors.toList())); + } + + public static , T> DirectedNested direct(Object[] elements, + boolean... directions) { + return direct(nest(elements), directions); + } + + protected DirectedNestedArray(boolean isUpper, List elements) { + super(elements); + this.isUpper = isUpper; + directions = calculateDirections(); + } + + @Override + public boolean matches(DirectedNested other) { + return isUpper == other.getDirection() && this.matches(other); + } + + public boolean getDirection() { + return isUpper; + } + + private boolean[] calculateDirections() { + boolean[] lowerDimensions = elements.get(0).getDirections(); + boolean[] dimensions = new boolean[lowerDimensions.length + 1]; + dimensions[0] = isUpper; + System.arraycopy(lowerDimensions, 0, dimensions, 1, lowerDimensions.length); + return dimensions; + } + + @Override + public boolean[] getDirections() { + return directions; + } + + @Override + public String toString() { + return (isUpper ? "v" : "c") + super.toString(); + } + + public static class DirectedEndpoint, T> extends NestedEndpoint + implements DirectedNested { + + public DirectedEndpoint(T contained) { + super(contained); + } + + @Override + public boolean matches(DirectedNested other) { + return other instanceof DirectedEndpoint; + } + + @Override + public boolean getDirection() { + throw new IllegalStateException("Endpoints have no direction."); // TODO deal with this exception + } + + @Override + public boolean[] getDirections() { + return new boolean[0]; + } + } +} diff --git a/src/tensors/Indexable.java b/src/tensors/Indexable.java new file mode 100644 index 00000000..b07c6be9 --- /dev/null +++ b/src/tensors/Indexable.java @@ -0,0 +1,7 @@ +package tensors; + +public interface Indexable { + T getAtIndex(int... index); + void setAtIndex(T toSet, int... index); + int[] getDimensions(); +} diff --git a/src/tensors/Nested.java b/src/tensors/Nested.java new file mode 100644 index 00000000..23dbb91a --- /dev/null +++ b/src/tensors/Nested.java @@ -0,0 +1,32 @@ +package tensors; + +import java.util.List; +import java.util.function.UnaryOperator; + +public interface Nested, T> extends Indexable { + + int getRank(); + + boolean matches(Nested other); + + default boolean deepMatches(Nested other) { + return matches(other) && new Zip<>( // TODO test this with opposite upper/lower + getElements().iterator(), + other.getElements().iterator(), + Nested::deepMatches + ).fullReduce(true, (t, r) -> t && r); + } + + List getElements(); + + Nested modifyWith(UnaryOperator elementModifier, + UnaryOperator endpointModifier); + + default Nested modifyWith(UnaryOperator endpointModifier) { + return modifyWith(i -> i, endpointModifier); + } + + String toString(); + + +} diff --git a/src/tensors/NestedArray.java b/src/tensors/NestedArray.java new file mode 100644 index 00000000..edc27219 --- /dev/null +++ b/src/tensors/NestedArray.java @@ -0,0 +1,181 @@ +package tensors; + +import java.util.*; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class NestedArray, T> implements Nested { + + public static int indexOffset = 0; + public static boolean assertValidity = true; + + private final int rank; + protected final List elements; + private final int[] dimensions; + + @SuppressWarnings({ "unchecked" }) + public static , T> NestedArray nest(Object[] elements) { + if (elements[0] instanceof Object[]) + return new NestedArray<>( + Arrays.stream(elements) + .map(e -> (I) nest((Object[]) e)) + .collect(Collectors.toList())); + else + return new NestedArray<>( + Arrays.stream(elements) + .map(e -> (I) new NestedEndpoint<>((T) e)) + .collect(Collectors.toList())); + } + + @SuppressWarnings("unchecked") + public static , T> Nested createSquare(int rank, int dimension, T fill) { + if (rank == 0) + return new NestedEndpoint<>(fill); + else + return new NestedArray<>( + IntStream.range(0, dimension) + .mapToObj(t -> (I) createSquare(rank - 1, dimension, fill)) + .collect(Collectors.toList())); + } + + protected NestedArray(List elements) { + this.elements = elements; + if (assertValidity) + assertValidity(); + this.rank = calculateRank(); + this.dimensions = calculateDimensions(); + } + + private void assertValidity() { + try { + Iterator iter = elements.listIterator(); + I check = iter.next(); + while (iter.hasNext()) + if (!check.deepMatches(iter.next())) + throw new IllegalArgumentException("Elements of NestedArray do not satisfy deepMatches."); + } catch (NullPointerException e) { + throw new IllegalStateException("Exception in assertValidity", e); + } + } + + private int calculateRank() { + return elements.get(0).getRank() + 1; + } + + public int getRank() { + return rank; + } + + public int getSize() { + return elements.size(); + } + + @Override + public T getAtIndex(int... index) { // maybe there should be a check both here and below for length + return elements.get(index[index.length - rank] + indexOffset).getAtIndex(index); + } + + @Override + public void setAtIndex(T toSet, int... index) { + elements.get(index[index.length - rank] + indexOffset).setAtIndex(toSet, index); + } + + private int[] calculateDimensions() { + int[] lowerDimensions = elements.get(0).getDimensions(); + int[] dimensions = new int[lowerDimensions.length + 1]; + dimensions[0] = elements.size(); + System.arraycopy(lowerDimensions, 0, dimensions, 1, lowerDimensions.length); + return dimensions; + } + + @Override + public int[] getDimensions() { + return dimensions; + } + + public boolean matches(Nested other) { + return elements.size() == other.getElements().size(); + } + + public List getElements() { + return elements; + } + + @SuppressWarnings("unchecked") + public Nested modifyWith(UnaryOperator elementModifier, + UnaryOperator endpointModifier) { + return new NestedArray<>( + elements.stream() + .map(e -> (I) e.modifyWith(elementModifier, endpointModifier)) + .map(elementModifier) + .collect(Collectors.toList())); + } + + public String toString() { + return elements.toString(); + } + + @SuppressWarnings("unchecked") + public boolean equals(Object other) { + return other instanceof Nested nested && equals((Nested) nested); + } + + public boolean equals(Nested other) { // TODO test rigorously with subclasses + return matches(other) && elements.equals(other.getElements()); + } + + public static class NestedEndpoint, T> implements Nested { + + protected T contained; + + public NestedEndpoint(T contained) { + this.contained = contained; + } + + @Override + public int getRank() { + return 0; + } + + @Override + public boolean matches(Nested other) { + return other instanceof NestedEndpoint; + } + + @Override + public List getElements() { + return Collections.emptyList(); + } + + @Override + public Nested modifyWith(UnaryOperator elementModifier, UnaryOperator endpointModifier) { + return new NestedEndpoint<>(endpointModifier.apply(contained)); + } + + @Override + public T getAtIndex(int... index) { + return contained; + } + + @Override + public void setAtIndex(T toSet, int... index) { + contained = toSet; + } + + @Override + public int[] getDimensions() { + return new int[0]; + } + + @Override + public String toString() { + return String.valueOf(contained); + } + + public boolean equals(Object other) { + return other instanceof NestedEndpoint endpoint && contained.equals(endpoint.contained); + } + + } +} diff --git a/src/tensors/Space.java b/src/tensors/Space.java new file mode 100644 index 00000000..94d4d1d7 --- /dev/null +++ b/src/tensors/Space.java @@ -0,0 +1,176 @@ +package tensors; + +import core.functions.GeneralFunction; +import core.functions.commutative.Sum; +import core.functions.endpoint.Constant; +import core.functions.unitary.transforms.PartialDerivative; +import core.tools.defaults.DefaultFunctions; +import tensors.elementoperations.ElementAccessor; +import tensors.elementoperations.ElementProduct; +import tensors.elementoperations.ElementSum; +import tensors.elementoperations.ElementWrapper; + +import java.util.*; + +import static tensors.TensorTools.*; +import static tensors.TensorTools.negative; +import static core.tools.defaults.DefaultFunctions.*; + +public class Space { + + protected final String[] variableStrings; + public final int dimension; + public final Tensor metric; + public final Tensor inverseMetric; + public final Tensor delta; + public final DirectedNested christoffel; + public final Tensor riemannTensor; + public final Tensor ricciTensor; + public final GeneralFunction ricciScalar; + public final Tensor einsteinTensor; + + public Space(String[] variableStrings, Tensor metric, Tensor inverseMetric) { + this.variableStrings = variableStrings; + this.dimension = variableStrings.length; + this.metric = metric; + this.inverseMetric = inverseMetric; + this.delta = TensorTools.identityTensor(dimension); + christoffel = calculateChristoffel(); + riemannTensor = calculateRiemannTensor(); + ricciTensor = TensorTools.magicTensor( + riemannTensor.index("\\gamma", "\\beta", "\\gamma", "\\delta")); + ricciScalar = TensorTools.unwrap(TensorTools.magicTensor( + product(ricciTensor.index("\\alpha", "\\beta"), inverseMetric.index("\\alpha", "\\beta")))); + einsteinTensor = TensorTools.magicTensor( + sum(ricciTensor.index("\\alpha", "\\beta"), + product(wrap(NEGATIVE_HALF), wrap(ricciScalar), metric.index("\\alpha", "\\beta")))); + } + + public static Space fromDiagonalMetric(String[] variableStrings, GeneralFunction... diagonal) { + if (variableStrings.length != diagonal.length) + throw new IllegalArgumentException("variableStrings length " + variableStrings.length + + " and diagonal length " + diagonal.length + " do not match."); + GeneralFunction[][] metric = new GeneralFunction[diagonal.length][diagonal.length]; + for (GeneralFunction[] row : metric) + Arrays.fill(row, ZERO); + GeneralFunction[][] inverseMetric = new GeneralFunction[diagonal.length][diagonal.length]; + for (GeneralFunction[] row : inverseMetric) + Arrays.fill(row, ZERO); + + for (int i = 0; i < diagonal.length; i++) { + metric[i][i] = diagonal[i].simplify(); + inverseMetric[i][i] = DefaultFunctions.reciprocal(diagonal[i]).simplify(); + } + + return new Space( + variableStrings, + ArrayTensor.tensor(metric, false, false), + ArrayTensor.tensor(inverseMetric, true, true)); + } + + public Partial partial(String index, ElementAccessor operand) { + return new Partial(index, operand); + } + + private DirectedNested calculateChristoffel() { + // note we're down up down + return createFrom( + List.of("\\mu", "\\sigma", "\\nu"), + new boolean[] { false, true, false }, + product( + wrap(HALF), + inverseMetric.index("\\sigma", "\\rho"), + sum( + partial("\\mu", metric.index("\\nu", "\\rho")), + partial("\\nu", metric.index("\\rho", "\\mu")), + negative(partial("\\rho", metric.index("\\mu", "\\nu")))))); + } + + private Tensor calculateRiemannTensor() { + // note the factor of 1/2 in this convention + return ArrayTensor.tensor(createFrom( + List.of("\\alpha", "\\beta", "\\gamma", "\\delta"), + new boolean[] { false, false, true, false }, + product( + wrap(HALF), + sum( + partial("\\alpha", + TensorTools.indexTensor(christoffel, "\\beta", "\\gamma", "\\delta")), + product( + TensorTools.indexTensor(christoffel, "\\alpha", "\\gamma", "\\sigma"), + TensorTools.indexTensor(christoffel, "\\beta", "\\sigma", "\\delta")), + negative(partial("\\beta", + TensorTools.indexTensor(christoffel, "\\alpha", "\\gamma", "\\delta"))), + negative(product( + TensorTools.indexTensor(christoffel, "\\beta", "\\gamma", "\\sigma"), + TensorTools.indexTensor(christoffel, "\\alpha", "\\sigma", "\\delta"))))))); + } + + public Tensor covariantDerivative(String respectTo, Tensor tensor, String... tensorIndices) { + // TODO assert tensorIndices length matches rank + // TODO assert alpha is free and can be dummy + int oldRank = tensor.getRank(); + boolean[] oldDirections = tensor.getDirections(); + ElementAccessor[] toAdd = new ElementAccessor[oldRank + 1]; + int dimension = new ElementWrapper(tensor, tensorIndices).getDimension(); + + String[] currentTensorIndices = tensorIndices.clone(); + String current; + String dummy = "\\dmy" + (hashCode() ^ tensor.hashCode() ^ respectTo.hashCode()); + for (int i = 0; i < oldRank; i++) { + current = tensorIndices[i]; + currentTensorIndices[i] = dummy; + if (oldDirections[i]) + toAdd[i] = new ElementProduct(new ElementWrapper(tensor, currentTensorIndices.clone()), + new ElementWrapper(christoffel, dummy, current, respectTo)); + else + toAdd[i] = negative(new ElementProduct(new ElementWrapper(tensor, currentTensorIndices.clone()), + new ElementWrapper(christoffel, current, dummy, respectTo))); + currentTensorIndices[i] = current; + } + toAdd[oldRank] = partial(respectTo, new ElementWrapper(tensor, tensorIndices)); + + boolean[] newDirections = new boolean[oldRank + 1]; + newDirections[0] = false; + System.arraycopy(oldDirections, 0, newDirections, 1, oldRank); + + List newIndices = new ArrayList<>(List.of(tensorIndices)); + newIndices.add(0, respectTo); + + return ArrayTensor.tensor( + createFrom( + newIndices, + newDirections, + new ElementSum(toAdd))); + } + + public class Partial implements ElementAccessor { + + public final ElementAccessor operand; + public final String index; + + public Partial(String index, ElementAccessor operand) { + this.operand = operand; + this.index = index; + } + + @Override + public GeneralFunction getValueAt(Map indexValues, Map toSubstitute) { + return new PartialDerivative(operand.getValueAt(indexValues, toSubstitute), + variableStrings[indexValues.get(index)]); + } + + @Override + public void getIndices(Map indexStructure) { + TensorTools.addIndexStructure(index, false, indexStructure); + operand.getIndices(indexStructure); + } + + @Override + public int getDimension() { + return operand.getDimension(); + } + + } + +} diff --git a/src/tensors/Tensor.java b/src/tensors/Tensor.java new file mode 100644 index 00000000..4ba046c3 --- /dev/null +++ b/src/tensors/Tensor.java @@ -0,0 +1,18 @@ +package tensors; + +import java.util.function.UnaryOperator; + +import core.functions.GeneralFunction; +import tensors.elementoperations.ElementWrapper; + +public interface Tensor extends DirectedNested { + + default ElementWrapper index(String... indices) { + return TensorTools.indexTensor(this, indices); + } + + default Tensor modifyWithTensor(UnaryOperator endpointModifier) { + return ArrayTensor.tensor(ArrayTensor.direct(modifyWith(endpointModifier), getDirections())); + } + +} diff --git a/src/tensors/TensorTools.java b/src/tensors/TensorTools.java new file mode 100644 index 00000000..001a5fee --- /dev/null +++ b/src/tensors/TensorTools.java @@ -0,0 +1,289 @@ +package tensors; + +import core.functions.GeneralFunction; +import core.functions.commutative.Sum; +import core.functions.endpoint.Constant; +import core.functions.endpoint.Placeholder; +import core.tools.MiscTools; +import core.tools.defaults.DefaultFunctions; +import static core.tools.defaults.DefaultFunctions.reciprocal; +import core.tools.helperclasses.Pair; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import tensors.elementoperations.*; +import tensors.elementoperations.ElementAccessor.IndexStructure; + +public class TensorTools { + + public static final GeneralFunctionWrapper WRAPPED_ONE = wrap(DefaultFunctions.ONE); + public static final GeneralFunctionWrapper WRAPPED_HALF = wrap(DefaultFunctions.HALF); + public static final GeneralFunctionWrapper WRAPPED_NEGATIVE_ONE = wrap(DefaultFunctions.NEGATIVE_ONE); + + public static DirectedNested createFrom(List freeIndices, boolean[] directions, + ElementAccessor formula) { + int dimension = formula.getDimension(); + Nested array = NestedArray.createSquare(freeIndices.size(), dimension, null); + Map indexValues = new HashMap<>(); + Map toSubstitute = new HashMap<>(); + + Map formulaStructure = new HashMap<>(); + formula.getIndices(formulaStructure); + Set toContract = new HashSet<>(); + Set uncontracted = new HashSet<>(); + for (Map.Entry entry : formulaStructure.entrySet()) { + String index = entry.getKey(); + IndexStructure structure = entry.getValue(); + if (structure == IndexStructure.CONTRACTED) + toContract.add(index); + else if (structure == IndexStructure.TWODOWN) + throw new IllegalArgumentException("Index " + index + " is repeated down twice."); + else if (structure == IndexStructure.TWOUP) + throw new IllegalArgumentException("Index " + index + " is repeated up twice."); + else + uncontracted.add(index); + + } + if (!Set.copyOf(freeIndices).equals(uncontracted)) + throw new IllegalArgumentException("The free indices " + freeIndices + " do not match the uncontracted " + + uncontracted); + + List> contractedIndexValuesList = new ArrayList<>(); + contractedIndexValuesList.add(new HashMap<>()); + for (String index : toContract) { + List> newCIVL = new ArrayList<>(); + for (Map contractedIndexValues : contractedIndexValuesList) { + for (int i = 0; i < dimension; i++) { + Map newContractedIndexValues = new HashMap<>(contractedIndexValues); + newContractedIndexValues.put(index, i); + newCIVL.add(newContractedIndexValues); + } + } + contractedIndexValuesList = newCIVL; + } + assert contractedIndexValuesList.size() == Math.pow(dimension, toContract.size()); + + int[] freeValues = new int[freeIndices.size()]; + do { + for (int i = 0; i < freeValues.length; i++) { + indexValues.put(freeIndices.get(i), freeValues[i]); + toSubstitute.put(freeIndices.get(i), new Constant(freeValues[i])); // TODO make this more efficient by + // replacing the loop with stuff in + // incrementArray + } + GeneralFunction[] toAdd = new GeneralFunction[contractedIndexValuesList.size()]; + for (int i = 0; i < contractedIndexValuesList.size(); i++) { + HashMap curIndexValues = new HashMap<>(indexValues); + HashMap curToSubstitute = new HashMap<>(toSubstitute); + curIndexValues.putAll(contractedIndexValuesList.get(i)); + curToSubstitute.putAll(contractedIndexValuesList.get(i).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new Constant(e.getValue())))); + + toAdd[i] = formula.getValueAt(curIndexValues, curToSubstitute); + } + array.setAtIndex(new Sum(toAdd).simplify(), freeValues); + } while (directions.length != 0 && incrementArray(freeValues, dimension, 0)); + + return DirectedNestedArray.direct(array, directions); + } + + private static boolean incrementArray(int[] array, int max, int start) { + array[start]++; + if (array[start] < max) + return true; + array[start] = 0; + if (start + 1 < array.length) + return incrementArray(array, max, start + 1); + return false; + } + + public static ElementWrapper indexTensor(DirectedNested toAccess, String... indices) { + return new ElementWrapper(toAccess, indices); + } + + public static GeneralFunctionWrapper wrap(GeneralFunction toWrap) { + return new GeneralFunctionWrapper(toWrap); + } + + public static ElementAccessor sum(ElementAccessor... elements) { + return new ElementSum(elements); + } + + public static ElementAccessor product(ElementAccessor... elements) { + if (elements.length == 0) + return WRAPPED_ONE; + if (elements.length == 1) + return elements[0]; + + ElementProduct current = new ElementProduct(elements[0], elements[1]); + for (int i = 2; i < elements.length; i++) + current = new ElementProduct(current, elements[i]); + + return current; + } + + public static ElementAccessor negative(ElementAccessor elementAccessor) { + return new ElementProduct(WRAPPED_NEGATIVE_ONE, elementAccessor); + } + + public static Tensor identityTensor(int dimension) { + GeneralFunction[][] delta = new GeneralFunction[dimension][dimension]; + for (GeneralFunction[] row : delta) + Arrays.fill(row, DefaultFunctions.ZERO); + + for (int i = 0; i < dimension; i++) { + delta[i][i] = DefaultFunctions.ONE; + } + return ArrayTensor.tensor(delta, true, false); + } + + public static Pair placeholderMetrics(String... variables) { + int dimension = variables.length; + GeneralFunction[][] elements = new GeneralFunction[dimension][dimension]; + GeneralFunction[][] inverseElements = new GeneralFunction[dimension][dimension]; + for (int i = 0; i < dimension; i++) { + for (int j = 0; j < dimension; j++) { + int i_ = Math.min(i, j); + int j_ = Math.max(i, j); + String element_suffix = variables[i_] + variables[j_] + "}"; + elements[i][j] = new Placeholder("g_{" + element_suffix, false, variables); + inverseElements[i][j] = new Placeholder("g^{" + element_suffix, false, variables); + } + } + Tensor metric = ArrayTensor.tensor(elements, false, false); + Tensor inverseMetric = ArrayTensor.tensor(inverseElements, true, true); + return new Pair<>(metric, inverseMetric); + } + + public static Pair placeholderDiagonalMetrics(String... variables) { + int dimension = variables.length; + GeneralFunction[][] elements = new GeneralFunction[dimension][dimension]; + GeneralFunction[][] inverseElements = new GeneralFunction[dimension][dimension]; + for (int i = 0; i < dimension; i++) { + for (int j = 0; j < dimension; j++) { + if (i != j) { + elements[i][j] = DefaultFunctions.ZERO; + inverseElements[i][j] = DefaultFunctions.ZERO; + } else { + String element_string = "g_{" + variables[i] + variables[i] + "}"; + elements[i][i] = new Placeholder(element_string, false, variables); + inverseElements[i][i] = reciprocal(elements[i][i]); + } + } + } + Tensor metric = ArrayTensor.tensor(elements, false, false); + Tensor inverseMetric = ArrayTensor.tensor(inverseElements, true, true); + return new Pair<>(metric, inverseMetric); + } + + public static String prettyString(DirectedNested tensor, Space space, + String... indexLabels) { + String[] coords = space.variableStrings; + int dims = coords.length; + boolean[] directions = tensor.getDirections(); + int depth = directions.length; + if (indexLabels.length != depth) { + throw new IllegalArgumentException("indexLabels length " + indexLabels.length + " and depth " + depth + + " do not match."); + } + StringBuilder sb = new StringBuilder(); + sb.append("Directions are "); + for (int i = 0; i < depth; i++) { + sb.append(directions[i] ? "upper" : "lower"); + if (i != depth - 1) + sb.append(", "); + } + sb.append("\n"); + prettyStringHelper(sb, tensor.getDimensions(), depth, new int[depth], 0, coords, directions, indexLabels, + tensor); + return sb.toString(); + } + + public static void prettyStringHelper(StringBuilder sb, int[] dimensions, int depth, int[] currentIndex, + int currentDepth, String[] coords, boolean[] directions, String[] indexLabels, + DirectedNested tensor) { + if (currentDepth == depth) { + GeneralFunction cur = tensor.getAtIndex(currentIndex); + if (cur.equals(DefaultFunctions.ZERO)) + return; + for (int i = 0; i < currentIndex.length; i++) { + sb.append(indexLabels[i]); + sb.append("="); + sb.append(coords[currentIndex[i]]); + if (i != currentIndex.length - 1) + sb.append(", "); + } + sb.append(": "); + sb.append(cur.toString()); + sb.append("\n"); + return; + } + for (int i = 0; i < dimensions[currentDepth]; i++) { + currentIndex[currentDepth] = i; + prettyStringHelper(sb, dimensions, depth, currentIndex, currentDepth + 1, coords, directions, indexLabels, + tensor); + } + } + + public static void addIndexStructure(String index, boolean direction, Map indexStructure) { + // direction=false is down + if (direction) { + if (indexStructure.containsKey(index)) { + if (indexStructure.get(index) == IndexStructure.DOWN) + indexStructure.put(index, IndexStructure.CONTRACTED); + else if (indexStructure.get(index) == IndexStructure.UP + || indexStructure.get(index) == IndexStructure.CONTRACTED) + indexStructure.put(index, IndexStructure.TWOUP); + } else { + indexStructure.put(index, IndexStructure.UP); + } + } else { + if (indexStructure.containsKey(index)) { + if (indexStructure.get(index) == IndexStructure.UP) + indexStructure.put(index, IndexStructure.CONTRACTED); + else if (indexStructure.get(index) == IndexStructure.DOWN + || indexStructure.get(index) == IndexStructure.CONTRACTED) + indexStructure.put(index, IndexStructure.TWODOWN); + } else { + indexStructure.put(index, IndexStructure.DOWN); + } + } + } + + public static Tensor magicTensor(ElementAccessor formula) { + Map indexStructure = new HashMap<>(); + formula.getIndices(indexStructure); + List freeIndices = new ArrayList<>(); + List directionsList = new ArrayList<>(); + for (var entry : indexStructure.entrySet()) { + String index = entry.getKey(); + IndexStructure structure = entry.getValue(); + if (structure == IndexStructure.UP) { + freeIndices.add(index); + directionsList.add(true); + } else if (structure == IndexStructure.DOWN) { + freeIndices.add(index); + directionsList.add(false); + } + } + // convert directions list to array + boolean[] directions = new boolean[directionsList.size()]; + for (int i = 0; i < directionsList.size(); i++) { + directions[i] = directionsList.get(i); + } + DirectedNested tensor = createFrom(freeIndices, directions, formula); + + return ArrayTensor.tensor(tensor).modifyWithTensor(MiscTools::trigForSinners); + } + + public static GeneralFunction unwrap(DirectedNested tensor) { + assert tensor.getRank() == 0 : "Tensor is not a scalar: " + tensor.getDimensions(); + return tensor.getAtIndex(); + } + +} diff --git a/src/tensors/Zip.java b/src/tensors/Zip.java new file mode 100644 index 00000000..924cafeb --- /dev/null +++ b/src/tensors/Zip.java @@ -0,0 +1,37 @@ +package tensors; + +import java.util.Iterator; +import java.util.function.BiFunction; + +public class Zip implements Iterator { + + protected Iterator first; + protected Iterator second; + protected BiFunction combiner; + + public Zip(Iterator first, Iterator second, BiFunction combiner) { + this.first = first; + this.second = second; + this.combiner = combiner; + } + + + @Override + public boolean hasNext() { + if (first.hasNext() ^ second.hasNext()) + throw new IllegalStateException("Iterators do not have equal size in zip."); + return first.hasNext(); + } + + @Override + public T next() { + return combiner.apply(first.next(), second.next()); + } + + public R fullReduce(R identity, BiFunction combiner) { + R current = identity; + while (hasNext()) + current = combiner.apply(current, next()); + return current; + } +} diff --git a/src/tensors/elementoperations/ElementAccessor.java b/src/tensors/elementoperations/ElementAccessor.java new file mode 100644 index 00000000..6a326487 --- /dev/null +++ b/src/tensors/elementoperations/ElementAccessor.java @@ -0,0 +1,22 @@ +package tensors.elementoperations; + +import core.functions.GeneralFunction; + +import java.util.Map; +import java.util.Set; + +public interface ElementAccessor { + + // TODO pull dimension out to here + + GeneralFunction getValueAt(Map indexValues, Map toSubstitute); + + void getIndices(Map indexStructure); + + int getDimension(); + + public static enum IndexStructure { + UP, DOWN, CONTRACTED, TWODOWN, TWOUP + } + +} diff --git a/src/tensors/elementoperations/ElementProduct.java b/src/tensors/elementoperations/ElementProduct.java new file mode 100644 index 00000000..1447dba1 --- /dev/null +++ b/src/tensors/elementoperations/ElementProduct.java @@ -0,0 +1,42 @@ +package tensors.elementoperations; + +import core.functions.GeneralFunction; +import core.functions.commutative.Product; +import core.functions.commutative.Sum; +import core.functions.endpoint.Constant; + +import java.util.*; + +public class ElementProduct implements ElementAccessor { + + private final ElementAccessor first; + private final ElementAccessor second; + + public ElementProduct(ElementAccessor first, ElementAccessor second) { + this.first = first; + this.second = second; + } + + public GeneralFunction getValueAt(Map indexValues, Map toSubstitute) { + return new Product( + first.getValueAt(indexValues, toSubstitute), + second.getValueAt(indexValues, toSubstitute)); + } + + public void getIndices(Map indexStructure) { + first.getIndices(indexStructure); + second.getIndices(indexStructure); + } + + public int getDimension() { + int firstDimension = first.getDimension(); + int secondDimension = second.getDimension(); + if (firstDimension == -1 || secondDimension == -1) { + return Math.max(firstDimension, secondDimension); + } else { + assert firstDimension == secondDimension; + return firstDimension; + } + } + +} \ No newline at end of file diff --git a/src/tensors/elementoperations/ElementSum.java b/src/tensors/elementoperations/ElementSum.java new file mode 100644 index 00000000..edf6252d --- /dev/null +++ b/src/tensors/elementoperations/ElementSum.java @@ -0,0 +1,137 @@ +package tensors.elementoperations; + +import core.functions.GeneralFunction; +import core.functions.commutative.Sum; +import core.functions.endpoint.Constant; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class ElementSum implements ElementAccessor { + + private final ElementAccessor[] elements; + + public ElementSum(ElementAccessor... elements) { + this.elements = elements; + } + + public GeneralFunction wrapSubContraction(ElementAccessor formula, Map indexValues, + Map toSubstitute) { + // this is basically all a hack to handle different parts of the sum + // having different numbers of contracted indices. we just won't report any! + Map formulaStructure = new HashMap<>(); + formula.getIndices(formulaStructure); + Set toContract = new HashSet<>(); + Set uncontracted = new HashSet<>(); + // copied from createFrom + for (Map.Entry entry : formulaStructure.entrySet()) { + String index = entry.getKey(); + IndexStructure structure = entry.getValue(); + if (structure == IndexStructure.CONTRACTED) + toContract.add(index); + else if (structure == IndexStructure.TWODOWN) + throw new IllegalArgumentException("Index " + index + " is repeated down twice."); + else if (structure == IndexStructure.TWOUP) + throw new IllegalArgumentException("Index " + index + " is repeated up twice."); + else + uncontracted.add(index); + } + + if (toContract.size() == 0) { + return formula.getValueAt(indexValues, toSubstitute); + } + + int dimension = getDimension(); + List> contractedIndexValuesList = new ArrayList<>(); + contractedIndexValuesList.add(new HashMap<>()); + for (String index : toContract) { + List> newCIVL = new ArrayList<>(); + for (Map contractedIndexValues : contractedIndexValuesList) { + for (int i = 0; i < dimension; i++) { + Map newContractedIndexValues = new HashMap<>(contractedIndexValues); + newContractedIndexValues.put(index, i); + newCIVL.add(newContractedIndexValues); + } + } + contractedIndexValuesList = newCIVL; + } + assert contractedIndexValuesList.size() == Math.pow(dimension, toContract.size()); + GeneralFunction[] toAdd = new GeneralFunction[contractedIndexValuesList.size()]; + for (int i = 0; i < contractedIndexValuesList.size(); i++) { + HashMap curIndexValues = new HashMap<>(indexValues); + HashMap curToSubstitute = new HashMap<>(toSubstitute); + curIndexValues.putAll(contractedIndexValuesList.get(i)); + curToSubstitute.putAll(contractedIndexValuesList.get(i).entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new Constant(e.getValue())))); + + toAdd[i] = formula.getValueAt(curIndexValues, curToSubstitute); + } + return new Sum(toAdd).simplify(); + } + + @Override + public GeneralFunction getValueAt(Map indexValues, Map toSubstitute) { + // this is basically all a hack to handle different parts of the sum + // having different numbers of contracted indices. we just won't report any! + + return new Sum( + Arrays.stream(elements) + .map(e -> wrapSubContraction(e, indexValues, toSubstitute)) + .toArray(GeneralFunction[]::new)); + } + + public void getIndices(Map indexStructure) { + // this is basically all a hack to handle different parts of the sum + // having different numbers of contracted indices. we just won't report any! + List newContractions = new ArrayList<>(); + List> indexStructures = Arrays.stream(elements) + .map(e -> { + var map = new java.util.HashMap(); + e.getIndices(map); + // return (Map) map.entrySet().stream() + // .filter(en -> en.getValue() != IndexStructure.CONTRACTED) + // .collect( + // Collectors.toMap(en -> (String) en.getKey(), en -> (IndexStructure) + // en.getValue())); + for (String k : map.keySet()) { + if (map.get(k) == IndexStructure.CONTRACTED) { + newContractions.add(k); + } + } + for (String c : newContractions) { + map.remove(c); + } + + return (Map) map; + }) + .toList(); + for (int i = 1; i < indexStructures.size(); i++) { + if (!indexStructures.get(i).equals(indexStructures.get(0))) { + throw new IllegalArgumentException("All summands must have the same indices"); + } + } + elements[0].getIndices(indexStructure); + for (String c : newContractions) { + indexStructure.remove(c); + } + } + + public int getDimension() { + int dimension = -1; + for (int i = 1; i < elements.length; i++) { + int cur_dim = elements[i].getDimension(); + if (dimension == -1) + dimension = cur_dim; + else if (cur_dim != -1) + assert cur_dim == dimension; + } + return dimension; + } + +} diff --git a/src/tensors/elementoperations/ElementWrapper.java b/src/tensors/elementoperations/ElementWrapper.java new file mode 100644 index 00000000..5b28f05a --- /dev/null +++ b/src/tensors/elementoperations/ElementWrapper.java @@ -0,0 +1,49 @@ +package tensors.elementoperations; + +import core.functions.GeneralFunction; +import tensors.DirectedNested; +import tensors.TensorTools; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class ElementWrapper implements ElementAccessor { + + private final DirectedNested contained; + private final String[] indices; + + public ElementWrapper(DirectedNested contained, String... indices) { + this.contained = contained; + this.indices = indices; + } + + public GeneralFunction getValueAt(Map indexValues, Map toSubstitute) { + if (!indexValues.keySet().containsAll(List.of(indices))) + throw new IllegalStateException("Calling getValueAt with incomplete indexValues and/or toSubstitute, has " + + indexValues + " but expected values for " + Arrays.toString(indices)); + int[] index = Arrays.stream(indices) + .mapToInt(indexValues::get) + .toArray(); + return contained.getAtIndex(index); + } + + public void getIndices(Map indexStructure) { + var directions = contained.getDirections(); + assert directions.length == indices.length; + for (int i = 0; i < indices.length; i++) { + TensorTools.addIndexStructure(indices[i], directions[i], indexStructure); + } + } + + public int getDimension() { + int[] dimensions = contained.getDimensions(); + int dimension = dimensions[0]; + for (int i = 1; i < dimensions.length; i++) { + assert dimensions[i] == dimension : "Tensor is not square: " + Arrays.toString(dimensions); + } + return dimension; + } + +} diff --git a/src/tensors/elementoperations/GeneralFunctionWrapper.java b/src/tensors/elementoperations/GeneralFunctionWrapper.java new file mode 100644 index 00000000..61c67f7b --- /dev/null +++ b/src/tensors/elementoperations/GeneralFunctionWrapper.java @@ -0,0 +1,29 @@ +package tensors.elementoperations; + +import core.functions.GeneralFunction; + +import java.util.Map; +import java.util.Set; + +public class GeneralFunctionWrapper implements ElementAccessor { + + public final GeneralFunction contained; + + public GeneralFunctionWrapper(GeneralFunction contained) { + this.contained = contained; + } + + @Override + public GeneralFunction getValueAt(Map indexValues, Map toSubstitute) { + return contained.substituteVariables(toSubstitute); + } + + public void getIndices(Map indexStructure) { + // Do nothing + } + + public int getDimension() { + return -1; + } + +} diff --git a/tests/AlgebraTests.java b/tests/AlgebraTests.java deleted file mode 100644 index 4281dcc1..00000000 --- a/tests/AlgebraTests.java +++ /dev/null @@ -1,85 +0,0 @@ -import org.junit.jupiter.api.Test; -import core.functions.GeneralFunction; -import core.functions.binary.Logb; -import core.functions.binary.Pow; -import core.functions.commutative.Product; -import core.functions.commutative.Sum; -import core.functions.endpoint.Constant; -import core.functions.endpoint.Variable; -import core.functions.unitary.specialcases.Exp; -import core.functions.unitary.specialcases.Ln; -import core.tools.algebra.LogSimplify; -import core.tools.defaults.DefaultFunctions; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static core.tools.defaults.DefaultFunctions.*; - -public class AlgebraTests { - - private static final Variable A = new Variable("a"); - private static final Variable B = new Variable("b"); - private static final Variable C = new Variable("c"); - - - @Test - void lnOfAProduct() { - Ln test = new Ln(new Product(X, Y)); - assertEquals(new Sum(new Ln(X), new Ln(Y)), LogSimplify.logarithmOfAProduct(test)); - } - - @Test - void lnOfAnExponent() { - Ln test = new Ln(new Pow(X, Y)); - assertEquals(new Product(X, new Ln(Y)), LogSimplify.logarithmOfAnExponent(test)); - } - - @Test - void changeOfBase() { - Logb test = new Logb(X, new Constant(10)); - assertEquals(DefaultFunctions.frac(new Ln(X), new Ln(new Constant(10))).simplify(), LogSimplify.changeOfBase(test)); - } - - @Test - void logChainRuleBasic() { - Product test = new Product(new Logb(Y, X), new Logb(Z, Y)); - assertEquals(new Logb(Z, X), LogSimplify.logChainRule(test)); - } - - @Test - void logChainRuleMany() { - GeneralFunction test = LogSimplify.logChainRule(new Product(new Logb(Y, X), new Logb(T, PI), new Logb(Z, Y), new Ln(Y), new Logb(PI, T))); - if (test.equals(new Product(new Logb(Z, X), new Ln(Y)))) - assertEquals(new Product(new Logb(Z, X), new Ln(Y)), test); - else - assertEquals(new Product(new Logb(Y, X), new Ln(Z)), test); - } - - @Test - void logChainRuleCycle() { - Product test = new Product(new Logb(Y, X), new Logb(Z, Y), new Logb(X, Z)); - assertEquals(ONE, LogSimplify.logChainRule(test)); - } - - @Test - void logChainRuleCOB() { - Product test = new Product(new Logb(Y, X), new Pow(NEGATIVE_ONE, new Logb(Y, Z))); - assertEquals(new Logb(Z, X), LogSimplify.logChainRule(test)); - } - - - @Test - void sumOfLogsBasic() { - Sum test = new Sum(new Ln(X), new Ln(Y)); - assertEquals(new Ln(new Product(X,Y)), LogSimplify.sumOfLogs(test)); - } - - @Test - void sumOfLogsComplex() { - Sum test = new Sum(new Logb(Z, A), new Logb(X, A), new Logb(Y, B), new Logb(Z, C), new Logb(Z, B), new Logb(Y, C)); - assertEquals(new Sum(new Logb(new Product(X, Z), A), new Logb(new Product(Y, Z), B), new Logb(new Product(Y, Z), C)), LogSimplify.sumOfLogs(test)); - } - - -} diff --git a/tests/ComboTest.java b/tests/ComboTest.java deleted file mode 100644 index 754a380a..00000000 --- a/tests/ComboTest.java +++ /dev/null @@ -1,63 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class ComboTest { - @Test - void basicFactorial1() { - GeneralFunction test = FunctionParser.parseInfix("x!+2"); - assertEquals(8, test.evaluate(Map.of("x", 3.0))); - } - - @Test - void parenFactorial1() { - GeneralFunction test = FunctionParser.parseInfix("(x)!+2"); - assertEquals(8, test.evaluate(Map.of("x", 3.0))); - } - - @Test - void basicFactorial2() { - GeneralFunction test = FunctionParser.parseInfix("3!+2"); - assertEquals(8, test.evaluate(Map.of("x", 3.5))); - } - - @Test - void parenFactorial2() { - GeneralFunction test = FunctionParser.parseInfix("(2*x-54)!+2"); - assertEquals(26, test.evaluate(Map.of("x", 29.0))); - } - - @Test - void absFactorial1() { - GeneralFunction test = FunctionParser.parseInfix("(|x|)!"); // Might want to make this test use precedence when prefix precedence is added - assertEquals(6, test.evaluate(Map.of("x", -3.0))); - } - - @Test - void functionFactorial1() { - GeneralFunction test = FunctionParser.parseInfix("(\\ln(e^3))!"); // Might want to make this test use precedence when prefix precedence is added - assertEquals(6, test.evaluate(Map.of("x", -3.0))); - } - - @Test - void test6C4() { - GeneralFunction test = FunctionParser.parseSimplified("6C4"); - assertEquals(15, test.evaluate()); - } - - @Test - void test6P4() { - GeneralFunction test = FunctionParser.parseSimplified("6P4"); - assertEquals(360, test.evaluate()); - } - - @Test - void test6Cx() { - GeneralFunction test = FunctionParser.parseSimplified("6Cx"); - assertEquals(20, test.evaluate(Map.of("x", 3.0))); - } -} diff --git a/tests/DerivativeTest.java b/tests/DerivativeTest.java deleted file mode 100644 index 88acd5fe..00000000 --- a/tests/DerivativeTest.java +++ /dev/null @@ -1,81 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import commandui.KeywordInterface; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class DerivativeTest { - - @Test - void constantsGive0() { - GeneralFunction test = FunctionParser.parseInfix("2"); - assertEquals(0, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 3467.0))); - } - - @Test - void variablesGive1() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertEquals(1, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 3467.0))); - } - - @Test - void simpleSumAndProductDerivatives() { - GeneralFunction test; - test = FunctionParser.parseInfix("x+3"); - assertEquals(1, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 9.0))); - test = FunctionParser.parseInfix("x*7"); - assertEquals(7, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 9.0))); - test = FunctionParser.parseInfix("2*x+7"); - assertEquals(2, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 9.0))); - test = FunctionParser.parseInfix("2*(x+7)"); - assertEquals(2, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 9.0))); - } - - @Test - void longDerivative() { - GeneralFunction test = FunctionParser.parseInfix("(\\sin(x^0.5+1) * e^(x^0.5)) * x^-0.5").getSimplifiedDerivative("x").getSimplifiedDerivative("x"); - assertEquals(-0.13874, test.evaluate(Map.of("x", 4.0)), 0.0001); -// System.out.println("Second derivative simplified once:"); -// System.out.println(test); -// System.out.println("Second derivative simplified twice:"); -// System.out.println(test.simplify()); - } - - @Test - void arcTrigTests() { - GeneralFunction test; - test = FunctionParser.parseInfix("4\\acos(x)-10\\atan(x)"); - assertEquals(-12.773, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 0.456)), 0.01); - test = FunctionParser.parseInfix("\\asin(x)+x"); - assertEquals(2.638, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 0.792)), 0.01); - } - - @Test - void getNthDerivative() { - GeneralFunction test = FunctionParser.parseInfix("x^2"); - assertEquals(test.getNthDerivative("x", 0), test); - } - - @Test - void logbTests() { - GeneralFunction test; - test = FunctionParser.parseInfix("\\logb_{10}(x)"); - assertEquals(0.659, test.getSimplifiedDerivative("x").evaluate(Map.of("x", 0.659)), 0.01); - } - - @Test - void hardTrig() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("pdn x 3 \\sec(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\sec(x)*\\tan(x)*(5*(\\sec(x))^2+(\\tan(x))^2)"); - assertEquals(test2.evaluate(Map.of("x", 2.0)), test1.evaluate(Map.of("x", 2.0)), 0.001); - } - - @Test - void get4thSinDerivative() { - GeneralFunction test = FunctionParser.parseInfix("\\sin(x)"); - assertEquals(test, test.getNthDerivative("x", 4)); - } -} diff --git a/tests/DifferentialTest.java b/tests/DifferentialTest.java deleted file mode 100644 index ab96ca8c..00000000 --- a/tests/DifferentialTest.java +++ /dev/null @@ -1,92 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.commutative.Product; -import core.functions.unitary.transforms.Differential; -import core.functions.unitary.transforms.Integral; -import org.junit.jupiter.api.Test; -import core.tools.defaults.DefaultFunctions; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static parsing.FunctionParser.parseInfix; -import static parsing.FunctionParser.parseSimplified; - -public class DifferentialTest { - @Test - void basicDerivative1() { - GeneralFunction test = parseSimplified("d/dx x"); - assertEquals(1, test.evaluate()); - } - - @Test - void basicDerivative2() { - GeneralFunction test = parseSimplified("d/dx{x}"); - assertEquals(1, test.evaluate()); - } - - @Test - void basicDerivative3() { - GeneralFunction test = parseSimplified("d/dx(x)"); - assertEquals(1, test.evaluate()); - } - - @Test - void integral1() { - GeneralFunction test = parseInfix("\\int[2x]\\dx"); - assertEquals(parseInfix("x^2"), test.simplify()); - } - - @Test - void integralNullException() { - Integral test = new Integral(parseSimplified("x")); - assertThrows(Exception.class, test::execute); - test.simplify(); - } - - @Test - void integralDifferentialInside() { - Integral test = new Integral(parseInfix("x\\dx")); - assertEquals(parseInfix("x^2/2"), test.simplify()); - } - - @Test - void differentialProductIntegral() { - GeneralFunction test = new Product(new Integral(DefaultFunctions.X), new Differential("x")); - assertEquals(parseInfix("x^2/2"), test.simplify()); - } - - @Test - void differentialProductIntegral2() { - GeneralFunction test = new Product(DefaultFunctions.TWO, new Integral(DefaultFunctions.X), new Differential("x")); - assertEquals(parseInfix("x^2"), test.simplify()); - } - - @Test - void differentialProductIntegralNested1() { - GeneralFunction test = parseInfix("\\int(\\int(2x\\dx))\\dy"); - assertEquals(parseInfix("yx^2"), test.simplify()); - } - - @Test - void integralThatBreaks() { - GeneralFunction test = parseInfix("\\int(x^2\\dy)"); - assertEquals(parseInfix("y*x^2"), test.simplify()); - } - - @Test - void integralThatBreaksManualCreation() { - GeneralFunction test = new Integral(parseInfix("x^2"), "y"); - assertEquals(parseInfix("y*x^2"), test.simplify()); - } - - @Test - void integral2() { - GeneralFunction test = parseInfix("\\int[e^\\beta]\\d\\beta"); - assertEquals(parseInfix("e^\\beta"), test.simplify()); - } - - @Test - void integral3() { - GeneralFunction test = parseInfix("\\int[e^ϕ]\\dϕ"); - assertEquals(parseInfix("e^ϕ"), test.simplify()); - } -} diff --git a/tests/EqualsTest.java b/tests/EqualsTest.java deleted file mode 100644 index c0552748..00000000 --- a/tests/EqualsTest.java +++ /dev/null @@ -1,122 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - -public class EqualsTest { - - @Test - void unitaryEqualsUnitary() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\sin(x)"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void variablesAreDifferent() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\sin(y)"); - assertNotEquals(test1, test2); - } - - @Test - void differentUnitaryFunctions() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\cos(x)"); - assertNotEquals(test1, test2); - } - - @Test - void differentFunctionTypes() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("x+2"); - assertNotEquals(test1, test2); - } - - @Test - void multiplyAndAdd() { - GeneralFunction test1 = FunctionParser.parseInfix("x*2"); - GeneralFunction test2 = FunctionParser.parseInfix("x+2"); - assertNotEquals(test1, test2); - } - - @Test - void switchedOrderVariableConstant() { - GeneralFunction test1 = FunctionParser.parseInfix("1+2x"); - GeneralFunction test2 = FunctionParser.parseInfix("2x+1"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderVariables() { - GeneralFunction test1 = FunctionParser.parseInfix("x+y"); - GeneralFunction test2 = FunctionParser.parseInfix("y + x"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedVariablesWithPowers() { - GeneralFunction test1 = FunctionParser.parseInfix("x^2+x^3"); - GeneralFunction test2 = FunctionParser.parseInfix("x^3+x^2"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderVariableMultiply() { - GeneralFunction test1 = FunctionParser.parseInfix("x+2y"); - GeneralFunction test2 = FunctionParser.parseInfix("2y + x"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderMultiplies() { - GeneralFunction test1 = FunctionParser.parseInfix("3x+2y"); - GeneralFunction test2 = FunctionParser.parseInfix("2y + 3x"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderVariablesMul() { - GeneralFunction test1 = FunctionParser.parseInfix("x*y"); - GeneralFunction test2 = FunctionParser.parseInfix("yx"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedVariablesWithPowersMul() { - GeneralFunction test1 = FunctionParser.parseInfix("x^2*x^3"); - GeneralFunction test2 = FunctionParser.parseInfix("x^3*x^2"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderVariableMultiplyMul() { - GeneralFunction test1 = FunctionParser.parseInfix("x*2*y"); - GeneralFunction test2 = FunctionParser.parseInfix("2*y*x"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderMultipliesMul() { - GeneralFunction test1 = FunctionParser.parseInfix("3x*2y"); - GeneralFunction test2 = FunctionParser.parseInfix("2y*3x"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderComplicated() { - GeneralFunction test1 = FunctionParser.parseInfix("x^2+1+y+3\\sin(x)+2x"); - GeneralFunction test2 = FunctionParser.parseInfix("3(\\sin(x))+y+x^2+2x+1"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void switchedOrderTrig() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)+\\cos(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\cos(x)+\\sin(x)"); - assertEquals(test1.simplify(), test2.simplify()); - } - -} diff --git a/tests/ExtremaTest.java b/tests/ExtremaTest.java deleted file mode 100644 index 7de37f7c..00000000 --- a/tests/ExtremaTest.java +++ /dev/null @@ -1,94 +0,0 @@ -import core.config.Settings; -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.singlevariable.Extrema; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class ExtremaTest { - @Test - void simpleMinima() { - GeneralFunction test = FunctionParser.parseInfix("x^2-1"); - assertEquals(0, Extrema.findLocalMinimum(test, -3,3)); - } - - @Test - void lessSimpleMinima() { - GeneralFunction test = FunctionParser.parseInfix("x^2-6x+8"); - assertEquals(3, Extrema.findLocalMinimum(test, -5,5), Settings.equalsMargin); - } - - @Test - void simpleMaxima() { - GeneralFunction test = FunctionParser.parseInfix("1-x^2"); - assertEquals(0, Extrema.findLocalMaximum(test, -4, 3)); - } - - @Test - void simpleHighOrderMinima() { - GeneralFunction test = FunctionParser.parseInfix("(x-1)^4"); - assertArrayEquals(new double[]{1}, Extrema.findLocalMinima(test, -5.87329472, 5.023954780232345).stream().mapToDouble(i -> i).toArray(), 0.01); - } - - @Test - void simpleInflection() { - GeneralFunction test = FunctionParser.parseInfix("x^3"); - assertArrayEquals(new double[]{0}, Extrema.findInflectionPoints(test, -5.87329472, 5.023954780232345).stream().mapToDouble(i -> i).toArray()); - } - - @Test - void simpleInflectionWithNoInflection() { - GeneralFunction test = FunctionParser.parseInfix("x^2"); - assertArrayEquals(new double[]{}, Extrema.findInflectionPoints(test, -5.01238941, 7.80293154).stream().mapToDouble(i -> i).toArray()); - } - - @Test - void simpleMinimaWithNoMinima() { - GeneralFunction test = FunctionParser.parseInfix("1-x^2"); - assertEquals(Double.NaN, Extrema.findLocalMinimum(test, -7.62184632046246723904723482376450934, 4.788237402784035873405)); - } - - @Test - void simpleFindAnyMinima() { - GeneralFunction test = FunctionParser.parseInfix("x^{4}-3x^{3}+2x^{2}+x+1"); - assertArrayEquals(new double[]{-.175, 1.425}, Extrema.findLocalMinima(test, -6.30457892, 7.2543525).stream().mapToDouble(i -> i).toArray(), 0.01); - } - - @Test - void simpleFindAnyMaxima() { - GeneralFunction test = FunctionParser.parseInfix("x^{4}-3x^{3}+2x^{2}+x+1"); - assertArrayEquals(new double[]{1}, Extrema.findLocalMaxima(test, -6.30457892, 7.2543525).stream().mapToDouble(i -> i).toArray(), .01); - } - - @Test - void sinTest() { - GeneralFunction test = FunctionParser.parseInfix("\\sin(x)"); - assertEquals(Math.PI/2, Extrema.findLocalMaximum(test, 0, Math.PI), .01); - } - - @Test - void minOnRange() { - GeneralFunction test = FunctionParser.parseInfix("(x-1)^2+3"); - assertEquals(1, Extrema.findMinimumOnRange(test, -3, 17)); - } - - @Test - void minOnRangeBoundary() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertEquals(3, Extrema.findMinimumOnRange(test, 3, 17)); - } - - @Test - void maxOnRange() { - GeneralFunction test = FunctionParser.parseInfix("3-(x+2)^2"); - assertEquals(-2, Extrema.findMaximumOnRange(test, -3, 13)); - } - - @Test - void maxOnRangeBoundary() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertEquals(11, Extrema.findMaximumOnRange(test, 3, 11)); - } -} diff --git a/tests/FunctionTest.java b/tests/FunctionTest.java deleted file mode 100644 index f1dec705..00000000 --- a/tests/FunctionTest.java +++ /dev/null @@ -1,343 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.unitary.trig.inverse.*; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.defaults.DefaultFunctions; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class FunctionTest { - - @Test void fxReturnsX() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertEquals(2, test.evaluate(Map.of("x",2.0))); - } - - @Test void basicFunctionsWithX() { - GeneralFunction test = FunctionParser.parseInfix("x^x+2+5*x"); - assertEquals(44, test.evaluate(Map.of("x",3.0))); - } - - @Test void multipleVariablesWorks() { - GeneralFunction test = FunctionParser.parseInfix("x+y+y"); - assertEquals(11, test.evaluate(Map.of("x",3.0, "y", 4.0))); - } - - @Test void logbWorks() { - GeneralFunction test = FunctionParser.parseInfix("\\logb_3(x)"); - assertEquals(4, test.evaluate(Map.of("x",81.0))); - } - - @Test void trigWorks() { - GeneralFunction test = FunctionParser.parseInfix("(\\sin(x))^2+(\\cos x)^2"); - assertEquals(1, test.evaluate(Map.of("x",81.0))); - } - - @Test void eToTheXWorks() { - GeneralFunction test = FunctionParser.parseInfix("e^x"); - assertEquals(1, test.evaluate(Map.of("x",0.0))); - } - - @Test void lnWorks() { - GeneralFunction test = FunctionParser.parseInfix("\\ln(e)"); - assertEquals(1, test.evaluate(Map.of("x",1.5))); - } - - @Test void tanWorks() { - GeneralFunction test = FunctionParser.parseInfix("\\tan(x)"); - assertEquals(1, test.evaluate(Map.of("x",Math.PI/4)), 0.0000001); - } - - @Test void multiplyWorks() { - GeneralFunction test = FunctionParser.parseInfix("(1/(x+1))*(\\cos x)*(x^2-1)"); - assertEquals(-1, test.evaluate(Map.of("x",0.0))); - } - - @Test void addWorks() { - GeneralFunction test = FunctionParser.parseInfix("(1/(x+1))+(\\sec(x))+(x^3-1)"); - assertEquals(1, test.evaluate(Map.of("x",0.0))); - } - - @Test void noSpaces() { - GeneralFunction test = FunctionParser.parseInfix("1+x*-3"); - assertEquals(-5, test.evaluate(Map.of("x",2.0))); - } - - @Test void basicPolynomial() { - GeneralFunction test = FunctionParser.parseInfix("x^2+5*x+4"); -// System.out.println(test); - assertEquals(28, test.evaluate(Map.of("x",3.0))); - } - - @Test void mediumPolynomial() { - GeneralFunction test = FunctionParser.parseInfix("x^4+5*x^2+4"); -// System.out.println(test); - assertEquals(130, test.evaluate(Map.of("x",3.0))); - } - - @Test void orderOfOperations() { - GeneralFunction test = FunctionParser.parseInfix("10*4-2*(4^2/4)/2/0.5+9"); -// System.out.println(test); - assertEquals(41, test.evaluate(Map.of("x",1.0))); - } - - @Test void multiplyingByAdjacency() { - GeneralFunction test = FunctionParser.parseInfix("3x+5x^2"); - assertEquals(26, test.evaluate(Map.of("x",2.0))); - } - - @Test void multiplyingByAdjacencyAndParentheses() { - GeneralFunction test = FunctionParser.parseInfix("3(x+5x^2)"); - assertEquals(66, test.evaluate(Map.of("x",2.0))); - } - - @Test void multiplyingAdjacentVariables() { - GeneralFunction test = FunctionParser.parseInfix("xy"); - assertEquals(12, test.evaluate(Map.of("x",3.0, "y", 4.0))); - } - - @Test void multiplyingAdjacentVariablesAndPowers() { - GeneralFunction test = FunctionParser.parseInfix("x^2y^-1"); - assertEquals(8, test.evaluate(Map.of("x",4.0, "y", 2.0))); - } - - @Test void multiplyingByAdjacencyAndParenthesesBackwards() { - GeneralFunction test = FunctionParser.parseInfix("(x+5x^2)3"); - assertEquals(66, test.evaluate(Map.of("x",2.0))); - } - - @Test void multiplyingByAdjacencyFunctions() { - GeneralFunction test = FunctionParser.parseInfix("(5+x^2)(\\cos(x))"); - assertEquals(5, test.evaluate(Map.of("x",0.0))); - } - - @Test void multiplyingByAdjacencyThreeTerms0() { - GeneralFunction test = FunctionParser.parseInfix("(1/4)(2/3)\\sin(x)"); - assertEquals(0, test.evaluate(Map.of("x",0.0))); - } - - @Test void multiplyingByAdjacencyThreeTerms1() { - GeneralFunction test = FunctionParser.parseInfix("\\sin(\\pi/2)2(x)"); - assertEquals(2, test.evaluate(Map.of("x",1.0)), 0.01); - } - - - @Test void multiplyingAdjacencyLogb_2() { - GeneralFunction test = FunctionParser.parseInfix("\\logb_{2}(x)"); - assertEquals(2, test.evaluate(Map.of("x",4.0))); - } - - @Test void multiplyingByAdjacencyLogb_33() { - GeneralFunction test = FunctionParser.parseInfix("\\logb_{33}(x)"); - assertEquals(2, test.evaluate(Map.of("x",1089.0))); - } - - @Test void multiplyingAdjacencyLogb_y() { - GeneralFunction test = FunctionParser.parseInfix("-\\logb_{y}(x)"); - assertEquals(-2, test.evaluate(Map.of("x",4.0, "y", 2.0))); - } - - @Test void multiplyVariablesNoSpace() { - GeneralFunction test = FunctionParser.parseInfix("2xy+3x"); - assertEquals(4, test.evaluate(Map.of("x",4.0, "y", -1.0))); - } - - @Test void basicMap() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertEquals(2, test.evaluate(Map.of("x", 2.0))); - } - - @Test void overfullMap() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertEquals(2, test.evaluate(Map.of("x", 2.0, "n", 1.7, "q", Double.MIN_VALUE))); - } - - @Test void multivariableMap() { - GeneralFunction test = FunctionParser.parseInfix("x+2y"); - assertEquals(5, test.evaluate(Map.of("x", 2.4, "y", 1.3))); - } - - @Test void emptyMap() { - GeneralFunction test = FunctionParser.parseInfix("\\ln(e)"); - assertEquals(1, test.evaluate()); - } - - @Test void nullMap() { - GeneralFunction test = FunctionParser.parseInfix("\\ln(e)"); - assertEquals(1, test.evaluate()); - } - - @Test void usingEDoubles() { - GeneralFunction test = FunctionParser.parseInfix("16E-6*1E6"); - assertEquals(16, test.evaluate()); - } - - @Test void negativeEscape() { - GeneralFunction test = FunctionParser.parseInfix("-\\sin(\\pi/2)"); - assertEquals(-1, test.evaluate(), .01); - } - - @Test void frac() { - GeneralFunction test = FunctionParser.parseInfix("-\\frac{3}{-2}"); - assertEquals(1.5, test.evaluate(), .01); - } - - @Test void exp() { - GeneralFunction test = FunctionParser.parseInfix("\\exp(\\ln(x))"); - assertEquals(4, test.evaluate(Map.of("x", 4.0)), .01); - } - - @Test void gcd() { - GeneralFunction test = FunctionParser.parseSimplified("\\gcd(2, -4)"); - assertEquals(2, test.evaluate()); - } - - @Test void lcm() { - GeneralFunction test = FunctionParser.parseSimplified("\\lcm(2,-4)"); - assertEquals(-4, test.evaluate()); - } - - @Test void mod() { - GeneralFunction test = FunctionParser.parseSimplified("-4%3"); - assertEquals(-1, test.evaluate()); - } - - @Test void floor() { - GeneralFunction test = FunctionParser.parseSimplified("floor(2.5)"); - assertEquals(2, test.evaluate()); - } - - @Test void ceil() { - GeneralFunction test = FunctionParser.parseSimplified("ceil(2.5)"); - assertEquals(3, test.evaluate()); - } - - @Test void integerQuotient() { - GeneralFunction test = FunctionParser.parseSimplified("4 // 3"); - assertEquals(1, test.evaluate()); - } - - @Test void integerQuotientNoSpaces() { - GeneralFunction test = FunctionParser.parseSimplified("4//3"); - assertEquals(1, test.evaluate()); - } - - @Test void abs() { - GeneralFunction test = FunctionParser.parseSimplified("|x|"); - assertEquals(4, test.evaluate(Map.of("x", -4.0))); - } - - @Test void dirac() { - GeneralFunction test = FunctionParser.parseSimplified("\\dirac(x)"); - assertEquals(0, test.evaluate(Map.of("x", -4.0))); - } - - @Test void round() { - GeneralFunction test = FunctionParser.parseSimplified("\\round(x)"); - assertEquals(2, test.evaluate(Map.of("x", 1.5))); - } - - @Test void sign() { - GeneralFunction test = FunctionParser.parseSimplified("\\sign(x)"); - assertEquals(-1, test.evaluate(Map.of("x", -4.0))); - } - - - @Test void arctrigParsing() { - GeneralFunction test = FunctionParser.parseSimplified("\\arcsin(x)"); - assertEquals(new Asin(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arccos(x)"); - assertEquals(new Acos(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arctan(x)"); - assertEquals(new Atan(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arccsc(x)"); - assertEquals(new Acsc(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arcsec(x)"); - assertEquals(new Asec(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arccot(x)"); - assertEquals(new Acot(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arcsinh(x)"); - assertEquals(new Asinh(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arccosh(x)"); - assertEquals(new Acosh(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arctanh(x)"); - assertEquals(new Atanh(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arccsch(x)"); - assertEquals(new Acsch(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arcsech(x)"); - assertEquals(new Asech(DefaultFunctions.X), test); - test = FunctionParser.parseSimplified("\\arccoth(x)"); - assertEquals(new Acoth(DefaultFunctions.X), test); - } - - @Test void arctrigEval() { - GeneralFunction test = FunctionParser.parseSimplified("\\arcsin(0.7)"); - assertEquals(0.775397496611, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccos(0.7)"); - assertEquals(0.795398830184, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arctan(11.5)"); - assertEquals( 1.48405798812, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccsc(11.5)"); - assertEquals(0.0870664823474, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arcsec(11.5)"); - assertEquals(1.4837294445, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccot(-11.5)"); - assertEquals(3.05485421491, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arcsinh(-11.5)"); - assertEquals( -3.13737923732, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccosh(7)"); - assertEquals(2.63391579385, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arctanh(.6)"); - assertEquals(0.69314, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccsch(-.56)"); - assertEquals( -1.34348187431, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arcsech(.4)"); - assertEquals(1.56679923697, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccoth(1.5)"); - assertEquals(0.804718956217, test.evaluate(), 0.001); - } - - @Test void arcOfNormal() { - GeneralFunction test = FunctionParser.parseSimplified("\\arcsin(sin(43))"); - assertEquals(-0.982297150257, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccos(cos(43))"); - assertEquals(0.9822971, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arctan(tan(11.5))"); - assertEquals(-1.06637061, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccsc(csc(11.5))"); - assertEquals(-1.06637, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arcsec(sec(11.5))"); - assertEquals(1.06637061, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccot(cot(-11.5))"); - assertEquals( 1.06637061, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arcsinh(sinh(-11.5))"); - assertEquals( -11.5, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccosh(cosh(7))"); - assertEquals(7, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arctan(tan(.6))"); - assertEquals(.6, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccsch(csch(-.56))"); - assertEquals(-.56, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arcsech(sech(.4))"); - assertEquals(.4, test.evaluate(), 0.001); - test = FunctionParser.parseSimplified("\\arccoth(coth(1.5))"); - assertEquals(1.5, test.evaluate(), 0.001); - } - - @Test void noLeadingZero() { - GeneralFunction test; - test = FunctionParser.parseSimplified("1+.2"); - assertEquals(1.2, test.evaluate(), .000001); - test = FunctionParser.parseSimplified("1-.2"); - assertEquals(0.8, test.evaluate(), .000001); - test = FunctionParser.parseSimplified("5*.2"); - assertEquals(1.0, test.evaluate(), .000001); - test = FunctionParser.parseSimplified("1/.2"); - assertEquals(5.0, test.evaluate(), .000001); - test = FunctionParser.parseSimplified("9^.5"); - assertEquals(3.0, test.evaluate(), .000001); - } - -} diff --git a/tests/IntegerTest.java b/tests/IntegerTest.java deleted file mode 100644 index dd759ce7..00000000 --- a/tests/IntegerTest.java +++ /dev/null @@ -1,85 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.binary.Rand; -import core.functions.binary.integer.IntegerQuotient; -import core.functions.binary.integer.Modulo; -import core.functions.commutative.integer.GCD; -import core.functions.commutative.integer.LCM; -import core.functions.endpoint.Constant; -import core.functions.endpoint.Variable; -import core.functions.unitary.piecewise.Ceil; -import core.functions.unitary.piecewise.Floor; -import core.functions.unitary.piecewise.Round; -import core.functions.unitary.trig.normal.Sin; -import org.junit.jupiter.api.Test; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - -public class IntegerTest { - @Test - void basicIntegerQuotient1() { - GeneralFunction test = new IntegerQuotient(new Constant(7), new Constant(13)); - assertEquals(1, test.evaluate()); - } - - @Test - void basicIntegerQuotient2() { - GeneralFunction test = new IntegerQuotient(new Constant(4.999999999999999999999999999999999999999999999998), new Constant(25.000000000000000000000000002)); - assertEquals(5, test.evaluate()); - } - - @Test - void basicModulo1() { - GeneralFunction test = new Modulo(new Constant(7), new Constant(13)); - assertEquals(6, test.evaluate()); - } - - @Test - void basicModulo2() { - GeneralFunction test = new Modulo(new Constant(7.0000000000000000000000000000000000000000000000000067), new Constant(Math.pow(2, 18))); - assertEquals(1, test.evaluate()); - } - - @Test - void gcd() { - assertEquals(new Constant(4), new GCD(new Constant(4), new Constant(196), new Constant(80)).simplify()); - assertEquals(4, new GCD(new Constant(4), new Constant(196), new Constant(80)).evaluate()); - assertEquals(4, new GCD(new Constant(4), new Constant(-196), new Constant(80)).evaluate()); - } - - @Test - void lcm() { - assertEquals(new Constant(3920), new LCM(new Constant(4), new Constant(196), new Constant(80)).simplify()); - assertEquals(3920, new LCM(new Constant(4), new Constant(196), new Constant(80)).evaluate()); - assertEquals(-3920, new LCM(new Constant(4), new Constant(-196), new Constant(-80)).evaluate()); - } - - @Test - void basicFloor() { - GeneralFunction test = new Floor(new Sin(new Variable("x"))); - assertEquals(0, test.evaluate(Map.of("x", 1.0))); - } - - @Test - void basicCeil() { - GeneralFunction test = new Ceil(new Sin(new Variable("x"))); - assertEquals(1, test.evaluate(Map.of("x", 1.0))); - } - - @Test - void basicRound() { - GeneralFunction test = new Round(new Sin(new Variable("x"))); - assertEquals(1, test.evaluate(Map.of("x", 1.0))); - } - - @Test - void basicRand() { - GeneralFunction test = new Rand(new Constant(0.0), new Constant(10.0)); - assertNotEquals(test.evaluate(), test.evaluate()); - } - - - -} diff --git a/tests/IntegralTest.java b/tests/IntegralTest.java deleted file mode 100644 index 607dd4c7..00000000 --- a/tests/IntegralTest.java +++ /dev/null @@ -1,179 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.commutative.Product; -import core.functions.commutative.Sum; -import core.functions.endpoint.Constant; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.exceptions.IntegrationFailedException; -import core.tools.helperclasses.Pair; -import core.functions.unitary.transforms.Integral; -import core.tools.IntegralTools; - -import static org.junit.jupiter.api.Assertions.*; - - -public class IntegralTest { - - @Test - void splitAdds() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("x+e^x"), "x"); - GeneralFunction test2 = new Sum(FunctionParser.parseSimplified("0.5*x^2"), FunctionParser.parseSimplified("e^x")); - assertEquals(test1.execute().simplify(), test2); - } - - @Test - void unwrapsExponents() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("(x^2+2)^2"), "x"); - GeneralFunction test2 = new Sum(FunctionParser.parseSimplified("(x^5)/5"), FunctionParser.parseSimplified("4/3*x^3"), FunctionParser.parseSimplified("4x")); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void stripConstantsSimple() { - GeneralFunction test1 = FunctionParser.parseSimplified("3\\sin(x)"); - Pair test2 = IntegralTools.stripConstantsRespectTo(test1, "x"); - assertEquals(new Constant(3), test2.getFirst()); - assertEquals(FunctionParser.parseSimplified("\\sin(x)"), test2.getSecond()); - } - - @Test - void simpleExponentIntegral() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("e^x"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("e^x"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleExponentIntegralWithConstant() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("2e^x"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("2e^x"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleExponentIntegralWithLinerTermInExponent() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("2e^(2x-3)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("e^(2x-3)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simplePowers() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("x^2"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("1/3 * x^3"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleTrig() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("\\cos(x)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("\\sin(x)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleTrigWithConstants() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("4*\\cos(2x+3)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("2*\\sin(2x+3)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleReciprocal() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("e^x/(1+e^x)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("\\ln(1+e^x)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleSquareRoot() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("x*\\sqrt(1+x^2)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("1/3 * (1+x^2)^(3/2)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleExpUSub() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("x*e^(x^2)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("1/2*e^(x^2)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void simpleExpUSubThatNoWork() { - Integral test1 = new Integral(FunctionParser.parseSimplified("2x*\\sin(x)*e^(x^2)"), "x"); - assertThrows(IntegrationFailedException.class, test1::execute); - } - - @Test - void simpleOPIsOne() throws Exception { - GeneralFunction test1 = new Integral(FunctionParser.parseSimplified("\\cos(x)*\\sin(x)"), "x").execute().simplify(); - GeneralFunction test2 = FunctionParser.parseSimplified("1/2*(\\sin(x))^2"); - GeneralFunction test3 = FunctionParser.parseSimplified("-1/2*(\\cos(x))^2"); - assertTrue(test1.equals(test2) || test1.equals(test3)); - } - - @Test - void complexUSub() throws Exception { - Integral test1 = new Integral(FunctionParser.parseInfix("(\\cos(e^x))^2*\\sin(e^x)*e^x"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("-1/3*(\\cos(e^x))^3"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void severalVariableBasic() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("x^y"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("1/(y+1)*x^(y+1)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void severalVariableBasicWithoutX() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("y*z^y*\\ln(y)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("y*z^y*\\ln(y)*x"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void severalVariableBasicWithX() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("y*z^y*\\ln(y)x^3"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("y*z^y*\\ln(y)*x^4/4"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void severalVariableBasicWithXUnsimplified() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("y*z^y*\\ln(y)x^3"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("y*z^y*\\ln(y)*x^4/4"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void severalVariableBasicFunctionOfXAndY1() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("e^(3x+y)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("1/3*e^(3x+y)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void severalVariableBasicFunctionOfXAndY2() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("e^(3xy+y)"), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("1/(3y)*e^(3xy+y)"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void noIntegrand() throws Exception { - Integral test1 = new Integral(new Product(), "x"); - GeneralFunction test2 = FunctionParser.parseSimplified("x"); - assertEquals(test2, test1.execute().simplify()); - } - - @Test - void integralNonAsciiCharacter1() throws Exception { - Integral test1 = new Integral(FunctionParser.parseSimplified("e^ϕ"), "ϕ"); - GeneralFunction test2 = FunctionParser.parseSimplified("e^ϕ"); - assertEquals(test2, test1.execute().simplify()); - } - -} diff --git a/tests/IteratorTest.java b/tests/IteratorTest.java deleted file mode 100644 index 5d138dc3..00000000 --- a/tests/IteratorTest.java +++ /dev/null @@ -1,78 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.binary.Pow; -import core.functions.endpoint.Constant; -import core.functions.endpoint.Variable; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; - -import static org.junit.jupiter.api.Assertions.*; - -@SuppressWarnings("ChainOfInstanceofChecks") -public class IteratorTest { - @Test - void testCommutative1() { - GeneralFunction test = FunctionParser.parseSimplified("x^2+x^3+x^4"); - int i = 0; - boolean io = true; - for (GeneralFunction f : test) { - i++; - io = io && f instanceof Pow; - } - assertTrue(io); - assertEquals(i, 3); - } - - @Test - void testBinary1() { - GeneralFunction test = FunctionParser.parseSimplified("x^2"); - int i = 0; - for (GeneralFunction f : test) { - i++; - } - assertEquals(i, 2); - } - - @Test - void testUnitary1() { - GeneralFunction test = FunctionParser.parseSimplified("\\sin x"); - int i = 0; - for (GeneralFunction f : test) { - i++; - assertTrue(f instanceof Variable); - } - assertEquals(i, 1); - } - - @Test - void testSpecial1() { - GeneralFunction test = FunctionParser.parseSimplified("x"); - int i = 0; - for (GeneralFunction f : test) { - i++; - } - assertEquals(i, 0); - } - - @Test - void testRecursive1() { - GeneralFunction test = FunctionParser.parseSimplified("1+2x+x^2+x^3+x^4"); - int i = 0; - int j = 0; - for (GeneralFunction f : test) { - for (GeneralFunction g : f) { - if (g instanceof Variable) { - i++; - } else if (g instanceof Constant) { - j++; - } - } - if (f instanceof Variable) { - i++; - } else if (f instanceof Constant) { - j++; - } - } - assertEquals(i, 4); - assertEquals(j, 5); - } -} diff --git a/tests/KeywordInterfaceTest.java b/tests/KeywordInterfaceTest.java deleted file mode 100644 index 439979ea..00000000 --- a/tests/KeywordInterfaceTest.java +++ /dev/null @@ -1,178 +0,0 @@ -import core.config.Settings; -import core.functions.GeneralFunction; -import core.functions.binary.Pow; -import core.functions.commutative.Product; -import core.functions.commutative.Sum; -import core.functions.endpoint.Constant; -import core.functions.endpoint.Variable; -import core.functions.unitary.trig.normal.Cos; -import core.functions.unitary.trig.normal.Sin; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import commandui.KeywordInterface; -import core.tools.defaults.DefaultFunctions; - -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -@SuppressWarnings({"SpellCheckingInspection", "unchecked"}) -public class KeywordInterfaceTest { - - @Test - void partialDerivatives() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("pd x x^2"); - GeneralFunction test2 = FunctionParser.parseInfix("2x"); - assertEquals(test2.simplify(), test1); - } - - @Test - void doublePartialDerivatives() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("pd x pd x x^2"); - GeneralFunction test2 = FunctionParser.parseInfix("2"); - assertEquals(test2.simplify(), test1); - } - - @Test - void partialWithRespectToVariableDoesNotExist() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("pd n x^2"); - GeneralFunction test2 = FunctionParser.parseInfix("0"); - assertEquals(test2.simplify(), test1); - } - - @Test - void partialOfASimp() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("pd x simp 2x+3x"); - GeneralFunction test2 = FunctionParser.parseInfix("5"); - assertEquals(test2.simplify(), test1); - } - - @Test - void partialDerivativeNTimes() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("pdn x 4 \\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\sin(x)"); - assertEquals(test2.simplify(), test1); - } - - @Test - void basicEval() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("eval x^2 x=2"); - assertEquals(4, test.evaluate(Map.of())); - } - - @SuppressWarnings("SpellCheckingInspection") - @Test - void basicEvalWithNewVariable() { - // Note that addvar and clearvars aren"t actually things anymore, so this tests the resilience of the UI to bad commands. - KeywordInterface.safeKeywords("clearvars"); - KeywordInterface.safeKeywords("addvar y"); - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("eval y^2 y=2"); - assertEquals(4, test.evaluate(Map.of())); - KeywordInterface.safeKeywords("clearvars"); - KeywordInterface.safeKeywords("addvars x y z"); - } - - @Test - void basicEvalWithThreeVariables() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("eval y+x+z x=3 z=1 y=2"); - assertEquals(6, test.evaluate(Map.of())); - } - - @Test - void basicSimplify() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("simp 1*(x+2x+0)"); - GeneralFunction test2 = FunctionParser.parseInfix("3x"); - assertEquals(test2.simplify(), test1); - } - - @Test - void notSoBasicSubstitute() { - KeywordInterface.safeKeywords("def t x^2"); - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("sa sub z+y y=t"); - GeneralFunction test2 = FunctionParser.parseInfix("z+x^2"); - assertEquals(test2.simplify(), test1); - } - - @Test - void basicSolve() { - double[] test = ((List) KeywordInterface.safeKeywords("solve 5-5x 0 2")).stream().mapToDouble(i -> i).toArray(); - assertArrayEquals(new double[]{1}, test, Settings.equalsMargin); - } - - @Test - void basicExtremaMax() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("extrema max 1-x^2 -\\pi \\pi"); - assertEquals(0, test.evaluate(Map.of())); - } - - @Test - void basicTaylor() { - GeneralFunction test1 = (GeneralFunction) KeywordInterface.safeKeywords("tay \\cos(x) 1 0"); - GeneralFunction test2 = FunctionParser.parseInfix("1"); - assertEquals(test2.simplify(), test1); - } - - @Test - void basicNumericalIntegration() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("intn \\sin(x) 0 \\pi"); - assertEquals(2, test.evaluate(Map.of()), 0.01); - } - - @Test - void basicNumericalIntegrationWithError() { - double[] test = (double[]) KeywordInterface.safeKeywords("intne \\sin(x) 0 \\pi"); - assertArrayEquals(new double[]{2, 0.01}, test, 0.01); - } - - @Test - void basicApostropheParsing() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("def \\f' 2x"); - assertEquals(new Product(new Constant(2), new Variable("x")), test); - } - - @Test - void basicAlphaNumerics() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("\\ts543s"); - assertEquals(new Variable("\\ts543s"), test); - } - - @Test - void basicUnderscoreParsing() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("\\f2_4_5"); - assertEquals(new Variable("\\f2_4_5"), test); - } - - @Test - void basicVariableParsing() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("\\test"); - assertEquals(new Variable("\\test"), test); - } - - @Test - void integralEscapedVariable() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("simp \\int(2\\test)\\d\\test"); - assertEquals(DefaultFunctions.square(new Variable("\\test")), test); - } - - @Test - void basicTrigExample() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("def \\trig (\\sin(\\number1 * \\theta))^2 + (\\cos(\\number2 * \\theta))^2 "); - assertEquals(new Sum(new Pow(DefaultFunctions.TWO, new Sin(new Product(new Variable("\\number1"), new Variable("θ")))), new Pow(DefaultFunctions.TWO, new Cos(new Product(new Variable("\\number2"), new Variable("θ"))))), test); - } - - @Test - void gammaThing1() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("d/d\\Gamma[\\Gamma]"); - assertEquals(new Constant(1), test); - } - - @Test - void gammaThing2() { - GeneralFunction test = (GeneralFunction) KeywordInterface.safeKeywords("eval \\Gamma \\Gamma=1"); - assertEquals(1, test.evaluate(Map.of())); - } - -} - diff --git a/tests/LatexTest.java b/tests/LatexTest.java deleted file mode 100644 index a157320a..00000000 --- a/tests/LatexTest.java +++ /dev/null @@ -1,82 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class LatexTest { - - @Test - void adjMultiply() { - GeneralFunction test = FunctionParser.parseInfix("\\pi\\pi"); - assertEquals(10, test.evaluate(), .3); - } - - @Test - void testVar() { - GeneralFunction test = FunctionParser.parseInfix("\\pi \\Gamma"); - assertEquals(10, test.evaluate(Map.of("Γ", 3.2)), .3); - } - - @Test - void latexNot() { - GeneralFunction test = FunctionParser.parseInfix("\\pi x"); - assertEquals(10, test.evaluate(Map.of("x", 3.2)), .3); - } - - @Test - void rightNumber() { - GeneralFunction test = FunctionParser.parseInfix("\\pi 2"); - assertEquals(6.3, test.evaluate(Map.of("x", 3.2)), .3); - } - - @Test - void leftNumber() { - GeneralFunction test = FunctionParser.parseInfix("2\\pi "); - assertEquals(6.3, test.evaluate(Map.of("x", 3.2)), .3); - } - - @Test - void leftParen() { - GeneralFunction test = FunctionParser.parseInfix("(1+1)\\pi "); - assertEquals(6.3, test.evaluate(Map.of("x", 3.2)), .3); - } - - @Test - void rightParen() { - GeneralFunction test = FunctionParser.parseInfix("\\pi (1+1)"); - assertEquals(6.3, test.evaluate(Map.of("x", 3.2)), .3); - } - - @Test - void log() { - GeneralFunction test = FunctionParser.parseInfix("\\log(x)+\\log(1)"); - assertEquals(1, test.evaluate(Map.of("x", 10.0)), .3); - } - - @Test - void spaceEscapedLatex() { - GeneralFunction test = FunctionParser.parseInfix("1 + \\sin(x)"); - assertEquals(1, test.evaluate(Map.of("x", 3.0)), .3); - } - - @Test - void adjacentWords1() { - GeneralFunction test = FunctionParser.parseInfix("\\pi\\Gamma"); - assertEquals(6.3, test.evaluate(Map.of("Γ", 2.)), .3); - } - - @Test - void adjacentWords2() { - GeneralFunction test = FunctionParser.parseInfix("\\epsilon\\Gamma\\epsilon\\pi"); - assertEquals(6.3, test.evaluate(Map.of("ϵ", 1., "Γ", 2.)), .3); - } - - @Test - void sinx() { - GeneralFunction test = FunctionParser.parseSimplified("sinx"); - assertEquals(FunctionParser.parseSimplified("s*i*n*x"), test); - } -} diff --git a/tests/MiscTest.java b/tests/MiscTest.java deleted file mode 100644 index 37a10c53..00000000 --- a/tests/MiscTest.java +++ /dev/null @@ -1,72 +0,0 @@ -import core.functions.endpoint.Variable; -import org.junit.jupiter.api.Test; -import core.tools.exceptions.IllegalNameException; -import parsing.FunctionParser; -import core.tools.MiscTools; -import core.tools.ParsingTools; -import core.tools.helperclasses.AbstractMutablePair; -import core.tools.helperclasses.AbstractPair; -import core.tools.helperclasses.MutablePair; -import core.tools.helperclasses.Pair; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.*; - -public class MiscTest { - @Test - void immutablePair() { - AbstractPair pair = new Pair<>(1, .5); - assertEquals(1, pair.getFirst()); - assertEquals(.5, pair.getSecond()); - } - - @Test - void mutablePair() { - AbstractMutablePair pair = new MutablePair<>(1, .5); - assertEquals(1, pair.getFirst()); - assertEquals(.5, pair.getSecond()); - pair.setFirst(4); - pair.setSecond(5.0); - assertEquals(4, pair.getFirst()); - assertEquals(5, pair.getSecond()); - } - - @Test - void miscParsing() { - assertTrue(ParsingTools.parseBoolean("truE")); - assertFalse(ParsingTools.parseBoolean("falSE")); - assertEquals(4, ParsingTools.toInteger(4.00000000002)); - } - - @Test - void gcd() { - assertEquals(4, MiscTools.gcd(8, 12)); - assertEquals(1, MiscTools.gcd(9, 7)); - } - - @Test - void hashCode1() { - assertEquals(FunctionParser.parseSimplified("x+y").hashCode(), FunctionParser.parseSimplified("y+x").hashCode()); - assertEquals(FunctionParser.parseSimplified("\\sec(x)*\\tan(x)*(5*(\\sec(x))^2+(\\tan(x))^2)").hashCode(), FunctionParser.parseSimplified("(5*(\\sec(x))^2+(\\tan(x))^2)*\\sec(x)*\\tan(x)").hashCode()); - } - - @Test - void rounding() { - assertTrue(ParsingTools.isAlmostInteger(-186.000000000000000001)); - assertEquals(-186, ParsingTools.toInteger(-186.00000000000000001)); - } - - @Test - void multiCharVariable() { - assertEquals(3, new Variable("\\abc").evaluate(Map.of("\\abc", 3.0))); - assertEquals(3, FunctionParser.parseSimplified("\\el+1").evaluate(Map.of("\\el", 2.0))); - } - - @Test - void whitespaceNames() { - assertThrows(IllegalNameException.class, () -> new Variable("\u200B")); - assertThrows(IllegalNameException.class, () -> new Variable("\\\u2028")); - assertThrows(IllegalNameException.class, () -> new Variable("\\A\u2028")); - } -} diff --git a/tests/NoEscapeTest.java b/tests/NoEscapeTest.java deleted file mode 100644 index 5bc16405..00000000 --- a/tests/NoEscapeTest.java +++ /dev/null @@ -1,103 +0,0 @@ -import core.config.Settings; -import core.functions.GeneralFunction; -import core.functions.commutative.Product; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.defaults.DefaultFunctions; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class NoEscapeTest { - - @Test - void sinPi() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test = FunctionParser.parseInfix("pi (1+1)+sin(pi/2)"); - assertEquals(7.3, test.evaluate(Map.of("x", 3.2)), .3); - Settings.enforceEscapes = temp; - } - - @Test - void log() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test = FunctionParser.parseInfix("log(x)+log(1)"); - assertEquals(1, test.evaluate(Map.of("x", 10.0)), .3); - Settings.enforceEscapes = temp; - } - - @Test - void distributeTerms() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test1 = FunctionParser.parseInfix("sin(x)*(1+5x)"); - GeneralFunction test2 = FunctionParser.parseInfix("sin(x)+5*x*sin(x)"); - assertEquals(((Product)test1).distributeAll(), test2); - Settings.enforceEscapes = temp; - } - - @Test - void exp() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test = FunctionParser.parseInfix("exp(ln(x))"); - assertEquals(4, test.evaluate(Map.of("x", 4.0)), .01); - Settings.enforceEscapes = temp; - } - - @Test - void simpleInverseLnAndExp() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test1 = FunctionParser.parseInfix("exp(ln(x))"); - GeneralFunction test2 = FunctionParser.parseInfix("ln(exp(x))"); - assertEquals(test1.simplify(), test2.simplify()); - Settings.enforceEscapes = temp; - } - - @Test - void simpleInverseTrig() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test1 = FunctionParser.parseInfix("asin(sin(x))"); - GeneralFunction test2 = FunctionParser.parseInfix("cos(acos(x))"); - assertEquals(test1.simplify(), test2.simplify()); - Settings.enforceEscapes = temp; - } - - @Test - void inverseChain() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test1 = FunctionParser.parseInfix("asin(acos(exp(ln(sec(asec(cos(sin(x))))))))"); - assertEquals(DefaultFunctions.X, test1.simplify()); // this isn"t actually correct based on ranges, so if you add that this will break - Settings.enforceEscapes = temp; - } - - @Test - void expInverses() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test1 = FunctionParser.parseSimplified("ln(e^logb_e(exp(x)))"); - assertEquals(DefaultFunctions.X, test1); - Settings.enforceEscapes = temp; - } - - @Test - void logFOC() { - boolean temp = Settings.enforceEscapes; - Settings.enforceEscapes = false; - GeneralFunction test1 = FunctionParser.parseSimplified("log(100)"); - assertEquals(DefaultFunctions.TWO, test1); - Settings.enforceEscapes = temp; - } - - @Test - void spaceLatex() { - GeneralFunction test = FunctionParser.parseInfix("1 + sin(x)"); - assertEquals(1, test.evaluate(Map.of("x", 3.0)), .3); - } -} diff --git a/tests/NonCommutativeTest.java b/tests/NonCommutativeTest.java deleted file mode 100644 index f8ec2b4a..00000000 --- a/tests/NonCommutativeTest.java +++ /dev/null @@ -1,84 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class NonCommutativeTest { - - @Test - void basicSubtract() { - GeneralFunction test = FunctionParser.parseInfix("1-x+4-3+x+4-1-x"); - assertEquals(2, test.evaluate(Map.of("x", 3.0))); - } - - @Test - void subtractWithMultiply() { - GeneralFunction test = FunctionParser.parseInfix("x-2*x+1"); - assertEquals(-2, test.evaluate(Map.of("x", 3.0))); - } - - @Test - void basicNCPolynomial() { - GeneralFunction test = FunctionParser.parseInfix("x^2-5*x+4"); -// System.out.println(test); - assertEquals(-2,test.evaluate(Map.of("x", 3.0))); - } - - @Test - void mediumNCPolynomial() { - GeneralFunction test = FunctionParser.parseInfix("x^4-5*x^2+4"); -// System.out.println(test); - assertEquals(40,test.evaluate(Map.of("x", 3.0))); - } - - @Test - void negativeConstant() { - GeneralFunction test = FunctionParser.parseInfix("-3"); - assertEquals(-3, test.evaluate(Map.of("x", 17.0))); - } - - @Test - void leadingNegative() { - GeneralFunction test = FunctionParser.parseInfix("-x"); - assertEquals(-3, test.evaluate(Map.of("x", 3.0))); - } - - @Test - void multiVariableDivisionWithNegatives() { - GeneralFunction test = FunctionParser.parseInfix("-x/-y+-y/3"); - assertEquals(-1.0/3,test.evaluate(Map.of("x", 2.0, "y", 3.0)), .001); - } - - @Test - void dividingNegatives() { - GeneralFunction test = FunctionParser.parseInfix("1/-x"); - assertEquals(-1, test.evaluate(Map.of("x", 1.0))); - } - - @Test - void dividingByOneTerm() { - GeneralFunction test = FunctionParser.parseInfix("1/x^2+x"); - assertEquals(2, test.evaluate(Map.of("x", 1.0))); - } - - @Test - void dividingByPolynomial() { - GeneralFunction test = FunctionParser.parseInfix("1/(x^2+x-1)"); - assertEquals(1, test.evaluate(Map.of("x", 1.0))); - } - - @Test - void dividingAndMultiplying1() { - GeneralFunction test = FunctionParser.parseInfix("1/x*x"); - assertEquals(1, test.evaluate(Map.of("x", 1.786))); - } - - @Test - void dividingAndMultiplying2() { - GeneralFunction test = FunctionParser.parseInfix("1/x * x"); - assertEquals(1, test.evaluate(Map.of("x", 1.786))); - } -} diff --git a/tests/NumericalIntegrationTest.java b/tests/NumericalIntegrationTest.java deleted file mode 100644 index 37a59102..00000000 --- a/tests/NumericalIntegrationTest.java +++ /dev/null @@ -1,32 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.singlevariable.NumericalIntegration; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class NumericalIntegrationTest { - - @Test - void simpleTrigIntegral() { - GeneralFunction function = FunctionParser.parseInfix("\\sin(x)"); - double test = NumericalIntegration.simpsonsRule(function, 0, Math.PI); - assertEquals(2, test, 0.0001); - } - - @Test - void simplePolynomialIntegral() { - GeneralFunction function = FunctionParser.parseInfix("x^2"); - double test = NumericalIntegration.simpsonsRule(function, 0, 1); - assertEquals(0.33333333333333333333333333333333333333, test, 0.0001); - } - - @Test - void simpleTrigIntegralWithError() { - GeneralFunction function = FunctionParser.parseInfix("\\sin(x)"); - double[] test = NumericalIntegration.simpsonsRuleWithError(function, 0, Math.PI); - assertArrayEquals(new double[]{2, 1e-15}, test, 0.0001); - } - -} diff --git a/tests/OutputTest.java b/tests/OutputTest.java deleted file mode 100644 index 0d47b850..00000000 --- a/tests/OutputTest.java +++ /dev/null @@ -1,13 +0,0 @@ -import core.functions.endpoint.Constant; -import org.junit.jupiter.api.Test; -import core.tools.defaults.DefaultFunctions; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class OutputTest { - - @Test - void endpointTest1() { - assertEquals(DefaultFunctions.TWO.toOutputFunction(), new Constant(2)); - } -} diff --git a/tests/PolynomialTest.java b/tests/PolynomialTest.java deleted file mode 100644 index 553d4c89..00000000 --- a/tests/PolynomialTest.java +++ /dev/null @@ -1,122 +0,0 @@ -import core.config.Settings; -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import core.functions.binary.Pow; -import core.functions.commutative.Product; -import core.functions.commutative.Sum; -import core.functions.endpoint.Constant; -import core.functions.endpoint.Variable; -import core.functions.unitary.specialcases.Exp; -import core.tools.defaults.DefaultFunctions; -import core.tools.functiongenerators.HermitePolynomial; -import core.tools.functiongenerators.LaguerrePolynomial; -import core.tools.functiongenerators.LegrendePolynomial; -import core.tools.functiongenerators.TaylorSeries; -import parsing.FunctionParser; -import core.tools.PolynomialTools; - -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static core.tools.defaults.DefaultFunctions.*; - -public class PolynomialTest { - @Test - void isSimpleMonomial() { - GeneralFunction test = FunctionParser.parseInfix("x"); - assertTrue(PolynomialTools.isMonomial(test)); - } - - @Test - void isSimpleMonomialWithAConstant() { - GeneralFunction test = FunctionParser.parseInfix("3x"); - assertTrue(PolynomialTools.isMonomial(test)); - } - - @Test - void isSimpleMonomialWithAPower() { - GeneralFunction test = FunctionParser.parseInfix("x^2"); - assertTrue(PolynomialTools.isMonomial(test)); - } - - @Test - void isSimpleMonomialWithPowerAndConstant() { - GeneralFunction test = FunctionParser.parseInfix("3x^2"); - assertTrue(PolynomialTools.isMonomial(test)); - } - - @Test - void isGeneralMonomial() { - GeneralFunction test = FunctionParser.parseInfix("3.32145*x^(-4.4352)"); - assertTrue(PolynomialTools.isGeneralMonomial(test)); - } - - @Test - void isSimplePolynomialOfAMonomial() { - GeneralFunction test = FunctionParser.parseInfix("3x^2"); - assertTrue(PolynomialTools.isPolynomial(test)); - } - - @Test - void isNotSimplePolynomial() { - GeneralFunction test = FunctionParser.parseInfix("5x^-1"); - assertFalse(PolynomialTools.isPolynomial(test)); - } - - @Test - void isSimplePolynomial() { - GeneralFunction test = FunctionParser.parseSimplified("5x^3+x^2+5x+3269485"); - assertTrue(PolynomialTools.isPolynomial(test)); - } - - @Test - void legendrePolynomial() { - Variable test1 = new Variable(Settings.singleVariableDefault); - assertEquals(test1, LegrendePolynomial.legrendePolynomial(1)); - test1 = new Variable("j"); - assertEquals(test1, LegrendePolynomial.legrendePolynomial(1, "j")); - assertEquals(new Constant(1/Math.sqrt(2)), LegrendePolynomial.normalLegrendePolynomial(0)); - assertEquals(new Product(new Constant(Math.sqrt(3/2.)), new Variable("t")), LegrendePolynomial.normalLegrendePolynomial(1, "t")); - assertEquals(new Constant(Math.sqrt(2/5.)), LegrendePolynomial.normalizingConstant(2)); - - } - - @Test - void hermitePolynomial() { - Variable test1 = new Variable(Settings.singleVariableDefault); - assertEquals(new Product(TWO, test1), HermitePolynomial.hermitePolynomial(1)); - test1 = new Variable("j"); - assertEquals(new Product(TWO, test1), HermitePolynomial.hermitePolynomial(1, "j")); - assertEquals(new Pow(new Constant(-.25), PI), HermitePolynomial.normalHermitePolynomial(0)); - assertEquals(new Product(new Constant(Math.sqrt(2)), new Pow(new Constant(-.25), PI), new Variable("t")), HermitePolynomial.normalHermitePolynomial(1, "t")); - assertEquals(new Pow(new Constant(.25), PI), HermitePolynomial.normalizingConstant(0)); - - } - - @Test - void laguerrePolynomial() { - Variable test1 = new Variable(Settings.singleVariableDefault); - assertEquals(new Sum(ONE, negative(test1)), LaguerrePolynomial.laguerrePolynomial(1)); - test1 = new Variable("j"); - assertEquals(new Sum(ONE, negative(test1)), LaguerrePolynomial.laguerrePolynomial(1, "j")); - assertEquals(ONE, LaguerrePolynomial.laguerrePolynomial(0)); - assertEquals(FunctionParser.parseSimplified("(1/2 x^2-2x+1)"), LaguerrePolynomial.laguerrePolynomial(2)); - assertEquals(FunctionParser.parseSimplified("(-1/6 x^3+ 3/2 x^2-3x+1)"), LaguerrePolynomial.laguerrePolynomial(3)); - - } - - @Test - void taylorSeriesVariable1() { - Variable test1 = new Variable(Settings.singleVariableDefault); - assertEquals(new Sum(ONE, test1), TaylorSeries.makeTaylorSeries(new Exp(test1), 1)); - test1 = new Variable("j"); - assertEquals(new Sum(ONE, test1), TaylorSeries.makeTaylorSeries(new Exp(test1), 1)); - } - - @Test - void taylorSeriesVariable2() { - Variable x = new Variable(Settings.singleVariableDefault); - Variable y = new Variable("y"); - assertThrows(UnsupportedOperationException.class, () -> TaylorSeries.makeTaylorSeries(new Exp(new Sum(x, y)), 1)); - } - -} diff --git a/tests/SearchTest.java b/tests/SearchTest.java deleted file mode 100644 index 1786b548..00000000 --- a/tests/SearchTest.java +++ /dev/null @@ -1,73 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.commutative.CommutativeFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.SearchTools; -import core.tools.VariableTools; - -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.*; - -public class SearchTest { - - @Test - void basicSearch() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x+1)"); - GeneralFunction test2 = FunctionParser.parseInfix("x"); - assertTrue(SearchTools.existsAny(test1, test2::equalsFunction)); - } - - @Test - void searchExcluding() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x+1)"); - GeneralFunction test2 = FunctionParser.parseInfix("x"); - GeneralFunction test3 = FunctionParser.parseInfix("x+1"); - assertFalse(SearchTools.existsExcluding(test1, test2::equalsFunction, test3::equalsFunction)); - } - - @Test - void searchSurface() { - GeneralFunction test1 = FunctionParser.parseInfix("2\\sin(x+1)"); - GeneralFunction test2 = FunctionParser.parseInfix("x+1"); - GeneralFunction test3 = FunctionParser.parseInfix("\\sin(x+1)"); - assertFalse(SearchTools.existsSurface(test1, test2::equalsFunction)); - assertTrue(SearchTools.existsSurface(test1, test3::equalsFunction)); - } - - @Test - void surfaceSubset() { - CommutativeFunction test1 = (CommutativeFunction) FunctionParser.parseSimplified("a+b+\\sin(x+1)"); - GeneralFunction test2 = FunctionParser.parseSimplified("a+\\sin(x+1)"); - assertTrue(SearchTools.existsInSurfaceSubset(test1, test2::equalsFunction)); - } - - @Test - void simpleSubsetNoExclusion() { - CommutativeFunction test1 = (CommutativeFunction) FunctionParser.parseSimplified("x*\\sin(x)*e^x"); - GeneralFunction test2 = FunctionParser.parseSimplified("x*e^x"); - assertTrue(SearchTools.existsInOppositeSurfaceSubset(test1, (f -> SearchTools.existsAny(f, VariableTools.isVariable("x"))), test2::equalsFunction)); - } - - @Test - void simpleSubsetExclusion() { - CommutativeFunction test1 = (CommutativeFunction) FunctionParser.parseSimplified("x*\\sin(x)*e^x"); - GeneralFunction test2 = FunctionParser.parseSimplified("x*e^x"); - GeneralFunction test3 = FunctionParser.parseSimplified("\\sin(x)"); - assertFalse(SearchTools.existsInOppositeSurfaceSubset(test1, (f -> SearchTools.existsExcluding(f, VariableTools.isVariable("x"), test3::equalsFunction)), test2::equalsFunction)); - } - - @Test - void isVariable() { - assertTrue(VariableTools.isVariable("y").test(FunctionParser.parseSimplified("y"))); - assertFalse(VariableTools.isVariable("x").test(FunctionParser.parseSimplified("y"))); - assertFalse(VariableTools.isVariable("x").test(FunctionParser.parseSimplified("x+1"))); - assertFalse(VariableTools.isVariable("x").test(FunctionParser.parseSimplified("2x"))); - } - - @Test - void findVariables() { - GeneralFunction test = FunctionParser.parseSimplified("x+2a+3\\pi^2-17x"); - assertEquals(VariableTools.getAllVariables(test), Set.of("a", "x")); - } -} diff --git a/tests/SimplifyTest.java b/tests/SimplifyTest.java deleted file mode 100644 index 4059f03c..00000000 --- a/tests/SimplifyTest.java +++ /dev/null @@ -1,165 +0,0 @@ -import core.config.Settings; -import core.functions.GeneralFunction; -import core.functions.binary.Pow; -import core.functions.commutative.Product; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.defaults.DefaultFunctions; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotEquals; - -public class SimplifyTest { - - @Test - void equalWhenSimplified() { - GeneralFunction test1 = FunctionParser.parseInfix("x+(1+3-2)*1"); - GeneralFunction test2 = FunctionParser.parseInfix("x+2"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void constantEquality() { - GeneralFunction test1, test2; - test1 = FunctionParser.parseInfix("1"); - test2 = FunctionParser.parseInfix("0+1"); - assertEquals(test1.simplify(), test2.simplify()); - test1 = FunctionParser.parseInfix("1"); - test2 = FunctionParser.parseInfix("2"); - assertNotEquals(test1, test2); - test1 = FunctionParser.parseInfix("e"); - test2 = FunctionParser.parseInfix("" + Math.E); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simplifiesDivisionExponents() { - GeneralFunction test1 = FunctionParser.parseInfix("x^3/x^2"); - GeneralFunction test2 = FunctionParser.parseInfix("x"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void combineLikeTerms() { - GeneralFunction test1 = FunctionParser.parseInfix("3*x^2+5*x^-1+7*x^-1-3*x^2+1"); - GeneralFunction test2 = FunctionParser.parseInfix("1+12*x^-1"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void distributeTerms() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)*(1+5x)"); - GeneralFunction test2 = FunctionParser.parseInfix("\\sin(x)+5*x*\\sin(x)"); - assertEquals(((Product)test1).distributeAll(), test2); - } - - @Test - void distributeExponents() { - Settings.distributeExponents = true; - GeneralFunction test1 = FunctionParser.parseInfix("(2xy)^2"); - GeneralFunction test2 = FunctionParser.parseInfix("4x^2y^2"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void addExponents() { - GeneralFunction test1 = FunctionParser.parseInfix("x^2*x^4"); - GeneralFunction test2 = FunctionParser.parseInfix("x^6"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void combineLikeTermsMultExample() { - GeneralFunction test1 = FunctionParser.parseInfix("(3+x)(2+x)(1+x)"); - GeneralFunction test2 = FunctionParser.parseInfix("x^3+11x+6x^2+6"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simplifySimpleExponents() { - GeneralFunction test1 = FunctionParser.parseInfix("(x+1)^1"); - GeneralFunction test2 = FunctionParser.parseInfix("x+1"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simplifyMultiplyExponents() { - GeneralFunction test1 = FunctionParser.parseInfix("(x^3)^2"); - GeneralFunction test2 = FunctionParser.parseInfix("x^6"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simplifyIdentity() { - GeneralFunction test1 = FunctionParser.parseInfix("x+0"); - GeneralFunction test2 = FunctionParser.parseInfix("x*1"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simplifyPullAdd() { - GeneralFunction test1 = FunctionParser.parseInfix("(x+(y+z))"); - GeneralFunction test2 = FunctionParser.parseInfix("x+y+z"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simplifyPullMultiply() { - GeneralFunction test1 = FunctionParser.parseInfix("x*(yz)"); - GeneralFunction test2 = FunctionParser.parseInfix("x*y*z"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void timesZero() { - GeneralFunction test1 = FunctionParser.parseInfix("x*0"); - GeneralFunction test2 = FunctionParser.parseInfix("0"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void unwrapPowersTest() { - GeneralFunction test1 = FunctionParser.parseInfix("(x+1)^3"); - GeneralFunction test2 = FunctionParser.parseInfix("(x+1)*(x+1)*(x+1)"); - assertEquals(((Pow) test1).unwrapIntegerPowerSafe().simplify(), test2.simplify()); - } - - @Test - void unwrapPowersEdgeTest() { - GeneralFunction test1 = FunctionParser.parseInfix("(x+1)^0"); - GeneralFunction test2 = FunctionParser.parseInfix("1"); - assertEquals(((Pow) test1).unwrapIntegerPowerSafe().simplify(), test2); - } - - @Test - void simpleInverseLnAndExp() { - GeneralFunction test1 = FunctionParser.parseInfix("\\exp(\\ln(x))"); - GeneralFunction test2 = FunctionParser.parseInfix("\\ln(\\exp(x))"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void simpleInverseTrig() { - GeneralFunction test1 = FunctionParser.parseInfix("\\asin(\\sin(x))"); - GeneralFunction test2 = FunctionParser.parseInfix("\\cos(\\acos(x))"); - assertEquals(test1.simplify(), test2.simplify()); - } - - @Test - void inverseChain() { - GeneralFunction test1 = FunctionParser.parseInfix("\\asin(\\acos(\\exp(\\ln(\\sec(\\asec(\\cos(\\sin(x))))))))"); - assertEquals(DefaultFunctions.X, test1.simplify()); // this isn"t actually correct based on ranges, so if you add that this will break - } - - @Test - void expInverses() { - GeneralFunction test1 = FunctionParser.parseSimplified("\\ln(e^\\logb_e(\\exp(x)))"); - assertEquals(DefaultFunctions.X, test1); // this isn"t actually correct based on ranges, so if you add that this will break - } - - @Test - void logFOC() { - GeneralFunction test1 = FunctionParser.parseSimplified("\\log(100)"); - assertEquals(DefaultFunctions.TWO, test1); - } -} diff --git a/tests/SolverTest.java b/tests/SolverTest.java deleted file mode 100644 index ea60d37f..00000000 --- a/tests/SolverTest.java +++ /dev/null @@ -1,84 +0,0 @@ -import core.functions.GeneralFunction; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.singlevariable.Solver; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class SolverTest { - - @Test - void simplePolynomial() { - GeneralFunction test = FunctionParser.parseInfix("x^2+-1"); - assertEquals(1, Solver.getSolutionPointNewton(test, 3)); - } - - @Test - void moreAdvancedPolynomial() { - GeneralFunction test = FunctionParser.parseInfix("x^4-5x^2+4"); - assertArrayEquals(new double[]{-2, -1, 1, 2}, Solver.getSolutionsRangeNewton(test, -10, 10).stream().mapToDouble(i -> i).toArray(), 1e-10); - } - - @Test - void polynomialWithNoSolution() { - GeneralFunction test = FunctionParser.parseInfix("x^2+1"); - assertEquals(Double.NaN, Solver.getSolutionPointNewton(test, 4)); - } - - @Test - void polynomialWithNoSolutionRange() { - GeneralFunction test = FunctionParser.parseInfix("x^2+1"); - assertArrayEquals(new double[]{}, Solver.getSolutionsRangeNewton(test, -10, 10).stream().mapToDouble(i -> i).toArray()); - } - - @Test - void simpleNotPolynomial1() { - GeneralFunction test = FunctionParser.parseInfix("\\ln(x)"); - assertArrayEquals(new double[]{1}, Solver.getSolutionsRangeNewton(test, -10, 10).stream().mapToDouble(i -> i).toArray()); - } - - @Test - void simpleNotPolynomial2() { - GeneralFunction test = FunctionParser.parseInfix("e^(x-5) - 1"); - assertArrayEquals(new double[]{5}, Solver.getSolutionsRangeHalley(test, 0, 7.68785).stream().mapToDouble(i -> i).toArray()); - } - - @Test - void simpleTrigZero() { - GeneralFunction test = FunctionParser.parseInfix("\\sin(x-3)"); - assertEquals(3, Solver.getSolutionPointNewton(test, 3.5)); - } - - @Test - void simpleConstant() { - GeneralFunction test = FunctionParser.parseInfix("2"); - assertEquals(Double.NaN, Solver.getSolutionPointNewton(test, 23)); - } - - @Test - void simpleExponent() { - GeneralFunction test = FunctionParser.parseInfix("(x+1)^2"); - assertEquals(-1, Solver.getSolutionPointNewton(test, 23), 1e-6); - } - - @Test void chemTest1() { - GeneralFunction test = FunctionParser.parseInfix("x^2/(.2-x)-.013"); - assertArrayEquals(new double[]{-.057, .045}, Solver.getSolutionsRangeHalley(test, -10, 10).stream().mapToDouble(i -> i).toArray(), .05); - } - - @Test void chemTest2() { - GeneralFunction test = FunctionParser.parseInfix("(.12x)^2/((1-x).12)-6.3E-5"); - assertEquals(1, Solver.getSolutionsRangeHalley(test, 0, 1).size()); - } - - @Test void zeroAtZero() { - GeneralFunction test = FunctionParser.parseSimplified("2x^2+x"); - assertArrayEquals(new double[]{-.5, 0}, Solver.getSolutionsRange(test, -10, 10).stream().mapToDouble(i -> i).toArray(), .01); - } - - @Test void xToFour() { - GeneralFunction test = FunctionParser.parseSimplified("x^4"); - assertArrayEquals(new double[]{0}, Solver.getSolutionsRange(test, -10, 10).stream().mapToDouble(i -> i).toArray()); - } -} diff --git a/tests/SubstituteTest.java b/tests/SubstituteTest.java deleted file mode 100644 index e16db43e..00000000 --- a/tests/SubstituteTest.java +++ /dev/null @@ -1,47 +0,0 @@ -import core.functions.GeneralFunction; -import core.functions.commutative.Product; -import core.functions.unitary.UnitaryFunction; -import core.functions.unitary.trig.normal.Cos; -import core.functions.unitary.trig.normal.Sin; -import org.junit.jupiter.api.Test; -import parsing.FunctionParser; -import core.tools.defaults.DefaultFunctions; - -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class SubstituteTest { - - @Test - void simpleSubstitution() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("y^2"); - GeneralFunction test3 = FunctionParser.parseInfix("\\sin(y^2)"); - assertEquals(test1.substituteVariables(Map.of("x", test2)), test3); - } - - @Test - void simpleSameVariableSubstitution() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("x^2"); - GeneralFunction test3 = FunctionParser.parseInfix("\\sin(x^2)"); - assertEquals(test1.substituteVariables(Map.of("x", test2)), test3); - } - - @Test - void ifVariableIsNotPresentSubstitution() { - GeneralFunction test1 = FunctionParser.parseInfix("\\sin(x)"); - GeneralFunction test2 = FunctionParser.parseInfix("x^2"); - GeneralFunction test3 = FunctionParser.parseInfix("\\sin(x)"); - assertEquals(test1.substituteVariables(Map.of("y", test2)), test3); - } - - @Test - void complexSubstituteAll() { - GeneralFunction test1 = FunctionParser.parseSimplified("x+\\sin(x)+2\\sin(2x+y)"); - GeneralFunction test2 = FunctionParser.parseSimplified("x+\\cos(2x)+2\\cos(4x+2y)"); - GeneralFunction substituted = test1.substituteAll(f -> f instanceof Sin, f -> new Cos(new Product(DefaultFunctions.TWO, ((UnitaryFunction) f).operand))); - assertEquals(substituted, test2); - } -}