Generated on Mon Jul 6 18:09:01 2009 for Gecode by doxygen 1.5.9

efpa.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Mikael Lagerkvist <lagerkvist@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Mikael Lagerkvist, 2009
00008  *
00009  *  Last modified:
00010  *     $Date: 2009-05-12 14:56:30 +0200 (Tue, 12 May 2009) $ by $Author: zayenz $
00011  *     $Revision: 9067 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <gecode/driver.hh>
00039 #include <gecode/int.hh>
00040 #include <gecode/minimodel.hh>
00041 
00042 using namespace Gecode;
00043 
00049 class EFPAOptions : public Options {
00050 private:
00051   Driver::UnsignedIntOption _v;   
00052   Driver::UnsignedIntOption _q;   
00053   Driver::UnsignedIntOption _l;   
00054   Driver::UnsignedIntOption _d;   
00055   Driver::StringOption _permutation; 
00056   Driver::StringOption _symmetry; 
00057 
00058 public:
00060   EFPAOptions(const char* s,
00061               int v0 = 5, int q0 = 3, int lambda0 = 2, int d0 = 4)
00062     : Options(s),
00063       _v("-v", "number of sequences",                        v0     ),
00064       _q("-q", "number of symbols",                          q0     ),
00065       _l("-l", "sets of symbols per sequence (lambda)",      lambda0),
00066       _d("-d", "Hamming distance between sequences",         d0     ),
00067       _permutation("-permutation", "use permutation constraints if d=4", 
00068                    false),
00069       _symmetry("-symmetry", "use symmetry breaking",
00070                 true)
00071   {
00072     // Add options
00073     add(_d);
00074     add(_l);
00075     add(_q);
00076     add(_v);
00077     add(_permutation);
00078     add(_symmetry);
00079 
00080     // Add permutation options
00081     _permutation.add(true,  "true" );
00082     _permutation.add(false, "false");
00083     // Add symmetry options
00084     _symmetry.add(true,  "true" );
00085     _symmetry.add(false, "false");
00086   }
00088   void parse(int& argc, char* argv[]) {
00089     Options::parse(argc,argv);
00090   }
00092   int v(void) const { return _v.value(); }
00094   int q(void) const { return _q.value(); }
00096   int l(void) const { return _l.value(); }
00098   int d(void) const { return _d.value(); }
00099 
00101   bool permutation(void) const { return d() == 4 && _permutation.value(); }
00103   bool symmetry(void) const { return _symmetry.value(); }
00104 };
00105 
00106 
00121 class EFPA : public Script {
00122 protected:
00123   int v; 
00124   int q; 
00125   int l; 
00126   int d; 
00127   int n; 
00128   int nseqpair;  
00129   IntVarArray  c; 
00130   BoolVarArray diff; 
00131 
00132 public:
00134   EFPA(const EFPAOptions& opt)
00135     : v(opt.v()),
00136       q(opt.q()),
00137       l(opt.l()),
00138       d(opt.d()),
00139       n(q*l),
00140       nseqpair((v*(v-1))/2),
00141       c(*this, n*v, 1,q),
00142       diff(*this, n*nseqpair, 0, 1)
00143   {
00144     // Matrix access
00145     // q*lambda=n columns, and v rows
00146     Matrix<IntVarArray> cm(c, n, v);
00147     // q*lambda=n columns, and nseqpair rows
00148     Matrix<BoolVarArray> diffm(diff, n, nseqpair);
00149 
00150     // Counting symbols in rows
00151     {
00152       IntArgs values(q);
00153       for (int i = q; i--; ) values[i] = i+1;
00154       IntSet cardinality(l, l);
00155       for (int i = v; i--; )
00156         count(*this, cm.row(i), cardinality, values, opt.icl());
00157     }
00158     
00159     // Difference variables
00160     {
00161       int nseqi = 0;
00162       for (int a = 0; a < v; ++a) {
00163         for (int b = a+1; b < v; ++b) {
00164           for (int i = n; i--; ) {
00165             rel(*this, cm(i, a), IRT_NQ, cm(i, b), diffm(i, nseqi));
00166           }
00167           ++nseqi;
00168         }
00169       }
00170       assert(nseqi == nseqpair);
00171     }
00172 
00173     // Counting the Hamming difference
00174     {
00175       for (int i = nseqpair; i--; ) {
00176         linear(*this, diffm.row(i), IRT_EQ, d);
00177       }
00178     }
00179 
00180     // Symmetry breaking
00181     if (opt.symmetry()) {
00182       IntRelType row_less = d==0 ? IRT_EQ : IRT_LE;
00183       // order rows
00184       for (int r = 0; r<v-1; ++r) {
00185         rel(*this, cm.row(r), row_less, cm.row(r+1));
00186       }
00187       // order columns
00188       for (int c = 0; c<n-1; ++c) {
00189         rel(*this, cm.col(c), IRT_LQ, cm.col(c+1));
00190       }
00191       // Set first row according to symmetry breaking
00192       int color = 1;
00193       int ncolor = 0;
00194       for (int c = 0; c < n; ++c) {
00195         rel(*this, cm(c, 0), IRT_EQ, color);
00196         if (++ncolor == l) {
00197           ncolor = 0;
00198           ++color;
00199         }
00200       }
00201     }
00202 
00203     // Permutation constraints
00204     if (opt.permutation()) {
00205       const int k[][4] = { // inverse indexing of the permutation
00206         {0, 1, 3, 2}, // cform == 0, ((1, 2)(3, 4))
00207         {1, 2, 3, 0}, // cform == 1, ((1, 2, 3, 4))
00208       };
00209       assert(d == 4);
00210       // Constraint on each pair of rows
00211       for (int r1 = 0; r1 < v; ++r1) {
00212         for (int r2 = r1+1; r2 < v; ++r2) {
00213           IntVarArgs row1 = cm.row(r1);
00214           IntVarArgs row2 = cm.row(r2);
00215           // Perm is the 
00216           IntVarArgs perm(d);
00217           for (int i = d; i--; ) perm[i] = IntVar(*this, 0, n-1);
00218           // cform is the cycle-form of the permutation
00219           IntVar  cform(*this, 0, 1);
00220           BoolVar cformb = channel(*this, cform);
00221           
00222           /* Permutation mapping*/
00223           // Values from row1...
00224           IntVarArgs _p(2*d);
00225           for (int i = 2*d; i--; ) _p[i] = IntVar(*this, 1, q);
00226           Matrix<IntVarArgs> p(_p, d, 2);
00227           for (int i = 0; i < 2; ++i) {
00228             for (int j = 0; j < d; ++j) {
00229               element(*this, row1, perm[k[i][j]], p(j, i));
00230             }
00231           }
00232 
00233           // ...into values in row2
00234           for (int i = 0; i < d; ++i) {
00235             IntVar index(*this, 0, 2*d);
00236             post(*this, cform*d + i == index);
00237             IntVar value(*this, 1, q);
00238             element(*this, _p, index, value);
00239             element(*this, row2, perm[i], value);
00240           }
00241 
00242           /* Rows r1 and r2 are equal at indices not in perm */
00243           // uses Boolean representations pib for perm[i]
00244           BoolVarArray p1b(*this, n, 0, 1);
00245           channel(*this, p1b, perm[0]);
00246           BoolVarArray p2b(*this, n, 0, 1);
00247           channel(*this, p2b, perm[1]);
00248           BoolVarArray p3b(*this, n, 0, 1);
00249           channel(*this, p3b, perm[2]);
00250           BoolVarArray p4b(*this, n, 0, 1);
00251           channel(*this, p4b, perm[3]);
00252           for (int i = n; i--; ) {
00253             // No perm-variable uses i is equivalent to the reows
00254             // being equal at i
00255             post(*this, tt(eqv(!p1b[i] && !p2b[i] && !p3b[i] && !p4b[i],
00256                                ~(row1[i] == row2[i]))));
00257           }
00258           
00259           /* Constraints for fixing the permutation */
00260           // Common non-equality constraints - derangements
00261           rel(*this, perm[0], IRT_NQ, perm[1]);
00262           rel(*this, perm[2], IRT_NQ, perm[3]);
00263           // Conditional non-equality constraints - derangment of cform 1
00264           // Implements distinct(*this, perm, cformb);
00265           rel(*this, perm[0], IRT_NQ, perm[2], cformb);
00266           rel(*this, perm[0], IRT_NQ, perm[3], cformb);
00267           rel(*this, perm[1], IRT_NQ, perm[2], cformb);
00268           rel(*this, perm[1], IRT_NQ, perm[3], cformb);
00269           // Common ordering-constraints - symmetry breaking
00270           rel(*this, perm[0], IRT_LE, perm[1]);
00271           rel(*this, perm[0], IRT_LE, perm[2]);
00272           rel(*this, perm[0], IRT_LE, perm[3]);
00273           // Conditional ordering constraint - symmetry breaking for cform 0
00274           post(*this, tt(imp(!cformb,
00275                              ~(perm[2] < perm[3]))));
00276         }
00277       }
00278     }
00279 
00280     // Add branchings
00281     branch(*this, c, INT_VAR_NONE, INT_VAL_MIN);
00282   }
00283 
00285   virtual void
00286   print(std::ostream& os) const {
00287     Matrix<IntVarArray> cm(c, n, v);
00288     for (int i = 0; i < v; ++i) {
00289       IntVarArgs r = cm.row(i);
00290       os << r << std::endl;
00291     }
00292     os << std::endl;
00293   }
00294 
00296   EFPA(bool share, EFPA& s) 
00297     : Script(share,s),
00298       v(s.v),
00299       q(s.q),
00300       l(s.l),
00301       d(s.d),
00302       n(s.n),
00303       nseqpair(s.nseqpair)
00304   {
00305     c.update(*this, share, s.c);
00306     diff.update(*this, share, s.diff);
00307   }
00309   virtual Space*
00310   copy(bool share) {
00311     return new EFPA(share,*this);
00312   }
00313 };
00314 
00318 int
00319 main(int argc, char* argv[]) {
00320   EFPAOptions opt("Equidistant Frequency Permutation Arrays");
00321   opt.icl(ICL_DOM);
00322   opt.parse(argc,argv);
00323 
00324   Script::run<EFPA,DFS,EFPAOptions>(opt);
00325   return 0;
00326 }
00327 
00328 // STATISTICS: example-any