private boolean branchAndBoundHelper(MetaVariable metaVariable) {

    if (metaVariable == null) return false;

    preBacktrack();

    if (this.g.getRoot() == null) this.g.addVertex(currentVertex);
    ConstraintNetwork cn = metaVariable.getConstraintNetwork();

    logger.fine("Solving conflict: " + metaVariable);
    ConstraintNetwork[] values = metaVariable.getMetaConstraint().getMetaValues(metaVariable);

    if (metaVariable.getMetaConstraint().valOH != null)
      Arrays.sort(values, metaVariable.getMetaConstraint().valOH);

    if (values == null || values.length == 0) {
      this.g.addEdge(new NullConstraintNetwork(null), currentVertex, new TerminalNode(false));
      logger.fine("Failure... (1)");
    } else {
      for (ConstraintNetwork value : values) {
        if (animationTime != 0) {
          try {
            Thread.sleep(animationTime);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        logger.fine("Trying value: " + Arrays.toString(value.getConstraints()));

        if (hasConflictClause(value)) continue;

        this.addResolver(cn, value);
        setUpperBound();
        //				System.out.println("test: " + "U: " + getUpperBound() + " L: " + getLowerBound());
        if (getUpperBound() <= getLowerBound()) {
          this.retractResolver(cn, value);
          continue;
        }

        logger.fine("Success...");

        metaVariable.getMetaConstraint().markResolvedSub(metaVariable, value);
        MetaVariable newCon = this.getConflict();
        if (newCon != null) {
          this.g.addEdge(value, currentVertex, newCon);
          currentVertex = newCon;
        }
        if (newCon == null) setLowerBound();
        if (branchAndBoundHelper(newCon)) return true;
        logger.fine("Retracting value: " + Arrays.toString(value.getConstraints()));
        this.retractResolver(cn, value);
        logger.fine("Failure... (2)");
      }
    }
    resetFalseClause();
    logger.fine("Backtracking...");
    currentVertex = this.g.getParent(currentVertex);
    postBacktrack(metaVariable);
    return false;
  }
 /**
  * Retract all resolvers added to the ground-CSP(s) in order to obtain the current solution to the
  * meta-CSP. This is useful if one wants to "reset" the meta-CSP to its original unsolved state.
  */
 public void retractResolvers() {
   Set<ConstraintNetwork> vars = resolvers.keySet();
   for (ConstraintNetwork var : vars) {
     ConstraintNetwork value = resolvers.get(var);
     logger.fine("=== ||| === Retracting value: " + Arrays.toString(value.getConstraints()));
     this.retractResolver(var, value);
   }
   this.resolvers = new HashMap<ConstraintNetwork, ConstraintNetwork>();
   this.resolversInverseMapping = new HashMap<ConstraintNetwork, ConstraintNetwork>();
   this.metaVarsToMetaCons.clear();
 }
 protected final boolean addResolver(
     ConstraintNetwork metaVarConstraintNetwork, ConstraintNetwork resolverNetwork) {
   if (!this.addResolverSub(metaVarConstraintNetwork, resolverNetwork)) return false;
   Constraint[] resolverNetworkConstraints = resolverNetwork.getConstraints();
   HashMap<ConstraintSolver, Vector<Constraint>> solvers2constraints =
       new HashMap<ConstraintSolver, Vector<Constraint>>();
   for (Constraint c : resolverNetworkConstraints) {
     if (!solvers2constraints.containsKey(c.getScope()[0].getConstraintSolver())) {
       Vector<Constraint> newVec = new Vector<Constraint>();
       solvers2constraints.put(c.getScope()[0].getConstraintSolver(), newVec);
     }
     solvers2constraints.get(c.getScope()[0].getConstraintSolver()).add(c);
   }
   Vector<Constraint[]> addedConstraints = new Vector<Constraint[]>();
   for (ConstraintSolver cs : solvers2constraints.keySet()) {
     Constraint[] toAddOneSolver =
         solvers2constraints.get(cs).toArray(new Constraint[solvers2constraints.get(cs).size()]);
     if (cs.addConstraints(toAddOneSolver)) addedConstraints.add(toAddOneSolver);
     else {
       for (Constraint[] toDel : addedConstraints) {
         toDel[0].getScope()[0].getConstraintSolver().removeConstraints(toDel);
       }
       this.retractResolverSub(metaVarConstraintNetwork, resolverNetwork);
       return false;
     }
   }
   return true;
 }
  public static void main(String[] args) {
    MetaCSPLogging.setLevel(Level.FINEST);

    String[] symbols = new String[] {"B1", "B2", "B3", "B4", "B5"};
    SymbolicVariableConstraintSolver solver =
        new SymbolicVariableConstraintSolver(symbols, 100, true);
    solver.setSingleValue(false);

    int numRobots = 3;
    Variable[] vars = new Variable[numRobots];
    for (int i = 0; i < numRobots; i++) vars[i] = solver.createVariable("Robot" + i);

    ConstraintNetwork.draw(solver.getConstraintNetwork());

    ((SymbolicVariable) vars[0]).setDomain(new String[] {"B1", "B2", "B3"});
    //		SymbolicValueConstraint con01 = new SymbolicValueConstraint(Type.UNARYEQUALS);
    //		con01.setUnaryValue(new boolean[] {true, true, false, false, false});
    //		con01.setFrom(vars[0]);
    //		con01.setTo(vars[0]);

    ((SymbolicVariable) vars[1]).setDomain(new String[] {"B2", "B3", "B4"});
    //		SymbolicValueConstraint con02 = new SymbolicValueConstraint(Type.UNARYEQUALS);
    //		con02.setUnaryValue(new boolean[] {false, true, true, false, false});
    //		con02.setFrom(vars[1]);
    //		con02.setTo(vars[1]);

    ((SymbolicVariable) vars[2]).setDomain(new String[] {"B3"});
    //		SymbolicValueConstraint con03 = new SymbolicValueConstraint(Type.UNARYEQUALS);
    //		con03.setUnaryValue(new boolean[] {false, false, true, false, false});
    //		con03.setFrom(vars[2]);
    //		con03.setTo(vars[2]);

    // alldifferent constraint
    SymbolicValueConstraint con = new SymbolicValueConstraint(Type.DIFFERENT);
    con.setScope(vars);

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    System.out.println("Added constraints? " + solver.addConstraint(con));

    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    Variable varUnion1 = SymbolicVariableConstraintSolver.union(vars);
    System.out.println("Union of all vars (2): " + varUnion1);

    Variable varIntersection1 = SymbolicVariableConstraintSolver.intersection(vars);
    System.out.println("Intersection of all vars (2): " + varIntersection1);
  }
 public Sensor(String name, ConstraintNetworkAnimator animator) {
   this.animator = animator;
   this.ans = animator.getActivityNetworkSolver();
   this.cn = animator.getConstraintNetwork();
   this.name = name;
   for (Variable timeAct : cn.getVariables("Time")) {
     if (((SymbolicVariableActivity) timeAct)
         .getSymbolicVariable()
         .getSymbols()[0]
         .equals("Future")) future = (SymbolicVariableActivity) timeAct;
   }
 }
  protected final void retractResolver(ConstraintNetwork metaVar, ConstraintNetwork res) {
    this.logger.finest("Retracting resolver:");
    this.logger.finest("  MetaVariable: " + metaVar.toString());
    this.logger.finest("  MetaValue: " + res.toString());

    Constraint[] groundConstraints = res.getConstraints();
    HashMap<ConstraintSolver, Vector<Constraint>> solvers2constraints =
        new HashMap<ConstraintSolver, Vector<Constraint>>();
    for (Constraint c : groundConstraints) {
      if (!solvers2constraints.containsKey(c.getScope()[0].getConstraintSolver())) {
        Vector<Constraint> newVec = new Vector<Constraint>();
        solvers2constraints.put(c.getScope()[0].getConstraintSolver(), newVec);
      }
      solvers2constraints.get(c.getScope()[0].getConstraintSolver()).add(c);
    }
    for (ConstraintSolver cs : solvers2constraints.keySet()) {
      Constraint[] toAddOneSolver =
          solvers2constraints.get(cs).toArray(new Constraint[solvers2constraints.get(cs).size()]);
      cs.removeConstraints(toAddOneSolver);
    }

    this.retractResolverSub(metaVar, res);
    this.logger.finest("Done retracting resolver.");
  }
  public static void main(String[] args) {
    String[] symbols = new String[] {"mug1", "mug2", "mug3"};
    NameMatchingConstraintSolver solver = new NameMatchingConstraintSolver(symbols);

    ConstraintNetwork.draw(solver.getConstraintNetwork());

    NameVariable[] vars = (NameVariable[]) solver.createVariables(5);

    vars[0].setConstant("mug1");
    //		vars[3].setConstant("mug2");

    NameMatchingConstraint con01 = new NameMatchingConstraint(Type.EQUALS);
    con01.setFrom(vars[0]);
    con01.setTo(vars[1]);

    System.out.println("n0: " + vars[0]);
    System.out.println("n1 ground? " + vars[1] + vars[1].isGround());
    //		System.out.println("n2 ground? " + vars[2] + vars[2].isGround());

    System.out.println("Add con01: " + solver.addConstraint(con01));

    System.out.println("Removing con01: ");
    solver.removeConstraint(con01);
    System.out.println("n1 ground? " + vars[1] + " " + vars[1].isGround()); // Should not be ground

    //		NameMatchingConstraint con12 = new NameMatchingConstraint(Type.EQUALS);
    //		con12.setFrom(vars[1]);
    //		con12.setTo(vars[2]);
    ////		NameMatchingConstraint con23Equals = new NameMatchingConstraint(Type.EQUALS);
    ////		con23Equals.setFrom(vars[2]);
    ////		con23Equals.setTo(vars[3]);
    ////		System.out.println("Add con12 + con23?" + solver.addConstraints(new Constraint[] {con12,
    // con23Equals}));
    //
    //
    //		NameMatchingConstraint con23Different = new NameMatchingConstraint(Type.DIFFERENT);
    //		con23Different.setFrom(vars[2]);
    //		con23Different.setTo(vars[3]);
    //		System.out.println("Add con12 + con23?" + solver.addConstraints(new Constraint[] {con12,
    // con23Different}));

  }
  /** @param args */
  public static void main(String[] args) {

    MetaCSPLogging.setLevel(TimelinePublisher.class, Level.FINEST);

    SimplePlanner planner = new SimplePlanner(0, 600, 0);
    // This is a pointer toward the ActivityNetwork solver of the Scheduler
    ActivityNetworkSolver groundSolver = (ActivityNetworkSolver) planner.getConstraintSolvers()[0];

    MetaCSPLogging.setLevel(planner.getClass(), Level.FINE);

    //		MetaCSPLogging.setLevel(Level.FINEST);
    //		MetaCSPLogging.setLevel(planner.getClass(), Level.FINE);

    SimpleDomain rd = new SimpleDomain(new int[] {2}, new String[] {"arm"}, "TestDomain");

    AllenIntervalConstraint atCupAfterPlace =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint atCup1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint placeCupAfterholding =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint placeCup1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint holdingCupAfterPick =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint holdingCup1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint pickCup1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));

    AllenIntervalConstraint atKnifeAfterPlace =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint atKnife1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint placeKnifeAfterholding =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint placeKnife1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint holdingKnifeAfterPick =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint holdingKnife1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint pickKnife1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));

    AllenIntervalConstraint atForkAfterPlace =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint atFork1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint placeForkAfterholding =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint placeFork1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint holdingForkAfterPick =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.After,
            AllenIntervalConstraint.Type.After.getDefaultBounds());
    AllenIntervalConstraint holdingFork1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));
    AllenIntervalConstraint pickFork1Duration =
        new AllenIntervalConstraint(
            AllenIntervalConstraint.Type.Duration, new Bounds(10, APSPSolver.INF));

    SimpleOperator operator1 =
        new SimpleOperator(
            "robot1::at_cup1_table1()",
            new AllenIntervalConstraint[] {atCupAfterPlace},
            new String[] {"robot1::place_cup1_table1(arm)"},
            new int[] {1});
    operator1.addConstraint(atCup1Duration, 0, 0);
    rd.addOperator(operator1);

    SimpleOperator operator2 =
        new SimpleOperator(
            "robot1::place_cup1_table1(arm)",
            new AllenIntervalConstraint[] {placeCupAfterholding},
            new String[] {"robot1::holding_cup1(arm)"},
            new int[] {1});
    operator2.addConstraint(placeCup1Duration, 0, 0);
    rd.addOperator(operator2);

    SimpleOperator operator3 =
        new SimpleOperator(
            "robot1::holding_cup1(arm)",
            new AllenIntervalConstraint[] {holdingCupAfterPick},
            new String[] {"robot1::pick_cup1(arm)"},
            new int[] {1});
    operator3.addConstraint(holdingCup1Duration, 0, 0);
    rd.addOperator(operator3);

    SimpleOperator operator1res =
        new SimpleOperator("robot1::pick_cup1(arm)", null, null, new int[] {1});
    operator1res.addConstraint(pickCup1Duration, 0, 0);
    rd.addOperator(operator1res);

    // ........................

    SimpleOperator operator4 =
        new SimpleOperator(
            "robot1::at_knife1_table1()",
            new AllenIntervalConstraint[] {atKnifeAfterPlace},
            new String[] {"robot1::place_knife1_table1(arm)"},
            new int[] {1});
    operator4.addConstraint(atKnife1Duration, 0, 0);
    rd.addOperator(operator4);

    SimpleOperator operator5 =
        new SimpleOperator(
            "robot1::place_knife1_table1(arm)",
            new AllenIntervalConstraint[] {placeKnifeAfterholding},
            new String[] {"robot1::holding_knife1(arm)"},
            new int[] {1});
    operator5.addConstraint(placeKnife1Duration, 0, 0);
    rd.addOperator(operator5);

    SimpleOperator operator6 =
        new SimpleOperator(
            "robot1::holding_knife1(arm)",
            new AllenIntervalConstraint[] {holdingKnifeAfterPick},
            new String[] {"robot1::pick_knife1(arm)"},
            new int[] {1});
    operator6.addConstraint(holdingKnife1Duration, 0, 0);
    rd.addOperator(operator6);

    SimpleOperator operator2res =
        new SimpleOperator("robot1::pick_knife1(arm)", null, null, new int[] {1});
    operator2res.addConstraint(pickKnife1Duration, 0, 0);
    rd.addOperator(operator2res);

    // ........................

    SimpleOperator operator7 =
        new SimpleOperator(
            "robot1::at_fork_table1()",
            new AllenIntervalConstraint[] {atForkAfterPlace},
            new String[] {"robot1::place_fork1_table1(arm)"},
            new int[] {1});
    operator7.addConstraint(atFork1Duration, 0, 0);
    rd.addOperator(operator7);

    SimpleOperator operator8 =
        new SimpleOperator(
            "robot1::place_fork1_table1(arm)",
            new AllenIntervalConstraint[] {placeForkAfterholding},
            new String[] {"robot1::holding_fork1(arm)"},
            new int[] {1});
    operator8.addConstraint(placeFork1Duration, 0, 0);
    rd.addOperator(operator8);

    SimpleOperator operator9 =
        new SimpleOperator(
            "robot1::holding_fork1(arm)",
            new AllenIntervalConstraint[] {holdingForkAfterPick},
            new String[] {"robot1::pick_fork1(arm)"},
            new int[] {1});
    operator9.addConstraint(holdingFork1Duration, 0, 0);
    rd.addOperator(operator9);

    SimpleOperator operator3res =
        new SimpleOperator("robot1::pick_fork1(arm)", null, null, new int[] {1});
    operator3res.addConstraint(pickFork1Duration, 0, 0);
    rd.addOperator(operator3res);

    // This adds the domain as a meta-constraint of the SimplePlanner
    planner.addMetaConstraint(rd);
    // ... and we also add all its resources as separate meta-constraints
    MetaCSPLogging.setLevel(Schedulable.class, Level.FINEST);
    for (Schedulable sch : rd.getSchedulingMetaConstraints()) planner.addMetaConstraint(sch);

    // INITIAL AND GOAL STATE DEFS
    Activity three = (Activity) groundSolver.createVariable("robot1");
    three.setSymbolicDomain("at_knife1_table1()");
    three.setMarking(markings.UNJUSTIFIED);

    Activity one = (Activity) groundSolver.createVariable("robot1");
    one.setSymbolicDomain("at_cup1_table1()");
    one.setMarking(markings.UNJUSTIFIED);

    Activity two = (Activity) groundSolver.createVariable("robot1");
    two.setSymbolicDomain("at_fork1_table1()");
    two.setMarking(markings.UNJUSTIFIED);

    planner.backtrack();
    TimelinePublisher tp = new TimelinePublisher(groundSolver, new Bounds(0, 100), "robot1");
    // TimelinePublisher can also be instantiated w/o bounds, in which case the bounds are
    // calculated every time publish is called
    //		TimelinePublisher tp = new TimelinePublisher(groundSolver, "Robot1", "Robot2",
    // "LocalizationService", "RFIDReader1", "LaserScanner1");
    TimelineVisualizer viz = new TimelineVisualizer(tp);
    tp.publish(false, false);
    // the following call is marked as "skippable" and will most likely be skipped because the
    // previous call has not finished rendering...
    tp.publish(false, true);

    ConstraintNetwork.draw(groundSolver.getConstraintNetwork(), "Constraint Network");

    planner.draw();
    tp.publish(true, false);
  }
  /**
   * This backtrack method uses serialization to back up {@link ConstraintNetwork}s before
   * branching. This allows to backtrack without propagation - but is very memory intensive. In
   * practice, this does not work on reasonably sized problems.
   */
  private boolean backtrackHelperWithSerialization(MetaVariable metaVariable) {
    preBacktrack();
    if (this.g.getRoot() == null) this.g.addVertex(currentVertex);
    ConstraintNetwork mostProblematicNetwork = metaVariable.getConstraintNetwork();
    logger.fine("Solving conflict: " + metaVariable);
    ConstraintNetwork[] values = metaVariable.getMetaConstraint().getMetaValues(metaVariable);
    if (metaVariable.getMetaConstraint().valOH != null && values != null)
      Arrays.sort(values, metaVariable.getMetaConstraint().valOH);
    if (values == null || values.length == 0) {
      this.g.addEdge(new NullConstraintNetwork(null), currentVertex, new TerminalNode(false));
      logger.fine("Failure (1)...");
    } else {
      for (ConstraintNetwork value : values) {
        if (animationTime != 0) {
          try {
            Thread.sleep(animationTime);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        String valString = "";
        if (value.getVariables().length != 0)
          valString += "Vars = " + Arrays.toString(value.getVariables());
        if (value.getConstraints().length != 0)
          valString += " Cons = " + Arrays.toString(value.getConstraints());
        logger.fine("Trying value: " + valString);

        this.backedUpCNs.add(backupCNs(this));

        /** * PRINT INFO ** */
        /*
        long sizeOfBackup = 0;
        for (HashMap<ConstraintSolver,byte[]> oneHM : backedUpCNs) {
        	for (byte[] oneCN : oneHM.values())
        		sizeOfBackup += oneCN.length;
        }
        DecimalFormat df = new DecimalFormat("#.##");
        logger.info("Current backup size: " + df.format((sizeOfBackup/1024.00)) + " KB");
        */
        /** * END PRINT INFO ** */
        if (this.addResolver(mostProblematicNetwork, value)) {
          this.resolvers.put(mostProblematicNetwork, value);
          this.metaVarsToMetaCons.put(mostProblematicNetwork, metaVariable.getMetaConstraint());
          this.resolversInverseMapping.put(value, mostProblematicNetwork);
          this.counterMoves++;

          logger.fine("Success...");

          metaVariable.getMetaConstraint().markResolvedSub(metaVariable, value);
          MetaVariable newConflict = this.getConflict();

          if (newConflict == null || breakSearch) {
            this.g.addEdge(value, currentVertex, new TerminalNode(true));
            breakSearch = false;
            return true;
          }
          // addEdege(e,v,v)
          this.g.addEdge(value, currentVertex, newConflict);
          currentVertex = newConflict;
          if (backtrackHelper(newConflict)) return true;
          logger.fine("Retracting value: " + Arrays.toString(value.getConstraints()));

          // this.retractResolver(mostProblematicNetwork, value);
          this.restoreCNs();
          this.retractResolverSub(mostProblematicNetwork, value);
          this.resolvers.remove(mostProblematicNetwork);
          this.metaVarsToMetaCons.remove(mostProblematicNetwork);
          this.resolversInverseMapping.remove(value);
          this.counterMoves--;
        } else {
          this.g.addEdge(value, currentVertex, new TerminalNode(false));
          logger.fine("Failure... (2)");
        }
      }
    }
    logger.fine("Backtracking...");
    currentVertex = this.g.getParent(currentVertex);
    postBacktrack(metaVariable);
    return false;
  }
  private boolean backtrackHelper(MetaVariable metaVariable) {
    preBacktrack();
    if (this.g.getRoot() == null) this.g.addVertex(currentVertex);
    ConstraintNetwork mostProblematicNetwork = metaVariable.getConstraintNetwork();
    logger.fine("Solving conflict: " + metaVariable);
    ConstraintNetwork[] values = metaVariable.getMetaConstraint().getMetaValues(metaVariable);
    if (values != null) for (ConstraintNetwork value : values) value.setAnnotation(metaVariable);
    if (metaVariable.getMetaConstraint().valOH != null && values != null) {
      // System.out.println("SORTING with " + metaVariable.getMetaConstraint().valOH.getClass());
      Arrays.sort(values, metaVariable.getMetaConstraint().valOH);
    }
    if (values == null || values.length == 0) {
      this.g.addEdge(new NullConstraintNetwork(null), currentVertex, new TerminalNode(false));
      logger.fine("Failure (1)...");
    } else {
      for (ConstraintNetwork value : values) {
        if (animationTime != 0) {
          try {
            Thread.sleep(animationTime);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
        }
        String valString = "";
        if (value.getVariables().length != 0)
          valString += "Vars = " + Arrays.toString(value.getVariables());
        if (value.getConstraints().length != 0)
          valString += " Cons = " + Arrays.toString(value.getConstraints());
        logger.fine("Trying value: " + valString);

        if (this.addResolver(mostProblematicNetwork, value)) {
          this.resolvers.put(mostProblematicNetwork, value);
          this.metaVarsToMetaCons.put(mostProblematicNetwork, metaVariable.getMetaConstraint());
          this.resolversInverseMapping.put(value, mostProblematicNetwork);
          this.counterMoves++;

          logger.fine("Success...");

          metaVariable.getMetaConstraint().markResolvedSub(metaVariable, value);
          MetaVariable newConflict = this.getConflict();

          if (newConflict == null || breakSearch) {
            this.g.addEdge(value, currentVertex, new TerminalNode(true));
            breakSearch = false;
            return true;
          }
          // addEdege(e,v,v)
          this.g.addEdge(value, currentVertex, newConflict);
          currentVertex = newConflict;
          if (backtrackHelper(newConflict)) return true;
          logger.fine("Retracting value: " + Arrays.toString(value.getConstraints()));
          this.retractResolver(mostProblematicNetwork, value);
          this.resolvers.remove(mostProblematicNetwork);
          this.metaVarsToMetaCons.remove(mostProblematicNetwork);
          this.resolversInverseMapping.remove(value);
          this.counterMoves--;

        } else {
          this.g.addEdge(value, currentVertex, new TerminalNode(false));
          logger.fine("Failure... (2)");
        }
      }
    }
    logger.fine("Backtracking...");
    currentVertex = this.g.getParent(currentVertex);
    postBacktrack(metaVariable);
    return false;
  }