All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.chocosolver.solver.search.strategy.Search Maven / Gradle / Ivy

There is a newer version: 4.10.16
Show newest version
/**
 * Copyright (c) 2016, Ecole des Mines de Nantes
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the .
 * 4. Neither the name of the  nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY  ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.chocosolver.solver.search.strategy;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.ResolutionPolicy;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.search.strategy.assignments.DecisionOperator;
import org.chocosolver.solver.search.strategy.assignments.DecisionOperatorFactory;
import org.chocosolver.solver.search.strategy.selectors.values.*;
import org.chocosolver.solver.search.strategy.selectors.variables.*;
import org.chocosolver.solver.search.strategy.strategy.*;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.RealVar;
import org.chocosolver.solver.variables.SetVar;
import org.chocosolver.solver.variables.Variable;

import java.util.ArrayList;
import java.util.List;

public class Search {

    // ************************************************************************************
   	// GENERIC PATTERNS
   	// ************************************************************************************

    /**
   	 * Use the last conflict heuristic as a pluggin to improve a former search heuristic
   	 * Should be set after specifying a search strategy.
   	 * @return last conflict strategy
   	 */
    public static AbstractStrategy lastConflict(AbstractStrategy formerSearch) {
   		return lastConflict(formerSearch, 1);
   	}

    /**
     * Use the last conflict heuristic as a pluggin to improve a former search heuristic
     * Should be set after specifying a search strategy.
     * @param k the maximum number of conflicts to store
     * @return last conflict strategy
     */
    public static AbstractStrategy lastConflict(AbstractStrategy formerSearch, int k) {
        return new LastConflict(formerSearch.getVariables()[0].getModel(), formerSearch, k);
    }

    /**
     * Use the conflict ordering search as a pluggin to improve a former search heuristic
     * Should be set after specifying a search strategy.
     * @return last conflict strategy
     */
    public static AbstractStrategy conflictOrderingSearch(AbstractStrategy formerSearch) {
        return new ConflictOrderingSearch<>(formerSearch.getVariables()[0].getModel(), formerSearch);
    }

   	/**
   	 * Make the input search strategy greedy, that is, decisions can be applied but not refuted.
   	 * @param search a search heuristic building branching decisions
   	 * @return a greedy form of search
   	 */
    public static AbstractStrategy greedySearch(AbstractStrategy search){
   		return new GreedyBranching(search);
   	}

    public static AbstractStrategy sequencer(AbstractStrategy... searches){
   		return new StrategiesSequencer(searches);
   	}

    // ************************************************************************************
    // SETVAR STRATEGIES
    // ************************************************************************************

    /**
     * Generic strategy to branch on set variables
     *
     * @param varS         variable selection strategy
     * @param valS         integer  selection strategy
     * @param enforceFirst branching order true = enforce first; false = remove first
	 * @param sets         SetVar array to branch on
     * @return a strategy to instantiate sets
     */
    public static SetStrategy setVarSearch(VariableSelector varS, SetValueSelector valS, boolean enforceFirst, SetVar... sets) {
        return new SetStrategy(sets, varS, valS, enforceFirst);
    }

    /**
     * strategy to branch on sets by choosing the first unfixed variable and forcing its first unfixed value
     *
     * @param sets variables to branch on
     * @return a strategy to instantiate sets
     */
    public static SetStrategy setVarSearch(SetVar... sets) {
        return setVarSearch(new GeneralizedMinDomVarSelector(), new SetDomainMin(), true, sets);
    }

    // ************************************************************************************
    // REALVAR STRATEGIES
    // ************************************************************************************

    /**
     * Generic strategy to branch on real variables, based on domain splitting
     * @param varS  variable selection strategy
     * @param valS  strategy to select where to split domains
     * @param rvars RealVar array to branch on
     * @return a strategy to instantiate reals
     */
    public static RealStrategy realVarSearch(VariableSelector varS, RealValueSelector valS, RealVar... rvars) {
        return new RealStrategy(rvars, varS, valS);
    }

    /**
     * strategy to branch on real variables by choosing sequentially the next variable domain
     * to split in two, wrt the middle value
     * @param reals variables to branch on
     * @return a strategy to instantiate real variables
     */
    public static RealStrategy realVarSearch(RealVar... reals) {
        return realVarSearch(new Cyclic<>(), new RealDomainMiddle(), reals);
    }

    // ************************************************************************************
    // INTVAR STRATEGIES
    // ************************************************************************************

    /**
     * Builds your own search strategy based on binary decisions.
     *
     * @param varSelector defines how to select a variable to branch on.
     * @param valSelector defines how to select a value in the domain of the selected variable
     * @param decisionOperator defines how to modify the domain of the selected variable with the selected value
     * @param vars         variables to branch on
     * @return a custom search strategy
     */
    public static IntStrategy intVarSearch(VariableSelector varSelector,
                                     IntValueSelector valSelector,
                                     DecisionOperator decisionOperator,
                                     IntVar... vars) {
        return new IntStrategy(vars, varSelector, valSelector, decisionOperator);
    }

    /**
     * Builds your own assignment strategy based on binary decisions.
     * Selects a variable X and a value V to make the decision X = V.
     * Note that value assignments are the public static decision operators.
     * Therefore, they are not mentioned in the search heuristic name.
     * @param varSelector defines how to select a variable to branch on.
     * @param valSelector defines how to select a value in the domain of the selected variable
     * @param vars         variables to branch on
     * @return a custom search strategy
     */
    public static IntStrategy intVarSearch(VariableSelector varSelector,
                                     IntValueSelector valSelector,
                                     IntVar... vars) {
        return intVarSearch(varSelector, valSelector, DecisionOperatorFactory.makeIntEq(), vars);
    }

    /**
     * Builds a default search heuristics of integer variables
     * Relies on {@link #domOverWDegSearch(IntVar...)}
     * @param vars         variables to branch on
     * @return a default search strategy
     */
    public static AbstractStrategy intVarSearch(IntVar... vars) {
        // sets booleans to 1 and intvar to upper bound for maximisation
        // branch on lower bound otherwise
        boolean satOrMin = vars[0].getModel().getResolutionPolicy()!= ResolutionPolicy.MAXIMIZE;
        IntValueSelector valSel = new IntValueSelector() {
            @Override
            public int selectValue(IntVar var) {
                if(var.isBool() || !satOrMin){
                    return var.getUB();
                }else {
                    return var.getLB();
                }
            }
        };
        return new DomOverWDeg(vars, 0, valSel);
    }

    /**
     * Assignment strategy which selects a variable according to DomOverWDeg and assign it to its lower bound
     * @param vars list of variables
     * @return assignment strategy
     */
    public static AbstractStrategy domOverWDegSearch(IntVar... vars) {
        return new DomOverWDeg(vars, 0, new IntDomainMin());
    }

    /**
     * Create an Activity based search strategy.
     * 

* "Activity-Based Search for Black-Box Constraint Propagramming Solver", * Laurent Michel and Pascal Van Hentenryck, CPAIOR12. *
* Uses public static parameters (GAMMA=0.999d, DELTA=0.2d, ALPHA=8, RESTART=1.1d, FORCE_SAMPLING=1) * * @param vars collection of variables * @return an Activity based search strategy. */ public static AbstractStrategy activityBasedSearch(IntVar... vars) { return new ActivityBased(vars); } /** * Randomly selects a variable and assigns it to a value randomly taken in * - the domain in case the variable has an enumerated domain * - {LB,UB} (one of the two bounds) in case the domain is bounded * * @param vars list of variables * @param seed a seed for random * @return assignment strategy */ public static IntStrategy randomSearch(IntVar[] vars, long seed) { IntValueSelector value = new IntDomainRandom(seed); IntValueSelector bound = new IntDomainRandomBound(seed); IntValueSelector selector = var -> { if (var.hasEnumeratedDomain()) { return value.selectValue(var); } else { return bound.selectValue(var); } }; return intVarSearch(new Random<>(seed), selector, vars); } // ************************************************************************************ // SOME EXAMPLES OF STRATEGIES YOU CAN BUILD // ************************************************************************************ /** * Assigns the first non-instantiated variable to its lower bound. * @param vars list of variables * @return int strategy based on value assignments */ public static IntStrategy inputOrderLBSearch(IntVar... vars) { return intVarSearch(new InputOrder<>(vars[0].getModel()), new IntDomainMin(), vars); } /** * Assigns the first non-instantiated variable to its upper bound. * @param vars list of variables * @return assignment strategy */ public static IntStrategy inputOrderUBSearch(IntVar... vars) { return intVarSearch(new InputOrder<>(vars[0].getModel()), new IntDomainMax(), vars); } /** * Assigns the non-instantiated variable of smallest domain size to its lower bound. * @param vars list of variables * @return assignment strategy */ public static IntStrategy minDomLBSearch(IntVar... vars) { return intVarSearch(new FirstFail(vars[0].getModel()), new IntDomainMin(), vars); } /** * Assigns the non-instantiated variable of smallest domain size to its upper bound. * @param vars list of variables * @return assignment strategy */ public static IntStrategy minDomUBSearch(IntVar... vars) { return intVarSearch(new FirstFail(vars[0].getModel()), new IntDomainMax(), vars); } // ************************************************************************************ // DEFAULT STRATEGY (COMPLETE) // ************************************************************************************ /** * Creates a default search strategy for the given model. * This heuristic is complete (handles IntVar, BoolVar, SetVar and RealVar) * * @param model a model requiring a default search strategy */ public static AbstractStrategy defaultSearch(Model model){ Solver r = model.getSolver(); // 1. retrieve variables, keeping the declaration order, and put them in four groups: List livars = new ArrayList<>(); // integer and boolean variables List lsvars = new ArrayList<>(); // set variables List lrvars = new ArrayList<>();// real variables. Variable[] variables = model.getVars(); Variable objective = null; for (Variable var : variables) { int type = var.getTypeAndKind(); if ((type & Variable.CSTE) == 0) { int kind = type & Variable.KIND; switch (kind) { case Variable.BOOL: case Variable.INT: livars.add((IntVar) var); break; case Variable.SET: lsvars.add((SetVar) var); break; case Variable.REAL: lrvars.add((RealVar) var); break; default: break; // do not throw exception to allow ad hoc variable kinds } } } // 2. extract the objective variable if any (to avoid branching on it) if (r.getObjectiveManager().isOptimization()) { objective = r.getObjectiveManager().getObjective(); if((objective.getTypeAndKind() & Variable.REAL) != 0){ lrvars.remove(objective);// real var objective }else{ assert (objective.getTypeAndKind() & Variable.INT) != 0; livars.remove(objective);// bool/int var objective } } // 3. Creates a default search strategy for each variable kind ArrayList strats = new ArrayList<>(); if (livars.size() > 0) { strats.add(intVarSearch(livars.toArray(new IntVar[livars.size()]))); } if (lsvars.size() > 0) { strats.add(setVarSearch(lsvars.toArray(new SetVar[lsvars.size()]))); } if (lrvars.size() > 0) { strats.add(realVarSearch(lrvars.toArray(new RealVar[lrvars.size()]))); } // 4. lexico LB/UB branching for the objective variable if (objective != null) { boolean max = r.getObjectiveManager().getPolicy() == ResolutionPolicy.MAXIMIZE; if((objective.getTypeAndKind() & Variable.REAL) != 0){ strats.add(realVarSearch(new Cyclic<>(), max?new RealDomainMax():new RealDomainMin(), (RealVar) objective)); }else{ strats.add(max ? minDomUBSearch((IntVar) objective) : minDomLBSearch((IntVar) objective)); } } // 5. avoid null pointers in case all variables are instantiated if (strats.isEmpty()) { strats.add(minDomLBSearch(model.boolVar(true))); } // 6. add last conflict return lastConflict(sequencer(strats.toArray(new AbstractStrategy[strats.size()]))); } }