/**
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2017, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.solver.search.strategy.selectors.values;

import org.chocosolver.solver.Cause;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.ResolutionPolicy;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.search.strategy.assignments.DecisionOperator;
import org.chocosolver.solver.variables.IntVar;

/**
 * Value selector for optimization problems:
 * Branches on the value with the best objective bound (evaluated each possible assignment)
 *
 * @author Jean-Guillaume FAGES
 */
public final class IntDomainBest implements IntValueSelector {

    /**
     * Maximum enumerated domain size this selector falls into.
     * Otherwise, {@link #altern} is used.
     */
    private int maxdom;

    /**
     * Alternative value selector when an enumerated variable domain exceeds {@link #maxdom}.
     */
    private IntValueSelector altern;

    /**
     * The decision operator used to make the decision
     */
    private DecisionOperator<IntVar> dop;

    /**
     * Create a value selector that returns the best value wrt to the objective to optimize. When an
     * enumerated variable domain exceeds {@link #maxdom}, {@link #altern} value selector is used.
     *
     * @param maxdom a maximum domain size to satisfy to use this value selector.
     * @param altern value selector to use when an enumerated variable domain exceed {@link
     *               #maxdom}.
     * @param dop    the decision operator used to make the decision
     */
    public IntDomainBest(int maxdom, IntValueSelector altern, DecisionOperator<IntVar> dop) {
        this.maxdom = maxdom;
        this.altern = altern;
        this.dop = dop;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int selectValue(IntVar var) {
        assert var.getModel().getObjective() != null;
        if (var.hasEnumeratedDomain()) {
            if (var.getDomainSize() < maxdom) {
                int bestCost = Integer.MAX_VALUE;
                int ub = var.getUB();
                int bestV = ub;
                for (int v = var.getLB(); v <= ub; v = var.nextValue(v)) {
                    int bound = bound(var, v);
                    if (bound < bestCost) {
                        bestCost = bound;
                        bestV = v;
                    }
                }
                return bestV;
            } else {
                return altern.selectValue(var);
            }
        } else {
            int lbB = bound(var, var.getLB());
            int ubB = bound(var, var.getUB());
            return lbB < ubB ? var.getLB() : var.getUB();
        }
    }

    private int bound(IntVar var, int val) {
        Model model = var.getModel();
        int cost;
        model.getEnvironment().worldPush();
        try {
            dop.apply(var, val, Cause.Null);
            model.getSolver().getEngine().propagate();
            ResolutionPolicy rp = model.getSolver().getObjectiveManager().getPolicy();
            if (rp == ResolutionPolicy.SATISFACTION) {
                cost = 1;
            } else if (rp == ResolutionPolicy.MINIMIZE) {
                cost = ((IntVar) model.getObjective()).getLB();
            } else {
                cost = -((IntVar) model.getObjective()).getUB();
            }
        } catch (ContradictionException cex) {
            cost = Integer.MAX_VALUE;
        }
        model.getSolver().getEngine().flush();
        model.getEnvironment().worldPop();
        return cost;
    }
}

@@ -572,16 +572,99 @@
 erator;%0A
+import org.chocosolver.solver.search.strategy.assignments.DecisionOperatorFactory;%0A
 import o
@@ -1358,16 +1358,45 @@
 %3E dop;%0A%0A
+    private byte ss = 0b00;%0A%0A
     /**%0A
@@ -2062,16 +2062,177 @@
  = dop;%0A
+        ss %7C= (dop == DecisionOperatorFactory.makeIntSplit() ? 0b10 : 0b00);%0A        ss %7C= (dop == DecisionOperatorFactory.makeIntReverseSplit() ? 0b01 : 0b00);%0A
     %7D%0A%0A 
@@ -2573,19 +2573,135 @@
     
-int bestV =
+// if decision is '%3C=', default value is LB, UB in any other cases%0A                int bestV = (ss & 0b10) != 0 ? var.getLB() :
  ub;
@@ -3204,24 +3204,268 @@
 r.getUB());%0A
+            // if values are equivalent%0A            if(lbB == ubB)%7B%0A                // if decision is '%3C=', default value is LB, UB in any other cases%0A                return (ss & 0b10) != 0 ? var.getLB() : var.getUB();%0A            %7Delse %7B%0A    
             
@@ -3502,32 +3502,46 @@
  : var.getUB();%0A
+            %7D%0A
         %7D%0A    %7D%0A
@@ -3638,24 +3638,245 @@
   int cost;%0A
+        // // if decision is '%3C=' ('%3E='), UB (LB) should be ignored to avoid infinite loop%0A        if(ss == 0b10 && val == var.getUB() %7C%7C ss == 0b01 && val == var.getLB())%7B%0A            return Integer.MAX_VALUE;%0A        %7D%0A
         mode

Update patch IntDomainBest for '<=' and '>='