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