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

org.chocosolver.solver.objective.ParetoMaximizer 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) 2023, 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.objective;

import org.chocosolver.solver.Model;
import org.chocosolver.solver.Solution;
import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.constraints.PropagatorPriority;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.search.loop.monitors.IMonitorSolution;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;

import java.util.LinkedList;
import java.util.List;
import java.util.stream.Stream;

/**
 * Class to store the pareto front (multi-objective optimization).
 * 

* Based on "Multi-Objective Large Neighborhood Search", P. Schaus , R. Hartert (CP'2013) *

* * @author Charles Vernerey * @author Charles Prud'homme * @author Jean-Guillaume Fages */ public class ParetoMaximizer extends Propagator implements IMonitorSolution { //*********************************************************************************** // VARIABLES //*********************************************************************************** // Set of incomparable and Pareto-best solutions private final LinkedList paretoSolutions; private final LinkedList paretoFront; private final Model model; // Allow to recycle (dominated) Solution objects private final LinkedList poolSols = new LinkedList<>(); // objective function private final IntVar[] objectives; private final int n; //private final int[] vals; //*********************************************************************************** // CONSTRUCTOR //*********************************************************************************** /** * Create an object to compute the Pareto front of a multi-objective problem. * Objectives are expected to be maximized (use {@link org.chocosolver.solver.variables.IViewFactory#intMinusView(IntVar)} in case of minimisation). *

* Maintain the set of dominating solutions and * posts constraints dynamically to prevent search from computing dominated ones. *

* The Solutions store decision variables (those declared in the search strategy) * BEWARE: requires the objectives to be declared in the search strategy * * @param objectives objective variables (must all be optimized in the same direction) */ public ParetoMaximizer(final IntVar[] objectives) { super(objectives, PropagatorPriority.QUADRATIC, false); this.paretoSolutions = new LinkedList<>(); this.paretoFront = new LinkedList<>(); this.objectives = objectives.clone(); n = objectives.length; model = objectives[0].getModel(); //vals = new int[n]; } //*********************************************************************************** // METHODS //*********************************************************************************** /** * @return the set of Pareto-best (possibly optimal) solutions found so far */ public List getParetoFront() { return paretoSolutions; } @Override public void onSolution() { // get objective values int[] vals = Stream.of(objectives).mapToInt(IntVar::getValue).toArray(); // remove dominated solutions for (int i = paretoFront.size() - 1; i >= 0; i--) { if (isDominated(paretoSolutions.get(i), vals)) { poolSols.add(paretoSolutions.remove(i)); paretoFront.remove(i); } } // store current solution Solution solution; if (poolSols.isEmpty()) { solution = new Solution(model); } else { solution = poolSols.remove(); } solution.record(); paretoSolutions.add(solution); paretoFront.add(vals); } private boolean isDominated(Solution solution, int[] vals) { for (int i = 0; i < n; i++) { int delta = solution.getIntVal(objectives[i]) - vals[i]; if (delta > 0) { return false; } } return true; } @Override public void propagate(int evtmask) throws ContradictionException { for (int i = 0; i < objectives.length; i++) { computeTightestPoint(i); } } /** * Compute tightest point for objective i * i.e. the point that dominates DP_i and has the biggest obj_i * * @param i index of the variable */ private void computeTightestPoint(int i) throws ContradictionException { int tightestPoint = Integer.MIN_VALUE; int[] dominatedPoint = computeDominatedPoint(i); for (int[] sol : paretoFront) { int dominates = dominates(sol, dominatedPoint, i); if (dominates > 0) { int currentPoint = dominates == 1 ? sol[i] : sol[i] + 1; if (tightestPoint < currentPoint) { tightestPoint = currentPoint; } } } if (tightestPoint > Integer.MIN_VALUE) { objectives[i].updateLowerBound(tightestPoint, this); } } /** * Compute dominated point for objective i, * i.e. DP_i = (obj_1_max,...,obj_i_min,...,obj_m_max) * * @param i index of the variable * @return dominated point */ private int[] computeDominatedPoint(int i) { int[] dp = Stream.of(objectives).mapToInt(IntVar::getUB).toArray(); dp[i] = objectives[i].getLB(); return dp; } /** * Return an int : * 0 if a doesn't dominate b * 1 if a dominates b and a = b if we don't take into account index i * 2 if a dominates b and a dominates b if we don't take into account index i * * @param a vector * @param b vector * @param i index * @return an int representing the fact that a dominates b */ private int dominates(int[] a, int[] b, int i) { int dominates = 0; for (int j = 0; j < objectives.length; j++) { if (a[j] < b[j]) return 0; if (a[j] > b[j]) { if (dominates == 0) dominates = 1; if (j != i) dominates = 2; } } return dominates; } @Override public ESat isEntailed() { return ESat.TRUE; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy