diff --git a/java/expression/AbstractBinaryOperation.java b/java/expression/AbstractBinaryOperation.java new file mode 100644 index 0000000..625d46a --- /dev/null +++ b/java/expression/AbstractBinaryOperation.java @@ -0,0 +1,114 @@ +package expression; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; + +/** + * @author Doschennikov Nikita (me@fymio.us) + */ +public abstract class AbstractBinaryOperation extends AbstractExpression { + + protected final AbstractExpression left; + protected final AbstractExpression right; + + protected AbstractBinaryOperation( + AbstractExpression left, + AbstractExpression right + ) { + this.left = left; + this.right = right; + } + + protected abstract String getOperator(); + + protected abstract int getPriority(); + + protected abstract boolean isRightAssoc(); + + protected abstract int applyInt(int a, int b); + + protected abstract BigInteger applyBi(BigInteger a, BigInteger b); + + protected abstract BigDecimal applyBd(BigDecimal a, BigDecimal b); + + @Override + public int evaluate(int x) { + return applyInt(left.evaluate(x), right.evaluate(x)); + } + + @Override + public int evaluate(int x, int y, int z) { + return applyInt(left.evaluate(x, y, z), right.evaluate(x, y, z)); + } + + @Override + public int evaluate(List vars) { + return applyInt(left.evaluate(vars), right.evaluate(vars)); + } + + @Override + public BigInteger evaluateBi(List vars) { + return applyBi(left.evaluateBi(vars), right.evaluateBi(vars)); + } + + @Override + public BigDecimal evaluateBd(List vars) { + return applyBd(left.evaluateBd(vars), right.evaluateBd(vars)); + } + + @Override + public String toString() { + return "(" + left + " " + getOperator() + " " + right + ")"; + } + + @Override + public String toMiniString() { + return miniLeft() + " " + getOperator() + " " + miniRight(); + } + + private String miniLeft() { + if ( + left instanceof AbstractBinaryOperation op && + op.getPriority() < getPriority() + ) { + return "(" + op.toMiniString() + ")"; + } + return left.toMiniString(); + } + + private String miniRight() { + if (right instanceof AbstractBinaryOperation op) { + boolean samePriority = op.getPriority() == getPriority(); + boolean lowerPriority = op.getPriority() < getPriority(); + boolean needParens = + lowerPriority || + (samePriority && isRightAssoc()) || + (samePriority && op.isRightAssoc() && getPriority() > 1) || + (samePriority && + !getOperator().equals(op.getOperator()) && + !op.isRightAssoc() && + !isRightAssoc()); + if (needParens) { + return "(" + op.toMiniString() + ")"; + } + } + return right.toMiniString(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + AbstractBinaryOperation other = (AbstractBinaryOperation) obj; + return left.equals(other.left) && right.equals(other.right); + } + + @Override + public int hashCode() { + return ( + 31 * (31 * left.hashCode() + right.hashCode()) + + getClass().hashCode() + ); + } +} diff --git a/java/expression/AbstractExpression.java b/java/expression/AbstractExpression.java new file mode 100644 index 0000000..d955117 --- /dev/null +++ b/java/expression/AbstractExpression.java @@ -0,0 +1,42 @@ +package expression; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; + +/** + * @author Doschennikov Nikita (me@fymio.us) + */ +public abstract class AbstractExpression + implements + Expression, + TripleExpression, + ListExpression, + BigIntegerListExpression, + BigDecimalListExpression +{ + + @Override + public abstract int evaluate(int x); + + @Override + public abstract int evaluate(int x, int y, int z); + + @Override + public abstract int evaluate(List vars); + + @Override + public abstract BigInteger evaluateBi(List vars); + + @Override + public abstract BigDecimal evaluateBd(List vars); + + @Override + public abstract String toString(); + + @Override + public abstract boolean equals(Object obj); + + @Override + public abstract int hashCode(); +} diff --git a/java/expression/Add.java b/java/expression/Add.java new file mode 100644 index 0000000..38bb5e6 --- /dev/null +++ b/java/expression/Add.java @@ -0,0 +1,44 @@ +package expression; + +import java.math.BigDecimal; +import java.math.BigInteger; + +/** + * @author Doschennikov Nikita (me@fymio.us) + */ +public class Add extends AbstractBinaryOperation { + + public Add(AbstractExpression l, AbstractExpression r) { + super(l, r); + } + + @Override + protected String getOperator() { + return "+"; + } + + @Override + protected int getPriority() { + return 1; + } + + @Override + protected boolean isRightAssoc() { + return false; + } + + @Override + protected int applyInt(int a, int b) { + return a + b; + } + + @Override + protected BigInteger applyBi(BigInteger a, BigInteger b) { + return a.add(b); + } + + @Override + protected BigDecimal applyBd(BigDecimal a, BigDecimal b) { + return a.add(b); + } +} diff --git a/java/expression/BigDecimalListExpression.java b/java/expression/BigDecimalListExpression.java new file mode 100644 index 0000000..7914c38 --- /dev/null +++ b/java/expression/BigDecimalListExpression.java @@ -0,0 +1,363 @@ +package expression; + +import base.Asserts; +import base.Pair; +import base.TestCounter; +import expression.common.ExpressionKind; +import expression.common.Type; +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.IntStream; + +/** + * One-argument arithmetic expression over {@link BigDecimal}s. + * + * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) + */ +@FunctionalInterface +@SuppressWarnings("ClassReferencesSubclass") +public interface BigDecimalListExpression extends ToMiniString { + BigDecimal evaluateBd(List variables); + + // Tests follow. You may temporarily remove everything til the end. + + Add EXAMPLE = new Add( + new Subtract(new Variable(0), new Const(BigDecimal.ONE)), + new Multiply(new Variable(1), new Const(BigDecimal.TEN)) + ); + + Type TYPE = new Type<>( + v -> new BigDecimal(v + ".000"), + random -> BigDecimal.valueOf(random.getRandom().nextGaussian()), + BigDecimal.class + ); + ExpressionKind KIND = + new ExpressionKind<>( + TYPE, + BigDecimalListExpression.class, + (r, c) -> + IntStream.range(0, c) + .mapToObj(name -> + Pair.of( + "$" + name, + new Variable(name) + ) + ) + .toList(), + (expr, variables, values) -> expr.evaluateBd(values) + ); + + @SuppressWarnings("BigDecimalMethodWithoutRoundingCalled") + static ExpressionTester tester(final TestCounter counter) { + Asserts.assertEquals( + "Example toString()", + "(($0 - 1) + ($1 * 10))", + EXAMPLE.toString() + ); + Asserts.assertEquals( + EXAMPLE + " at (2, 3)", + BigDecimal.valueOf(31), + EXAMPLE.evaluateBd( + List.of(BigDecimal.valueOf(2), BigDecimal.valueOf(3)) + ) + ); + + final Variable vx = new Variable(0); + final Variable vy = new Variable(1); + + return new ExpressionTester<>( + counter, + KIND, + c -> v -> c, + (op, a, b) -> v -> op.apply(a.evaluateBd(v), b.evaluateBd(v)), + BigDecimal::add, + BigDecimal::subtract, + BigDecimal::multiply, + BigDecimal::divide + ) + .basic("10", "10", v -> v(10), c(10)) + .basic("$x", "$x", BigDecimalListExpression::x, vx) + .basic("$y", "$y", BigDecimalListExpression::y, vy) + .basic("($x + $y)", "$x + $y", v -> x(v).add(y(v)), new Add(vx, vy)) + .basic("($x + 2)", "$x + 2", v -> x(v).add(v(2)), new Add(vx, c(2))) + .basic( + "(2 - $x)", + "2 - $x", + v -> v(2).subtract(x(v)), + new Subtract(c(2), vx) + ) + .basic( + "(3 * $x)", + "3 * $x", + v -> v(3).multiply(x(v)), + new Multiply(c(3), vx) + ) + .basic("($x + $x)", "$x + $x", v -> x(v).add(x(v)), new Add(vx, vx)) + .basic( + "($x / -2)", + "$x / -2", + v -> x(v).divide(v(-2)), + new Divide(vx, c(-2)) + ) + .basic("(2 + $x)", "2 + $x", v -> v(2).add(x(v)), new Add(c(2), vx)) + .basic( + "((1 + 2) + 3)", + "1 + 2 + 3", + v -> v(6), + new Add(new Add(c(1), c(2)), c(3)) + ) + .basic( + "(1 + (2 * 3))", + "1 + 2 * 3", + v -> v(7), + new Add(c(1), new Multiply(c(2), c(3))) + ) + .basic( + "(1 - (2 * 3))", + "1 - 2 * 3", + v -> v(-5), + new Subtract(c(1), new Multiply(c(2), c(3))) + ) + .basic( + "(1 + (2 + 3))", + "1 + 2 + 3", + v -> v(6), + new Add(c(1), new Add(c(2), c(3))) + ) + .basic( + "((1 - 2) - 3)", + "1 - 2 - 3", + v -> v(-4), + new Subtract(new Subtract(c(1), c(2)), c(3)) + ) + .basic( + "(1 - (2 - 3))", + "1 - (2 - 3)", + v -> v(2), + new Subtract(c(1), new Subtract(c(2), c(3))) + ) + .basic( + "((1 * 2) * 3)", + "1 * 2 * 3", + v -> v(6), + new Multiply(new Multiply(c(1), c(2)), c(3)) + ) + .basic( + "(1 * (2 * 3))", + "1 * 2 * 3", + v -> v(6), + new Multiply(c(1), new Multiply(c(2), c(3))) + ) + .basic( + "((10 / 2) / 3)", + "10 / 2 / 3", + v -> v(10).divide(v(2)).divide(v(3)), + new Divide(new Divide(c(10), c(2)), c(3)) + ) + .basic( + "(10 / (3 / 2))", + "10 / (3 / 2)", + v -> v(10).divide(v(3).divide(v(2))), + new Divide(c(10), new Divide(c(3), c(2))) + ) + .basic( + "(($x * $x) + (($x - 1) / 10))", + "$x * $x + ($x - 1) / 10", + v -> x(v).multiply(x(v)).add(x(v).subtract(v(1)).divide(v(10))), + new Add( + new Multiply(vx, vx), + new Divide(new Subtract(vx, c(1)), c(10)) + ) + ) + .basic( + "($x * -1000000000)", + "$x * -1000000000", + v -> x(v).multiply(v(-1_000_000_000)), + new Multiply(vx, c(-1_000_000_000)) + ) + .basic( + "($x * -1000000000000000)", + "$x * -1000000000000000", + v -> x(v).multiply(v(-1_000_000_000_000_000L)), + new Multiply(vx, c(-1_000_000_000_000_000L)) + ) + .basic( + "(10 / $x)", + "10 / $x", + v -> v(10).divide(x(v)), + new Divide(c(10), vx) + ) + .basic( + "($x / $x)", + "$x / $x", + v -> x(v).divide(x(v)), + new Divide(vx, vx) + ) + .advanced("(2 + 1)", "2 + 1", v -> v(2 + 1), new Add(c(2), c(1))) + .advanced( + "($x - 1)", + "$x - 1", + v -> x(v).subtract(v(1)), + new Subtract(vx, c(1)) + ) + .advanced( + "(1 * 2)", + "1 * 2", + v -> v(1 * 2), + new Multiply(c(1), c(2)) + ) + .advanced( + "($x / 1)", + "$x / 1", + v -> x(v).divide(v(1)), + new Divide(vx, c(1)) + ) + .advanced( + "(1 + (2 + 1))", + "1 + 2 + 1", + v -> v(1 + 2 + 1), + new Add(c(1), new Add(c(2), c(1))) + ) + .advanced( + "($x - ($x - 1))", + "$x - ($x - 1)", + v -> x(v).subtract(x(v).subtract(v(1))), + new Subtract(vx, new Subtract(vx, c(1))) + ) + .advanced( + "(2 * ($x / 1))", + "2 * ($x / 1)", + v -> v(2).multiply(x(v).divide(v(1))), + new Multiply(c(2), new Divide(vx, c(1))) + ) + .advanced( + "(2 / ($x - 1))", + "2 / ($x - 1)", + v -> v(2).divide(x(v).subtract(v(1))), + new Divide(c(2), new Subtract(vx, c(1))) + ) + .advanced( + "((1 * 2) + $x)", + "1 * 2 + $x", + v -> v(1 * 2).add(x(v)), + new Add(new Multiply(c(1), c(2)), vx) + ) + .advanced( + "(($x - 1) - 2)", + "$x - 1 - 2", + v -> x(v).subtract(v(3)), + new Subtract(new Subtract(vx, c(1)), c(2)) + ) + .advanced( + "(($x / 1) * 2)", + "$x / 1 * 2", + v -> x(v).multiply(v(2)), + new Multiply(new Divide(vx, c(1)), c(2)) + ) + .advanced( + "((2 + 1) / 1)", + "(2 + 1) / 1", + v -> v(3), + new Divide(new Add(c(2), c(1)), c(1)) + ) + .advanced( + "(1 + (1 + (2 + 1)))", + "1 + 1 + 2 + 1", + v -> v(1 + 1 + 2 + 1), + new Add(c(1), new Add(c(1), new Add(c(2), c(1)))) + ) + .advanced( + "($x - ((1 * 2) + $x))", + "$x - (1 * 2 + $x)", + v -> x(v).subtract(v(1 * 2).add(x(v))), + new Subtract(vx, new Add(new Multiply(c(1), c(2)), vx)) + ) + .advanced( + "($x * (2 / ($x - 1)))", + "$x * (2 / ($x - 1))", + v -> x(v).multiply(v(2).divide(x(v).subtract(v(1)))), + new Multiply(vx, new Divide(c(2), new Subtract(vx, c(1)))) + ) + .advanced( + "($x / (1 + (2 + 1)))", + "$x / (1 + 2 + 1)", + v -> x(v).divide(v(1 + 2 + 1)), + new Divide(vx, new Add(c(1), new Add(c(2), c(1)))) + ) + .advanced( + "((1 * 2) + (2 + 1))", + "1 * 2 + 2 + 1", + v -> v(1 * 2 + 2 + 1), + new Add(new Multiply(c(1), c(2)), new Add(c(2), c(1))) + ) + .advanced( + "((2 + 1) - (2 + 1))", + "2 + 1 - (2 + 1)", + v -> v(2 + 1 - (2 + 1)), + new Subtract(new Add(c(2), c(1)), new Add(c(2), c(1))) + ) + .advanced( + "(($x - 1) * ($x / 1))", + "($x - 1) * ($x / 1)", + v -> x(v).subtract(v(1)).multiply(x(v).divide(v(1))), + new Multiply(new Subtract(vx, c(1)), new Divide(vx, c(1))) + ) + .advanced( + "(($x - 1) / (1 * 2))", + "($x - 1) / (1 * 2)", + v -> x(v).subtract(v(1)).divide(v(2)), + new Divide(new Subtract(vx, c(1)), new Multiply(c(1), c(2))) + ) + .advanced( + "((($x - 1) - 2) + $x)", + "$x - 1 - 2 + $x", + v -> x(v).subtract(v(3)).add(x(v)), + new Add(new Subtract(new Subtract(vx, c(1)), c(2)), vx) + ) + .advanced( + "(((1 * 2) + $x) - 1)", + "1 * 2 + $x - 1", + v -> v(1).add(x(v)), + new Subtract(new Add(new Multiply(c(1), c(2)), vx), c(1)) + ) + .advanced( + "(((2 + 1) / 1) * $x)", + "(2 + 1) / 1 * $x", + v -> v(3).multiply(x(v)), + new Multiply(new Divide(new Add(c(2), c(1)), c(1)), vx) + ) + .advanced( + "((2 / ($x - 1)) / 2)", + "2 / ($x - 1) / 2", + v -> v(2).divide(x(v).subtract(v(1))).divide(v(2)), + new Divide(new Divide(c(2), new Subtract(vx, c(1))), c(2)) + ); + } + + private static BigDecimal x(final List vars) { + return vars.get(0); + } + + private static BigDecimal y(final List vars) { + return vars.get(1); + } + + private static Const c(final BigDecimal v) { + return TYPE.constant(v); + } + + private static Const c(final long v) { + return TYPE.constant(v(v)); + } + + private static BigDecimal v(final long v) { + return BigDecimal.valueOf(v); + } + + static void main(final String... args) { + TripleExpression.SELECTOR.variant( + "BigDecimalList", + ExpressionTest.v(BigDecimalListExpression::tester) + ).main(args); + } +} diff --git a/java/expression/BigIntegerListExpression.java b/java/expression/BigIntegerListExpression.java new file mode 100644 index 0000000..92128c2 --- /dev/null +++ b/java/expression/BigIntegerListExpression.java @@ -0,0 +1,357 @@ +package expression; + +import base.Asserts; +import base.Pair; +import base.TestCounter; +import expression.common.ExpressionKind; +import expression.common.Type; +import java.math.BigInteger; +import java.util.List; +import java.util.stream.IntStream; + +/** + * @author Georgiy Korneev (kgeorgiy@kgeorgiy.info) + */ +@FunctionalInterface +@SuppressWarnings("ClassReferencesSubclass") +public interface BigIntegerListExpression extends ToMiniString { + BigInteger evaluateBi(List variables); + + // Tests follow. You may temporarily remove everything til the end. + + Add EXAMPLE = new Add( + new Subtract(new Variable(0), new Const(BigInteger.ONE)), + new Multiply(new Variable(1), new Const(BigInteger.TEN)) + ); + + Type TYPE = new Type<>( + BigInteger::valueOf, + random -> v(random.getRandom().nextLong()), + BigInteger.class + ); + ExpressionKind KIND = + new ExpressionKind<>( + TYPE, + BigIntegerListExpression.class, + (r, c) -> + IntStream.range(0, c) + .mapToObj(name -> + Pair.of( + "$" + name, + new Variable(name) + ) + ) + .toList(), + (expr, variables, values) -> expr.evaluateBi(values) + ); + + @SuppressWarnings("PointlessArithmeticExpression") + static ExpressionTester tester(final TestCounter counter) { + Asserts.assertEquals( + "Example toString()", + "(($0 - 1) + ($1 * 10))", + EXAMPLE.toString() + ); + Asserts.assertEquals( + EXAMPLE + " at (2, 3)", + BigInteger.valueOf(31), + EXAMPLE.evaluateBi( + List.of(BigInteger.valueOf(2), BigInteger.valueOf(3)) + ) + ); + + final Variable vx = new Variable(0); + final Variable vy = new Variable(1); + + return new ExpressionTester<>( + counter, + KIND, + c -> v -> c, + (op, a, b) -> v -> op.apply(a.evaluateBi(v), b.evaluateBi(v)), + BigInteger::add, + BigInteger::subtract, + BigInteger::multiply, + BigInteger::divide + ) + .basic("10", "10", v -> v(10), c(10)) + .basic("$x", "$x", BigIntegerListExpression::x, vx) + .basic("$y", "$y", BigIntegerListExpression::y, vy) + .basic("($x + $y)", "$x + $y", v -> x(v).add(y(v)), new Add(vx, vy)) + .basic("($x + 2)", "$x + 2", v -> x(v).add(v(2)), new Add(vx, c(2))) + .basic( + "(2 - $x)", + "2 - $x", + v -> v(2).subtract(x(v)), + new Subtract(c(2), vx) + ) + .basic( + "(3 * $x)", + "3 * $x", + v -> v(3).multiply(x(v)), + new Multiply(c(3), vx) + ) + .basic("($x + $x)", "$x + $x", v -> x(v).add(x(v)), new Add(vx, vx)) + .basic( + "($x / -2)", + "$x / -2", + v -> x(v).divide(v(-2)), + new Divide(vx, c(-2)) + ) + .basic("(2 + $x)", "2 + $x", v -> v(2).add(x(v)), new Add(c(2), vx)) + .basic( + "((1 + 2) + 3)", + "1 + 2 + 3", + v -> v(6), + new Add(new Add(c(1), c(2)), c(3)) + ) + .basic( + "(1 + (2 * 3))", + "1 + 2 * 3", + v -> v(7), + new Add(c(1), new Multiply(c(2), c(3))) + ) + .basic( + "(1 - (2 * 3))", + "1 - 2 * 3", + v -> v(-5), + new Subtract(c(1), new Multiply(c(2), c(3))) + ) + .basic( + "(1 + (2 + 3))", + "1 + 2 + 3", + v -> v(6), + new Add(c(1), new Add(c(2), c(3))) + ) + .basic( + "((1 - 2) - 3)", + "1 - 2 - 3", + v -> v(-4), + new Subtract(new Subtract(c(1), c(2)), c(3)) + ) + .basic( + "(1 - (2 - 3))", + "1 - (2 - 3)", + v -> v(2), + new Subtract(c(1), new Subtract(c(2), c(3))) + ) + .basic( + "((1 * 2) * 3)", + "1 * 2 * 3", + v -> v(6), + new Multiply(new Multiply(c(1), c(2)), c(3)) + ) + .basic( + "(1 * (2 * 3))", + "1 * 2 * 3", + v -> v(6), + new Multiply(c(1), new Multiply(c(2), c(3))) + ) + .basic( + "((10 / 2) / 3)", + "10 / 2 / 3", + v -> v(10 / 2 / 3), + new Divide(new Divide(c(10), c(2)), c(3)) + ) + .basic( + "(10 / (3 / 2))", + "10 / (3 / 2)", + v -> v(10 / (3 / 2)), + new Divide(c(10), new Divide(c(3), c(2))) + ) + .basic( + "(($x * $x) + (($x - 1) / 10))", + "$x * $x + ($x - 1) / 10", + v -> x(v).multiply(x(v)).add(x(v).subtract(v(1)).divide(v(10))), + new Add( + new Multiply(vx, vx), + new Divide(new Subtract(vx, c(1)), c(10)) + ) + ) + .basic( + "($x * -1000000000)", + "$x * -1000000000", + v -> x(v).multiply(v(-1_000_000_000)), + new Multiply(vx, c(-1_000_000_000)) + ) + .basic( + "($x * -1000000000000000)", + "$x * -1000000000000000", + v -> x(v).multiply(v(-1_000_000_000_000_000L)), + new Multiply(vx, c(-1_000_000_000_000_000L)) + ) + .basic( + "(10 / $x)", + "10 / $x", + v -> v(10).divide(x(v)), + new Divide(c(10), vx) + ) + .basic( + "($x / $x)", + "$x / $x", + v -> x(v).divide(x(v)), + new Divide(vx, vx) + ) + .advanced("(2 + 1)", "2 + 1", v -> v(2 + 1), new Add(c(2), c(1))) + .advanced( + "($x - 1)", + "$x - 1", + v -> x(v).subtract(v(1)), + new Subtract(vx, c(1)) + ) + .advanced( + "(1 * 2)", + "1 * 2", + v -> v(1 * 2), + new Multiply(c(1), c(2)) + ) + .advanced( + "($x / 1)", + "$x / 1", + v -> x(v).divide(v(1)), + new Divide(vx, c(1)) + ) + .advanced( + "(1 + (2 + 1))", + "1 + 2 + 1", + v -> v(1 + 2 + 1), + new Add(c(1), new Add(c(2), c(1))) + ) + .advanced( + "($x - ($x - 1))", + "$x - ($x - 1)", + v -> x(v).subtract(x(v).subtract(v(1))), + new Subtract(vx, new Subtract(vx, c(1))) + ) + .advanced( + "(2 * ($x / 1))", + "2 * ($x / 1)", + v -> v(2).multiply(x(v).divide(v(1))), + new Multiply(c(2), new Divide(vx, c(1))) + ) + .advanced( + "(2 / ($x - 1))", + "2 / ($x - 1)", + v -> v(2).divide(x(v).subtract(v(1))), + new Divide(c(2), new Subtract(vx, c(1))) + ) + .advanced( + "((1 * 2) + $x)", + "1 * 2 + $x", + v -> v(1 * 2).add(x(v)), + new Add(new Multiply(c(1), c(2)), vx) + ) + .advanced( + "(($x - 1) - 2)", + "$x - 1 - 2", + v -> x(v).subtract(v(3)), + new Subtract(new Subtract(vx, c(1)), c(2)) + ) + .advanced( + "(($x / 1) * 2)", + "$x / 1 * 2", + v -> x(v).multiply(v(2)), + new Multiply(new Divide(vx, c(1)), c(2)) + ) + .advanced( + "((2 + 1) / 1)", + "(2 + 1) / 1", + v -> v(3), + new Divide(new Add(c(2), c(1)), c(1)) + ) + .advanced( + "(1 + (1 + (2 + 1)))", + "1 + 1 + 2 + 1", + v -> v(1 + 1 + 2 + 1), + new Add(c(1), new Add(c(1), new Add(c(2), c(1)))) + ) + .advanced( + "($x - ((1 * 2) + $x))", + "$x - (1 * 2 + $x)", + v -> x(v).subtract(v(1 * 2).add(x(v))), + new Subtract(vx, new Add(new Multiply(c(1), c(2)), vx)) + ) + .advanced( + "($x * (2 / ($x - 1)))", + "$x * (2 / ($x - 1))", + v -> x(v).multiply(v(2).divide(x(v).subtract(v(1)))), + new Multiply(vx, new Divide(c(2), new Subtract(vx, c(1)))) + ) + .advanced( + "($x / (1 + (2 + 1)))", + "$x / (1 + 2 + 1)", + v -> x(v).divide(v(1 + 2 + 1)), + new Divide(vx, new Add(c(1), new Add(c(2), c(1)))) + ) + .advanced( + "((1 * 2) + (2 + 1))", + "1 * 2 + 2 + 1", + v -> v(1 * 2 + 2 + 1), + new Add(new Multiply(c(1), c(2)), new Add(c(2), c(1))) + ) + .advanced( + "((2 + 1) - (2 + 1))", + "2 + 1 - (2 + 1)", + v -> v(2 + 1 - (2 + 1)), + new Subtract(new Add(c(2), c(1)), new Add(c(2), c(1))) + ) + .advanced( + "(($x - 1) * ($x / 1))", + "($x - 1) * ($x / 1)", + v -> x(v).subtract(v(1)).multiply(x(v).divide(v(1))), + new Multiply(new Subtract(vx, c(1)), new Divide(vx, c(1))) + ) + .advanced( + "(($x - 1) / (1 * 2))", + "($x - 1) / (1 * 2)", + v -> x(v).subtract(v(1)).divide(v(2)), + new Divide(new Subtract(vx, c(1)), new Multiply(c(1), c(2))) + ) + .advanced( + "((($x - 1) - 2) + $x)", + "$x - 1 - 2 + $x", + v -> x(v).subtract(v(3)).add(x(v)), + new Add(new Subtract(new Subtract(vx, c(1)), c(2)), vx) + ) + .advanced( + "(((1 * 2) + $x) - 1)", + "1 * 2 + $x - 1", + v -> v(1).add(x(v)), + new Subtract(new Add(new Multiply(c(1), c(2)), vx), c(1)) + ) + .advanced( + "(((2 + 1) / 1) * $x)", + "(2 + 1) / 1 * $x", + v -> v(3).multiply(x(v)), + new Multiply(new Divide(new Add(c(2), c(1)), c(1)), vx) + ) + .advanced( + "((2 / ($x - 1)) / 2)", + "2 / ($x - 1) / 2", + v -> v(2).divide(x(v).subtract(v(1))).divide(v(2)), + new Divide(new Divide(c(2), new Subtract(vx, c(1))), c(2)) + ); + } + + private static BigInteger x(final List vars) { + return vars.get(0); + } + + private static BigInteger y(final List vars) { + return vars.get(1); + } + + private static Const c(final long v) { + return TYPE.constant(v(v)); + } + + private static BigInteger v(final long v) { + return BigInteger.valueOf(v); + } + + static void main(final String... args) { + TripleExpression.SELECTOR.variant( + "BigIntegerList", + ExpressionTest.v(BigIntegerListExpression::tester) + ).main(args); + } +}