From b75b1b97d846d7dd7ab6e3f5f5eb4ec38d060108 Mon Sep 17 00:00:00 2001 From: Alex Birkett Date: Fri, 17 Oct 2014 10:15:33 +0200 Subject: [PATCH 1/2] Add test for editvars with required strength --- .../org/klomp/cassowary/CassowaryTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/test/java/org/klomp/cassowary/CassowaryTest.java b/src/test/java/org/klomp/cassowary/CassowaryTest.java index 62f95d8..a570404 100644 --- a/src/test/java/org/klomp/cassowary/CassowaryTest.java +++ b/src/test/java/org/klomp/cassowary/CassowaryTest.java @@ -185,6 +185,43 @@ public void multiedit() throws CLInternalError, RequiredConstraintFailureExcepti assertEquals(40, h.getValue(), EPSILON); } + @Test + public void multieditRequired() throws CLInternalError, RequiredConstraintFailureException, CLException { + ClVariable x = new ClVariable("x"); + ClVariable y = new ClVariable("y"); + ClVariable w = new ClVariable("w"); + ClVariable h = new ClVariable("h"); + ClSimplexSolver solver = new ClSimplexSolver(); + + solver.addStay(x).addStay(y).addStay(w).addStay(h); + + solver.addEditVar(x, ClStrength.required).addEditVar(y, ClStrength.required).beginEdit(); + + solver.suggestValue(x, 10).suggestValue(y, 20).resolve(); + + assertEquals(10, x.getValue(), EPSILON); + assertEquals(20, y.getValue(), EPSILON); + assertEquals(0, w.getValue(), EPSILON); + assertEquals(0, h.getValue(), EPSILON); + + solver.addEditVar(w).addEditVar(h).beginEdit(); + + solver.suggestValue(w, 30).suggestValue(h, 40).endEdit(); + + assertEquals(10, x.getValue(), EPSILON); + assertEquals(20, y.getValue(), EPSILON); + assertEquals(30, w.getValue(), EPSILON); + assertEquals(40, h.getValue(), EPSILON); + + solver.suggestValue(x, 50).suggestValue(y, 60).endEdit(); + + assertEquals(50, x.getValue(), EPSILON); + assertEquals(60, y.getValue(), EPSILON); + assertEquals(30, w.getValue(), EPSILON); + assertEquals(40, h.getValue(), EPSILON); + } + + @Test public void requiredEditVar() { ClVariable x = new ClVariable("x"); From b48f6f567b64034f1bbd8b61a6df138110a9e16f Mon Sep 17 00:00:00 2001 From: Alex Birkett Date: Fri, 17 Oct 2014 11:24:58 +0200 Subject: [PATCH 2/2] Partial fix for adding "required" edit variables This change was worked out by studying the differences between the java and js implementations of cassowary When the tests are run, an assertion occurs in removeConstraintInternal (line 455 - "eVars != null"). If the assertion is commented out, the library appears to work although it may be leaking --- .../java/org/klomp/cassowary/ClEditInfo.java | 10 +++++----- .../org/klomp/cassowary/ClSimplexSolver.java | 20 ++++++++++++------- .../clconstraint/ClLinearInequality.java | 1 + 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/klomp/cassowary/ClEditInfo.java b/src/main/java/org/klomp/cassowary/ClEditInfo.java index e805e44..d6338f8 100644 --- a/src/main/java/org/klomp/cassowary/ClEditInfo.java +++ b/src/main/java/org/klomp/cassowary/ClEditInfo.java @@ -22,7 +22,7 @@ * smalltalk version of the code. */ class ClEditInfo { - public ClEditInfo(ClConstraint cn_, ClSlackVariable eplus_, ClSlackVariable eminus_, double prevEditConstant_, int i_) { + public ClEditInfo(ClConstraint cn_, ClAbstractVariable eplus_, ClAbstractVariable eminus_, double prevEditConstant_, int i_) { cn = cn_; clvEditPlus = eplus_; clvEditMinus = eminus_; @@ -38,11 +38,11 @@ public ClConstraint Constraint() { return cn; } - public ClSlackVariable ClvEditPlus() { + public ClAbstractVariable ClvEditPlus() { return clvEditPlus; } - public ClSlackVariable ClvEditMinus() { + public ClAbstractVariable ClvEditMinus() { return clvEditMinus; } @@ -55,8 +55,8 @@ public void SetPrevEditConstant(double prevEditConstant_) { } private ClConstraint cn; - private ClSlackVariable clvEditPlus; - private ClSlackVariable clvEditMinus; + private ClAbstractVariable clvEditPlus; + private ClAbstractVariable clvEditMinus; private double prevEditConstant; private int i; diff --git a/src/main/java/org/klomp/cassowary/ClSimplexSolver.java b/src/main/java/org/klomp/cassowary/ClSimplexSolver.java index ac97435..1671e2a 100644 --- a/src/main/java/org/klomp/cassowary/ClSimplexSolver.java +++ b/src/main/java/org/klomp/cassowary/ClSimplexSolver.java @@ -124,7 +124,7 @@ public final ClSimplexSolver addConstraint(ClConstraint cn) throws RequiredConst if (fTraceOn) fnenterprint("addConstraint: " + cn); - List eplus_eminus = new ArrayList(2); + List eplus_eminus = new ArrayList(2); ClDouble prevEConstant = new ClDouble(); ClLinearExpression expr = newExpression(cn, eplus_eminus, prevEConstant); boolean fAddedOkDirectly = false; @@ -150,8 +150,8 @@ public final ClSimplexSolver addConstraint(ClConstraint cn) throws RequiredConst if (cn.isEditConstraint()) { int i = _editVarMap.size(); ClEditConstraint cnEdit = (ClEditConstraint) cn; - ClSlackVariable clvEplus = eplus_eminus.get(0); - ClSlackVariable clvEminus = eplus_eminus.get(1); + ClAbstractVariable clvEplus = eplus_eminus.get(0); + ClAbstractVariable clvEminus = eplus_eminus.get(1); _editVarMap.put(cnEdit.variable(), new ClEditInfo(cnEdit, clvEplus, clvEminus, prevEConstant.doubleValue(), i)); } @@ -456,7 +456,7 @@ private final ClSimplexSolver removeConstraintInternal(ClConstraint cn, ClAbstra ClEditConstraint cnEdit = (ClEditConstraint) cn; ClVariable clv = cnEdit.variable(); ClEditInfo cei = _editVarMap.get(clv); - ClSlackVariable clvEditMinus = cei.ClvEditMinus(); + ClAbstractVariable clvEditMinus = cei.ClvEditMinus(); // ClSlackVariable clvEditPlus = cei.ClvEditPlus(); // the clvEditPlus is a marker variable that is removed elsewhere removeColumn(clvEditMinus); @@ -534,8 +534,8 @@ public final ClSimplexSolver suggestValue(ClVariable v, double x) throws CLExcep System.err.println("suggestValue for variable " + v + ", but var is not an edit variable\n"); throw new CLException(); } - ClSlackVariable clvEditPlus = cei.ClvEditPlus(); - ClSlackVariable clvEditMinus = cei.ClvEditMinus(); + ClAbstractVariable clvEditPlus = cei.ClvEditPlus(); + ClAbstractVariable clvEditMinus = cei.ClvEditMinus(); double delta = x - cei.PrevEditConstant(); cei.SetPrevEditConstant(x); deltaEditConstant(delta, clvEditPlus, clvEditMinus); @@ -902,7 +902,7 @@ protected final void dualOptimize() throws CLInternalError { // Normalize if necessary so that the constant is non-negative. If // the constraint is non-required give its error variables an // appropriate weight in the objective function. - protected final ClLinearExpression newExpression(ClConstraint cn, List eplus_eminus, ClDouble prevEConstant) { + protected final ClLinearExpression newExpression(ClConstraint cn, List eplus_eminus, ClDouble prevEConstant) { if (fTraceOn) fnenterprint("newExpression: " + cn); if (fTraceOn) @@ -917,6 +917,7 @@ protected final ClLinearExpression newExpression(ClConstraint cn, List cnTerms = cnExpr.terms(); + for (Map.Entry entry : cnTerms.entrySet()) { final ClAbstractVariable v = entry.getKey(); double c = entry.getValue().doubleValue(); @@ -947,6 +948,11 @@ protected final ClLinearExpression newExpression(ClConstraint cn, List