@Override
 public void propagate(int evtmask) throws ContradictionException {
   if (PropagatorEventType.isFullPropagation(evtmask)) {
     if (n2 < n + vars[n].getLB()) {
       fails(); // TODO: could be more precise, for explanation purpose
     }
     buildDigraph();
   }
   digraph.removeNode(n2);
   digraph.removeNode(n2 + 1);
   free.clear();
   for (int i = 0; i < n; i++) {
     if (digraph.getPredOf(i).size() == 0) {
       free.set(i);
     }
   }
   for (int i = n; i < n2; i++) {
     if (digraph.getSuccOf(i).size() == 0) {
       free.set(i);
     }
   }
   int card = repairMatching();
   vars[n].updateUpperBound(card, this);
   if (vars[n].getLB() == card) {
     filter();
   }
   for (int i = 0; i < idms.length; i++) {
     idms[i].unfreeze();
   }
 }
 private void buildDigraph() {
   for (int i = 0; i < n2; i++) {
     digraph.getSuccOf(i).clear();
     digraph.getPredOf(i).clear();
   }
   free.set(0, n2);
   int j, k, ub;
   IntVar v;
   for (int i = 0; i < n2 + 2; i++) {
     digraph.removeNode(i);
   }
   for (int i = 0; i < n; i++) {
     v = vars[i];
     ub = v.getUB();
     for (k = v.getLB(); k <= ub; k = v.nextValue(k)) {
       j = map.get(k);
       digraph.addArc(i, j);
     }
   }
 }
 private int augmentPath_BFS(int root) {
   in.clear();
   int indexFirst = 0, indexLast = 0;
   fifo[indexLast++] = root;
   int x;
   ISetIterator succs;
   while (indexFirst != indexLast) {
     x = fifo[indexFirst++];
     succs = digraph.getSuccOf(x).iterator();
     while (succs.hasNext()) {
       int y = succs.nextInt();
       if (!in.get(y)) {
         father[y] = x;
         fifo[indexLast++] = y;
         in.set(y);
         if (free.get(y)) {
           return y;
         }
       }
     }
   }
   return -1;
 }