001package org.cpsolver.ifs.algorithms; 002 003import java.util.Collection; 004import java.util.Map; 005 006import org.apache.logging.log4j.Logger; 007import org.cpsolver.ifs.assignment.Assignment; 008import org.cpsolver.ifs.assignment.context.AssignmentContext; 009import org.cpsolver.ifs.assignment.context.NeighbourSelectionWithContext; 010import org.cpsolver.ifs.heuristics.NeighbourSelection; 011import org.cpsolver.ifs.model.Model; 012import org.cpsolver.ifs.model.Neighbour; 013import org.cpsolver.ifs.model.SimpleNeighbour; 014import org.cpsolver.ifs.model.Value; 015import org.cpsolver.ifs.model.Variable; 016import org.cpsolver.ifs.solution.Solution; 017import org.cpsolver.ifs.solution.SolutionListener; 018import org.cpsolver.ifs.solver.ParallelSolver; 019import org.cpsolver.ifs.solver.Solver; 020import org.cpsolver.ifs.util.DataProperties; 021import org.cpsolver.ifs.util.ToolBox; 022 023 024/** 025 * A simple neighbourhood selection extension suitable for the {@link ParallelSolver} 026 * during the construction phase. If the best ever found solution was found by a different 027 * thread ({@link Assignment#getIndex()} does not match) and the current solution has 028 * a smaller number of variables assigned for at least the given number of iterations 029 * (parameter ParallelConstruction.MaxIdle, defaults to 100), start assigning unassigned variables 030 * to their best values. Otherwise, pass the selection to the provided neighbourhood selection. 031 * 032 * @version IFS 1.3 (Iterative Forward Search)<br> 033 * Copyright (C) 2014 Tomáš Müller<br> 034 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 035 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 036 * <br> 037 * This library is free software; you can redistribute it and/or modify 038 * it under the terms of the GNU Lesser General Public License as 039 * published by the Free Software Foundation; either version 3 of the 040 * License, or (at your option) any later version. <br> 041 * <br> 042 * This library is distributed in the hope that it will be useful, but 043 * WITHOUT ANY WARRANTY; without even the implied warranty of 044 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 045 * Lesser General Public License for more details. <br> 046 * <br> 047 * You should have received a copy of the GNU Lesser General Public 048 * License along with this library; if not see 049 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 050 * @param <V> Variable 051 * @param <T> Value 052 */ 053public class ParallelConstruction<V extends Variable<V, T>, T extends Value<V, T>> extends NeighbourSelectionWithContext<V, T, ParallelConstruction<V, T>.ConstructionContext> implements SolutionListener<V, T> { 054 protected static Logger sLog = org.apache.logging.log4j.LogManager.getLogger(ParallelConstruction.class); 055 protected NeighbourSelection<V, T> iParent = null; 056 protected Double iBestValue = null; 057 protected int iBestIndex = -1, iBestAssigned = 0; 058 protected int iMaxIdle = 100; 059 060 public ParallelConstruction(DataProperties config, NeighbourSelection<V, T> parent) { 061 iParent = parent; 062 iMaxIdle = config.getPropertyInt("ParallelConstruction.MaxIdle", iMaxIdle); 063 } 064 065 @Override 066 public void init(Solver<V, T> solver) { 067 super.init(solver); 068 iParent.init(solver); 069 solver.currentSolution().addSolutionListener(this); 070 } 071 072 073 @Override 074 public void solutionUpdated(Solution<V, T> solution) { 075 } 076 077 @Override 078 public void getInfo(Solution<V, T> solution, Map<String, String> info) { 079 } 080 081 @Override 082 public void getInfo(Solution<V, T> solution, Map<String, String> info, Collection<V> variables) { 083 } 084 085 @Override 086 public void bestCleared(Solution<V, T> solution) { 087 } 088 089 @Override 090 public void bestSaved(Solution<V, T> solution) { 091 iBestValue = solution.getBestValue(); 092 iBestIndex = solution.getAssignment().getIndex(); 093 iBestAssigned = solution.getAssignment().nrAssignedVariables(); 094 getContext(solution.getAssignment()).reset(); 095 } 096 097 @Override 098 public void bestRestored(Solution<V, T> solution) { 099 } 100 101 @Override 102 public Neighbour<V, T> selectNeighbour(Solution<V, T> solution) { 103 if (iBestValue != null && iBestIndex != solution.getAssignment().getIndex()) { 104 ConstructionContext context = getContext(solution.getAssignment()); 105 if (solution.getAssignment().nrAssignedVariables() == iBestAssigned) { 106 context.reset(); 107 } else if (solution.getAssignment().nrAssignedVariables() < iBestAssigned && context.inc() >= iMaxIdle) { 108 Model<V, T> model = solution.getModel(); 109 Assignment<V, T> assignment = solution.getAssignment(); 110 int idx = ToolBox.random(model.countVariables()); 111 for (int i = 0; i < model.countVariables(); i++) { 112 V variable = model.variables().get((i + idx) % model.countVariables()); 113 T value = assignment.getValue(variable); 114 T best = variable.getBestAssignment(); 115 if (value == null && best != null) 116 return new SimpleNeighbour<V, T>(variable, best, model.conflictValues(solution.getAssignment(), best)); 117 } 118 } 119 } 120 return iParent.selectNeighbour(solution); 121 } 122 123 @Override 124 public ConstructionContext createAssignmentContext(Assignment<V, T> assignment) { 125 return new ConstructionContext(assignment); 126 } 127 128 public class ConstructionContext implements AssignmentContext { 129 private int iCounter = 0; 130 131 public ConstructionContext(Assignment<V, T> assignment) { 132 } 133 134 public int inc() { return iCounter++; } 135 public void reset() { iCounter = 0; } 136 137 } 138 139}