Initial revision
[ardour.git] / libs / cassowary / ClFDBinaryOneWayConstraint.cc
1 // $Id$
2 //
3 // Cassowary Incremental Constraint Solver
4 // Original Smalltalk Implementation by Alan Borning
5 // This C++ Implementation by Greg J. Badros, <gjb@cs.washington.edu>
6 // http://www.cs.washington.edu/homes/gjb
7 // (C) 1998, 1999 Greg J. Badros and Alan Borning
8 // See ../LICENSE for legal details regarding this software
9 //
10 // ClFDBinaryOneWayConstraint.cc
11
12
13 #ifdef HAVE_CONFIG_H
14 #include <config.h>
15 #define CONFIG_H_INCLUDED
16 #endif
17
18 #include <cassowary/ClFDBinaryOneWayConstraint.h>
19 #include <cassowary/ClLinearConstraint.h>
20 #include <cassowary/ClTypedefs.h>
21 #include <cassowary/ClLinearExpression.h>
22
23
24 void 
25 ClFDBinaryOneWayConstraint::EnsurePreconditionsForCn(const ClConstraint &cn)
26 {
27   ClVarSet setRO = cn.ReadOnlyVars();
28   if (setRO.size() > 1) 
29     throw ExCLTooDifficultSpecial("Only 0 or 1 read only variables are allowed");
30   const ClLinearExpression &expr = cn.Expression();
31   const ClVarToNumberMap &terms = expr.Terms();
32   if (terms.size() > 2)
33     throw ExCLTooDifficultSpecial("Cannot have more than 2 variables");
34   if (terms.size() == 0)
35     throw ExCLTooDifficultSpecial("Must have at least 1 variable");
36   if (terms.size() == 2 && setRO.size() == 0)
37     throw ExCLTooDifficultSpecial("Both variables cannot be read-write, one must be read-only");
38   if (terms.size() == 1 && setRO.size() == 1)
39     throw ExCLTooDifficultSpecial("Single read-only variable in LinearConstraint -- must not be read-only.");
40   ClVariable clv = (*terms.begin()).first;
41   /* GJB:FIXME:: iterate over all the variables */
42   if (!clv->IsFDVariable()) {
43     throw ExCLTooDifficultSpecial("FD constraint contains non-FD variables");
44   }
45 }
46
47 bool 
48 ClFDBinaryOneWayConstraint::FCanConvertCn(const ClConstraint &cn)
49 {
50   try {
51     EnsurePreconditionsForCn(cn);
52     return true;
53   } catch (...) {
54     return false;
55   }
56 }
57
58
59 ClFDBinaryOneWayConstraint::ClFDBinaryOneWayConstraint(const ClConstraint &cn)
60     :ClFDConstraint(cn.strength(), cn.weight())
61 {
62   EnsurePreconditionsForCn(cn);
63   list<FDNumber> l;
64   /* GJB:FIXME:: varargs inteface, with sentinel as first arg? */
65   l.push_back(9);
66   l.push_back(10);
67   l.push_back(12);
68   l.push_back(14);
69   l.push_back(20);
70
71   ClVarSet setRO = cn.ReadOnlyVars();
72
73   ClVariable clvRO = clvNil;
74   ClVariable clvROLinear = clvNil;
75   Number coeffRO = 0;
76
77   ClVariable clvRW = clvNil;
78   Number coeffRW = 0;
79
80   if (setRO.size() == 1) {
81     const ClVariable &clv = *(setRO.begin());
82     if (clv->IsFDVariable())
83       clvRO = clv;
84     else
85       clvRO = new ClFDVariable(clv.Name(),clv.IntValue(),l);
86     clvROLinear = clv;
87   }
88   const ClLinearExpression &expr = cn.Expression();
89   const ClVarToNumberMap &terms = expr.Terms();
90
91   for (ClVarToNumberMap::const_iterator it = terms.begin();
92        it != terms.end();
93        ++it) {
94     ClVariable clv = (*it).first;
95     if (clv == clvROLinear) {
96       coeffRO = (*it).second;
97     } else {
98       if (clv->IsFDVariable())
99         clvRW = clv;
100       else
101         clvRW = new ClFDVariable(clv.Name(),clv.Value(),l);
102       coeffRW = (*it).second;
103     }
104   }
105   assert(!clvRW.IsNil());
106   if (coeffRW == 0) {
107     throw ExCLTooDifficultSpecial("RW variable's coefficient must be non-zero");
108   }
109
110   bool fInequality = cn.IsInequality();
111   bool fStrictInequality = cn.IsStrictInequality();
112   double rhs_constant = expr.Constant();
113
114   // now we have:
115   // coeffRW * clvRW + coeffRO * clvRO <REL> rhs_constant
116   //   where <REL> is >= if fInequality, or = if !fInequality
117   // 
118   // need:
119   //   clvRW <REL> coefficient * clvRO + constant
120   // 
121   // so:
122   // coefficient = -coeffRO/coeffRW
123   // constant = rhs_constant/coeffRW
124
125   if (fStrictInequality)
126     _rel = cnGT;
127   else if (fInequality)
128     _rel = cnGEQ;
129   else
130     _rel = cnEQ;
131
132   if (coeffRW < 0)
133     _rel = ReverseInequality(_rel);
134
135   _coefficient = -coeffRO/coeffRW;
136   _constant = -rhs_constant/coeffRW;
137   _vRW = clvRW;
138   _vRO = clvRO;
139   return;
140 }