/// The actual problem OpenShop(const SizeOptions& opt) : spec(examples[opt.size()]), b(*this, (spec.n+spec.m-2)*spec.n*spec.m/2, 0,1), makespan(*this, 0, Int::Limits::max), _start(*this, spec.m*spec.n, 0, Int::Limits::max) { Matrix<IntVarArray> start(_start, spec.m, spec.n); IntArgs _dur(spec.m*spec.n, spec.p); Matrix<IntArgs> dur(_dur, spec.m, spec.n); int minmakespan; int maxmakespan; crosh(dur, minmakespan, maxmakespan); rel(*this, makespan <= maxmakespan); rel(*this, makespan >= minmakespan); int k=0; for (int m=0; m<spec.m; m++) for (int j0=0; j0<spec.n-1; j0++) for (int j1=j0+1; j1<spec.n; j1++) { // The tasks on machine m of jobs j0 and j1 must be disjoint rel(*this, b[k] == (start(m,j0) + dur(m,j0) <= start(m,j1))); rel(*this, b[k++] == (start(m,j1) + dur(m,j1) > start(m,j0))); } for (int j=0; j<spec.n; j++) for (int m0=0; m0<spec.m-1; m0++) for (int m1=m0+1; m1<spec.m; m1++) { // The tasks in job j on machine m0 and m1 must be disjoint rel(*this, b[k] == (start(m0,j) + dur(m0,j) <= start(m1,j))); rel(*this, b[k++] == (start(m1,j) + dur(m1,j) > start(m0,j))); } // The makespan is greater than the end time of the latest job for (int m=0; m<spec.m; m++) { for (int j=0; j<spec.n; j++) { rel(*this, start(m,j) + dur(m,j) <= makespan); } } // First branch over the precedences branch(*this, b, INT_VAR_AFC_MAX(opt.decay()), INT_VAL_MAX()); // When the precedences are fixed, simply assign the start times assign(*this, _start, INT_ASSIGN_MIN()); // When the start times are fixed, use the tightest makespan assign(*this, makespan, INT_ASSIGN_MIN()); }
/// Actual model WordSquare(const SizeOptions& opt) : w_l(opt.size()), letters(*this, w_l*w_l) { // Initialize letters Matrix<IntVarArray> ml(letters, w_l, w_l); for (int i=0; i<w_l; i++) for (int j=i; j<w_l; j++) ml(i,j) = ml(j,i) = IntVar(*this, 'a','z'); // Number of words with that length const int n_w = dict.words(w_l); // Initialize word array IntVarArgs words(*this, w_l, 0, n_w-1); // All words must be different distinct(*this, words); // Link words with letters for (int i=0; i<w_l; i++) { // Map each word to i-th letter in that word IntSharedArray w2l(n_w); for (int n=n_w; n--; ) w2l[n]=dict.word(w_l,n)[i]; for (int j=0; j<w_l; j++) element(*this, w2l, words[j], ml(i,j)); } // Symmetry breaking: the last word must be later in the wordlist rel(*this, words[0], IRT_LE, words[w_l-1]); switch (opt.branching()) { case BRANCH_WORDS: // Branch by assigning words branch(*this, words, INT_VAR_SIZE_MIN(), INT_VAL_SPLIT_MIN()); break; case BRANCH_LETTERS: // Branch by assigning letters branch(*this, letters, INT_VAR_AFC_SIZE_MAX(opt.decay()), INT_VAL_MIN()); break; } }
/// Actual model Partition(const SizeOptions& opt) : x(*this,opt.size(),1,2*opt.size()), y(*this,opt.size(),1,2*opt.size()) { const int n = opt.size(); // Break symmetries by ordering numbers in each group rel(*this, x, IRT_LE); rel(*this, y, IRT_LE); rel(*this, x[0], IRT_LE, y[0]); IntVarArgs xy(2*n); for (int i = n; i--; ) { xy[i] = x[i]; xy[n+i] = y[i]; } distinct(*this, xy, opt.icl()); IntArgs c(2*n); for (int i = n; i--; ) { c[i] = 1; c[n+i] = -1; } linear(*this, c, xy, IRT_EQ, 0); // Array of products IntVarArgs sxy(2*n), sx(n), sy(n); for (int i = n; i--; ) { sx[i] = sxy[i] = expr(*this, sqr(x[i])); sy[i] = sxy[n+i] = expr(*this, sqr(y[i])); } linear(*this, c, sxy, IRT_EQ, 0); // Redundant constraints linear(*this, x, IRT_EQ, 2*n*(2*n+1)/4); linear(*this, y, IRT_EQ, 2*n*(2*n+1)/4); linear(*this, sx, IRT_EQ, 2*n*(2*n+1)*(4*n+1)/12); linear(*this, sy, IRT_EQ, 2*n*(2*n+1)*(4*n+1)/12); branch(*this, xy, INT_VAR_AFC_SIZE_MAX(opt.decay()), INT_VAL_MIN()); }
/// The actual problem Kakuro(const SizeOptions& opt) : w(examples[opt.size()][0]), h(examples[opt.size()][1]), f(*this,w*h) { IntVar black(*this,0,0); // Initialize all fields as black (unused). Only if a field // is actually used in a constraint, create a fresh variable // for it (done via init). for (int i=w*h; i--; ) f[i] = black; // Cache of already computed tuple sets Cache cache; // Matrix for accessing board fields Matrix<IntVarArray> b(f,w,h); // Access to hints const int* k = &examples[opt.size()][2]; // Process vertical hints while (*k >= 0) { int x=*k++; int y=*k++; int n=*k++; int s=*k++; IntVarArgs col(n); for (int i=n; i--; ) col[i]=init(b(x,y+i+1)); distinctlinear(cache,col,s,opt); } k++; // Process horizontal hints while (*k >= 0) { int x=*k++; int y=*k++; int n=*k++; int s=*k++; IntVarArgs row(n); for (int i=n; i--; ) row[i]=init(b(x+i+1,y)); distinctlinear(cache,row,s,opt); } branch(*this, f, INT_VAR_AFC_SIZE_MAX(opt.decay()), INT_VAL_SPLIT_MIN()); }
/// The actual model GraphColor(const SizeOptions& opt) : IntMinimizeScript(opt), g(opt.size() == 1 ? g2 : g1), v(*this,g.n_v,0,g.n_v-1), m(*this,0,g.n_v-1) { rel(*this, v, IRT_LQ, m); for (int i = 0; g.e[i] != -1; i += 2) rel(*this, v[g.e[i]], IRT_NQ, v[g.e[i+1]]); const int* c = g.c; for (int i = *c++; i--; c++) rel(*this, v[*c], IRT_EQ, i); while (*c != -1) { int n = *c; IntVarArgs x(n); c++; for (int i = n; i--; c++) x[i] = v[*c]; distinct(*this, x, opt.icl()); if (opt.model() == MODEL_CLIQUE) rel(*this, m, IRT_GQ, n-1); } /// Branching on the number of colors branch(*this, m, INT_VAL_MIN()); if (opt.symmetry() == SYMMETRY_NONE) { /// Branching without symmetry breaking switch (opt.branching()) { case BRANCH_SIZE: branch(*this, v, INT_VAR_SIZE_MIN(), INT_VAL_MIN()); break; case BRANCH_DEGREE: branch(*this, v, tiebreak(INT_VAR_DEGREE_MAX(),INT_VAR_SIZE_MIN()), INT_VAL_MIN()); break; case BRANCH_SIZE_DEGREE: branch(*this, v, INT_VAR_DEGREE_SIZE_MAX(), INT_VAL_MIN()); break; case BRANCH_SIZE_AFC: branch(*this, v, INT_VAR_AFC_SIZE_MAX(opt.decay()), INT_VAL_MIN()); break; case BRANCH_SIZE_ACTIVITY: branch(*this, v, INT_VAR_ACTIVITY_SIZE_MAX(opt.decay()), INT_VAL_MIN()); break; default: break; } } else { // opt.symmetry() == SYMMETRY_LDSB /// Branching while considering value symmetry breaking /// (every permutation of color values gives equivalent solutions) Symmetries syms; syms << ValueSymmetry(IntArgs::create(g.n_v,0)); switch (opt.branching()) { case BRANCH_SIZE: branch(*this, v, INT_VAR_SIZE_MIN(), INT_VAL_MIN(), syms); break; case BRANCH_DEGREE: branch(*this, v, tiebreak(INT_VAR_DEGREE_MAX(),INT_VAR_SIZE_MIN()), INT_VAL_MIN(), syms); break; case BRANCH_SIZE_DEGREE: branch(*this, v, INT_VAR_DEGREE_SIZE_MAX(), INT_VAL_MIN(), syms); break; case BRANCH_SIZE_AFC: branch(*this, v, INT_VAR_AFC_SIZE_MAX(opt.decay()), INT_VAL_MIN(), syms); break; case BRANCH_SIZE_ACTIVITY: branch(*this, v, INT_VAR_ACTIVITY_SIZE_MAX(opt.decay()), INT_VAL_MIN(), syms); break; default: break; } } }