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 * @version CourseTT 1.4 (University Course Timetabling)<br> 028 * Copyright (C) 2024 Tomáš Müller<br> 029 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 030 * <a href="http://muller.unitime.org">http://muller.unitime.org</a><br> 031 * <br> 032 * This library is free software; you can redistribute it and/or modify 033 * it under the terms of the GNU Lesser General Public License as 034 * published by the Free Software Foundation; either version 3 of the 035 * License, or (at your option) any later version. <br> 036 * <br> 037 * This library is distributed in the hope that it will be useful, but 038 * WITHOUT ANY WARRANTY; without even the implied warranty of 039 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 040 * Lesser General Public License for more details. <br> 041 * <br> 042 * You should have received a copy of the GNU Lesser General Public 043 * License along with this library; if not see 044 * <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>. 045 */ 046public class RandomStudentSwap extends StudentSwapGenerator implements HillClimberSelection { 047 protected boolean iHC = false; 048 protected boolean iEnabled = true; 049 050 public RandomStudentSwap(DataProperties config) { 051 super(); 052 } 053 054 @Override 055 public void init(Solver<Lecture, Placement> solver) { 056 super.init(solver); 057 iEnabled = solver.hasSingleSolution(); 058 } 059 060 @Override 061 public Neighbour<Lecture, Placement> selectNeighbour(Solution<Lecture, Placement> solution) { 062 if (!iEnabled) return null; // not enabled 063 TimetableModel model = (TimetableModel)solution.getModel(); 064 if (model.getAllStudents().isEmpty()) return null; // no students 065 if (!model.isOnFlySectioningEnabled()) 066 model.setOnFlySectioningEnabled(true); 067 Assignment<Lecture, Placement> assignment = solution.getAssignment(); 068 // select a random lecture 069 Lecture lecture = ToolBox.random(model.variables()); 070 // get all students 071 Set<Student> students = lecture.students(); 072 // iterate over the students from a random index 073 if (students != null && !students.isEmpty()) { 074 int stdCnt = students.size(); 075 Iterator<Student> iterator = students.iterator(); 076 int stdIdx = ToolBox.random(stdCnt); 077 for (int i = 0; i < stdIdx; i++) iterator.next(); 078 for (int i = 0; i < stdCnt; i++) { 079 if (!iterator.hasNext()) iterator = students.iterator(); 080 Student student = iterator.next(); 081 Neighbour<Lecture, Placement> n = generateSwap(model, assignment, student, lecture.getConfiguration()); 082 if (n != null && (!iHC || n.value(assignment) <= 0.0)) return n; 083 } 084 } 085 return null; 086 } 087 088 @Override 089 public void setHcMode(boolean hcMode) { 090 iHC = hcMode; 091 } 092}