001    package net.sf.cpsolver.studentsct.heuristics;
002    
003    import java.util.Enumeration;
004    import java.util.Vector;
005    
006    import net.sf.cpsolver.ifs.heuristics.NeighbourSelection;
007    import net.sf.cpsolver.ifs.model.Neighbour;
008    import net.sf.cpsolver.ifs.solution.Solution;
009    import net.sf.cpsolver.ifs.solver.Solver;
010    import net.sf.cpsolver.ifs.util.DataProperties;
011    import net.sf.cpsolver.studentsct.StudentSectioningModel;
012    import net.sf.cpsolver.studentsct.model.Student;
013    
014    /**
015     * Two-phase (Batch) student sectioning neighbour selection.
016     * It is based on {@link StudentSctNeighbourSelection}, however in the first round, only real students are sectioned.
017     * All dummy students are removed from the problem during initialization of this neighbour selection, they 
018     * are returned into the problem after the first round of {@link StudentSctNeighbourSelection}.
019     * 
020     * <br><br>
021     * 
022     * @version
023     * StudentSct 1.1 (Student Sectioning)<br>
024     * Copyright (C) 2007 Tomáš Müller<br>
025     * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
026     * Lazenska 391, 76314 Zlin, Czech Republic<br>
027     * <br>
028     * This library is free software; you can redistribute it and/or
029     * modify it under the terms of the GNU Lesser General Public
030     * License as published by the Free Software Foundation; either
031     * version 2.1 of the License, or (at your option) any later version.
032     * <br><br>
033     * This library is distributed in the hope that it will be useful,
034     * but WITHOUT ANY WARRANTY; without even the implied warranty of
035     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
036     * Lesser General Public License for more details.
037     * <br><br>
038     * You should have received a copy of the GNU Lesser General Public
039     * License along with this library; if not, write to the Free Software
040     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
041     */
042    
043    public class TwoPhaseStudentSctNeighbourSelection extends StudentSctNeighbourSelection {
044        private int iNrRounds = 7;
045    
046        public TwoPhaseStudentSctNeighbourSelection(DataProperties properties) throws Exception {
047            super(properties);
048            iNrRounds = properties.getPropertyInt("TwoPhaseSectioning.NrRoundsFirstPhase", iNrRounds);
049        }
050        
051        /** Initialization -- also remove all the dummy students from the problem */
052        public void init(Solver solver) {
053            super.init(solver);
054            if (removeDummyStudents(solver.currentSolution())) 
055                registerSelection(new RestoreDummyStudents());
056        }
057        
058        Vector iDummyStudents = null;
059        private boolean removeDummyStudents(Solution solution) {
060            StudentSectioningModel model = (StudentSectioningModel)solution.getModel();
061            if (model.getNrLastLikeStudents(false)==0 || model.getNrRealStudents(false)==0) return false;
062            iDummyStudents = new Vector();
063            for (Enumeration e=new Vector(model.getStudents()).elements();e.hasMoreElements();) {
064                Student student = (Student)e.nextElement();
065                if (student.isDummy()) {
066                    iDummyStudents.add(student);
067                    model.removeStudent(student);
068                }
069            }
070            return true;
071        }
072    
073        private boolean addDummyStudents(Solution solution) {
074            if (iDummyStudents==null || iDummyStudents.isEmpty()) return false;
075            iNrRounds--;
076            if (iNrRounds>0) return false;
077            solution.restoreBest();
078            StudentSectioningModel model = (StudentSectioningModel)solution.getModel();
079            for (Enumeration e=iDummyStudents.elements();e.hasMoreElements();) {
080                Student student = (Student)e.nextElement();
081                model.addStudent(student);
082            }
083            iDummyStudents = null;
084            solution.saveBest();
085            return true;
086        }
087    
088        /** Return all dummy students into the problem, executed as the last phase of the first round */
089        protected class RestoreDummyStudents implements NeighbourSelection {
090            public RestoreDummyStudents() {}
091            public void init(Solver solver) {}
092            /** Return all (removed) dummy students into the problem */
093            public Neighbour selectNeighbour(Solution solution) {
094                addDummyStudents(solution);
095                return null;
096            }
097        }
098    }