/** * Copyright 2010 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.planner.examples.examination.solver.selector; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.drools.planner.core.localsearch.LocalSearchSolverScope; import org.drools.planner.core.localsearch.StepScope; import org.drools.planner.core.localsearch.decider.Decider; import org.drools.planner.core.localsearch.decider.acceptor.tabu.TabuPropertyEnabled; import org.drools.planner.core.localsearch.decider.selector.AbstractSelector; import org.drools.planner.core.move.Move; import org.drools.planner.core.move.factory.MoveFactory; import org.drools.planner.examples.examination.domain.Exam; import org.drools.planner.examples.examination.domain.Examination; import org.drools.planner.examples.examination.solver.move.factory.ExamSwitchMoveFactory; import org.drools.planner.examples.examination.solver.move.factory.PeriodChangeMoveFactory; import org.drools.planner.examples.examination.solver.move.factory.RoomChangeMoveFactory; /** * A custom selector implementation for the Examination example. * @author Geoffrey De Smet */ public class AllMovesOfOneExamSelector extends AbstractSelector { protected PeriodChangeMoveFactory periodChangeMoveFactory = new PeriodChangeMoveFactory(); protected RoomChangeMoveFactory roomChangeMoveFactory = new RoomChangeMoveFactory(); protected ExamSwitchMoveFactory examSwitchMoveFactory = new ExamSwitchMoveFactory(); protected Map<Exam, List<Move>> cachedExamToMoveMap; protected List<Exam> shuffledExamList; protected int nextShuffledExamListIndex; @Override public void setDecider(Decider decider) { super.setDecider(decider); periodChangeMoveFactory.setDecider(decider); roomChangeMoveFactory.setDecider(decider); examSwitchMoveFactory.setDecider(decider); } // ************************************************************************ // Worker methods // ************************************************************************ @Override public void solvingStarted(LocalSearchSolverScope localSearchSolverScope) { periodChangeMoveFactory.solvingStarted(localSearchSolverScope); roomChangeMoveFactory.solvingStarted(localSearchSolverScope); examSwitchMoveFactory.solvingStarted(localSearchSolverScope); createCachedExamToMoveMap(localSearchSolverScope); } private void createCachedExamToMoveMap(LocalSearchSolverScope localSearchSolverScope) { Examination examination = (Examination) localSearchSolverScope.getWorkingSolution(); int examListSize = examination.getExamList().size(); List<Move> cachedPeriodChangeMoveList = periodChangeMoveFactory.getCachedMoveList(); List<Move> cachedRoomChangeMoveList = roomChangeMoveFactory.getCachedMoveList(); List<Move> cachedExamSwitchMoveList = examSwitchMoveFactory.getCachedMoveList(); cachedExamToMoveMap = new HashMap<Exam, List<Move>>(cachedPeriodChangeMoveList.size() + cachedRoomChangeMoveList.size() + cachedExamSwitchMoveList.size()); addToCachedExamToMoveMap(examListSize, cachedPeriodChangeMoveList); addToCachedExamToMoveMap(examListSize, cachedRoomChangeMoveList); addToCachedExamToMoveMap(examListSize, cachedExamSwitchMoveList); shuffledExamList = new ArrayList<Exam>(cachedExamToMoveMap.keySet()); // shuffling is lazy (just in time in the selectMoveList method) nextShuffledExamListIndex = Integer.MAX_VALUE; } private void addToCachedExamToMoveMap(int examListSize, List<Move> cachedMoveList) { for (Move cachedMove : cachedMoveList) { TabuPropertyEnabled tabuPropertyEnabledMove = (TabuPropertyEnabled) cachedMove; for (Object o : tabuPropertyEnabledMove.getTabuProperties()) { Exam exam = (Exam) o; List<Move> moveList = cachedExamToMoveMap.get(exam); if (moveList == null) { moveList = new ArrayList<Move>(examListSize); cachedExamToMoveMap.put(exam, moveList); } moveList.add(cachedMove); } } } @Override public void beforeDeciding(StepScope stepScope) { periodChangeMoveFactory.beforeDeciding(stepScope); roomChangeMoveFactory.beforeDeciding(stepScope); examSwitchMoveFactory.beforeDeciding(stepScope); } public Iterator<Move> moveIterator(StepScope stepScope) { if (nextShuffledExamListIndex >= shuffledExamList.size()) { // Just in time shuffling Collections.shuffle(shuffledExamList, stepScope.getWorkingRandom()); nextShuffledExamListIndex = 0; } Exam exam = shuffledExamList.get(nextShuffledExamListIndex); List<Move> moveList = cachedExamToMoveMap.get(exam); nextShuffledExamListIndex++; return moveList.iterator(); } @Override public void stepDecided(StepScope stepScope) { periodChangeMoveFactory.stepDecided(stepScope); roomChangeMoveFactory.stepDecided(stepScope); examSwitchMoveFactory.stepDecided(stepScope); } @Override public void stepTaken(StepScope stepScope) { periodChangeMoveFactory.stepTaken(stepScope); roomChangeMoveFactory.stepTaken(stepScope); examSwitchMoveFactory.stepTaken(stepScope); } @Override public void solvingEnded(LocalSearchSolverScope localSearchSolverScope) { periodChangeMoveFactory.solvingEnded(localSearchSolverScope); roomChangeMoveFactory.solvingEnded(localSearchSolverScope); examSwitchMoveFactory.solvingEnded(localSearchSolverScope); } }