/// Post a distinct-linear constraint on variables \a x with sum \a c void distinctlinear(Cache& dc, const IntVarArgs& x, int c, const SizeOptions& opt) { int n=x.size(); if (opt.model() == MODEL_DECOMPOSE) { if (n < 8) linear(*this, x, IRT_EQ, c, opt.icl()); else if (n == 8) rel(*this, x, IRT_NQ, 9*(9+1)/2 - c); distinct(*this, x, opt.icl()); } else { switch (n) { case 0: return; case 1: rel(*this, x[0], IRT_EQ, c); return; case 8: // Prune the single missing digit rel(*this, x, IRT_NQ, 9*(9+1)/2 - c); break; case 9: break; default: if (c == n*(n+1)/2) { // sum has unique decomposition: 1 + ... + n rel(*this, x, IRT_LQ, n); } else if (c == n*(n+1)/2 + 1) { // sum has unique decomposition: 1 + ... + n-1 + n+1 rel(*this, x, IRT_LQ, n+1); rel(*this, x, IRT_NQ, n); } else if (c == 9*(9+1)/2 - (9-n)*(9-n+1)/2) { // sum has unique decomposition: (9-n+1) + (9-n+2) + ... + 9 rel(*this, x, IRT_GQ, 9-n+1); } else if (c == 9*(9+1)/2 - (9-n)*(9-n+1)/2 + 1) { // sum has unique decomposition: (9-n) + (9-n+2) + ... + 9 rel(*this, x, IRT_GQ, 9-n); rel(*this, x, IRT_NQ, 9-n+1); } else { extensional(*this, x, dc.get(n,c)); return; } } distinct(*this, x, opt.icl()); } }
/// The actual model GraphColor(const SizeOptions& opt) : g(opt.size() == 1 ? g2 : g1), v(*this,g.n_v,0,g.n_v), m(*this,0,g.n_v) { 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); } branch(*this, m, INT_VAL_MIN); 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_SIZE_DEGREE_MIN, INT_VAL_MIN); break; case BRANCH_SIZE_AFC: branch(*this, v, INT_VAR_SIZE_AFC_MIN, INT_VAL_MIN); break; default: break; } }
/// Actual model AllInterval(const SizeOptions& opt) : Script(opt), x(*this, opt.size(), 0, 66) { // 66 or opt.size() - 1 const int n = x.size(); IntVarArgs d(n-1); IntVarArgs dd(66); IntVarArgs xx_(n); // pitch class for AllInterval Chords IntVar douze; Rnd r(1U); if ((opt.model() == MODEL_SET) || (opt.model() == MODEL_SET_CHORD) || (opt.model() == MODEL_SSET_CHORD) ||(opt.model() == MODEL_SYMMETRIC_SET)) // Modele original : serie { // Set up variables for distance for (int i=0; i<n-1; i++) d[i] = expr(*this, abs(x[i+1]-x[i]), opt.ipl()); // Constrain them to be between 1 and n-1 dom(*this, d, 1, n-1); dom(*this, x, 0, n-1); if((opt.model() == MODEL_SET_CHORD) || (opt.model() == MODEL_SSET_CHORD)) { /*expr(*this,dd[0]==0); // Set up variables for distance for (int i=0; i<n-1; i++) { expr(*this, dd[i+1] == (dd[i]+d[i])%12, opt.icl()); } // Constrain them to be between 1 and n-1 dom(*this, dd,0, n-1); distinct(*this, dd, opt.icl()); */ rel(*this, abs(x[0]-x[n-1]) == 6, opt.ipl()); } if(opt.symmetry()) { // Break mirror symmetry (renversement) rel(*this, x[0], IRT_LE, x[1]); // Break symmetry of dual solution (retrograde de la serie) -> 1928 solutions pour accords de 12 sons rel(*this, d[0], IRT_GR, d[n-2]); } //series symetriques if ((opt.model() == MODEL_SYMMETRIC_SET)|| (opt.model() == MODEL_SSET_CHORD)) { rel (*this, d[n/2 - 1] == 6); // pivot = triton for (int i=0; i<(n/2)-2; i++) rel(*this,d[i]+d[n-i-2]==12); } } else { for (int j=0; j<n; j++) xx_[j] = expr(*this, x[j] % 12); dom(*this, xx_, 0, 11); distinct(*this, xx_, opt.ipl()); //intervalles for (int i=0; i<n-1; i++) d[i] = expr(*this,x[i+1] - x[i],opt.ipl()); dom(*this, d, 1, n-1); dom(*this, x, 0, n * (n - 1) / 2.); //d'autres choses dont on est certain (contraintes redondantes) : rel(*this, x[0] == 0); rel(*this, x[n-1] == n * (n - 1) / 2.); // break symmetry of dual solution (renversement de l'accord) if(opt.symmetry()) rel(*this, d[0], IRT_GR, d[n-2]); //accords symetriques if (opt.model() == MODEL_SYMMETRIC_CHORD) { rel (*this, d[n/2 - 1] == 6); // pivot = triton for (int i=0; i<(n/2)-2; i++) rel(*this,d[i]+d[n-i-2]==12); } if (opt.model() == MODEL_PARALLEL_CHORD) { rel (*this, d[n/2 - 1] == 6); // pivot = triton for (int i=0; i<(n/2)-2; i++) rel(*this,d[i]+d[n/2 + i]==12); } } distinct(*this, x, opt.ipl()); distinct(*this, d, opt.ipl()); #if 0 //TEST IntVarArray counter(*this,12,0,250); IntVar testcounter(*this,0,250); for (int i=1; i<11; i++) { count(*this, d, i,IRT_EQ,testcounter,opt.icl()); // OK } count(*this, d, counter,opt.icl()); // OK #endif //END TEST if(opt.branching() == 0) branch(*this, x, INT_VAR_SIZE_MIN(), INT_VAL_SPLIT_MIN()); else branch(*this, x, INT_VAR_RND(r), INT_VAL_RND(r)); }
/// 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; } } }
/// Actual model Steiner(const SizeOptions& opt) : n(opt.size()), noOfTriples((n*(n-1))/6), triples(*this, noOfTriples, IntSet::empty, 1, n, 3, 3) { for (int i=0; i<noOfTriples; i++) { for (int j=i+1; j<noOfTriples; j++) { SetVar x = triples[i]; SetVar y = triples[j]; SetVar atmostOne(*this,IntSet::empty,1,n,0,1); rel(*this, (x & y) == atmostOne); IntVar x1(*this,1,n); IntVar x2(*this,1,n); IntVar x3(*this,1,n); IntVar y1(*this,1,n); IntVar y2(*this,1,n); IntVar y3(*this,1,n); if (opt.model() == MODEL_NONE) { /* Naive alternative: * just including the ints in the set */ rel(*this, singleton(x1) <= x); rel(*this, singleton(x2) <= x); rel(*this, singleton(x3) <= x); rel(*this, singleton(y1) <= y); rel(*this, singleton(y2) <= y); rel(*this, singleton(y3) <= y); } else if (opt.model() == MODEL_MATCHING) { /* Smart alternative: * Using matching constraints */ channelSorted(*this, IntVarArgs()<<x1<<x2<<x3, x); channelSorted(*this, IntVarArgs()<<y1<<y2<<y3, y); } else if (opt.model() == MODEL_SEQ) { SetVar sx1 = expr(*this, singleton(x1)); SetVar sx2 = expr(*this, singleton(x2)); SetVar sx3 = expr(*this, singleton(x3)); SetVar sy1 = expr(*this, singleton(y1)); SetVar sy2 = expr(*this, singleton(y2)); SetVar sy3 = expr(*this, singleton(y3)); sequence(*this,SetVarArgs()<<sx1<<sx2<<sx3,x); sequence(*this,SetVarArgs()<<sy1<<sy2<<sy3,y); } /* Breaking symmetries */ rel(*this, x1 < x2); rel(*this, x2 < x3); rel(*this, x1 < x3); rel(*this, y1 < y2); rel(*this, y2 < y3); rel(*this, y1 < y3); linear(*this, IntArgs(6,(n+1)*(n+1),n+1,1,-(n+1)*(n+1),-(n+1),-1), IntVarArgs()<<x1<<x2<<x3<<y1<<y2<<y3, IRT_LE, 0); } } branch(*this, triples, SET_VAR_NONE, SET_VAL_MIN_INC); }
queens(const SizeOptions& opt) : q(*this, 2*opt.size() - 1, -opt.size(), 2*opt.size() - 1) { // construct the variables const int n = opt.size(); const int varSize = 2*n - 1; // stores all possible values for the determined key map< int, set<int> > allPossibleValueMap; // set the domains for the variables for (int index = 0; index < varSize; ++index) { int i = 1 - n + index; int end = varSize - abs(i); // the set stores all the possible values for q[index] set<int> possibleValueSet; possibleValueSet.insert(-n); for (int element = abs(i) + 1; element <= end; element += 2) { possibleValueSet.insert(element); } allPossibleValueMap.insert(make_pair(index, possibleValueSet)); for (int position = -n + 1; position <= 2*n - 1; ++position) { if (!possibleValueSet.count(position)) { rel(*this, q[index] != position); } } } // the first and second constraints // the number of (yi != -n) is n, // which equals that the number of (yi == -n) is n - 1 count(*this, q, -n, IRT_EQ, n - 1); for (int j = 1; j <= varSize; ++j) { count(*this, q, j, IRT_LQ, 1); } // the third constraint, use three models switch (opt.model()) { // the arithmetic constraint case MODEL_ONE: { for (int indexI = 0; indexI < varSize; ++indexI) { for (int indexJ = indexI + 1; indexJ < varSize; ++indexJ) { rel(*this, abs(q[indexI] - q[indexJ]) != abs(indexI - indexJ)); } } break; } // the tuple sets constraint case MODEL_TWO: { // initialize the iterator map to iteratively add tuples map<int, set<int>::const_iterator> setIterator; map<int, set<int>::const_iterator> iteEnd; for (int index = 0; index < varSize; ++index) { set<int>::const_iterator ite = allPossibleValueMap[index].begin(); setIterator.insert(make_pair(index, ite)); set<int>::const_iterator endIte = allPossibleValueMap[index].end(); iteEnd.insert(make_pair(index, endIte)); } // stores all the tuples to be added TupleSet allTupleSet; // this iterator is used to detect end conditions set<int>::const_iterator firstIteEnd = iteEnd[0]; const int lastIndex = varSize - 1; // test all the possible tuples, then add the valid ones which satisfy the third constraint into tuple set while (setIterator[0] != firstIteEnd) { // stores each tuple IntArgs tuple; // use to detect whether a tuple is valid vector<int> tupleVec; bool validFlag = true; for (int index = 0; index < varSize; ++index) { set<int>::const_iterator ite = setIterator[index]; int value = *ite; if (tupleVec.empty()) { tupleVec.push_back(value); tuple << value; } else { // using the third constraint, if a new value doesn't satisfy the constraint, skip this tuple for (int vecIndex = 0; vecIndex < tupleVec.size(); ++vecIndex) { if (abs(index - vecIndex) == abs(tuple[vecIndex] - value)) { validFlag = false; break; } } if (validFlag == true) { tupleVec.push_back(value); tuple << value; } else { break; } } } // if it is valid then add this tuple if (validFlag == true) { allTupleSet.add(tuple); } // try next possible tuple ++setIterator[lastIndex]; if (setIterator[lastIndex] == iteEnd[lastIndex]) { setIterator[lastIndex] = allPossibleValueMap[lastIndex].begin(); for (int index = lastIndex - 1; index >= 0; --index) { ++setIterator[index]; if (setIterator[index] != iteEnd[index]) { break; } else if (index != 0) { setIterator[index] = allPossibleValueMap[index].begin(); } } } } allTupleSet.finalize(); extensional(*this, q, allTupleSet); break; } // the DFAs constraint case MODEL_THREE: { // use the third constraint to test every pair of two variables for (int index = 0; index < varSize; ++index) { // all the possible value for the first variable set<int> valueSet1 = allPossibleValueMap[index]; for (int subIndex = index + 1; subIndex < varSize; ++subIndex) { // use for testing cout << index << endl; cout << subIndex << endl; // stores the transition status. DFA::Transition *t = new DFA::Transition[2*n*n]; // use this index to set the transition values int transitionIndex = 0; // key: transition state, value: the first variable's value map<int, int> transitionMap; // get transtion states {0, value1, 2}, {0, value2, 3}... for (set<int>::const_iterator set1Ite = valueSet1.begin(); set1Ite != valueSet1.end(); ++set1Ite) { t[transitionIndex] = {0, *set1Ite, transitionIndex + 2}; transitionMap.insert(make_pair(transitionIndex + 2, *set1Ite)); ++transitionIndex; } //all the possible value for the second variable set<int> valueSet2 = allPossibleValueMap[subIndex]; // tests every state, if the second variable satisfy the third constraint, then add the variable into the transition for (map<int, int>::const_iterator mapIte = transitionMap.begin(); mapIte != transitionMap.end(); ++mapIte) { for (set<int>::const_iterator set2Ite = valueSet2.begin(); set2Ite != valueSet2.end(); ++set2Ite) { if (abs(index - subIndex) != abs(mapIte->second - *set2Ite)) { t[transitionIndex] = {mapIte->first, *set2Ite, 1}; ++transitionIndex; } } } t[transitionIndex] = {-1, 0, 0}; // use 1 as the final state int f[] = {1, -1}; DFA d(0, t, f); cout << d << endl; IntVarArgs x; x << q[index] << q[subIndex]; extensional(*this, x, d); delete[] t; } } break; } default: break; } // post branching branch(*this, q, INT_VAR_SIZE_MIN(), INT_VAL_SPLIT_MIN()); }