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

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

The newest version!
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2024, 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;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.ResolutionPolicy;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.search.restart.AbstractRestart;
import org.chocosolver.solver.search.restart.GeometricalCutoff;
import org.chocosolver.solver.search.restart.Restarter;
import org.chocosolver.solver.search.strategy.selectors.values.RealDomainMax;
import org.chocosolver.solver.search.strategy.selectors.values.RealDomainMin;
import org.chocosolver.solver.search.strategy.selectors.variables.Cyclic;
import org.chocosolver.solver.search.strategy.strategy.AbstractStrategy;
import org.chocosolver.solver.variables.*;
import org.chocosolver.util.tools.VariableUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * A blackbox declaration assistant.
 * Taking a model as parameter, it analyses the variables declared
 * and create a black box strategy.
 * 
* The set of variables is first separated with respect to their type (integers, sets, ...). * Then, for each type, a search strategy is declared: a combination of variable selector * and value selector. * The order can be revised. *
* Then, a restart policy is applied, together with meta-strategy (like last conflict). * * @author Charles Prud'homme * @since 10/05/2023 */ @SuppressWarnings("UnusedReturnValue") public class BlackBoxConfigurator { /** * Strategy to use on integer variables (default is {@link Search#intVarSearch(IntVar...)} */ Function> intVarStrategy; /** * Strategy to use on integer objective. */ BiFunction> intObjVarStrategy; /** * Strategy to use on set variables (default is {@link Search#setVarSearch(SetVar...)} */ Function> setVarStrategy; /** * Strategy to use on graph variables (default is {@link Search#graphVarSearch(GraphVar...)} */ Function[], AbstractStrategy>> graphVarSearch; /** * Strategy to use on real variables (default is {@link Search#realVarSearch(RealVar...)} */ Function> realVarStrategy; /** * Strategy to use on real objective. */ BiFunction> realObjVarStrategy; /** * Meta strategy to use (default is {@link Search#lastConflict(AbstractStrategy)} */ Function, AbstractStrategy> metaStrategy; /** * Restart strategy (default is "no restart") */ Function restartPolicy; /** * Set nogood recording in restart (default is false) */ boolean nogoodOnRestart; /** * Add Generating Partial Assignment procedure (default is false) */ boolean generatePartialAssignment; /** * Force restart on solution */ boolean restartOnSolution; /** * Set to true to exclude views in the search strategy scope (default is false) */ boolean excludeViews; /** * Exclude the objective variable, if any, from the search strategy. */ boolean excludeObjective; private BlackBoxConfigurator() { } /** * Initialize the black box builder with default settings. * * @return return a pre-configured black box configurator */ public static BlackBoxConfigurator init() { return new BlackBoxConfigurator() .setIntVarStrategy(Search::intVarSearch) .setIntObjVarStrategy((obj, max) -> max ? Search.minDomUBSearch(obj) : Search.minDomLBSearch(obj)) .setSetVarStrategy(Search::setVarSearch) .setGraphVarSearch(Search::graphVarSearch) .setRealVarStrategy(Search::realVarSearch) .setRealObjVarStrategy((obj, max) -> Search.realVarSearch(new Cyclic<>(), max ? new RealDomainMax() : new RealDomainMin(), !max, obj)) .setMetaStrategy(Search::lastConflict) .setRestartPolicy(solver -> AbstractRestart.NO_RESTART) .setRestartOnSolution(false) .setNogoodOnRestart(false) .setExcludeViews(false) .setExcludeObjective(true); } /** * Build a black box strategy from the model, using default settings. * The resolution policy is used to select the appropriate combination of strategies. * * @param model the model to use * @return a black box strategy configured for the given model */ public static BlackBoxConfigurator prepare(Model model) { if (model.getSolver().getObjectiveManager().getPolicy() == ResolutionPolicy.SATISFACTION) { return forCSP(); } else { return forCOP(); } } /** * Build a black box strategy from the model adapted to constraint satisfaction problems (CSP) * * @return a black box strategy configured for CSP */ public static BlackBoxConfigurator forCSP() { BlackBoxConfigurator bb = init(); // search strategy SearchParams.ValSelConf defaultValSel = new SearchParams.ValSelConf( SearchParams.ValueSelection.MIN, false, 16, true); SearchParams.VarSelConf defaultVarSel = new SearchParams.VarSelConf( SearchParams.VariableSelection.DOMWDEG_CACD, 32); bb.setIntVarStrategy((vars) -> defaultVarSel.make().apply(vars, defaultValSel.make().apply(vars[0].getModel()))); // restart policy bb.setRestartPolicy(s -> new Restarter(new GeometricalCutoff(5, 1.05), c -> s.getFailCount() >= c, 50_000, true)); // complementary settings bb.setNogoodOnRestart(true) .setRestartOnSolution(false) .setExcludeObjective(true) .setExcludeViews(false) .setMetaStrategy(m -> Search.lastConflict(m, 4)); return bb; } /** * Build a black box strategy from the model adapted to constraint optimization problems (COP) * * @return a black box strategy configured for COP */ public static BlackBoxConfigurator forCOP() { BlackBoxConfigurator bb = init(); // search strategy SearchParams.ValSelConf defaultValSel = new SearchParams.ValSelConf( SearchParams.ValueSelection.MIN, true, 16, true); SearchParams.VarSelConf defaultVarSel = new SearchParams.VarSelConf( SearchParams.VariableSelection.DOMWDEG, 32); bb.setIntVarStrategy((vars) -> defaultVarSel.make().apply(vars, defaultValSel.make().apply(vars[0].getModel()))); // restart policy SearchParams.ResConf defaultResConf = new SearchParams.ResConf( SearchParams.Restart.GEOMETRIC, 10, 1.05, 50_000, true); bb.setRestartPolicy(defaultResConf.make()); // complementary settings bb.setNogoodOnRestart(true) .setRestartOnSolution(true) .setExcludeObjective(true) .setExcludeViews(false) .setMetaStrategy(m -> Search.lastConflict(m, 1)); return bb; } /** * Creates a default search strategy for the given model. This heuristic is complete (handles * IntVar, BoolVar, SetVar, GraphVar, and RealVar) * * @param model a model requiring a default search strategy */ public void make(Model model) { complete(model, null); } /** * Complete a declared strategy with a default search strategy for the given model. * This heuristic is complete (handles IntVar, BoolVar, SetVar, GraphVar, and RealVar) * * @param model a model requiring a default search strategy * @param declaredStrategy a declared strategy to complete with this default strategy (can be null) */ public void complete(Model model, AbstractStrategy declaredStrategy) { Solver solver = 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> lgvars = new ArrayList<>(); // graph variables List lrvars = new ArrayList<>();// real variables. Variable[] variables = model.getVars(); Variable objective = null; for (Variable var : variables) { if (VariableUtils.isConstant(var)) continue; if (VariableUtils.isView(var) && excludeViews) continue; int type = var.getTypeAndKind(); 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.GRAPH: lgvars.add((GraphVar) 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 (solver.getObjectiveManager().isOptimization() && excludeObjective) { objective = solver.getObjectiveManager().getObjective(); if ((objective.getTypeAndKind() & Variable.REAL) != 0) { //noinspection SuspiciousMethodCalls lrvars.remove(objective);// real var objective } else { assert (objective.getTypeAndKind() & Variable.INT) != 0; //noinspection SuspiciousMethodCalls livars.remove(objective);// bool/int var objective } } // 3. Creates a default search strategy for each variable kind ArrayList> strats = new ArrayList<>(); if (declaredStrategy != null) { strats.add(declaredStrategy); } if (livars.size() > 0) { strats.add(intVarStrategy.apply(livars.toArray(new IntVar[0]))); } if (lsvars.size() > 0) { strats.add(setVarStrategy.apply(lsvars.toArray(new SetVar[0]))); } if (lgvars.size() > 0) { strats.add(graphVarSearch.apply(lgvars.toArray(new GraphVar[0]))); } if (lrvars.size() > 0) { strats.add(realVarStrategy.apply(lrvars.toArray(new RealVar[0]))); } // 4. lexico LB/UB branching for the objective variable if (objective != null) { boolean max = solver.getObjectiveManager().getPolicy() == ResolutionPolicy.MAXIMIZE; if ((objective.getTypeAndKind() & Variable.REAL) != 0) { strats.add(realObjVarStrategy.apply((RealVar) objective, max)); } else { strats.add(intObjVarStrategy.apply((IntVar) objective, max)); } } // 5. avoid null pointers in case all variables are instantiated if (strats.isEmpty()) { strats.add(Search.minDomLBSearch(model.boolVar(true))); } AbstractStrategy main = Search.sequencer(strats.toArray(new AbstractStrategy[0])); solver.addRestarter(restartPolicy.apply(solver)); if (nogoodOnRestart) { solver.setNoGoodRecordingFromRestarts(); } // 6. add meta strats AbstractStrategy strat = metaStrategy.apply(main); if (generatePartialAssignment) { strat = Search.generatePartialAssignment( livars.toArray(new IntVar[0]), 20, false, strat); } solver.setSearch(strat); } public BlackBoxConfigurator setIntVarStrategy(Function> intVarStrategy) { this.intVarStrategy = intVarStrategy; return this; } public BlackBoxConfigurator setIntObjVarStrategy(BiFunction> intObjVarStrategy) { this.intObjVarStrategy = intObjVarStrategy; return this; } public BlackBoxConfigurator setSetVarStrategy(Function> setVarStrategy) { this.setVarStrategy = setVarStrategy; return this; } public BlackBoxConfigurator setGraphVarSearch(Function[], AbstractStrategy>> graphVarSearch) { this.graphVarSearch = graphVarSearch; return this; } public BlackBoxConfigurator setRealVarStrategy(Function> realVarStrategy) { this.realVarStrategy = realVarStrategy; return this; } public BlackBoxConfigurator setRealObjVarStrategy(BiFunction> realObjVarStrategy) { this.realObjVarStrategy = realObjVarStrategy; return this; } public BlackBoxConfigurator setMetaStrategy(Function, AbstractStrategy> metaStrategy) { this.metaStrategy = metaStrategy; return this; } public BlackBoxConfigurator setRestartPolicy(SearchParams.Restart pol, int cutoff, double geo, int offset, boolean resetOnSolution) { SearchParams.ResConf conf = new SearchParams.ResConf(pol, cutoff, geo, offset, resetOnSolution); this.restartPolicy = conf.make(); return this; } public BlackBoxConfigurator setRestartPolicy(Function restartPolicy) { this.restartPolicy = restartPolicy; return this; } public BlackBoxConfigurator setNogoodOnRestart(boolean nogoodOnRestart) { this.nogoodOnRestart = nogoodOnRestart; return this; } public BlackBoxConfigurator setRestartOnSolution(boolean restartOnSolution) { this.restartOnSolution = restartOnSolution; return this; } public void setRefinedPartialAssignmentGeneration(boolean rgpa) { this.generatePartialAssignment = rgpa; } public BlackBoxConfigurator setExcludeViews(boolean excludeViews) { this.excludeViews = excludeViews; return this; } public BlackBoxConfigurator setExcludeObjective(boolean excludeObjective) { this.excludeObjective = excludeObjective; return this; } @Override public String toString() { return "BlackBoxConfigurator{" + "intVarStrategy=" + intVarStrategy + ", intObjVarStrategy=" + intObjVarStrategy + ", setVarStrategy=" + setVarStrategy + ", graphVarSearch=" + graphVarSearch + ", realVarStrategy=" + realVarStrategy + ", realObjVarStrategy=" + realObjVarStrategy + ", metaStrategy=" + metaStrategy + ", restartPolicy=" + restartPolicy + ", nogoodOnRestart=" + nogoodOnRestart + ", restartOnSolution=" + restartOnSolution + ", rgpa=" + generatePartialAssignment + ", excludeViews=" + excludeViews + ", excludeObjective=" + excludeObjective + '}'; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy