001package org.cpsolver.coursett.sectioning; 002 003import java.util.Iterator; 004import java.util.Set; 005 006import org.cpsolver.coursett.model.Lecture; 007import org.cpsolver.coursett.model.Placement; 008import org.cpsolver.coursett.model.Student; 009import org.cpsolver.coursett.model.TimetableModel; 010import org.cpsolver.ifs.algorithms.neighbourhoods.HillClimberSelection; 011import org.cpsolver.ifs.assignment.Assignment; 012import org.cpsolver.ifs.model.Neighbour; 013import org.cpsolver.ifs.solution.Solution; 014import org.cpsolver.ifs.solver.Solver; 015import org.cpsolver.ifs.util.DataProperties; 016import org.cpsolver.ifs.util.ToolBox; 017 018/** 019 * A neihbourhood selection that attempts to swap a student between alternative sections of a course. 020 * To be used with the Hill Climber (HC), Great Deluge (GD), or Simulated Annealing (SA) algorithms by 021 * adding this class in the AdditionalNeighbours property. 022 * Based on {@link StudentSwapGenerator}, but making a random selection of a lecture and of a student. 023 * The selection is only available/enabled when the solver is using a single thread 024 * ({@link Solver#hasSingleSolution()} is true) as student class assignments are not included in the 025 * solution. 026 * 027 * @author Tomáš Müller 028 * @version CourseTT 1.4 (University Course Timetabling)<br> 029 * Copyright (C) 2024 Tomáš Müller<br> 030 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 031 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 032 * <br> 033 * This library is free software; you can redistribute it and/or modify 034 * it under the terms of the GNU Lesser General Public License as 035 * published by the Free Software Foundation; either version 3 of the 036 * License, or (at your option) any later version. <br> 037 * <br> 038 * This library is distributed in the hope that it will be useful, but 039 * WITHOUT ANY WARRANTY; without even the implied warranty of 040 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 041 * Lesser General Public License for more details. <br> 042 * <br> 043 * You should have received a copy of the GNU Lesser General Public 044 * License along with this library; if not see 045 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 046 */ 047public class RandomStudentSwap extends StudentSwapGenerator implements HillClimberSelection { 048 protected boolean iHC = false; 049 protected boolean iEnabled = true; 050 051 public RandomStudentSwap(DataProperties config) { 052 super(); 053 } 054 055 @Override 056 public void init(Solver<Lecture, Placement> solver) { 057 super.init(solver); 058 iEnabled = solver.hasSingleSolution(); 059 } 060 061 @Override 062 public Neighbour<Lecture, Placement> selectNeighbour(Solution<Lecture, Placement> solution) { 063 if (!iEnabled) return null; // not enabled 064 TimetableModel model = (TimetableModel)solution.getModel(); 065 if (model.getAllStudents().isEmpty()) return null; // no students 066 if (!model.isOnFlySectioningEnabled()) 067 model.setOnFlySectioningEnabled(true); 068 Assignment<Lecture, Placement> assignment = solution.getAssignment(); 069 // select a random lecture 070 Lecture lecture = ToolBox.random(model.variables()); 071 // get all students 072 Set<Student> students = lecture.students(); 073 // iterate over the students from a random index 074 if (students != null && !students.isEmpty()) { 075 int stdCnt = students.size(); 076 Iterator<Student> iterator = students.iterator(); 077 int stdIdx = ToolBox.random(stdCnt); 078 for (int i = 0; i < stdIdx; i++) iterator.next(); 079 for (int i = 0; i < stdCnt; i++) { 080 if (!iterator.hasNext()) iterator = students.iterator(); 081 Student student = iterator.next(); 082 Neighbour<Lecture, Placement> n = generateSwap(model, assignment, student, lecture.getConfiguration()); 083 if (n != null && (!iHC || n.value(assignment) <= 0.0)) return n; 084 } 085 } 086 return null; 087 } 088 089 @Override 090 public void setHcMode(boolean hcMode) { 091 iHC = hcMode; 092 } 093}