From 76014e190341affc09c65baa4e615151058c9e14 Mon Sep 17 00:00:00 2001 From: Alex Birkett Date: Sun, 1 Feb 2015 20:45:20 +0100 Subject: [PATCH] Added Symbolics class Some tests now passing! --- src/main/java/no/birkett/kiwi/Constraint.java | 7 +- src/main/java/no/birkett/kiwi/Expression.java | 4 + src/main/java/no/birkett/kiwi/Symbolics.java | 410 ++++++++++++++++++ src/main/java/no/birkett/kiwi/Variable.java | 10 +- src/test/java/no/birkett/kiwi/Tests.java | 87 ++-- 5 files changed, 472 insertions(+), 46 deletions(-) create mode 100644 src/main/java/no/birkett/kiwi/Symbolics.java diff --git a/src/main/java/no/birkett/kiwi/Constraint.java b/src/main/java/no/birkett/kiwi/Constraint.java index 10192fd..3619da0 100644 --- a/src/main/java/no/birkett/kiwi/Constraint.java +++ b/src/main/java/no/birkett/kiwi/Constraint.java @@ -22,8 +22,8 @@ public class Constraint { this.strength = Strength.clip(strength); } - public Constraint(Constraint other, RelationalOperator op) { - this(other.expression, other.op, other.strength); + public Constraint(Constraint other, double strength) { + this(other.expression, other.op, strength); } public Expression getExpression() { @@ -38,8 +38,9 @@ public class Constraint { return strength; } - public void setStrength(double strength) { + public Constraint setStrength(double strength) { this.strength = strength; + return this; } public RelationalOperator getOp() { diff --git a/src/main/java/no/birkett/kiwi/Expression.java b/src/main/java/no/birkett/kiwi/Expression.java index ba095d6..750af3e 100644 --- a/src/main/java/no/birkett/kiwi/Expression.java +++ b/src/main/java/no/birkett/kiwi/Expression.java @@ -36,6 +36,10 @@ public class Expression { this.constant = constant; } + public Expression(List terms) { + this(terms, 0); + } + public double getConstant() { return constant; } diff --git a/src/main/java/no/birkett/kiwi/Symbolics.java b/src/main/java/no/birkett/kiwi/Symbolics.java new file mode 100644 index 0000000..19319c9 --- /dev/null +++ b/src/main/java/no/birkett/kiwi/Symbolics.java @@ -0,0 +1,410 @@ +package no.birkett.kiwi; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by alex on 31/01/15. + */ +public class Symbolics { + + private Symbolics() { + } + + // Variable multiply, divide, and unary invert + public static Term multiply(Variable variable, double coefficient) { + return new Term(variable, coefficient); + } + + public static Term divide(Variable variable, double denominator) { + return multiply(variable, (1.0 / denominator)); + } + + public static Term negate(Variable variable) { + return multiply(variable, -1.0); + } + + // Term multiply, divide, and unary invert + public static Term multiply(Term term, double coefficient) { + return new Term(term.getVariable(), term.getCoefficient() * coefficient); + } + + public static Term divide(Term term, double denominator) { + return multiply(term, (1.0 / denominator)); + } + + public static Term negate(Term term) { + return multiply(term, -1.0); + } + + // Expression multiply, divide, and unary invert + public static Expression multiply(Expression expression, double coefficient) { + + List terms = new ArrayList(); + + for (Term term : expression.getTerms()) { + terms.add(multiply(term, coefficient)); + } + + // TODO Do we need to make a copy of the term objects in the array? + return new Expression(terms, expression.getConstant() * coefficient); + } + + public static Expression divide(Expression expression, double denominator) { + return multiply(expression, (1.0 / denominator)); + } + + + public static Expression negate(Expression expression) { + return multiply(expression, -1.0); + } + + // Double multiply + public static Expression multiply(double coefficient, Expression expression) { + return multiply(expression, coefficient); + } + + + public static Term multiply(double coefficient, Term term) { + return multiply(term, coefficient); + } + + + public static Term multiply(double coefficient, Variable variable) { + return multiply(variable, coefficient); + } + + // Expression add and subtract + public static Expression add(Expression first, Expression second) { + //TODO do we need to copy term objects? + List terms = new ArrayList(first.getTerms().size() + second.getTerms().size()); + + terms.addAll(first.getTerms()); + terms.addAll(second.getTerms()); + + return new Expression(terms, first.getConstant() + second.getConstant()); + } + + public static Expression add(Expression first, Term second) { + //TODO do we need to copy term objects? + List terms = new ArrayList(first.getTerms().size() + 1); + + terms.addAll(first.getTerms()); + terms.add(second); + + return new Expression(terms, first.getConstant()); + } + + public static Expression add(Expression expression, Variable variable) { + return add(expression, new Term(variable)); + } + + public static Expression add(Expression expression, double constant) { + return new Expression(expression.getTerms(), expression.getConstant() + constant); + } + + public static Expression subtract(Expression first, Expression second) { + return add(first, negate(second)); + } + + public static Expression subtract(Expression expression, Term term) { + return add(expression, negate(term)); + } + + public static Expression subtract(Expression expression, Variable variable) { + return add(expression, negate(variable)); + } + + public static Expression subtract(Expression expression, double constant) { + return add(expression, -constant); + } + + // Term add and subtract + public static Expression add(Term term, Expression expression) { + return add(expression, term); + } + + public static Expression add(Term first, Term second) { + List terms = new ArrayList(2); + terms.add(first); + terms.add(second); + return new Expression(terms); + } + + public static Expression add(Term term, Variable variable) { + return add(term, new Term(variable)); + } + + public static Expression add(Term term, double constant) { + return new Expression(term, constant); + } + + public static Expression subtract(Term term, Expression expression) { + return add(negate(expression), term); + } + + public static Expression subtract(Term first, Term second) { + return add(first, negate(second)); + } + + public static Expression subtract(Term term, Variable variable) { + return add(term, negate(variable)); + } + + public static Expression subtract(Term term, double constant) { + return add(term, -constant); + } + + // Variable add and subtract + public static Expression add(Variable variable, Expression expression) { + return add(expression, variable); + } + + public static Expression add(Variable variable, Term term) { + return add(term, variable); + } + + public static Expression add(Variable first, Variable second) { + return add(new Term(first), second); + } + + public static Expression add(Variable variable, double constant) { + return add(new Term(variable), constant); + } + + public static Expression subtract(Variable variable, Expression expression) { + return add(variable, negate(expression)); + } + + public static Expression subtract(Variable variable, Term term) { + return add(variable, negate(term)); + } + + public static Expression subtract(Variable first, Variable second) { + return add(first, negate(second)); + } + + public static Expression subtract(Variable variable, double constant) { + return add(variable, -constant); + } + + // Double add and subtract + + public static Expression add(double constant, Expression expression) { + return add(expression, constant); + } + + public static Expression add(double constant, Term term) { + return add(term, constant); + } + + public static Expression add(double constant, Variable variable) { + return add(variable, constant); + } + + public static Expression subtract(double constant, Expression expression) { + return add(negate(expression), constant); + } + + public static Expression subtract(double constant, Term term) { + return add(negate(term), constant); + } + + public static Expression subtract(double constant, Variable variable) { + return add(negate(variable), constant); + } + + // Expression relations + public static Constraint equals(Expression first, Expression second) { + return new Constraint(subtract(first, second), RelationalOperator.OP_EQ); + } + + public static Constraint equals(Expression expression, Term term) { + return equals(expression, new Expression(term)); + } + + public static Constraint equals(Expression expression, Variable variable) { + return equals(expression, new Term(variable)); + } + + public static Constraint equals(Expression expression, double constant) { + return equals(expression, new Expression(constant)); + } + + public static Constraint lessThanOrEqualTo(Expression first, Expression second) { + return new Constraint(subtract(first, second), RelationalOperator.OP_LE); + } + + public static Constraint lessThanOrEqualTo(Expression expression, Term term) { + return lessThanOrEqualTo(expression, new Expression(term)); + } + + public static Constraint lessThanOrEqualTo(Expression expression, Variable variable) { + return lessThanOrEqualTo(expression, new Term(variable)); + } + + public static Constraint lessThanOrEqualTo(Expression expression, double constant) { + return lessThanOrEqualTo(expression, new Expression(constant)); + } + + public static Constraint greaterThanOrEqualTo(Expression first, Expression second) { + return new Constraint(subtract(first, second), RelationalOperator.OP_GE); + } + + public static Constraint greaterThanOrEqualTo(Expression expression, Term term) { + return greaterThanOrEqualTo(expression, new Expression(term)); + } + + public static Constraint greaterThanOrEqualTo(Expression expression, Variable variable) { + return greaterThanOrEqualTo(expression, new Term(variable)); + } + + public static Constraint greaterThanOrEqualTo(Expression expression, double constant) { + return greaterThanOrEqualTo(expression, new Expression(constant)); + } + + // Term relations + public static Constraint equals(Term term, Expression expression) { + return equals(expression, term); + } + + public static Constraint equals(Term first, Term second) { + return equals(new Expression(first), second); + } + + public static Constraint equals(Term term, Variable variable) { + return equals(new Expression(term), variable); + } + + public static Constraint equals(Term term, double constant) { + return equals(new Expression(term), constant); + } + + public static Constraint lessThanOrEqualTo(Term term, Expression expression) { + return lessThanOrEqualTo(expression, term); + } + + public static Constraint lessThanOrEqualTo(Term first, Term second) { + return lessThanOrEqualTo(new Expression(first), second); + } + + public static Constraint lessThanOrEqualTo(Term term, Variable variable) { + return lessThanOrEqualTo(new Expression(term), variable); + } + + public static Constraint lessThanOrEqualTo(Term term, double constant) { + return lessThanOrEqualTo(new Expression(term), constant); + } + + public static Constraint greaterThanOrEqualTo(Term term, Expression expression) { + return greaterThanOrEqualTo(expression, term); + } + + public static Constraint greaterThanOrEqualTo(Term first, Term second) { + return greaterThanOrEqualTo(new Expression(first), second); + } + + public static Constraint greaterThanOrEqualTo(Term term, Variable variable) { + return greaterThanOrEqualTo(new Expression(term), variable); + } + + public static Constraint greaterThanOrEqualTo(Term term, double constant) { + return greaterThanOrEqualTo(new Expression(term), constant); + } + + // Variable relations + public static Constraint equals(Variable variable, Expression expression) { + return equals(expression, variable); + } + + public static Constraint equals(Variable variable, Term term) { + return equals(term, variable); + } + + public static Constraint equals(Variable first, Variable second) { + return equals(new Term(first), second); + } + + public static Constraint equals(Variable variable, double constant) { + return equals(new Term(variable), constant); + } + + public static Constraint lessThanOrEqualTo(Variable variable, Expression expression) { + return lessThanOrEqualTo(expression, variable); + } + + public static Constraint lessThanOrEqualTo(Variable variable, Term term) { + return lessThanOrEqualTo(term, variable); + } + + public static Constraint lessThanOrEqualTo(Variable first, Variable second) { + return lessThanOrEqualTo(new Term(first), second); + } + + public static Constraint lessThanOrEqualTo(Variable variable, double constant) { + return lessThanOrEqualTo(new Term(variable), constant); + } + + public static Constraint greaterThanOrEqualTo(Variable variable, Expression expression) { + return greaterThanOrEqualTo(expression, variable); + } + + public static Constraint greaterThanOrEqualTo(Variable variable, Term term) { + return greaterThanOrEqualTo(term, variable); + } + + public static Constraint greaterThanOrEqualTo(Variable first, Variable second) { + return greaterThanOrEqualTo(new Term(first), second); + } + + public static Constraint greaterThanOrEqualTo(Variable variable, double constant) { + return greaterThanOrEqualTo(new Term(variable), constant); + } + + // Double relations + public static Constraint equals(double constant, Expression expression) { + return equals(expression, constant); + } + + public static Constraint equals(double constant, Term term) { + return equals(term, constant); + } + + public static Constraint equals(double constant, Variable variable) { + return equals(variable, constant); + } + + public static Constraint lessThanOrEqualTo(double constant, Expression expression) { + return lessThanOrEqualTo(expression, constant); + } + + public static Constraint lessThanOrEqualTo(double constant, Term term) { + return lessThanOrEqualTo(term, constant); + } + + public static Constraint lessThanOrEqualTo(double constant, Variable variable) { + return lessThanOrEqualTo(variable, constant); + } + + public static Constraint greaterThanOrEqualTo(double constant, Expression expression) { + return greaterThanOrEqualTo(expression, constant); + } + + public static Constraint greaterThanOrEqualTo(double constant, Term term) { + return greaterThanOrEqualTo(term, constant); + } + + public static Constraint greaterThanOrEqualTo(double constant, Variable variable) { + return greaterThanOrEqualTo(variable, constant); + } + + // Constraint strength modifier + public static Constraint modifyStrength(Constraint constraint, double strength) { + return new Constraint(constraint, strength); + } + + public static Constraint modifyStrength(double strength, Constraint constraint) { + return modifyStrength(strength, constraint); + } + +} diff --git a/src/main/java/no/birkett/kiwi/Variable.java b/src/main/java/no/birkett/kiwi/Variable.java index 68dc903..9959000 100644 --- a/src/main/java/no/birkett/kiwi/Variable.java +++ b/src/main/java/no/birkett/kiwi/Variable.java @@ -14,9 +14,8 @@ public class Variable { } public Variable(double value) { - } - + public double getValue() { return value; } @@ -25,11 +24,4 @@ public class Variable { this.value = value; } - public Expression times(double value) { - return null; - } - - public Expression plus(double value) { - return null; - } } diff --git a/src/test/java/no/birkett/kiwi/Tests.java b/src/test/java/no/birkett/kiwi/Tests.java index 27443e4..9d88f11 100644 --- a/src/test/java/no/birkett/kiwi/Tests.java +++ b/src/test/java/no/birkett/kiwi/Tests.java @@ -10,36 +10,73 @@ public class Tests { private static double EPSILON = 1.0e-8; @Test - public void testKiwi() throws UnsatisfiableConstraintException, DuplicateConstraintException { + public void simpleNew() throws UnsatisfiableConstraintException, DuplicateConstraintException { + Solver solver = new Solver(); + Variable x = new Variable("x"); + + + solver.addConstraint(Symbolics.equals(Symbolics.add(x,2), 20)); + + solver.updateVariables(); + + assertEquals(x.getValue(), 18, EPSILON); + } + + @Test + public void simple0() throws UnsatisfiableConstraintException, DuplicateConstraintException { Solver solver = new Solver(); Variable x = new Variable("x"); Variable y = new Variable("y"); + // x = 20 + solver.addConstraint(Symbolics.equals(x, 20)); - Term term = new Term(x); + // x + 2 == y + 10 + // + solver.addConstraint(Symbolics.equals(Symbolics.add(x,2), Symbolics.add(y, 10))); - Expression expression = new Expression(term); - - Constraint constraint = new Constraint(expression, RelationalOperator.OP_EQ); - - solver.addConstraint(constraint); solver.updateVariables(); + + System.out.println("x " + x.getValue() + " y " + y.getValue()); + + assertEquals(y.getValue(), 12, EPSILON); + assertEquals(x.getValue(), 20, EPSILON); } - /*@Test - public void simple1() { - Variable x = new Variable(167); - Variable y = new Variable(2); + @Test + public void simple1() throws DuplicateConstraintException, UnsatisfiableConstraintException { + Variable x = new Variable("x"); + Variable y = new Variable("y"); + Solver solver = new Solver(); + solver.addConstraint(Symbolics.equals(x, y)); + solver.updateVariables(); + assertEquals(x.getValue(), y.getValue(), EPSILON); + } + + @Test + public void casso1() throws DuplicateConstraintException, UnsatisfiableConstraintException { + Variable x = new Variable("x"); + Variable y = new Variable("y"); Solver solver = new Solver(); - Constraint eq = new Constraint(x, Constraint.Operator.EQ, new Expression(y)); - //ClLinearEquation eq = new ClLinearEquation(x, new ClLinearExpression(y)); - solver.addConstraint(eq); - assertEquals(x.value(), y.value(), EPSILON); + solver.addConstraint(Symbolics.lessThanOrEqualTo(x, y)); + solver.addConstraint(Symbolics.equals(y, Symbolics.add(x, 3.0))); + solver.addConstraint(Symbolics.equals(x, 10.0).setStrength(Strength.WEAK)); + solver.addConstraint(Symbolics.equals(y, 10.0).setStrength(Strength.WEAK)); + + solver.updateVariables(); + + if (Math.abs(x.getValue() - 10.0) < EPSILON) { + assertEquals(10, x.getValue(), EPSILON); + assertEquals(13, y.getValue(), EPSILON); + } else { + assertEquals(7, x.getValue(), EPSILON); + assertEquals(10, y.getValue(), EPSILON); + } } - @Test + /*@Test public void addDelete1() { Variable x = new Variable("x"); Solver solver = new Solver(); @@ -112,25 +149,7 @@ public class Tests { assertEquals(120, y.value(), EPSILON); } - @Test - public void casso1() { - Variable x = new Variable("x"); - Variable y = new Variable("y"); - Solver solver = new Solver(); - solver.addConstraint(new Constraint(x, Constraint.Operator.LEQ, y)); - solver.addConstraint(new Constraint(y, Constraint.Operator.EQ, x.plus(3.0))); - solver.addConstraint(new Constraint(x, Constraint.Operator.EQ, 10.0, Strength.WEAK)); - solver.addConstraint(new Constraint(y, Constraint.Operator.EQ, 10.0, Strength.WEAK)); - - if (Math.abs(x.getValue() - 10.0) < EPSILON) { - assertEquals(10, x.value(), EPSILON); - assertEquals(13, y.value(), EPSILON); - } else { - assertEquals(7, x.value(), EPSILON); - assertEquals(10, y.value(), EPSILON); - } - } @Test(expected = RequiredFailure.class) public void inconsistent1() throws InternalError {