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

org.chocosolver.solver.search.IResolutionHelper Maven / Gradle / Ivy

There is a newer version: 4.10.17
Show newest version
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2019, 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;

import org.chocosolver.solver.ISelf;
import org.chocosolver.solver.Solution;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.constraints.Constraint;
import org.chocosolver.solver.constraints.nary.lex.PropLexInt;
import org.chocosolver.solver.objective.ParetoOptimizer;
import org.chocosolver.solver.search.limits.ACounter;
import org.chocosolver.solver.search.measure.IMeasures;
import org.chocosolver.solver.search.strategy.Search;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;
import org.chocosolver.util.criteria.Criterion;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Spliterator;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

/**
 * Interface to define most commonly used resolution procedures.
 * 

* Project: choco-solver. * * @author Jean-Guillaum Fages * @author Charles Prud'homme * @author Guillaume Lelouet * @since 25/04/2016. */ public interface IResolutionHelper extends ISelf { /** * Attempts to find a solution of the declared satisfaction problem. *

    *
  • If the method returns null:
  • *
      *
    • either a stop criterion (e.g., a time limit) stops the search before a solution has been found,
    • *
    • or no solution exists for the problem (i.e., over-constrained).
    • *
    *
  • if the method returns a {@link Solution}:
  • *
      *
    • a solution has been found. This method can be called anew to look for the next solution, if any.
    • *
    *
*

* If a solution has been found, since the search process stops on that solution, variables' value can be read, e.g., * {@code intvar.getValue()} or the solution can be recorded: *

*

     *    {@code
     * 	Solution s = new Solution(model);
     * 	s.record();
     * }
     * 
*

* Basically, this method runs the following instructions: *

*

     *     {@code
     *     if(ref().solve()) {
     *          return new Solution(ref()).record();
     *     }else{
     *          return null;
     *       }
     *     }
     * 
* * Note that all variables will be recorded * * Note that it clears the current objective function, if any * * @param stop optional criterion to stop the search before finding a solution * @return a {@link Solution} if and only if a solution has been found, null otherwise. */ default Solution findSolution(Criterion... stop) { ref().getModel().clearObjective(); ref().addStopCriterion(stop); boolean found = ref().solve(); ref().removeStopCriterion(stop); if (found) { return new Solution(ref().getModel()).record(); } else { return null; } } /** * Attempts to find all solutions of the declared satisfaction problem. *
    *
  • If the method returns an empty list:
  • *
      *
    • * either a stop criterion (e.g., a time limit) stops the search before any solution has been found, *
    • *
    • * or no solution exists for the problem (i.e., over-constrained). *
    • *
    *
  • if the method returns a list with at least one element in it:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion before finding all solutions,
    • *
    • or all solutions have been found.
    • *
    *
*

* This method run the following instructions: *

     *     {@code
     *     List solutions = new ArrayList<>();
     *     while (model.getSolver().solve()){
     *          solutions.add(new Solution(model).record());
     *     }
     *     return solutions;
     *     }
     * 
* * Note that all variables will be recorded * * Note that it clears the current objective function, if any * * @param stop optional criterion to stop the search before finding all solutions * @return a list that contained the found solutions. */ default List findAllSolutions(Criterion... stop) { ref().getModel().clearObjective(); ref().addStopCriterion(stop); List solutions = new ArrayList<>(); while (ref().solve()) { solutions.add(new Solution(ref().getModel()).record()); } ref().removeStopCriterion(stop); return solutions; } /** * Attempts to find all solutions of the declared problem. *
    *
  • If the method returns an empty list:
  • *
      *
    • either a stop criterion (e.g., a time limit) stops the search before any solution has been found,
    • *
    • or no solution exists for the problem (i.e., over-constrained).
    • *
    *
  • if the method returns a list with at least one element in it:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion before finding all solutions,
    • *
    • or all solutions have been found.
    • *
    *
*

* Basically, this method runs the following instructions: *

*

     * {@code
     * 	List solutions = new ArrayList<>();
     * 	while (model.getSolver().solve()) {
     * 		solutions.add(new Solution(model).record());
     *    }
     * 	return solutions;
     * }
     * 
* * Note that all variables will be recorded * * @param stop optional criterion to stop the search before finding all/best solution * @return a list that contained the found solutions. */ default Stream streamSolutions(Criterion... stop) { ref().addStopCriterion(stop); Spliterator it = new Spliterator() { @Override public boolean tryAdvance(Consumer action) { if (ref().solve()) { action.accept(new Solution(ref().getModel()).record()); return true; } ref().removeStopCriterion(stop); return false; } @Override public Spliterator trySplit() { return null; } @Override public long estimateSize() { return Long.MAX_VALUE; } @Override public int characteristics() { return Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.NONNULL | Spliterator.CONCURRENT; } }; return StreamSupport.stream(it, false); } /** * Attempt to find the solution that optimizes the mono-objective problem defined by a unique objective variable and * an optimization criteria. *
    *
  • If this method returns null:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion (e.g., a time limit) and no solution has been found * so far,
    • *
    • or the problem cannot be satisfied (i.e., over constrained).
    • *
    *
  • If this method returns a {@link Solution}:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion and the solution is the best found so far but not * necessarily the optimal one,
    • *
    • or it is the optimal one.
    • *
    *
*

* Basically, this method runs the following instructions: *

*

     *     {@code
     *     model.setObjective(maximize, objective);
     *     Solution s = new Solution(model);
     *     while (model.getSolver().solve()) {
     *          s.record();
     *     }
     *     return model.getSolver().isFeasible() == ESat.TRUE ? s : null;
     *     }
     * 
* * Note that all variables will be recorded * * @param objective integer variable to optimize * @param maximize set to true to solve a maximization problem, set to false to solve a minimization * problem. * @param stop optional criterion to stop the search before finding all/best solution * @return
    *
  • null if the problem has no solution or a stop criterion stops the search before finding a * first solution
  • *
  • a {@link Solution} if at least one solution has been found. The solution is proven to be optimal if no * stop criterion stops the search.
  • *
*/ default Solution findOptimalSolution(IntVar objective, boolean maximize, Criterion... stop) { ref().getModel().setObjective(maximize, objective); ref().addStopCriterion(stop); Solution s = new Solution(ref().getModel()); while (ref().solve()) { s.record(); } ref().removeStopCriterion(stop); return ref().isFeasible() == ESat.TRUE ? s : null; } /** * Attempt to find the solution that optimizes the mono-objective problem defined by * a unique objective variable and an optimization criteria, then finds and stores all optimal solution. * Searching for all optimal solutions is only triggered if the first search is complete. * This method works as follow: *
    *
  1. It finds and prove the optimum
  2. *
  3. It resets the search and enumerates all solutions of optimal cost
  4. *
* Note that the returned list can be empty. *
    *
  • If the method returns an empty list:
  • *
      *
    • * either a stop criterion (e.g., a time limit) stops the search before any solution has been found, *
    • *
    • * or no solution exists for the problem (i.e., over-constrained). *
    • *
    *
  • if the method returns a list with at least one element in it:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion before finding all solutions,
    • *
    • or all optimal solutions have been found.
    • *
    *
* * This method runs the following instructions: *
     *     {@code
     *     ref().findOptimalSolution(objective, maximize, stop);
     *     if (!ref().isStopCriterionMet()  &&
     *          model.getSolver().getMeasures().getSolutionCount() > 0) {
     *         int opt = _model.getSolver().getObjectiveManager().getBestSolutionValue().intValue();
     *         model.getSolver().reset();
     *         model.clearObjective();
     *         model.arithm(objective, "=", opt).post();
     *         return findAllSolutions();
     *     } else {
     *          return Collections.emptyList();
     *     }
     *     }
     * 
* * Note that all variables will be recorded * * @param objective the variable to optimize * @param maximize set to true to solve a maximization problem, * set to false to solve a minimization problem. * @param stop optional criterion to stop the search before finding all/best solution * @return a list that contained the solutions found. */ default List findAllOptimalSolutions(IntVar objective, boolean maximize, Criterion... stop) { ref().addStopCriterion(stop); boolean defaultS = ref().getSearch()==null;// best bound (in default) is only for optim ref().findOptimalSolution(objective, maximize); if (!ref().isStopCriterionMet() && ref().getSolutionCount() > 0) { ref().removeStopCriterion(stop); int opt = ref().getObjectiveManager().getBestSolutionValue().intValue(); ref().reset(); ref().getModel().clearObjective(); ref().getModel().arithm(objective, "=", opt).post(); if(defaultS) ref().setSearch(Search.defaultSearch(ref().getModel()));// best bound (in default) is only for optim return findAllSolutions(stop); } else { ref().removeStopCriterion(stop); return Collections.emptyList(); } } /** * Attempt to find the solution that optimizes the mono-objective problem defined by a unique objective variable and * an optimization criteria, then finds and stores all optimal solution. This method works as follow: *
    *
  1. It finds and prove the optimum
  2. *
  3. It resets the search and enumerates all solutions of optimal cost
  4. *
* Note that the returned list can be empty. *
    *
  • If the method returns an empty list:
  • *
      *
    • either a stop criterion (e.g., a time limit) stops the search before any solution has been found,
    • *
    • or no solution exists for the problem (i.e., over-constrained).
    • *
    *
  • if the method returns a list with at least one element in it:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion before finding all solutions,
    • *
    • or all optimal solutions have been found.
    • *
    *
*

* Basically, this method runs the following instructions: *

*

     *     {@code
     *     ref().findOptimalSolution(objective, maximize);
     *     if (model.getSolver().getMeasures().getSolutionCount() > 0) {
     *         int opt = _model.getSolver().getObjectiveManager().getBestSolutionValue().intValue();
     *         model.getSolver().reset();
     *         model.clearObjective();
     *         model.arithm(objective, "=", opt).post();
     *         return findAllSolutions();
     *     } else {
     *          return Collections.emptyList();
     *     }
     *     }
     * 
* * Note that all variables will be recorded * * @param objective the variable to optimize * @param maximize set to true to solve a maximization problem, set to false to solve a minimization * problem. * @param stop optional criterion to stop the search before finding all/best solution * @return a list that contained the solutions found. */ default Stream streamOptimalSolutions(IntVar objective, boolean maximize, Criterion... stop) { ref().addStopCriterion(stop); boolean defaultS = ref().getSearch()==null;// best bound (in default) is only for optim ref().findOptimalSolution(objective, maximize); if (!ref().isStopCriterionMet() && ref().getSolutionCount() > 0) { ref().removeStopCriterion(stop); int opt = ref().getObjectiveManager().getBestSolutionValue().intValue(); ref().reset(); ref().getModel().clearObjective(); ref().getModel().arithm(objective, "=", opt).post(); if(defaultS) ref().setSearch(Search.defaultSearch(ref().getModel()));// best bound (in default) is only for optim return streamSolutions(stop); } else { ref().removeStopCriterion(stop); return Stream.empty(); } } /** * Attempts optimize the value of the objectives variable w.r.t. to an optimization criteria. Finds and stores * all optimal solution. Note that the returned list can be empty. *
    *
  • If the method returns an empty list:
  • *
      *
    • either a stop criterion (e.g., a time limit) stops the search before any solution has been found,
    • *
    • or no solution exists for the problem (i.e., over-constrained).
    • *
    *
  • if the method returns a list with at least one element in it:
  • *
      *
    • either the resolution stops eagerly du to a stop criterion before finding all solutions,
    • *
    • or all optimal solutions have been found.
    • *
    *
* Basically, this method runs the following instructions: *

*

     * {@code
     * ParetoOptimizer pareto = new ParetoOptimizer(maximize, objectives);
     * 	while (ref().solve()) {
     * 		pareto.onSolution();
     * 	}
     * 	return pareto.getParetoFront();
     * }
     * 
* * Note that all variables will be recorded * * @param objectives the array of variables to optimize * @param maximize set to true to solve a maximization problem, set to false to solve a minimization * problem. * @param stop optional criterions to stop the search before finding all/best solution * @return a list that contained the solutions found. */ default List findParetoFront(IntVar[] objectives, boolean maximize, Criterion... stop) { ref().addStopCriterion(stop); ParetoOptimizer pareto = new ParetoOptimizer(maximize, objectives); while (ref().solve()) { pareto.onSolution(); } ref().removeStopCriterion(stop); return pareto.getParetoFront(); } /** * Attempts optimize the value of the objectives variable w.r.t. to an optimization criteria. * Finds and stores the optimal solution, if any. * Moreover, the objective variables are ordered wrt their significance. * The first objective variable is more significant or equally significant to the second one, * which in turn is more significant or equally significant to the third one, etc. * On an optimal solution of a maximization problem, the first variable is maximized, then the second one is maximized, etc. * * Note that if a stop criteria stops the search eagerly, no optimal solution may have been found. * In that case, the best solution, if at least one has been found, is returned. * * Note that all variables will be recorded * * @param objectives * the list of objectives to find the optimal. A solution o1..on is optimal if lexicographically better than * any other correct solution s1..sn * @param maximize * to maximize the objective, false to minimize. * @param stop * stop criterion are added before search and removed after search. * @return A solution with the optimal objectives value, null if no solution exists or search was stopped before a * solution could be found. If null, check if a criterion was met to find out was caused the null. */ default Solution findLexOptimalSolution(IntVar[] objectives, boolean maximize, Criterion... stop) { if (objectives == null || objectives.length == 0) { return findSolution(stop); } ref().addStopCriterion(stop); Solution sol = null; Constraint clint = null; PropLexInt plint = null; // 1. copy objective variables and transform it if necessary IntVar[] mobj = new IntVar[objectives.length]; for (int i = 0; i < objectives.length; i++) { mobj[i] = maximize ? ref().getModel().intMinusView(objectives[i]) : objectives[i]; } // 2. try to find a first solution while (ref().solve()) { if (sol == null) { sol = new Solution(ref().getModel()); } sol.record(); // 3. extract values of each objective int[] bestFound = new int[objectives.length]; for (int vIdx = 0; vIdx < objectives.length; vIdx++) { bestFound[vIdx] = sol.getIntVal(objectives[vIdx]) * (maximize ? -1 : 1); } // 4. either update the constraint, or declare it if first solution if (plint != null) { plint.updateIntVector(bestFound); } else { plint = new PropLexInt(mobj, bestFound, true); clint = new Constraint("lex objectives", plint); clint.post(); } } if (clint != null) { ref().getModel().unpost(clint); } ref().removeStopCriterion(stop); return sol; } /** * Explore the model, calling a {@link BiConsumer} for each {@link Solution} with its corresponding {@link IMeasures}. *

* The {@link Solution} and the {@link IMeasures} provided by the Biconsumer are always the same reference, consider * either extracting values from them or copy them. See {@link IMeasures} and {@link Solution#copySolution()} *

*

* The consumer and the criterion should not be linked ; instead use {@link ACounter} sub-classes. *

* * Note that all variables will be recorded * * @param cons the consumer of solution and measure couples * @param stop optional criterions to stop the search before finding all/best solution */ default void eachSolutionWithMeasure(BiConsumer cons, Criterion... stop) { ref().addStopCriterion(stop); Solution s = new Solution(ref().getModel()); while (ref().solve()) { cons.accept(s.record(), ref().getMeasures()); } ref().removeStopCriterion(stop); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy