├── .gitignore ├── LICENSE.txt ├── README.md ├── cost.pl ├── find_heuristic.pl ├── find_heuristic_astar.pl ├── find_optimal.pl ├── large_long_instance.pl ├── large_short_instance.pl ├── print.pl ├── small_instance.pl ├── utils.pl └── valid.pl /.gitignore: -------------------------------------------------------------------------------- 1 | /report 2 | *.pdf 3 | *.zip 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jens Nevens 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Exam Scheduling Problem 2 | 3 | ## Note 4 | 5 | This project is part of the course Declarative Programming taught at Vrije Universiteit Brussel. It can be executed by running the _swipl_ program in the directory of this project. SWI-Prolog is available [here](http://www.swi-prolog.org/). First, one of the instances should be loaded. This can be done by one of the following commands: 6 | 7 | - `load_module(small_instance).` 8 | - `load_module(large_long_instance).` 9 | - `load_module(large_short_instance).` 10 | 11 | Next, the program files can be loaded in the same way (i.e. using `load_module`) and the available predicates can be executed. These are summarized below: 12 | 13 | | File | Predicates | 14 | |------|------------| 15 | | *valid.pl* | __is_valid(?Schedule)__ | 16 | | *cost.pl* | __cost(+Schedule, ?Cost), violates_sc(+Schedule, -Constraints)__ | 17 | | *print.pl* | __pretty_print(+Schedule), pretty_print(+PID, +Schedule)__ | 18 | | *find_optimal.pl* | __find_optimal(-Schedule), is_optimal(?Schedule)__ | 19 | | *find_heuristic_astar.pl* | __find_heuristically(-Schedule)__ | 20 | | *find_heuristic.pl* | __find_heuristically(-Schedule), find_heuristically(-Schedule, +Time)__ | 21 | 22 | ## The Exam Timetabling Problem 23 | 24 | The examination timetabling problem can be stated as follows: Where and when to schedule which exams, during the examination period? Making a good schedule is challenging due to the large number of students enrolled, often with individual programs, lecturers teaching multiple courses and the limited number and capacity of rooms. Furthermore, both lecturers and students have (often conflicting) preferences. E.g. While lecturers want sufficient correction time, students want more time to study. It therefore represents a major administrative activity for academic institutions. Partial automation of this task is an active research area. 25 | 26 | ## Problem Instances 27 | To test your scheduler, problem instances are provided. Each defines a set of courses, their exams, lecturers teaching and students following them, as well as a set of rooms and their capacity/availabilities. Each specifies the following knowledge: 28 | 29 | - A set of students: **student(SID,Name)**: A student with unique identifier 'SID' and name 'Name'. 30 | 31 | - A set of lecturers: **lecturer(LID,Name)**: A lecturer with unique identifier 'LID' and name 'Name'. 32 | 33 | - A set of courses: **course(CID,Name)**: A course with unique identifier 'CID' and name 'Name'. 34 | 35 | - A set of exams: **exam(EID,Name)**: An exam with unique identifier 'EID' and name 'Name'. 36 | 37 | - A set of rooms: **room(RID,Name)**: A room with unique identifier 'RID' and name 'Name'. 38 | 39 | - Which course has which exams: **has_exam(CID,EID)**: The course with 'CID' has the exam with 'EID'. (Note: Each exam is related to exactly 1 course) 40 | 41 | - Duration of each exam: **duration(EID,Duration)**: The exam with 'EID' takes 'Duration' hours. 42 | 43 | - Students following a course: **follows(SID,CID)**: The student with 'SID' follows the course with 'CID'. 44 | 45 | - Which lecturer teaches which courses: **teaches(LID,CID)**: The lecturer with 'LID' teaches the course with 'CID'. (Note: Each course is taught by exactly 1 lecturer) 46 | 47 | - The capacity of rooms: **capacity(RID,Capacity)**: The room with 'RID' can facilitate at most 'Capacity' students. 48 | 49 | - The first day of the study/exam period: **first_day(FirstDay)**. 50 | 51 | - The last day of the correction/exam period: **last_day(LastDay)**. 52 | 53 | - The availabilities of rooms: **availability(RID,Day,From,Till)**: The room with 'RID' is available day 'Day' from 'From' o'clock till 'Till' o'clock. 54 | 55 | - The correction time required for each exam: **sc_correction_time(EID,Days)**: 'Days' days are required to correct the exam with 'EID'. (Note: The day of the exam excluded) 56 | 57 | - The study time required for each exam: **sc_study_time(EID,Days)**: 'Days' days are required to study for the exam with 'EID'. (Note: The day of the exam excluded) The following table gives an overview of the instances provided: 58 | 59 | | # | name | students | lecturers | courses | rooms | exam period length | optimal sq | 60 | |---|------|----------|-----------|---------|-------|--------------------|------------| 61 | | 1 | small | 4 | 4 | 5 | 2 | 5 Days | 1.875 | 62 | | 2 | large_short | 100 | 19 | 34 | 3 | 9 Days | ??? | 63 | | 3 | large_long | 100 | 19 | 34 | 3 | 23 Days | 0 | 64 | 65 | ## Hard Constraints 66 | The following constraints must be met in order for a schedule to be admissable: 67 | 68 | - All exams must be scheduled exactly once and start at the hour (e.g. 15:00 but not 15:30). 69 | - Exams can only take place in a room that is available for the entire period of the exam (start to end) whose capacity exceeds or equals the number of students attending the exam (subscribed to the course). 70 | - No 2 exams can take place at the same time 71 | -- in the same room 72 | -- if 1 or more students are subscribed to both courses (this includes multiple exams of the same course). 73 | -- if the same lecturer teaches both courses. 74 | 75 | ## Soft Constraints 76 | Soft constraints, unlike hard constraints, are not required for the schedule to be admissable. Rather, they are desirable (for lecturers, students or both). Each soft-constraint has a corresponding penalty, which is imposed when it is not met. One schedule is better than another if it has a lower sum of penalties. For the project we consider the following soft constraints: 77 | 78 | - **sc_lunch_break(PID,Penalty)**: A penalty of 'Penalty' is imposed for each exam a Lecturer/Student with 'PID' has during lunch break (i.e. from 12 till 13 o'clock). 79 | - **sc_no_exam_in_period(LID,Day,From,Till,Penalty)**: A penalty of 'Penalty' is imposed for each exam Lecturer with 'LID' has on day 'Day', (partially) in the period from 'From' o'clock till 'Till' o'clock. 80 | - **sc_not_in_period(PID,EID,Day,From,Till,Penalty)**: A penalty of 'Penalty' is imposed if the exam with 'EID' is held on day 'Day', (partially) in the period from 'From' o'clock till 'Till' o'clock. It is a constraint of Person with 'PID'. 81 | - **sc_same_day(PID,Penalty)**: A penalty of 'Penalty' is imposed for each pair of exams the person with 'PID' has on the same day. E.g. if the person has 3 exams on one day, 'Penalty' is imposed 3 times. 82 | - **sc_b2b(PID,Penalty)**: A penalty of 'Penalty' is imposed for each pair of exams the person with 'PID' has back-to-back (same day and consecutively). E.g. if the person has 3 exams consecutively, 'Penalty' is imposed 2 times. 83 | - **sc_correction_penalty(LID,Penalty)**: A penalty of 'Penalty' is imposed for each day the lecturer with 'LID' has too little to correct all his exams. Note that a lecturer can correct exams, the same day he has another exam (just not the exam itself). E.g. assume a lecturer has 2 exams in a 1-5 day exam period, each requiring 2 days to correct. If exams are held day X and Y, Z times 'Penalty' is imposed. 84 | 85 | | | | | | | | | | | | | | | | | | 86 | |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| 87 | | X | 1 | 1 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 4 | 4 | 5 | 88 | | Y | 1 | 2 | 3 | 4 | 5 | 2 | 3 | 4 | 5 | 3 | 4 | 5 | 4 | 5 | 5 | 89 | | Z | 0 | 0 | 0 | 1 | 2 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 4 | 90 | - **sc_study_penalty(SID,Penalty)**: A penalty of 'Penalty' is imposed for each day the student with 'SID' has too little to study for all his exams. Note that a student can study for exams, the same day he has another exam (just for the exam itself). E.g. assume a student has 2 exams in a 1-5 day exam period, each requiring 2 days to study for. If exams are held day X and Y, Z times 'Penalty' is imposed. 91 | 92 | | | | | | | | | | | | | | | | | | 93 | |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| 94 | | X| 1| 1| 1| 1| 1| 2| 2| 2| 2| 3| 3| 3| 4| 4| 5| 95 | | Y| 1| 2| 3| 4| 5| 2| 3| 4| 5| 3| 4| 5| 4| 5| 5| 96 | | Z| 4| 3| 2| 2| 2| 3| 2| 1| 1| 2| 1| 0| 1| 0| 0| 97 | 98 | -------------------------------------------------------------------------------- /cost.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % cost(+S,?C) % 6 | % violates_sc(+S, -SC) % 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | :- module(cost, [cost/2, 10 | violates_sc/2]). 11 | 12 | %:- use_module(small_instance). 13 | %:- use_module(large_short_instance). 14 | %:- use_module(large_long_instance). 15 | 16 | :- use_module(utils). 17 | 18 | % cost(+Scedule, ?Cost) 19 | % +Schedule: schedule/1 functor with list of 20 | % event/4 functors 21 | % ?Cost: Total cost of given Schedule 22 | % 23 | % Computed total cost and violated constraints 24 | % but returns only the former, or checks whether 25 | % they can be unified. 26 | cost(Schedule, Cost) :- 27 | ccost(Schedule, Cost, _). 28 | 29 | % violates_sc(+Scedule, -Violates) 30 | % +Schedule: schedule/1 functor with list of 31 | % event/4 functors 32 | % -Violates: All soft constraints violated by 33 | % the given Schedule. 34 | % 35 | % Computes total cost and violated constraints 36 | % but only returns the latter. 37 | violates_sc(Schedule, Violates) :- 38 | ccost(Schedule, _, Violates). 39 | 40 | % ccost(+Schedule, ?Cost, -Violates) 41 | % +Schedule: schedule/1 functor that contains list 42 | % of event/4 functors. 43 | % ?Cost: Total cost of given Schedule 44 | % -Violates: Soft constraints violated by Schedule 45 | % 46 | % First, preprocessing is done. Afterwards, all costs 47 | % and violated constraints for lecturer and students 48 | % are computed seperately. Finally, the total cost 49 | % is computed. 50 | ccost(schedule(Events), Cost, Violates) :- 51 | findall(EID, exam(EID,_), ExamIDs), 52 | findall(LID, lecturer(LID,_), Lecturers), 53 | findall(SID, student(SID,_), Students), 54 | do_preprocess(ExamIDs), 55 | for_person(Lecturers, Events, LCost, LViolates), 56 | for_person(Students, Events, SCost, SViolates), 57 | length(Lecturers, LecturerSize), 58 | length(Students, StudentSize), 59 | Cost is ((LCost / LecturerSize) + (SCost / StudentSize)) / 2, 60 | append(SViolates, LViolates, Violates). 61 | 62 | % for_person(+Persons, +Events, -Cost, -Violates) 63 | % +Persons: List of PID were PID is ID of student 64 | % or lecturer 65 | % +Events: List of event/4 functors 66 | % -Cost: Total penalty for this person 67 | % -Violates: All constraints violated by this 68 | % person 69 | % 70 | % Loops through the list of Persons. When current 71 | % PID is a lecturer, the soft constraint 72 | % correction_time is calculated and all other 73 | % soft constraints are checked by for_event/4. 74 | % When PID is a student, soft constraint 75 | % study_time is calculated and other soft 76 | % constraint are checked by for_event/4. Uses 77 | % an accumulator to sum all costs and append 78 | % all violated constraints. 79 | for_person(Persons, Events, Cost, Violates) :- 80 | for_person_acc(Persons, Events, 0, [], Cost, Violates). 81 | 82 | for_person_acc([], _, Cost, Violates, Cost, Violates). 83 | 84 | for_person_acc([PID|RestPersons], Events, Cost0, Violates0, Cost, Violates) :- 85 | lecturer(PID,_), 86 | % 87 | for_event(PID, Events, EventCost, EventViolates), 88 | sort_functors_dec(3, Events, SortedEvents), 89 | last_day(LastDay), 90 | correction_time(PID, SortedEvents, LastDay, 0, DTL, CorrectionCost), 91 | NewCost is Cost0 + EventCost + CorrectionCost, 92 | append_constraint(PID, DTL, CorrectionCost, Violates0, CorrectionViolates), 93 | append(CorrectionViolates, EventViolates, NewViolates), 94 | !, 95 | for_person_acc(RestPersons, Events, NewCost, NewViolates, Cost, Violates). 96 | 97 | for_person_acc([PID|RestPersons], Events, Cost0, Violates0, Cost, Violates) :- 98 | student(PID,_), 99 | % 100 | for_event(PID, Events, EventCost, EventViolates), 101 | sort_functors_asc(3, Events, SortedEvents), 102 | first_day(FirstDay), 103 | study_time(PID, SortedEvents, FirstDay, 0, DTL, StudyCost), 104 | NewCost is Cost0 + EventCost + StudyCost, 105 | append_constraint(PID, DTL, StudyCost, Violates0, StudyViolates), 106 | append(StudyViolates, EventViolates, NewViolates), 107 | !, 108 | for_person_acc(RestPersons, Events, NewCost, NewViolates, Cost, Violates). 109 | 110 | % append_constraint(+PID, +DTL, +Cost, +Violates, -NewViolates) 111 | % +PID: ID of student or lecturer 112 | % +DTL: Amount of days to little to study or correct 113 | % +Cost: Penalty for study_time or correction_time 114 | % +Violates: List of violated constraints 115 | % -NewViolates: Extended list of violates constraints 116 | % 117 | % When the DTL and Cost for study_time or correction_time 118 | % are 0, the list of violated constraints is not extended. 119 | % When DTL and Cost are different from 0, and PID is a 120 | % lecturer, then list of violated constraints is extended 121 | % with sc_correction_time/3 functor. In case were PID 122 | % is a student, list of violated constraints is extended 123 | % with sc_study_time/3 functor. 124 | append_constraint(_, 0, 0, Violates, Violates). 125 | 126 | append_constraint(PID, DTL, Cost, Violates, NewViolates) :- 127 | lecturer(PID, _), 128 | append([sc_correction_time(PID, DTL, Cost)], Violates, NewViolates), 129 | !. 130 | 131 | append_constraint(PID, DTL, Cost, Violates, NewViolates) :- 132 | student(PID,_), 133 | append([sc_study_time(PID, DTL, Cost)], Violates, NewViolates), 134 | !. 135 | 136 | % for_event(+PID, +Events, -Cost, -Violates) 137 | % +PID: ID of student or lecturer 138 | % +Events: List of event/4 functors 139 | % -Cost: Penalty of soft constraints 140 | % -Violates: Violated soft constraints 141 | % 142 | % Loops through the list of Events. When person 143 | % with PID is linked to event, the following 144 | % soft constraints are checked: no_exam_in_period, 145 | % lunch_break, not_in_period, same_day and b2b. 146 | % The cost of all these constraints are added and 147 | % the violated constraints are appended using an 148 | % accumulator. 149 | for_event(PID, Events, Cost, Violates) :- 150 | for_event_acc(PID, Events, 0, [], Cost, Violates). 151 | 152 | for_event_acc(_, [], Cost, Violates, Cost, Violates). 153 | 154 | for_event_acc(PID, [event(EID,RID,Day,Start)|RestEvents], Cost0, Violates0, Cost, Violates) :- 155 | link_to_exam(PID,EID), 156 | no_exam_in_period(PID, event(EID,RID,Day,Start), Cost1, Violates1), 157 | lunch_break(PID, event(EID,RID,Day,Start), Cost2, Violates2), 158 | not_in_period(PID, event(EID,RID,Day,Start), Cost3, Violates3), 159 | same_day(PID, event(EID,RID,Day,Start), RestEvents, Cost4, Violates4), 160 | b2b(PID, event(EID,RID,Day,Start), RestEvents, Cost5, Violates5), 161 | NewCost is Cost0 + Cost1 + Cost2 + Cost3 + Cost4 + Cost5, 162 | append(Violates1, Violates0, V1), 163 | append(Violates2, V1, V2), 164 | append(Violates3, V2, V3), 165 | append(Violates4, V3, V4), 166 | append(Violates5, V4, NewViolates), 167 | !, 168 | for_event_acc(PID, RestEvents, NewCost, NewViolates, Cost, Violates). 169 | 170 | for_event_acc(PID, [_|RestEvents], Cost0, Violates0, Cost, Violates) :- 171 | for_event_acc(PID, RestEvents, Cost0, Violates0, Cost, Violates). 172 | 173 | % correction_time(+PID, +Events, +LastDay, +CorrectionDays, -DTL, -Cost) 174 | % +PID: ID of student or lecturer 175 | % +Events: Sorted list of event/4 functors 176 | % Sorted descending on Day. 177 | % +LastDay: Day of previously encountered exam. 178 | % Initialized with last day of exam period 179 | % +CorrectionDays: Number of days person with PID 180 | % has left to correct exams. Initialized 181 | % with 0. 182 | % -DTL: Number of days lecturer has too little 183 | % to correct 184 | % -Cost: Total penalty. This equal DTL * Penalty 185 | % 186 | % Checks for each event in Events whether the lecturer 187 | % with PID is linked to this event. When this is the case, 188 | % the number of days this lecturer has available to correct 189 | % exams is computed and the number of days this lecturer 190 | % needs to correct is queried. Delta is the difference. 191 | % When Delta is negative, the lecturer has not enough time 192 | % to correct. When this is zero or positive, the lecturer 193 | % does have enough time to correct exams. Then, the next 194 | % event in the list is studied. LastDay is replaced by the 195 | % day of the current event and CorrectionDays is replaced 196 | % by the number of days the lecturer has left to correct. 197 | % Since the events are sorted descending, these days left 198 | % can be used to correct to next exam. At every loop the 199 | % Cost is incremented with Penalty * DTL. 200 | correction_time(PID, Events, LastDay, CorrectionDays, DTL, Cost) :- 201 | correction_time_acc(PID, Events, LastDay, CorrectionDays, 0, 0, DTL, Cost). 202 | 203 | correction_time_acc(_, [], _, _, DTL, Cost, DTL, Cost). 204 | 205 | correction_time_acc(PID, [event(EID,_,Day,_)|RestEvents], LastDay, CorrectionDays, DTL0, Cost0, DTL, Cost) :- 206 | has_exam(CID,EID), 207 | teaches(PID,CID), 208 | % 209 | DaysAvailable is CorrectionDays + (LastDay - Day), 210 | sc_correction_time(EID, DaysNeeded), 211 | Delta is DaysAvailable - DaysNeeded, 212 | DaysLeft is max(0, Delta), 213 | PenaltyDays is min(0,Delta), 214 | sc_correction_penalty(PID, Penalty), 215 | NewCost is Cost0 + (Penalty * abs(PenaltyDays)), 216 | NewDTL is DTL0 + abs(PenaltyDays), 217 | !, 218 | correction_time_acc(PID, RestEvents, Day, DaysLeft, NewDTL, NewCost, DTL, Cost). 219 | 220 | correction_time_acc(PID, [_|RestEvents], LastDay, CorrectionDays, DTL0, Cost0, DTL, Cost) :- 221 | correction_time_acc(PID, RestEvents, LastDay, CorrectionDays, DTL0, Cost0, DTL, Cost). 222 | 223 | % study_time(+PID, +Events, +FirstDay, +StudyDays, -DTL, -Cost) 224 | % +PID: ID of student or lecturer 225 | % +Events: Sorted list of event/4 functors. 226 | % Sorted ascending on Day. 227 | % +FirstDay: Day of previously encountered exam. 228 | % Initialized with first day of exam period 229 | % +StudyDays: Number of days person with PID 230 | % has left to study. Initialized with 0. 231 | % -DTL: Number of days student has too little 232 | % to study 233 | % -Cost: Total penalty. This equals DTL * Penalty 234 | % 235 | % Checks for each event in Events whether the student 236 | % with PID is linked to this event. When this is the case, 237 | % the number of days this student has available to study 238 | % is computed and the number of days this student needs 239 | % to study is queried. Delta is the difference of these 2. 240 | % When Delta is negative, the student has not enough time 241 | % to study. When this is zero or positive, the student has 242 | % enough time to study. Then, the next event in the list is 243 | % studied. FirstDay is replaced by the Day of the previously 244 | % encountered exam and StudyDays is replaced by the number 245 | % of days the student has left to study. Since the events are 246 | % sorted ascending, these days left can be used for the 247 | % next exam. Each time, the Cost incremented with Penalty * DTL. 248 | study_time(PID, Events, FirstDay, StudyDays, DTL, Cost) :- 249 | study_time_acc(PID, Events, FirstDay, StudyDays, 0, 0, DTL, Cost). 250 | 251 | study_time_acc(_, [], _, _, DTL, Cost, DTL, Cost). 252 | 253 | study_time_acc(PID, [event(EID,_,Day,_)|RestEvents], FirstDay, StudyDays, DTL0, Cost0, DTL, Cost) :- 254 | has_exam(CID,EID), 255 | follows_course(CID, Students), 256 | member(PID, Students), 257 | % 258 | DaysAvailable is StudyDays + (Day - FirstDay), 259 | sc_study_time(EID, DaysNeeded), 260 | Delta is DaysAvailable - DaysNeeded, 261 | DaysLeft is max(0,Delta), 262 | PenaltyDays is min(0,Delta), 263 | sc_study_penalty(PID,Penalty), 264 | NewCost is Cost0 + (Penalty * abs(PenaltyDays)), 265 | NewDTL is DTL0 + abs(PenaltyDays), 266 | !, 267 | study_time_acc(PID, RestEvents, Day, DaysLeft, NewDTL, NewCost, DTL, Cost). 268 | 269 | study_time_acc(PID, [_|RestEvents], FirstDay, StudyDays, DTL0, Cost0, DTL, Cost) :- 270 | study_time_acc(PID, RestEvents, FirstDay, StudyDays, DTL0, Cost0, DTL, Cost). 271 | 272 | % no_exam_in_period(+PID, +Event, -Cost, -Violates) 273 | % +PID: ID of student or lecturer 274 | % +Event: event/4 functor 275 | % -Cost: Resulting penalty 276 | % -Violates: Violated constraints 277 | % 278 | % When Event falls in period not preferred by 279 | % person with PID, Cost=Penalty and Violates= 280 | % sc_no_exam_in_period/5 functor. Note some extra 281 | % arithmetic is needed since between(A,B,C) returns 282 | % true when A =< C =< B, while we want A =< C < B 283 | % in case of the end-hour and A < C =< B in case of 284 | % the start hour. When constraint is not violated 285 | % Cost=0 and Violates=[] 286 | no_exam_in_period(PID, event(_,_,Day,Start), Penalty, [sc_no_exam_in_period(PID,Day,From,Till,Penalty)]) :- 287 | sc_no_exam_in_period(PID,Day,From,Till,Penalty), 288 | TillMin is Till - 1, 289 | between(From,TillMin,Start). 290 | 291 | no_exam_in_period(PID, event(EID,_,Day,Start), Penalty, [sc_no_exam_in_period(PID,Day,From,Till,Penalty)]) :- 292 | sc_no_exam_in_period(PID,Day,From,Till,Penalty), 293 | duration(EID,Duration), 294 | End is Start + Duration, 295 | FromPlus is From + 1, 296 | between(FromPlus,Till,End). 297 | 298 | no_exam_in_period(_,_,0,[]). 299 | 300 | % lunch_break(+PID, +Event, -Cost, -Violates) 301 | % +PID: ID of student or lecturer 302 | % +Event: event/4 functor 303 | % -Cost: Resulting penalty 304 | % -Violates: Violated constraints 305 | % 306 | % When Event falls during lunch break and 307 | % person with PID does not prefer this, 308 | % Cost=Penalty and Violates=sc_lunch_break/2 309 | % functor. When this is not the case, Cost=0 310 | % and Violates=[] 311 | lunch_break(PID, event(EID,_,_,Start), Penalty, [sc_lunch_break(PID,EID,Penalty)]) :- 312 | Start == 12, 313 | sc_lunch_break(PID,Penalty). 314 | 315 | lunch_break(PID, event(EID,_,_,Start), Penalty, [sc_lunch_break(PID,EID,Penalty)]) :- 316 | duration(EID,Duration), 317 | End is Start + Duration, 318 | End == 13, 319 | sc_lunch_break(PID,Penalty). 320 | 321 | lunch_break(_,_,0,[]). 322 | 323 | % not_in_period(+PID, +Event, -Cost, -Violates) 324 | % +PID: ID of student or lecturer 325 | % +Event: event/4 functor 326 | % -Cost: Resulting penalty 327 | % -Violates: Violated constraints 328 | % 329 | % When Event falls within period not preferred by 330 | % person PID, Cost=Penalty and Violates= 331 | % sc_not_in_period/6 functor. Note some extra 332 | % arithmetic is needed since between(A,B,C) returns 333 | % true when A =< C =< B, while we want A =< C < B 334 | % in case of the end-hour and A < C =< B in case of 335 | % the start hour. When constraint is not violated, 336 | % Cost=0 and Violates=[]. 337 | not_in_period(PID, event(EID,_,Day,Start), Penalty, [sc_not_in_period(PID,EID,Day,From,Till,Penalty)]) :- 338 | sc_not_in_period(PID,EID,Day,From,Till,Penalty), 339 | TillMin is Till - 1, 340 | between(From,TillMin,Start). 341 | 342 | not_in_period(PID, event(EID,_,Day,Start), Penalty, [sc_not_in_period(PID,EID,Day,From,Till,Penalty)]) :- 343 | sc_not_in_period(PID,EID,Day,From,Till,Penalty), 344 | duration(EID,Duration), 345 | End is Start + Duration, 346 | FromPlus is From + 1, 347 | between(FromPlus,Till,End). 348 | 349 | not_in_period(_, _, 0, []). 350 | 351 | % same_day(+PID, +Event, +RestEvents, -Cost, -Violates) 352 | % +PID: ID of student or lecturer 353 | % +Event: event/4 functor 354 | % +RestEvents: List of event/4 functors 355 | % -Cost: Resulting penalty 356 | % -Violates: Violated constraints 357 | % 358 | % Loops over RestEvents. When Event and element of 359 | % RestEvents are on the same day, Cost is incremented 360 | % with a penalty and an sc_same_day/4 functor is 361 | % appended to Violates. When this condition is not met 362 | % the next element in the list is checked. This uses an 363 | % accumulator. 364 | same_day(PID, Event, OtherEvents, Cost, Violates) :- 365 | same_day_acc(PID, Event, OtherEvents, 0, [], Cost, Violates). 366 | 367 | same_day_acc(_, _, [], Cost, Violates, Cost, Violates). 368 | 369 | same_day_acc(PID, event(EID,RID,Day,Start), [event(EID2,_,Day,_)|RestEvents], Cost0, Violates0, Cost, Violates) :- 370 | link_to_exam(PID, EID2), 371 | % 372 | sc_same_day(PID,Penalty), 373 | NewCost is Cost0 + Penalty, 374 | append([sc_same_day(PID, EID2, EID, Penalty)], Violates0, NewViolates), 375 | !, 376 | same_day_acc(PID, event(EID,RID,Day,Start), RestEvents, NewCost, NewViolates, Cost, Violates). 377 | 378 | same_day_acc(PID, event(EID,RID,Day,Start), [_|RestEvents], Cost0, Violates0, Cost, Violates) :- 379 | same_day_acc(PID, event(EID,RID,Day,Start), RestEvents, Cost0, Violates0, Cost, Violates). 380 | 381 | % b2b(+PID, +Event, +RestEvents, -Cost, -Violates) 382 | % +PID: ID of student or lecturer 383 | % +Event: event/4 functor 384 | % +RestEvents: List of event/4 functors 385 | % -Cost: Resulting penalty 386 | % -Violates: Violated constraints 387 | % 388 | % Loops over RestEvents. When Event and element of 389 | % RestEvents are back 2 back, i.e. the same day and 390 | % consecutively, Cost is incremented with a penalty 391 | % and an sc_b2b/4 functor is appended to Violates. 392 | % When the conditions are not met, next element in 393 | % the list is checked. This uses an accumulator. 394 | b2b(PID, Event, OtherEvents, Cost, Violates) :- 395 | b2b_acc(PID, Event, OtherEvents, 0, [], Cost, Violates). 396 | 397 | b2b_acc(_, _, [], Cost, Violates, Cost, Violates). 398 | 399 | b2b_acc(PID, event(EID,RID,Day,Start1), [event(EID2,_,Day,Start2)|RestEvents], Cost0, Violates0, Cost, Violates) :- 400 | duration(EID,Duration), 401 | Start2 is Start1 + Duration, 402 | link_to_exam(PID, EID2), 403 | % 404 | sc_b2b(PID,Penalty), 405 | NewCost is Cost0 + Penalty, 406 | append([sc_b2b(PID,EID2,EID,Penalty)], Violates0, NewViolates), 407 | !, 408 | b2b_acc(PID, event(EID,RID,Day,Start1), RestEvents, NewCost, NewViolates, Cost, Violates). 409 | 410 | b2b_acc(PID, event(EID,RID,Day,Start1), [event(EID2,_,Day,Start2)|RestEvents], Cost0, Violates0, Cost, Violates) :- 411 | duration(EID2,Duration), 412 | Start1 is Start2 + Duration, 413 | link_to_exam(PID, EID2), 414 | % 415 | sc_b2b(PID,Penalty), 416 | NewCost is Cost0 + Penalty, 417 | append([sc_b2b(PID,EID2,EID,Penalty)], Violates0, NewViolates), 418 | !, 419 | b2b_acc(PID, event(EID,RID,Day,Start1), RestEvents, NewCost, NewViolates, Cost, Violates). 420 | 421 | b2b_acc(PID, event(EID,RID,Day,Start), [_|RestEvents], Cost0, Violates0, Cost, Violates) :- 422 | b2b_acc(PID, event(EID,RID,Day,Start), RestEvents, Cost0, Violates0, Cost, Violates). 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | -------------------------------------------------------------------------------- /find_heuristic.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % find_heuristically(-S) % 6 | % find_heuristically(-S,+T) % 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | :- module(find_heuristic, [find_heuristically/1, 10 | find_heuristically/2]). 11 | 12 | %:- use_module(small_instance). 13 | %:- use_module(large_short_instance). 14 | %:- use_module(large_long_instance). 15 | 16 | :- use_module(utils). 17 | :- use_module(valid). 18 | :- use_module(cost). 19 | 20 | %find_heuristically(-Schedule) 21 | % -Schedule: a schedule/1 functor that contains a list 22 | % of event/4 functors 23 | % 24 | % Calls find_heuristically/2. The result of this is 25 | % passed on. 26 | find_heuristically(schedule(Events)) :- 27 | find_heuristically(schedule(Events),100). 28 | 29 | % find_heuristically(-Schedule,+Time) 30 | % -Schedule: a schedule/1 functor that contains a list 31 | % of event/4 functors 32 | % +Time: Number of seconds this predicate can take. 33 | % 34 | % The current time is bound to a variable. A valid 35 | % schedule, together with its cost, is generated and 36 | % duplicated 3 times. The outer_loop/4 predicate 37 | % tries to modify these schedules to find a better one, 38 | % it wil do this until Time is over. 39 | find_heuristically(schedule(Events),Time) :- 40 | get_time(StartTime), 41 | is_valid(schedule(InitEvents)), 42 | cost(schedule(InitEvents), InitCost), 43 | duplicate(node(InitEvents, InitCost), 3, NodeList), 44 | outer_loop(NodeList, StartTime, Time, Events), 45 | !. 46 | 47 | % outer_loop(+NodeList, +StartTime, +Time, -Events) 48 | % +NodeList: List of node/2 functors. Each node contains 49 | % list of event/4 functors and cost 50 | % +StartTime: Timestamp when searching started 51 | % +Time: Amount of time searching can take 52 | % -Events: List of events/4 functor with lowest cost 53 | % found after Time seconds. 54 | % 55 | % When Time seconds have elapsed, the best node has to 56 | % be found from NodeList. Otherwise, another set of 57 | % modifications can be made. Each iteration includes 58 | % the 3 best nodes and a random extra node. This extra 59 | % node makes this PAC. If there were no Time limit, all 60 | % valid schedules would be evaluated. 61 | outer_loop(NodeList, StartTime, Time, Events) :- 62 | get_time(EndTime), 63 | Diff is EndTime - StartTime, 64 | Diff < Time, 65 | !, 66 | modify(NodeList, NewNodeList), 67 | sort_functors_asc(2,NewNodeList,SortedNodeList), 68 | getN(SortedNodeList, 3, BestNodes), 69 | length(SortedNodeList, Length), 70 | random_between(4, Length, X), 71 | nth1(X, SortedNodeList, ExtraNode), 72 | outer_loop([ExtraNode|BestNodes], StartTime, Time, Events). 73 | 74 | outer_loop(NodeList, _, _, Events) :- 75 | find_best(NodeList, node(Events, Cost)), 76 | format("Cost is ~f", Cost). 77 | 78 | % modify(+NodeList, -NewList) 79 | % +NodeList: List of node/2 functors 80 | % -NewList: List of modified node/2 functors 81 | % 82 | % Each node/2 functors contains a list of event/4 83 | % functors. From each of these, a random event will 84 | % be chosen. This will be modified by modify_event/2. 85 | % When this results in a valid schedule, a new node is 86 | % created and added to NewList. If not, the modification 87 | % is retried by backtracking. The original node is 88 | % preserved as well, in case all modifications are worse. 89 | modify([], []). 90 | 91 | modify([node(Events,Cost)|RestNodes], NewList) :- 92 | modify(RestNodes, List), 93 | random_element(Events, Event), 94 | modify_event(Event, ModEvent), 95 | delete_first(Event, Events, Removed), 96 | is_valid(schedule([ModEvent|Removed])), 97 | cost(schedule([ModEvent|Removed]), NewCost), 98 | append([node(Events,Cost)], [node([ModEvent|Removed],NewCost)], Temp), 99 | append(Temp, List, NewList). 100 | 101 | % modify_event(+Event, -ModEvent) 102 | % +Event: an event/4 functor 103 | % -ModEvent: a modified event/4 functor 104 | % 105 | % The Event is modified; the Day and Start is adjusted. 106 | % This is done by a random permutation of all possible 107 | % Days and Hours. The use of member/2 allows backtracking. 108 | % The two events must be on different days OR at different 109 | % start hours. 110 | modify_event(event(EID,RID,Day,Start), event(EID,RID,Day2,Start2)) :- 111 | first_day(FirstDay), 112 | last_day(LastDay), 113 | findall(Days, between(FirstDay, LastDay, Days), Range), 114 | random_permutation(Range, DayPermutation), 115 | member(Day2, DayPermutation), 116 | availability(RID,Day2,StartHour,EndHour), 117 | duration(EID, Duration), 118 | Max is EndHour - Duration, 119 | findall(Hour, between(StartHour,Max,Hour), Hours), 120 | random_permutation(Hours, HourPermutation), 121 | member(Start2, HourPermutation), 122 | (Day =\= Day2; Start =\= Start2). 123 | 124 | % duplicate(+Elem, +N, -List) 125 | % +Elem: An item to be duplicated 126 | % +N: How many duplicates are needed 127 | % -List: List containing N times Elem 128 | % 129 | % The item Elem is copied N times, resulting 130 | % in List. 131 | duplicate(Node, N, List) :- 132 | duplicate_acc(Node, N, [], List). 133 | 134 | duplicate_acc(_, 0, List, List). 135 | 136 | duplicate_acc(Node, N, List0, List) :- 137 | N1 is N - 1, 138 | duplicate_acc(Node, N1, [Node|List0], List). 139 | 140 | % random_element(+List, -Elem) 141 | % +List: A list of which a random item will be 142 | % chosen 143 | % -Elem: A random item from List. 144 | % 145 | % A random item from List is chosen and bound to 146 | % Elem. 147 | random_element(List, Elem) :- 148 | length(List, Length), 149 | random(1, Length, X), 150 | nth1(X, List, Elem). 151 | 152 | % getN(+List, +N, -Result) 153 | % +List: A list of items 154 | % +N: How many items to take 155 | % -Result: Contains the first N items of List 156 | % 157 | % The first N items of List are bound to Result. 158 | getN(List, N, Result) :- 159 | getN_acc(List, N, [], Result). 160 | 161 | getN_acc([], _, Result, Result). 162 | 163 | getN_acc(_, 0, Result, Result). 164 | 165 | getN_acc([First|Rest], N, Result0, Result) :- 166 | N1 is N - 1, 167 | getN_acc(Rest, N1, [First|Result0], Result). 168 | 169 | % find_best(+List, -Best) 170 | % +List: A list of nodes 171 | % -Best: The best item of List 172 | % 173 | % Calls the helper predicate find_best/3. 174 | % This predicate assumes List contains 175 | % node/2 functors. The first node is initialized 176 | % as the best. 177 | find_best([First|Rest], Best) :- 178 | find_best(First,Rest,Best). 179 | 180 | % find_best(+CurrentBest, +Rest, -Best) 181 | % +CurrentBest: The current best node 182 | % +Rest: The rest of the node-list 183 | % -Best: The best item after going through Rest 184 | % 185 | % Each node in Rest is checked. When its cost is lower 186 | % than that of CurrentBest, CurrentBest is replaced. 187 | % When at the end of the list, Best is bound to 188 | % CurrentBest. 189 | find_best(Best,[],Best). 190 | 191 | find_best(node(_, CurrentCost), [node(NewEvents, NewCost)|Rest], Best) :- 192 | NewCost < CurrentCost, 193 | !, 194 | find_best(node(NewEvents,NewCost), Rest, Best). 195 | 196 | find_best(Current, [_|Rest], Best) :- 197 | find_best(Current, Rest, Best). 198 | -------------------------------------------------------------------------------- /find_heuristic_astar.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % find_heuristically(-S) % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | :- module(find_heuristic_astar, [find_heuristically/1]). 9 | 10 | %:- use_module(small_instance). 11 | %:- use_module(large_short_instance). 12 | %:- use_module(large_long_instance). 13 | 14 | :- use_module(utils). 15 | :- use_module(valid). 16 | :- use_module(cost). 17 | 18 | :- dynamic to_schedule/1. 19 | 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % NOTE: THIS DOES NOT ALWAYS WORK IN UNDER % 22 | % 2 MINUTES FOR THE LARGE SHORT INSTANCE % 23 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 24 | 25 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 26 | % A* Algorithm % 27 | % % 28 | % Nodes have form node(S,D,F) % 29 | % where S describes the state or configuration % 30 | % D is the depth of the node % 31 | % F is the evaluation function value % 32 | % Based on % 33 | % http://www.cpp.edu/~jrfisher/www/prolog_tutorial/5_1.html % 34 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 35 | 36 | % solve(+State, -Solution) 37 | % +State: Starting state description 38 | % -Solution: Solution found by the A* Algorithm 39 | % 40 | % Evalutate the search function f on the start state 41 | % and start the search process. 42 | solve(State, Solution) :- 43 | f_function(State, 0, F), 44 | search([node(State,0,F)], Solution). 45 | 46 | % f_function(+State, +Depth, -Cost) 47 | % +State: A State description 48 | % +Depth: Depth of current state 49 | % -Cost: Effort to successfully get from start 50 | % to goal by going through this node 51 | % 52 | % Evalutate f-function for current state 53 | f_function(State,D,F) :- 54 | h_function(State,H), 55 | F is D + H. 56 | 57 | % search(+OpenList, -Solution) 58 | % +OpenList: List of states to be investigated 59 | % -Solution: Solution found by A* Algorithm 60 | % 61 | % If first element of OpenList is a goal, return 62 | % this state. We only want 1 solution, so cut. 63 | % Otherwise, expand all children of current node, 64 | % sort them according to cost and proceed with this 65 | % as OpenList. 66 | search([node(State,_,_)|_], State) :- 67 | goal(State), 68 | retract(to_schedule(_)), 69 | !. 70 | 71 | search([Node|_], Solution) :- 72 | expand(Node,Children), 73 | sort_functors_asc(3, Children, SortedChildren), 74 | search(SortedChildren, Solution). 75 | 76 | % expand(+State, -Children) 77 | % +State: A state description 78 | % -Children: All children of State 79 | % 80 | % Generate all children of State. These all have 81 | % depth+1 and know their cost via f_function. 82 | expand(node(State,D,_), AllChildren) :- 83 | bagof(node(Child, D1, F), 84 | (D1 is D+1, 85 | move(State,Child), 86 | f_function(Child,D1,F)), 87 | AllChildren). 88 | 89 | %%%%%%%%%%%%%%%%%%%%%%% 90 | % End of A* Algorithm % 91 | %%%%%%%%%%%%%%%%%%%%%%% 92 | 93 | % find_heuristically(-Schedule) 94 | % -Schedule: schedule/1 functor that contains a 95 | % list of event/4 functors 96 | % 97 | % Invoke preprocessing, assert the exams to be 98 | % scheduled in a random order and start the 99 | % A* Algorithm. 100 | find_heuristically(Schedule) :- 101 | findall(EID, exam(EID,_), ExamIDs), 102 | do_preprocess(ExamIDs), 103 | random_permutation(ExamIDs, Shuffled), 104 | asserta(to_schedule(Shuffled)), 105 | solve([], Events), 106 | Schedule = schedule(Events), 107 | cost(Schedule,Cost), 108 | format("Cost of this solution is ~f", Cost). 109 | 110 | % h_function(+State, -Cost) 111 | % +State: a State description 112 | % -Cost: Cost of this State 113 | % 114 | % f_function in A* Algorithm is the 115 | % h_function + depth. h_function in this case 116 | % is the cost of the schedule. 117 | h_function(State,H) :- 118 | cost(schedule(State),H). 119 | 120 | % goal(+State) 121 | % +State: a State description 122 | % 123 | % A state is a goal state if it is a valid schedule 124 | goal(State) :- 125 | is_valid(schedule(State)). 126 | 127 | % move(+State, -Child) 128 | % +State: A State description 129 | % -Child: A child of this State 130 | % 131 | % The next exam that needs to be scheduled is taken. 132 | % An event is created for this exam and added to the schedule 133 | % in such a way that the schedule remains valid. This is done 134 | % in the next_valid/3 predicate. 135 | move(State,ChildState) :- 136 | to_schedule([EID|RestExams]), 137 | retract(to_schedule(_)), 138 | asserta(to_schedule(RestExams)), 139 | next_valid(State, EID, Child), 140 | append([Child],State,ChildState). 141 | 142 | % next_valid(+Events, +EID, -Event) 143 | % +Events: Already scheduled events 144 | % +EID: Exam ID of the exam to be scheduled 145 | % -Event: Resulting event so the schedule remains valid 146 | % 147 | % An event can be added when the room is large enough 148 | % for the number of students in the course, when a room is 149 | % available and when it does not cause conflicts with any 150 | % of the already scheduled events. 151 | next_valid(Events, EID, event(EID,RID,Day,Start)) :- 152 | exam(EID,_), 153 | has_exam(CID,EID), 154 | follows_course(CID,Students), 155 | length(Students, StudentSize), 156 | room(RID,_), 157 | capacity(RID, Capacity), 158 | Capacity >= StudentSize, 159 | availability(RID, Day, StartHour, EndHour), 160 | between(StartHour, EndHour, Start), 161 | duration(EID,Duration), 162 | End is Start + Duration, 163 | End =< EndHour, 164 | not(conflict(event(EID,RID,Day,Start), Events)). 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /find_optimal.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % find_optimal(-S) % 6 | % is_optimal(?S) % 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | :- module(find_optimal, [find_optimal/1, 10 | is_optimal/1]). 11 | %:- use_module(small_instance). 12 | %:- use_module(large_short_instance). 13 | %:- use_module(large_long_instance). 14 | :- use_module(utils). 15 | :- use_module(valid). 16 | :- use_module(cost). 17 | 18 | :- dynamic best/2. 19 | 20 | % find_optimal(-S) 21 | % -S: Schedule with lowest cost. 22 | % 23 | % Binds S to a schedule with the lowest cost. 24 | % For this, the optimal/1 predicate is called. 25 | % This will assert all best schedules with the 26 | % best/2 functor. Since find_optimal/1 only needs 27 | % to return one possible schedule, a cut is placed 28 | % at the end. 29 | find_optimal(Schedule) :- 30 | optimal(_), 31 | best(Schedule, Cost), 32 | format("Best Cost is ~f", Cost), 33 | retractall(best(_,_)), 34 | !. 35 | 36 | % is_optimal(-S) 37 | % -S: Schedule with lowest cost 38 | % 39 | % Binds S to all possible schedules with lowest 40 | % cost. For this, the optimal/1 predicate is called. 41 | % This will assert all best schedules with the best/2 42 | % functor. Since is_optimal/1 needs to return all 43 | % optimal schedules, it is allowed to backtrack 44 | % over the best-predicate. 45 | is_optimal(Schedule) :- 46 | optimal(_), 47 | best(Schedule, Cost), 48 | format("Best Cost is ~f", Cost), 49 | retract(best(Schedule,_)). 50 | 51 | % optimal(-S) 52 | % -S: Schedule with lowest cost 53 | % 54 | % Generates all possible schedules, calculates their 55 | % cost and updates the best using update_best/2. 56 | % The fail at the end ensures backtracked over is_valid/1. 57 | % When this is no longer possible, optimal(-S) succeeds 58 | % through the second predicate. 59 | optimal(_) :- 60 | assert(best(nil,1000000)), 61 | is_valid(Schedule), 62 | cost(Schedule,Cost), 63 | update_best(Schedule,Cost), 64 | fail. 65 | 66 | optimal(_) :- !. 67 | 68 | % update_best(+Schedule, +Cost) 69 | % +Schedule: schedule/1 functor that contains a list of 70 | % event/4 functors. 71 | % +Cost: integer 72 | % 73 | % Succeeds when the best schedule, i.e. the schedule with 74 | % the lowest cost, is replaced with the given schedule with 75 | % given cost because its cost is even lower. When the cost is 76 | % the same, the schedule is also asserted using the best/2 77 | % function. When this is not the case, nothing is done. 78 | update_best(Schedule, Cost) :- 79 | best(_,BestCost), 80 | Cost == BestCost, 81 | !, 82 | assert(best(Schedule,Cost)). 83 | 84 | update_best(Schedule,Cost) :- 85 | best(_,BestCost), 86 | Cost < BestCost, 87 | !, 88 | retractall(best(_,_)), 89 | assert(best(Schedule,Cost)). 90 | 91 | update_best(_,_). 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /large_long_instance.pl: -------------------------------------------------------------------------------- 1 | :- module(large_long_instance, [lecturer/2, 2 | student/2, 3 | course/2, 4 | exam/2, 5 | room/2, 6 | has_exam/2, 7 | duration/2, 8 | follows/2, 9 | teaches/2, 10 | capacity/2, 11 | first_day/1, 12 | last_day/1, 13 | availability/4, 14 | sc_lunch_break/2, 15 | sc_b2b/2, 16 | sc_same_day/2, 17 | sc_no_exam_in_period/5, 18 | sc_not_in_period/6, 19 | sc_correction_time/2, 20 | sc_correction_penalty/2, 21 | sc_study_time/2, 22 | sc_study_penalty/2]). 23 | 24 | %Allow grouping constraints per students/lecturers 25 | :- discontiguous 26 | sc_lunch_break/2, 27 | sc_not_in_period/6, 28 | sc_same_day/2, 29 | sc_b2b/2. 30 | 31 | % Students: 32 | student(s1,'Cythia Serpe'). 33 | student(s2,'Christeen Friedli'). 34 | student(s3,'Kacie Faragoza'). 35 | student(s4,'Yuonne Cormany'). 36 | student(s5,'Marilu Brauner'). 37 | student(s6,'Myrl Weader'). 38 | student(s7,'Jani Sinks'). 39 | student(s8,'Wyatt Enriguez'). 40 | student(s9,'Lamont Vanduyn'). 41 | student(s10,'Shawanda Vanwyngaarden'). 42 | student(s11,'Shizue Utecht'). 43 | student(s12,'Demarcus Mervyn'). 44 | student(s13,'Charline Predom'). 45 | student(s14,'Yukiko Chaffins'). 46 | student(s15,'Reynaldo Portlock'). 47 | student(s16,'Cory Sauerbry'). 48 | student(s17,'Esta Ciraulo'). 49 | student(s18,'Nicky Testolin'). 50 | student(s19,'Eliana Updike'). 51 | student(s20,'Larisa Bachicha'). 52 | student(s21,'Wesley Mederios'). 53 | student(s22,'Orpha Caballes'). 54 | student(s23,'Agripina Husak'). 55 | student(s24,'Jerrica Getzschman'). 56 | student(s25,'Britni Storks'). 57 | student(s26,'Dimple Cayetano'). 58 | student(s27,'Sydney Whitbeck'). 59 | student(s28,'Kaylee Palmateer'). 60 | student(s29,'Hope Lovick'). 61 | student(s30,'Bernarda Rosul'). 62 | student(s31,'Enriqueta Begeman'). 63 | student(s32,'Landon Plancarte'). 64 | student(s33,'Bonny Schwarm'). 65 | student(s34,'Joel Tiznado'). 66 | student(s35,'Echo Chillemi'). 67 | student(s36,'Ernestine Kadish'). 68 | student(s37,'Katelin Realmuto'). 69 | student(s38,'Erick Parman'). 70 | student(s39,'Sammy Qualey'). 71 | student(s40,'Linh Koppang'). 72 | student(s41,'Doris Honnen'). 73 | student(s42,'Agripina Shafto'). 74 | student(s43,'Aleshia Deines'). 75 | student(s44,'Lia Bandasak'). 76 | student(s45,'Lindsey Keens'). 77 | student(s46,'Wilmer Snerling'). 78 | student(s47,'Nelia Huie'). 79 | student(s48,'Corliss Jerman'). 80 | student(s49,'Margurite Hatake'). 81 | student(s50,'Eboni Harmeyer'). 82 | student(s51,'Richelle Cavaco'). 83 | student(s52,'Tommie Stipp'). 84 | student(s53,'Olen Verkuilen'). 85 | student(s54,'Sun Hase'). 86 | student(s55,'Robbie Hoschek'). 87 | student(s56,'Chara Coatsworth'). 88 | student(s57,'Breann Ozburn'). 89 | student(s58,'Jann Mcelhany'). 90 | student(s59,'Mandy Wharff'). 91 | student(s60,'Gregory Zarling'). 92 | student(s61,'Lavelle Benage'). 93 | student(s62,'Annice Booth'). 94 | student(s63,'Hannelore Stehly'). 95 | student(s64,'Dillon Russe'). 96 | student(s65,'Ricky Neblock'). 97 | student(s66,'Merrilee Tortelli'). 98 | student(s67,'Sade Jenks'). 99 | student(s68,'Enriqueta Haro'). 100 | student(s69,'Warren Polian'). 101 | student(s70,'Marybeth Jellison'). 102 | student(s71,'Salena Keidong'). 103 | student(s72,'Ilse Fontneau'). 104 | student(s73,'Annamaria Ganoung'). 105 | student(s74,'Haydee Burbano'). 106 | student(s75,'Angella Yundt'). 107 | student(s76,'Lenna Briski'). 108 | student(s77,'Garland Zakrajsek'). 109 | student(s78,'Geri Thoran'). 110 | student(s79,'Carola Hackbart'). 111 | student(s80,'Andrea Nwadiora'). 112 | student(s81,'Elease Weser'). 113 | student(s82,'Cynthia Antrobus'). 114 | student(s83,'Alberto Sumners'). 115 | student(s84,'Wilfredo Bassil'). 116 | student(s85,'Kattie Kierzewski'). 117 | student(s86,'Adolfo Mavai'). 118 | student(s87,'Eugenie Rigatti'). 119 | student(s88,'Shela Brisker'). 120 | student(s89,'Delena Groholski'). 121 | student(s90,'Inge Kassin'). 122 | student(s91,'Jerry Shinney'). 123 | student(s92,'Sueann Mitchem'). 124 | student(s93,'Cody Baadsgaard'). 125 | student(s94,'Calandra Berninger'). 126 | student(s95,'Maud Halwood'). 127 | student(s96,'Melina Hallford'). 128 | student(s97,'Alline Kluck'). 129 | student(s98,'Amira Trabucco'). 130 | student(s99,'Irena Quivers'). 131 | student(s100,'Dorene Winsley'). 132 | 133 | % Lecturers: 134 | lecturer(l1,'Janis Bolls'). 135 | lecturer(l2,'Ana Falacco'). 136 | lecturer(l3,'Morgan Nosek'). 137 | lecturer(l4,'Glenn Janson'). 138 | lecturer(l5,'Bethel Kievit'). 139 | lecturer(l6,'Hong Fedde'). 140 | lecturer(l7,'Nicky Waltos'). 141 | lecturer(l8,'Zulma Derwin'). 142 | lecturer(l9,'Shae Mostowy'). 143 | lecturer(l10,'Faye Bakhshian'). 144 | lecturer(l11,'Delmer Zwilling'). 145 | lecturer(l12,'Shalon Stains'). 146 | lecturer(l13,'Colleen Raike'). 147 | lecturer(l14,'Wanda Griffins'). 148 | lecturer(l15,'Oswaldo Bardo'). 149 | lecturer(l16,'Jama Nguyn'). 150 | lecturer(l17,'Charleen Mellema'). 151 | lecturer(l18,'Adelina Gord'). 152 | lecturer(l19,'Madeleine Ryba'). 153 | 154 | % Courses: 155 | course(c1,'Math 1.0'). 156 | course(c2,'Math 2.0'). 157 | course(c3,'Advanced Math 2.0'). 158 | course(c4,'Religion 1.0'). 159 | course(c5,'Religion 2.0'). 160 | course(c6,'Philosophy 1.0'). 161 | course(c7,'Philosophy 2.0'). 162 | course(c8,'History 1.0'). 163 | course(c9,'History 2.0'). 164 | course(c10,'Socio-Economic Initiation'). 165 | course(c11,'Politics & Sociology'). 166 | course(c12,'Psychology'). 167 | course(c13,'Art Initiation'). 168 | course(c14,'Art History'). 169 | course(c15,'Architecture'). 170 | course(c16,'Painting & Sculpture'). 171 | course(c17,'Music & Performing Art'). 172 | course(c18,'English 1.0'). 173 | course(c19,'English 2.0'). 174 | course(c20,'Advanced English 2.0'). 175 | course(c21,'French'). 176 | course(c22,'German'). 177 | course(c23,'Dutch'). 178 | course(c24,'Spanish'). 179 | course(c25,'Russian'). 180 | course(c26,'Chinese'). 181 | course(c27,'Latin'). 182 | course(c28,'Information & Communication Technology'). 183 | course(c29,'Science Initiation'). 184 | course(c30,'Biology'). 185 | course(c31,'Physics'). 186 | course(c32,'Chemistry'). 187 | course(c33,'Informatics'). 188 | course(c34,'Economy'). 189 | 190 | % Exams: 191 | exam(e1,'Math 1.0'). 192 | exam(e2,'Math 2.0'). 193 | exam(e3,'Advanced Math 2.0'). 194 | exam(e4,'Religion 1.0'). 195 | exam(e5,'Religion 2.0'). 196 | exam(e6,'Philosophy 1.0'). 197 | exam(e7,'Philosophy 2.0'). 198 | exam(e8,'History 1.0'). 199 | exam(e9,'History 2.0'). 200 | exam(e10,'Socio-Economic Initiation'). 201 | exam(e11,'Politics & Sociology'). 202 | exam(e12,'Psychology'). 203 | exam(e13,'Art Initiation'). 204 | exam(e14,'Art History'). 205 | exam(e15,'Architecture'). 206 | exam(e16,'Painting & Sculpture'). 207 | exam(e17,'Music & Performing Art'). 208 | exam(e18,'English 1.0'). 209 | exam(e19,'English 2.0'). 210 | exam(e20,'Advanced English 2.0'). 211 | exam(e21,'French'). 212 | exam(e22,'German'). 213 | exam(e23,'Dutch'). 214 | exam(e24,'Spanish'). 215 | exam(e25,'Russian'). 216 | exam(e26,'Chinese'). 217 | exam(e27,'Latin'). 218 | exam(e28,'Information & Communication Technology'). 219 | exam(e29,'Science Initiation'). 220 | exam(e30,'Biology'). 221 | exam(e31,'Physics'). 222 | exam(e32,'Chemistry'). 223 | exam(e33,'Informatics'). 224 | exam(e34,'Economy'). 225 | 226 | % Rooms: 227 | room(r1,'Small room'). 228 | room(r2,'Normal room'). 229 | room(r3,'Large room'). 230 | 231 | % Courses have exams: 232 | has_exam(c1,e1). 233 | has_exam(c2,e2). 234 | has_exam(c3,e3). 235 | has_exam(c4,e4). 236 | has_exam(c5,e5). 237 | has_exam(c6,e6). 238 | has_exam(c7,e7). 239 | has_exam(c8,e8). 240 | has_exam(c9,e9). 241 | has_exam(c10,e10). 242 | has_exam(c11,e11). 243 | has_exam(c12,e12). 244 | has_exam(c13,e13). 245 | has_exam(c14,e14). 246 | has_exam(c15,e15). 247 | has_exam(c16,e16). 248 | has_exam(c17,e17). 249 | has_exam(c18,e18). 250 | has_exam(c19,e19). 251 | has_exam(c20,e20). 252 | has_exam(c21,e21). 253 | has_exam(c22,e22). 254 | has_exam(c23,e23). 255 | has_exam(c24,e24). 256 | has_exam(c25,e25). 257 | has_exam(c26,e26). 258 | has_exam(c27,e27). 259 | has_exam(c28,e28). 260 | has_exam(c29,e29). 261 | has_exam(c30,e30). 262 | has_exam(c31,e31). 263 | has_exam(c32,e32). 264 | has_exam(c33,e33). 265 | has_exam(c34,e34). 266 | 267 | % Exams have durations: 268 | duration(e1,3). 269 | duration(e2,3). 270 | duration(e3,4). 271 | duration(e4,2). 272 | duration(e5,2). 273 | duration(e6,2). 274 | duration(e7,2). 275 | duration(e8,2). 276 | duration(e9,2). 277 | duration(e10,2). 278 | duration(e11,2). 279 | duration(e12,2). 280 | duration(e13,2). 281 | duration(e14,2). 282 | duration(e15,2). 283 | duration(e16,2). 284 | duration(e17,2). 285 | duration(e18,3). 286 | duration(e19,3). 287 | duration(e20,4). 288 | duration(e21,2). 289 | duration(e22,2). 290 | duration(e23,2). 291 | duration(e24,2). 292 | duration(e25,2). 293 | duration(e26,2). 294 | duration(e27,2). 295 | duration(e28,2). 296 | duration(e29,2). 297 | duration(e30,2). 298 | duration(e31,2). 299 | duration(e32,2). 300 | duration(e33,2). 301 | duration(e34,2). 302 | 303 | % Students follow courses: 304 | follows(s1,c1). 305 | follows(s2,c1). 306 | follows(s3,c1). 307 | follows(s6,c1). 308 | follows(s9,c1). 309 | follows(s10,c1). 310 | follows(s13,c1). 311 | follows(s15,c1). 312 | follows(s16,c1). 313 | follows(s17,c1). 314 | follows(s19,c1). 315 | follows(s20,c1). 316 | follows(s21,c1). 317 | follows(s22,c1). 318 | follows(s25,c1). 319 | follows(s26,c1). 320 | follows(s27,c1). 321 | follows(s30,c1). 322 | follows(s31,c1). 323 | follows(s33,c1). 324 | follows(s36,c1). 325 | follows(s46,c1). 326 | follows(s47,c1). 327 | follows(s50,c1). 328 | follows(s51,c1). 329 | follows(s55,c1). 330 | follows(s56,c1). 331 | follows(s58,c1). 332 | follows(s64,c1). 333 | follows(s67,c1). 334 | follows(s68,c1). 335 | follows(s69,c1). 336 | follows(s77,c1). 337 | follows(s79,c1). 338 | follows(s80,c1). 339 | follows(s82,c1). 340 | follows(s83,c1). 341 | follows(s84,c1). 342 | follows(s85,c1). 343 | follows(s86,c1). 344 | follows(s91,c1). 345 | follows(s92,c1). 346 | follows(s94,c1). 347 | follows(s96,c1). 348 | follows(s97,c1). 349 | follows(s99,c1). 350 | follows(s4,c2). 351 | follows(s5,c2). 352 | follows(s11,c2). 353 | follows(s28,c2). 354 | follows(s29,c2). 355 | follows(s32,c2). 356 | follows(s35,c2). 357 | follows(s37,c2). 358 | follows(s38,c2). 359 | follows(s39,c2). 360 | follows(s42,c2). 361 | follows(s44,c2). 362 | follows(s52,c2). 363 | follows(s54,c2). 364 | follows(s57,c2). 365 | follows(s59,c2). 366 | follows(s61,c2). 367 | follows(s71,c2). 368 | follows(s74,c2). 369 | follows(s75,c2). 370 | follows(s78,c2). 371 | follows(s88,c2). 372 | follows(s89,c2). 373 | follows(s90,c2). 374 | follows(s100,c2). 375 | follows(s7,c3). 376 | follows(s8,c3). 377 | follows(s12,c3). 378 | follows(s14,c3). 379 | follows(s18,c3). 380 | follows(s23,c3). 381 | follows(s24,c3). 382 | follows(s34,c3). 383 | follows(s40,c3). 384 | follows(s41,c3). 385 | follows(s43,c3). 386 | follows(s45,c3). 387 | follows(s48,c3). 388 | follows(s49,c3). 389 | follows(s53,c3). 390 | follows(s60,c3). 391 | follows(s62,c3). 392 | follows(s63,c3). 393 | follows(s65,c3). 394 | follows(s66,c3). 395 | follows(s70,c3). 396 | follows(s72,c3). 397 | follows(s73,c3). 398 | follows(s76,c3). 399 | follows(s81,c3). 400 | follows(s87,c3). 401 | follows(s93,c3). 402 | follows(s95,c3). 403 | follows(s98,c3). 404 | follows(s1,c4). 405 | follows(s2,c4). 406 | follows(s6,c4). 407 | follows(s15,c4). 408 | follows(s17,c4). 409 | follows(s19,c4). 410 | follows(s21,c4). 411 | follows(s22,c4). 412 | follows(s26,c4). 413 | follows(s30,c4). 414 | follows(s31,c4). 415 | follows(s33,c4). 416 | follows(s47,c4). 417 | follows(s56,c4). 418 | follows(s58,c4). 419 | follows(s68,c4). 420 | follows(s80,c4). 421 | follows(s82,c4). 422 | follows(s83,c4). 423 | follows(s86,c4). 424 | follows(s91,c4). 425 | follows(s92,c4). 426 | follows(s94,c4). 427 | follows(s99,c4). 428 | follows(s4,c5). 429 | follows(s5,c5). 430 | follows(s7,c5). 431 | follows(s11,c5). 432 | follows(s14,c5). 433 | follows(s23,c5). 434 | follows(s28,c5). 435 | follows(s29,c5). 436 | follows(s32,c5). 437 | follows(s34,c5). 438 | follows(s37,c5). 439 | follows(s38,c5). 440 | follows(s39,c5). 441 | follows(s41,c5). 442 | follows(s42,c5). 443 | follows(s44,c5). 444 | follows(s45,c5). 445 | follows(s49,c5). 446 | follows(s53,c5). 447 | follows(s54,c5). 448 | follows(s57,c5). 449 | follows(s59,c5). 450 | follows(s61,c5). 451 | follows(s62,c5). 452 | follows(s63,c5). 453 | follows(s66,c5). 454 | follows(s71,c5). 455 | follows(s72,c5). 456 | follows(s73,c5). 457 | follows(s74,c5). 458 | follows(s75,c5). 459 | follows(s76,c5). 460 | follows(s81,c5). 461 | follows(s88,c5). 462 | follows(s89,c5). 463 | follows(s90,c5). 464 | follows(s93,c5). 465 | follows(s95,c5). 466 | follows(s100,c5). 467 | follows(s3,c6). 468 | follows(s9,c6). 469 | follows(s10,c6). 470 | follows(s13,c6). 471 | follows(s16,c6). 472 | follows(s20,c6). 473 | follows(s25,c6). 474 | follows(s27,c6). 475 | follows(s36,c6). 476 | follows(s46,c6). 477 | follows(s50,c6). 478 | follows(s51,c6). 479 | follows(s55,c6). 480 | follows(s64,c6). 481 | follows(s67,c6). 482 | follows(s69,c6). 483 | follows(s77,c6). 484 | follows(s79,c6). 485 | follows(s84,c6). 486 | follows(s85,c6). 487 | follows(s96,c6). 488 | follows(s97,c6). 489 | follows(s8,c7). 490 | follows(s12,c7). 491 | follows(s18,c7). 492 | follows(s24,c7). 493 | follows(s35,c7). 494 | follows(s40,c7). 495 | follows(s43,c7). 496 | follows(s48,c7). 497 | follows(s52,c7). 498 | follows(s60,c7). 499 | follows(s65,c7). 500 | follows(s70,c7). 501 | follows(s78,c7). 502 | follows(s87,c7). 503 | follows(s98,c7). 504 | follows(s1,c8). 505 | follows(s2,c8). 506 | follows(s3,c8). 507 | follows(s6,c8). 508 | follows(s9,c8). 509 | follows(s10,c8). 510 | follows(s13,c8). 511 | follows(s15,c8). 512 | follows(s16,c8). 513 | follows(s17,c8). 514 | follows(s19,c8). 515 | follows(s20,c8). 516 | follows(s21,c8). 517 | follows(s22,c8). 518 | follows(s25,c8). 519 | follows(s26,c8). 520 | follows(s27,c8). 521 | follows(s30,c8). 522 | follows(s31,c8). 523 | follows(s33,c8). 524 | follows(s36,c8). 525 | follows(s46,c8). 526 | follows(s47,c8). 527 | follows(s50,c8). 528 | follows(s51,c8). 529 | follows(s55,c8). 530 | follows(s56,c8). 531 | follows(s58,c8). 532 | follows(s64,c8). 533 | follows(s67,c8). 534 | follows(s68,c8). 535 | follows(s69,c8). 536 | follows(s77,c8). 537 | follows(s79,c8). 538 | follows(s80,c8). 539 | follows(s82,c8). 540 | follows(s83,c8). 541 | follows(s84,c8). 542 | follows(s85,c8). 543 | follows(s86,c8). 544 | follows(s91,c8). 545 | follows(s92,c8). 546 | follows(s94,c8). 547 | follows(s96,c8). 548 | follows(s97,c8). 549 | follows(s99,c8). 550 | follows(s8,c9). 551 | follows(s11,c9). 552 | follows(s23,c9). 553 | follows(s24,c9). 554 | follows(s35,c9). 555 | follows(s37,c9). 556 | follows(s39,c9). 557 | follows(s43,c9). 558 | follows(s45,c9). 559 | follows(s52,c9). 560 | follows(s60,c9). 561 | follows(s63,c9). 562 | follows(s65,c9). 563 | follows(s70,c9). 564 | follows(s73,c9). 565 | follows(s76,c9). 566 | follows(s78,c9). 567 | follows(s81,c9). 568 | follows(s87,c9). 569 | follows(s88,c9). 570 | follows(s89,c9). 571 | follows(s95,c9). 572 | follows(s1,c10). 573 | follows(s2,c10). 574 | follows(s3,c10). 575 | follows(s6,c10). 576 | follows(s9,c10). 577 | follows(s10,c10). 578 | follows(s13,c10). 579 | follows(s15,c10). 580 | follows(s16,c10). 581 | follows(s17,c10). 582 | follows(s19,c10). 583 | follows(s20,c10). 584 | follows(s21,c10). 585 | follows(s22,c10). 586 | follows(s25,c10). 587 | follows(s26,c10). 588 | follows(s27,c10). 589 | follows(s30,c10). 590 | follows(s31,c10). 591 | follows(s33,c10). 592 | follows(s36,c10). 593 | follows(s46,c10). 594 | follows(s47,c10). 595 | follows(s50,c10). 596 | follows(s51,c10). 597 | follows(s55,c10). 598 | follows(s56,c10). 599 | follows(s58,c10). 600 | follows(s64,c10). 601 | follows(s67,c10). 602 | follows(s68,c10). 603 | follows(s69,c10). 604 | follows(s77,c10). 605 | follows(s79,c10). 606 | follows(s80,c10). 607 | follows(s82,c10). 608 | follows(s83,c10). 609 | follows(s84,c10). 610 | follows(s85,c10). 611 | follows(s86,c10). 612 | follows(s91,c10). 613 | follows(s92,c10). 614 | follows(s94,c10). 615 | follows(s96,c10). 616 | follows(s97,c10). 617 | follows(s99,c10). 618 | follows(s8,c11). 619 | follows(s23,c11). 620 | follows(s24,c11). 621 | follows(s43,c11). 622 | follows(s45,c11). 623 | follows(s60,c11). 624 | follows(s63,c11). 625 | follows(s65,c11). 626 | follows(s70,c11). 627 | follows(s73,c11). 628 | follows(s76,c11). 629 | follows(s81,c11). 630 | follows(s87,c11). 631 | follows(s95,c11). 632 | follows(s8,c12). 633 | follows(s23,c12). 634 | follows(s24,c12). 635 | follows(s43,c12). 636 | follows(s45,c12). 637 | follows(s60,c12). 638 | follows(s63,c12). 639 | follows(s65,c12). 640 | follows(s70,c12). 641 | follows(s73,c12). 642 | follows(s76,c12). 643 | follows(s81,c12). 644 | follows(s87,c12). 645 | follows(s95,c12). 646 | follows(s1,c13). 647 | follows(s2,c13). 648 | follows(s3,c13). 649 | follows(s6,c13). 650 | follows(s9,c13). 651 | follows(s10,c13). 652 | follows(s13,c13). 653 | follows(s15,c13). 654 | follows(s16,c13). 655 | follows(s17,c13). 656 | follows(s19,c13). 657 | follows(s20,c13). 658 | follows(s21,c13). 659 | follows(s22,c13). 660 | follows(s25,c13). 661 | follows(s26,c13). 662 | follows(s27,c13). 663 | follows(s30,c13). 664 | follows(s31,c13). 665 | follows(s33,c13). 666 | follows(s36,c13). 667 | follows(s46,c13). 668 | follows(s47,c13). 669 | follows(s50,c13). 670 | follows(s51,c13). 671 | follows(s55,c13). 672 | follows(s56,c13). 673 | follows(s58,c13). 674 | follows(s64,c13). 675 | follows(s67,c13). 676 | follows(s68,c13). 677 | follows(s69,c13). 678 | follows(s77,c13). 679 | follows(s79,c13). 680 | follows(s80,c13). 681 | follows(s82,c13). 682 | follows(s83,c13). 683 | follows(s84,c13). 684 | follows(s85,c13). 685 | follows(s86,c13). 686 | follows(s91,c13). 687 | follows(s92,c13). 688 | follows(s94,c13). 689 | follows(s96,c13). 690 | follows(s97,c13). 691 | follows(s99,c13). 692 | follows(s11,c14). 693 | follows(s35,c14). 694 | follows(s37,c14). 695 | follows(s39,c14). 696 | follows(s52,c14). 697 | follows(s78,c14). 698 | follows(s88,c14). 699 | follows(s89,c14). 700 | follows(s11,c15). 701 | follows(s35,c15). 702 | follows(s37,c15). 703 | follows(s39,c15). 704 | follows(s52,c15). 705 | follows(s78,c15). 706 | follows(s88,c15). 707 | follows(s89,c15). 708 | follows(s11,c16). 709 | follows(s35,c16). 710 | follows(s37,c16). 711 | follows(s39,c16). 712 | follows(s52,c16). 713 | follows(s78,c16). 714 | follows(s88,c16). 715 | follows(s89,c16). 716 | follows(s11,c17). 717 | follows(s35,c17). 718 | follows(s37,c17). 719 | follows(s39,c17). 720 | follows(s52,c17). 721 | follows(s78,c17). 722 | follows(s88,c17). 723 | follows(s89,c17). 724 | follows(s1,c18). 725 | follows(s2,c18). 726 | follows(s3,c18). 727 | follows(s6,c18). 728 | follows(s9,c18). 729 | follows(s10,c18). 730 | follows(s13,c18). 731 | follows(s15,c18). 732 | follows(s16,c18). 733 | follows(s17,c18). 734 | follows(s19,c18). 735 | follows(s20,c18). 736 | follows(s21,c18). 737 | follows(s22,c18). 738 | follows(s25,c18). 739 | follows(s26,c18). 740 | follows(s27,c18). 741 | follows(s30,c18). 742 | follows(s31,c18). 743 | follows(s33,c18). 744 | follows(s36,c18). 745 | follows(s46,c18). 746 | follows(s47,c18). 747 | follows(s50,c18). 748 | follows(s51,c18). 749 | follows(s55,c18). 750 | follows(s56,c18). 751 | follows(s58,c18). 752 | follows(s64,c18). 753 | follows(s67,c18). 754 | follows(s68,c18). 755 | follows(s69,c18). 756 | follows(s77,c18). 757 | follows(s79,c18). 758 | follows(s80,c18). 759 | follows(s82,c18). 760 | follows(s83,c18). 761 | follows(s84,c18). 762 | follows(s85,c18). 763 | follows(s86,c18). 764 | follows(s91,c18). 765 | follows(s92,c18). 766 | follows(s94,c18). 767 | follows(s96,c18). 768 | follows(s97,c18). 769 | follows(s99,c18). 770 | follows(s7,c19). 771 | follows(s8,c19). 772 | follows(s11,c19). 773 | follows(s12,c19). 774 | follows(s14,c19). 775 | follows(s18,c19). 776 | follows(s23,c19). 777 | follows(s24,c19). 778 | follows(s34,c19). 779 | follows(s35,c19). 780 | follows(s37,c19). 781 | follows(s39,c19). 782 | follows(s40,c19). 783 | follows(s41,c19). 784 | follows(s43,c19). 785 | follows(s45,c19). 786 | follows(s48,c19). 787 | follows(s49,c19). 788 | follows(s52,c19). 789 | follows(s53,c19). 790 | follows(s60,c19). 791 | follows(s62,c19). 792 | follows(s63,c19). 793 | follows(s65,c19). 794 | follows(s66,c19). 795 | follows(s70,c19). 796 | follows(s72,c19). 797 | follows(s73,c19). 798 | follows(s76,c19). 799 | follows(s78,c19). 800 | follows(s81,c19). 801 | follows(s87,c19). 802 | follows(s88,c19). 803 | follows(s89,c19). 804 | follows(s93,c19). 805 | follows(s95,c19). 806 | follows(s98,c19). 807 | follows(s4,c20). 808 | follows(s5,c20). 809 | follows(s28,c20). 810 | follows(s29,c20). 811 | follows(s32,c20). 812 | follows(s38,c20). 813 | follows(s42,c20). 814 | follows(s44,c20). 815 | follows(s54,c20). 816 | follows(s57,c20). 817 | follows(s59,c20). 818 | follows(s61,c20). 819 | follows(s71,c20). 820 | follows(s74,c20). 821 | follows(s75,c20). 822 | follows(s90,c20). 823 | follows(s100,c20). 824 | follows(s4,c21). 825 | follows(s5,c21). 826 | follows(s28,c21). 827 | follows(s29,c21). 828 | follows(s32,c21). 829 | follows(s38,c21). 830 | follows(s42,c21). 831 | follows(s44,c21). 832 | follows(s54,c21). 833 | follows(s57,c21). 834 | follows(s59,c21). 835 | follows(s61,c21). 836 | follows(s71,c21). 837 | follows(s74,c21). 838 | follows(s75,c21). 839 | follows(s90,c21). 840 | follows(s100,c21). 841 | follows(s4,c22). 842 | follows(s5,c22). 843 | follows(s28,c22). 844 | follows(s29,c22). 845 | follows(s32,c22). 846 | follows(s38,c22). 847 | follows(s42,c22). 848 | follows(s44,c22). 849 | follows(s54,c22). 850 | follows(s57,c22). 851 | follows(s59,c22). 852 | follows(s61,c22). 853 | follows(s71,c22). 854 | follows(s74,c22). 855 | follows(s75,c22). 856 | follows(s90,c22). 857 | follows(s100,c22). 858 | follows(s4,c23). 859 | follows(s5,c23). 860 | follows(s28,c23). 861 | follows(s29,c23). 862 | follows(s32,c23). 863 | follows(s38,c23). 864 | follows(s42,c23). 865 | follows(s44,c23). 866 | follows(s54,c23). 867 | follows(s57,c23). 868 | follows(s59,c23). 869 | follows(s61,c23). 870 | follows(s71,c23). 871 | follows(s74,c23). 872 | follows(s75,c23). 873 | follows(s90,c23). 874 | follows(s100,c23). 875 | follows(s29,c24). 876 | follows(s42,c24). 877 | follows(s54,c24). 878 | follows(s57,c24). 879 | follows(s59,c24). 880 | follows(s74,c24). 881 | follows(s4,c25). 882 | follows(s5,c25). 883 | follows(s71,c25). 884 | follows(s75,c25). 885 | follows(s100,c25). 886 | follows(s32,c26). 887 | follows(s28,c27). 888 | follows(s38,c27). 889 | follows(s44,c27). 890 | follows(s61,c27). 891 | follows(s90,c27). 892 | follows(s1,c28). 893 | follows(s2,c28). 894 | follows(s3,c28). 895 | follows(s6,c28). 896 | follows(s9,c28). 897 | follows(s10,c28). 898 | follows(s13,c28). 899 | follows(s15,c28). 900 | follows(s16,c28). 901 | follows(s17,c28). 902 | follows(s19,c28). 903 | follows(s20,c28). 904 | follows(s21,c28). 905 | follows(s22,c28). 906 | follows(s25,c28). 907 | follows(s26,c28). 908 | follows(s27,c28). 909 | follows(s30,c28). 910 | follows(s31,c28). 911 | follows(s33,c28). 912 | follows(s36,c28). 913 | follows(s46,c28). 914 | follows(s47,c28). 915 | follows(s50,c28). 916 | follows(s51,c28). 917 | follows(s55,c28). 918 | follows(s56,c28). 919 | follows(s58,c28). 920 | follows(s64,c28). 921 | follows(s67,c28). 922 | follows(s68,c28). 923 | follows(s69,c28). 924 | follows(s77,c28). 925 | follows(s79,c28). 926 | follows(s80,c28). 927 | follows(s82,c28). 928 | follows(s83,c28). 929 | follows(s84,c28). 930 | follows(s85,c28). 931 | follows(s86,c28). 932 | follows(s91,c28). 933 | follows(s92,c28). 934 | follows(s94,c28). 935 | follows(s96,c28). 936 | follows(s97,c28). 937 | follows(s99,c28). 938 | follows(s1,c29). 939 | follows(s2,c29). 940 | follows(s3,c29). 941 | follows(s6,c29). 942 | follows(s9,c29). 943 | follows(s10,c29). 944 | follows(s13,c29). 945 | follows(s15,c29). 946 | follows(s16,c29). 947 | follows(s17,c29). 948 | follows(s19,c29). 949 | follows(s20,c29). 950 | follows(s21,c29). 951 | follows(s22,c29). 952 | follows(s25,c29). 953 | follows(s26,c29). 954 | follows(s27,c29). 955 | follows(s30,c29). 956 | follows(s31,c29). 957 | follows(s33,c29). 958 | follows(s36,c29). 959 | follows(s46,c29). 960 | follows(s47,c29). 961 | follows(s50,c29). 962 | follows(s51,c29). 963 | follows(s55,c29). 964 | follows(s56,c29). 965 | follows(s58,c29). 966 | follows(s64,c29). 967 | follows(s67,c29). 968 | follows(s68,c29). 969 | follows(s69,c29). 970 | follows(s77,c29). 971 | follows(s79,c29). 972 | follows(s80,c29). 973 | follows(s82,c29). 974 | follows(s83,c29). 975 | follows(s84,c29). 976 | follows(s85,c29). 977 | follows(s86,c29). 978 | follows(s91,c29). 979 | follows(s92,c29). 980 | follows(s94,c29). 981 | follows(s96,c29). 982 | follows(s97,c29). 983 | follows(s99,c29). 984 | follows(s7,c30). 985 | follows(s12,c30). 986 | follows(s14,c30). 987 | follows(s18,c30). 988 | follows(s34,c30). 989 | follows(s40,c30). 990 | follows(s41,c30). 991 | follows(s48,c30). 992 | follows(s49,c30). 993 | follows(s53,c30). 994 | follows(s62,c30). 995 | follows(s66,c30). 996 | follows(s72,c30). 997 | follows(s93,c30). 998 | follows(s98,c30). 999 | follows(s7,c31). 1000 | follows(s12,c31). 1001 | follows(s14,c31). 1002 | follows(s18,c31). 1003 | follows(s34,c31). 1004 | follows(s40,c31). 1005 | follows(s41,c31). 1006 | follows(s48,c31). 1007 | follows(s49,c31). 1008 | follows(s53,c31). 1009 | follows(s62,c31). 1010 | follows(s66,c31). 1011 | follows(s72,c31). 1012 | follows(s93,c31). 1013 | follows(s98,c31). 1014 | follows(s7,c32). 1015 | follows(s12,c32). 1016 | follows(s14,c32). 1017 | follows(s18,c32). 1018 | follows(s34,c32). 1019 | follows(s40,c32). 1020 | follows(s41,c32). 1021 | follows(s48,c32). 1022 | follows(s49,c32). 1023 | follows(s53,c32). 1024 | follows(s62,c32). 1025 | follows(s66,c32). 1026 | follows(s72,c32). 1027 | follows(s93,c32). 1028 | follows(s98,c32). 1029 | follows(s7,c33). 1030 | follows(s12,c33). 1031 | follows(s14,c33). 1032 | follows(s18,c33). 1033 | follows(s34,c33). 1034 | follows(s40,c33). 1035 | follows(s41,c33). 1036 | follows(s48,c33). 1037 | follows(s49,c33). 1038 | follows(s53,c33). 1039 | follows(s62,c33). 1040 | follows(s66,c33). 1041 | follows(s72,c33). 1042 | follows(s93,c33). 1043 | follows(s98,c33). 1044 | follows(s8,c34). 1045 | follows(s23,c34). 1046 | follows(s24,c34). 1047 | follows(s43,c34). 1048 | follows(s45,c34). 1049 | follows(s60,c34). 1050 | follows(s63,c34). 1051 | follows(s65,c34). 1052 | follows(s70,c34). 1053 | follows(s73,c34). 1054 | follows(s76,c34). 1055 | follows(s81,c34). 1056 | follows(s87,c34). 1057 | follows(s95,c34). 1058 | 1059 | % Lectures teach courses: 1060 | teaches(l1,c1). 1061 | teaches(l2,c2). 1062 | teaches(l3,c3). 1063 | teaches(l4,c4). 1064 | teaches(l4,c5). 1065 | teaches(l5,c6). 1066 | teaches(l5,c7). 1067 | teaches(l6,c8). 1068 | teaches(l6,c9). 1069 | teaches(l7,c10). 1070 | teaches(l7,c11). 1071 | teaches(l8,c12). 1072 | teaches(l9,c13). 1073 | teaches(l6,c14). 1074 | teaches(l10,c15). 1075 | teaches(l9,c16). 1076 | teaches(l11,c17). 1077 | teaches(l12,c18). 1078 | teaches(l13,c19). 1079 | teaches(l13,c20). 1080 | teaches(l14,c21). 1081 | teaches(l12,c22). 1082 | teaches(l12,c23). 1083 | teaches(l14,c24). 1084 | teaches(l15,c25). 1085 | teaches(l16,c26). 1086 | teaches(l14,c27). 1087 | teaches(l1,c28). 1088 | teaches(l17,c29). 1089 | teaches(l17,c30). 1090 | teaches(l3,c31). 1091 | teaches(l18,c32). 1092 | teaches(l1,c33). 1093 | teaches(l2,c34). 1094 | 1095 | % Rooms have a capacity: 1096 | capacity(r1,10). 1097 | capacity(r2,30). 1098 | capacity(r3,50). 1099 | 1100 | %Exam/study period starts: 1101 | first_day(1). 1102 | 1103 | %Exam/correction period ends: 1104 | last_day(23). 1105 | 1106 | %Rooms have availabilities: 1107 | availability(Room,Day,9,17) :- room(Room,_), (between(3,7,Day);between(10,14,Day);between(17,21,Day)). 1108 | 1109 | %SOFT-CONSTRAINTS: 1110 | %lecturers 1111 | sc_lunch_break(L,1) :- lecturer(L,_). %Lecturers prefer a lunchbreak (12-13). 1112 | sc_b2b(L,2) :- lecturer(L,_). %lecturers prefer not to have exams back 2 back 1113 | %desired correction time (per exam): 1114 | sc_correction_time(e1,6). 1115 | sc_correction_time(e2,4). 1116 | sc_correction_time(e3,5). 1117 | sc_correction_time(e4,2). 1118 | sc_correction_time(e5,4). 1119 | sc_correction_time(e6,2). 1120 | sc_correction_time(e7,2). 1121 | sc_correction_time(e8,4). 1122 | sc_correction_time(e9,2). 1123 | sc_correction_time(e10,4). 1124 | sc_correction_time(e11,2). 1125 | sc_correction_time(e12,2). 1126 | sc_correction_time(e13,4). 1127 | sc_correction_time(e14,1). 1128 | sc_correction_time(e15,1). 1129 | sc_correction_time(e16,1). 1130 | sc_correction_time(e17,1). 1131 | sc_correction_time(e18,6). 1132 | sc_correction_time(e19,5). 1133 | sc_correction_time(e20,3). 1134 | sc_correction_time(e21,2). 1135 | sc_correction_time(e22,2). 1136 | sc_correction_time(e23,2). 1137 | sc_correction_time(e24,1). 1138 | sc_correction_time(e25,1). 1139 | sc_correction_time(e26,1). 1140 | sc_correction_time(e27,1). 1141 | sc_correction_time(e28,4). 1142 | sc_correction_time(e29,4). 1143 | sc_correction_time(e30,2). 1144 | sc_correction_time(e31,2). 1145 | sc_correction_time(e32,2). 1146 | sc_correction_time(e33,2). 1147 | sc_correction_time(e34,2). 1148 | sc_correction_penalty(L,2) :- lecturer(L,_). %Lecturers prefer sufficient correction time. 1149 | %Some exams shouldn't fall on the last days of the exam period 1150 | sc_not_in_period(l1,e1,21,0,24,10). 1151 | sc_not_in_period(l12,e18,21,0,24,10). 1152 | sc_not_in_period(l3,e3,21,0,24,5). 1153 | sc_not_in_period(l13,e19,21,0,24,5). 1154 | sc_not_in_period(l1,e1,20,0,24,5). 1155 | sc_not_in_period(l12,e18,20,0,24,5). 1156 | %Lecturer time preferences/unavailabilities 1157 | sc_no_exam_in_period(l1,10,0,24,5). %Janis Bolls prefers to have no exam day 10. 1158 | sc_no_exam_in_period(l1,18,0,12,2). %Janis Bolls prefers to have no exam before noon, day 18. 1159 | sc_no_exam_in_period(l2,7,0,24,5). %Ana Falacco prefers to have no exam day 7. 1160 | sc_no_exam_in_period(l2,11,0,12,5). %Ana Falacco prefers to have no exam before noon, day 11. 1161 | sc_no_exam_in_period(l2,17,12,24,2). %Ana Falacco prefers to have no exam in the afternoon, day 17. 1162 | sc_no_exam_in_period(l2,21,0,12,5). %Ana Falacco prefers to have no exam before noon, day 21. 1163 | sc_no_exam_in_period(l4,5,12,24,2). %Glenn Janson prefers to have no exam in the afternoon, day 5. 1164 | sc_no_exam_in_period(l4,12,12,24,2). %Glenn Janson prefers to have no exam in the afternoon, day 12. 1165 | sc_no_exam_in_period(l4,19,12,24,2). %Glenn Janson prefers to have no exam in the afternoon, day 19. 1166 | sc_no_exam_in_period(l4,6,12,24,2). %Glenn Janson prefers to have no exam in the afternoon, day 6. 1167 | sc_no_exam_in_period(l4,13,12,24,2). %Glenn Janson prefers to have no exam in the afternoon, day 13. 1168 | sc_no_exam_in_period(l4,20,12,24,2). %Glenn Janson prefers to have no exam in the afternoon, day 20. 1169 | sc_no_exam_in_period(l6,6,12,24,5). %Hong Fedde prefers to have no exam in the afternoon, day 6. 1170 | sc_no_exam_in_period(l6,12,0,12,5). %Hong Fedde prefers to have no exam before noon, day 12. 1171 | sc_no_exam_in_period(l6,14,0,24,5). %Hong Fedde prefers to have no exam day 14. 1172 | sc_no_exam_in_period(l7,3,0,24,2). %Nicky Waltos prefers to have no exam day 3. 1173 | sc_no_exam_in_period(l7,4,0,24,2). %Nicky Waltos prefers to have no exam day 4. 1174 | sc_no_exam_in_period(l7,5,0,24,2). %Nicky Waltos prefers to have no exam day 5. 1175 | sc_no_exam_in_period(l7,6,0,24,2). %Nicky Waltos prefers to have no exam day 6. 1176 | sc_no_exam_in_period(l7,7,0,24,2). %Nicky Waltos prefers to have no exam day 7. 1177 | sc_no_exam_in_period(l9,17,0,24,2). %Shae Mostowy prefers to have no exam day 17. 1178 | sc_no_exam_in_period(l9,18,0,24,2). %Shae Mostowy prefers to have no exam day 18. 1179 | sc_no_exam_in_period(l9,19,0,24,2). %Shae Mostowy prefers to have no exam day 19. 1180 | sc_no_exam_in_period(l9,20,0,24,2). %Shae Mostowy prefers to have no exam day 20. 1181 | sc_no_exam_in_period(l9,21,0,24,2). %Shae Mostowy prefers to have no exam day 21. 1182 | sc_no_exam_in_period(l11,10,0,24,5). %Delmer Zwilling prefers to have no exam day 10. 1183 | sc_no_exam_in_period(l11,11,0,24,5). %Delmer Zwilling prefers to have no exam day 11. 1184 | sc_no_exam_in_period(l11,12,0,24,5). %Delmer Zwilling prefers to have no exam day 12. 1185 | sc_no_exam_in_period(l11,13,0,24,5). %Delmer Zwilling prefers to have no exam day 13. 1186 | sc_no_exam_in_period(l11,14,0,24,5). %Delmer Zwilling prefers to have no exam day 14. 1187 | sc_no_exam_in_period(l12,6,0,12,5). %Shalon Stains prefers to have no exam before noon, day 6. 1188 | sc_no_exam_in_period(l12,13,0,12,5). %Shalon Stains prefers to have no exam before noon, day 13. 1189 | sc_no_exam_in_period(l12,20,0,12,5). %Shalon Stains prefers to have no exam before noon, day 20. 1190 | sc_no_exam_in_period(l12,7,0,12,5). %Shalon Stains prefers to have no exam before noon, day 7. 1191 | sc_no_exam_in_period(l12,14,0,12,5). %Shalon Stains prefers to have no exam before noon, day 14. 1192 | sc_no_exam_in_period(l12,21,0,12,5). %Shalon Stains prefers to have no exam before noon, day 21. 1193 | sc_no_exam_in_period(l13,6,12,24,5). %Colleen Raike prefers to have no exam in the afternoon, day 6. 1194 | sc_no_exam_in_period(l13,18,0,12,2). %Colleen Raike prefers to have no exam before noon, day 18. 1195 | sc_no_exam_in_period(l13,19,0,12,5). %Colleen Raike prefers to have no exam before noon, day 19. 1196 | sc_no_exam_in_period(l13,21,12,24,2). %Colleen Raike prefers to have no exam in the afternoon, day 21. 1197 | sc_no_exam_in_period(l15,10,12,24,2). %Oswaldo Bardo prefers to have no exam in the afternoon, day 10. 1198 | sc_no_exam_in_period(l16,5,0,12,5). %Jama Nguyn prefers to have no exam before noon, day 5. 1199 | sc_no_exam_in_period(l16,12,0,12,5). %Jama Nguyn prefers to have no exam before noon, day 12. 1200 | sc_no_exam_in_period(l16,19,0,12,5). %Jama Nguyn prefers to have no exam before noon, day 19. 1201 | sc_no_exam_in_period(l17,5,0,12,5). %Charleen Mellema prefers to have no exam before noon, day 5. 1202 | sc_no_exam_in_period(l18,Day,15,24,3) :- (between(3,7,Day);between(10,14,Day);between(17,21,Day)). %Adelina Gord prefers to have no exam after 15h. 1203 | sc_no_exam_in_period(l19,6,0,12,5). %Madeleine Ryba prefers to have no exam before noon, day 6. 1204 | sc_no_exam_in_period(l19,13,0,12,5). %Madeleine Ryba prefers to have no exam before noon, day 13. 1205 | sc_no_exam_in_period(l19,20,0,12,5). %Madeleine Ryba prefers to have no exam before noon, day 20. 1206 | 1207 | %students 1208 | sc_lunch_break(S,1) :- student(S,_). %Students prefer a lunchbreak (12-13). 1209 | sc_same_day(S,3) :- student(S,_). %students prefer not to have multiple exams on the same day 1210 | sc_b2b(S,5) :- student(S,_). %students prefer not to have exams back 2 back 1211 | %desired study time (per exam): 1212 | sc_study_time(e1,3). 1213 | sc_study_time(e2,3). 1214 | sc_study_time(e3,5). 1215 | sc_study_time(e4,2). 1216 | sc_study_time(e5,2). 1217 | sc_study_time(e6,2). 1218 | sc_study_time(e7,2). 1219 | sc_study_time(e8,2). 1220 | sc_study_time(e9,2). 1221 | sc_study_time(e10,2). 1222 | sc_study_time(e11,2). 1223 | sc_study_time(e12,2). 1224 | sc_study_time(e13,2). 1225 | sc_study_time(e14,2). 1226 | sc_study_time(e15,2). 1227 | sc_study_time(e16,2). 1228 | sc_study_time(e17,2). 1229 | sc_study_time(e18,3). 1230 | sc_study_time(e19,3). 1231 | sc_study_time(e20,5). 1232 | sc_study_time(e21,2). 1233 | sc_study_time(e22,2). 1234 | sc_study_time(e23,2). 1235 | sc_study_time(e24,2). 1236 | sc_study_time(e25,2). 1237 | sc_study_time(e26,2). 1238 | sc_study_time(e27,2). 1239 | sc_study_time(e28,2). 1240 | sc_study_time(e29,2). 1241 | sc_study_time(e30,2). 1242 | sc_study_time(e31,2). 1243 | sc_study_time(e32,2). 1244 | sc_study_time(e33,2). 1245 | sc_study_time(e34,2). 1246 | sc_study_penalty(S,2) :- student(S,_). %Students prefer sufficient study time. 1247 | %Some exams shouldn't fall on the first days of the exam period 1248 | sc_not_in_period(S,e3,3,0,24,8) :- student(S,_),follows(S,C),has_exam(C,e3). 1249 | sc_not_in_period(S,e19,3,0,24,8) :- student(S,_),follows(S,C),has_exam(C,e19). 1250 | sc_not_in_period(S,e3,4,0,24,4) :- student(S,_),follows(S,C),has_exam(C,e3). 1251 | sc_not_in_period(S,e19,4,0,24,4) :- student(S,_),follows(S,C),has_exam(C,e19). 1252 | -------------------------------------------------------------------------------- /large_short_instance.pl: -------------------------------------------------------------------------------- 1 | :- module(large_short_instance, [lecturer/2, 2 | student/2, 3 | course/2, 4 | exam/2, 5 | room/2, 6 | has_exam/2, 7 | duration/2, 8 | follows/2, 9 | teaches/2, 10 | capacity/2, 11 | first_day/1, 12 | last_day/1, 13 | availability/4, 14 | sc_lunch_break/2, 15 | sc_b2b/2, 16 | sc_same_day/2, 17 | sc_no_exam_in_period/5, 18 | sc_not_in_period/6, 19 | sc_correction_time/2, 20 | sc_correction_penalty/2, 21 | sc_study_time/2, 22 | sc_study_penalty/2]). 23 | 24 | %Allow grouping constraints per students/lecturers 25 | :- discontiguous 26 | sc_lunch_break/2, 27 | sc_not_in_period/6, 28 | sc_same_day/2, 29 | sc_b2b/2. 30 | 31 | % Students: 32 | student(s1,'Cythia Serpe'). 33 | student(s2,'Christeen Friedli'). 34 | student(s3,'Kacie Faragoza'). 35 | student(s4,'Yuonne Cormany'). 36 | student(s5,'Marilu Brauner'). 37 | student(s6,'Myrl Weader'). 38 | student(s7,'Jani Sinks'). 39 | student(s8,'Wyatt Enriguez'). 40 | student(s9,'Lamont Vanduyn'). 41 | student(s10,'Shawanda Vanwyngaarden'). 42 | student(s11,'Shizue Utecht'). 43 | student(s12,'Demarcus Mervyn'). 44 | student(s13,'Charline Predom'). 45 | student(s14,'Yukiko Chaffins'). 46 | student(s15,'Reynaldo Portlock'). 47 | student(s16,'Cory Sauerbry'). 48 | student(s17,'Esta Ciraulo'). 49 | student(s18,'Nicky Testolin'). 50 | student(s19,'Eliana Updike'). 51 | student(s20,'Larisa Bachicha'). 52 | student(s21,'Wesley Mederios'). 53 | student(s22,'Orpha Caballes'). 54 | student(s23,'Agripina Husak'). 55 | student(s24,'Jerrica Getzschman'). 56 | student(s25,'Britni Storks'). 57 | student(s26,'Dimple Cayetano'). 58 | student(s27,'Sydney Whitbeck'). 59 | student(s28,'Kaylee Palmateer'). 60 | student(s29,'Hope Lovick'). 61 | student(s30,'Bernarda Rosul'). 62 | student(s31,'Enriqueta Begeman'). 63 | student(s32,'Landon Plancarte'). 64 | student(s33,'Bonny Schwarm'). 65 | student(s34,'Joel Tiznado'). 66 | student(s35,'Echo Chillemi'). 67 | student(s36,'Ernestine Kadish'). 68 | student(s37,'Katelin Realmuto'). 69 | student(s38,'Erick Parman'). 70 | student(s39,'Sammy Qualey'). 71 | student(s40,'Linh Koppang'). 72 | student(s41,'Doris Honnen'). 73 | student(s42,'Agripina Shafto'). 74 | student(s43,'Aleshia Deines'). 75 | student(s44,'Lia Bandasak'). 76 | student(s45,'Lindsey Keens'). 77 | student(s46,'Wilmer Snerling'). 78 | student(s47,'Nelia Huie'). 79 | student(s48,'Corliss Jerman'). 80 | student(s49,'Margurite Hatake'). 81 | student(s50,'Eboni Harmeyer'). 82 | student(s51,'Richelle Cavaco'). 83 | student(s52,'Tommie Stipp'). 84 | student(s53,'Olen Verkuilen'). 85 | student(s54,'Sun Hase'). 86 | student(s55,'Robbie Hoschek'). 87 | student(s56,'Chara Coatsworth'). 88 | student(s57,'Breann Ozburn'). 89 | student(s58,'Jann Mcelhany'). 90 | student(s59,'Mandy Wharff'). 91 | student(s60,'Gregory Zarling'). 92 | student(s61,'Lavelle Benage'). 93 | student(s62,'Annice Booth'). 94 | student(s63,'Hannelore Stehly'). 95 | student(s64,'Dillon Russe'). 96 | student(s65,'Ricky Neblock'). 97 | student(s66,'Merrilee Tortelli'). 98 | student(s67,'Sade Jenks'). 99 | student(s68,'Enriqueta Haro'). 100 | student(s69,'Warren Polian'). 101 | student(s70,'Marybeth Jellison'). 102 | student(s71,'Salena Keidong'). 103 | student(s72,'Ilse Fontneau'). 104 | student(s73,'Annamaria Ganoung'). 105 | student(s74,'Haydee Burbano'). 106 | student(s75,'Angella Yundt'). 107 | student(s76,'Lenna Briski'). 108 | student(s77,'Garland Zakrajsek'). 109 | student(s78,'Geri Thoran'). 110 | student(s79,'Carola Hackbart'). 111 | student(s80,'Andrea Nwadiora'). 112 | student(s81,'Elease Weser'). 113 | student(s82,'Cynthia Antrobus'). 114 | student(s83,'Alberto Sumners'). 115 | student(s84,'Wilfredo Bassil'). 116 | student(s85,'Kattie Kierzewski'). 117 | student(s86,'Adolfo Mavai'). 118 | student(s87,'Eugenie Rigatti'). 119 | student(s88,'Shela Brisker'). 120 | student(s89,'Delena Groholski'). 121 | student(s90,'Inge Kassin'). 122 | student(s91,'Jerry Shinney'). 123 | student(s92,'Sueann Mitchem'). 124 | student(s93,'Cody Baadsgaard'). 125 | student(s94,'Calandra Berninger'). 126 | student(s95,'Maud Halwood'). 127 | student(s96,'Melina Hallford'). 128 | student(s97,'Alline Kluck'). 129 | student(s98,'Amira Trabucco'). 130 | student(s99,'Irena Quivers'). 131 | student(s100,'Dorene Winsley'). 132 | 133 | % Lecturers: 134 | lecturer(l1,'Janis Bolls'). 135 | lecturer(l2,'Ana Falacco'). 136 | lecturer(l3,'Morgan Nosek'). 137 | lecturer(l4,'Glenn Janson'). 138 | lecturer(l5,'Bethel Kievit'). 139 | lecturer(l6,'Hong Fedde'). 140 | lecturer(l7,'Nicky Waltos'). 141 | lecturer(l8,'Zulma Derwin'). 142 | lecturer(l9,'Shae Mostowy'). 143 | lecturer(l10,'Faye Bakhshian'). 144 | lecturer(l11,'Delmer Zwilling'). 145 | lecturer(l12,'Shalon Stains'). 146 | lecturer(l13,'Colleen Raike'). 147 | lecturer(l14,'Wanda Griffins'). 148 | lecturer(l15,'Oswaldo Bardo'). 149 | lecturer(l16,'Jama Nguyn'). 150 | lecturer(l17,'Charleen Mellema'). 151 | lecturer(l18,'Adelina Gord'). 152 | lecturer(l19,'Madeleine Ryba'). 153 | 154 | % Courses: 155 | course(c1,'Math 1.0'). 156 | course(c2,'Math 2.0'). 157 | course(c3,'Advanced Math 2.0'). 158 | course(c4,'Religion 1.0'). 159 | course(c5,'Religion 2.0'). 160 | course(c6,'Philosophy 1.0'). 161 | course(c7,'Philosophy 2.0'). 162 | course(c8,'History 1.0'). 163 | course(c9,'History 2.0'). 164 | course(c10,'Socio-Economic Initiation'). 165 | course(c11,'Politics & Sociology'). 166 | course(c12,'Psychology'). 167 | course(c13,'Art Initiation'). 168 | course(c14,'Art History'). 169 | course(c15,'Architecture'). 170 | course(c16,'Painting & Sculpture'). 171 | course(c17,'Music & Performing Art'). 172 | course(c18,'English 1.0'). 173 | course(c19,'English 2.0'). 174 | course(c20,'Advanced English 2.0'). 175 | course(c21,'French'). 176 | course(c22,'German'). 177 | course(c23,'Dutch'). 178 | course(c24,'Spanish'). 179 | course(c25,'Russian'). 180 | course(c26,'Chinese'). 181 | course(c27,'Latin'). 182 | course(c28,'Information & Communication Technology'). 183 | course(c29,'Science Initiation'). 184 | course(c30,'Biology'). 185 | course(c31,'Physics'). 186 | course(c32,'Chemistry'). 187 | course(c33,'Informatics'). 188 | course(c34,'Economy'). 189 | 190 | % Exams: 191 | exam(e1,'Math 1.0'). 192 | exam(e2,'Math 2.0'). 193 | exam(e3,'Advanced Math 2.0'). 194 | exam(e4,'Religion 1.0'). 195 | exam(e5,'Religion 2.0'). 196 | exam(e6,'Philosophy 1.0'). 197 | exam(e7,'Philosophy 2.0'). 198 | exam(e8,'History 1.0'). 199 | exam(e9,'History 2.0'). 200 | exam(e10,'Socio-Economic Initiation'). 201 | exam(e11,'Politics & Sociology'). 202 | exam(e12,'Psychology'). 203 | exam(e13,'Art Initiation'). 204 | exam(e14,'Art History'). 205 | exam(e15,'Architecture'). 206 | exam(e16,'Painting & Sculpture'). 207 | exam(e17,'Music & Performing Art'). 208 | exam(e18,'English 1.0'). 209 | exam(e19,'English 2.0'). 210 | exam(e20,'Advanced English 2.0'). 211 | exam(e21,'French'). 212 | exam(e22,'German'). 213 | exam(e23,'Dutch'). 214 | exam(e24,'Spanish'). 215 | exam(e25,'Russian'). 216 | exam(e26,'Chinese'). 217 | exam(e27,'Latin'). 218 | exam(e28,'Information & Communication Technology'). 219 | exam(e29,'Science Initiation'). 220 | exam(e30,'Biology'). 221 | exam(e31,'Physics'). 222 | exam(e32,'Chemistry'). 223 | exam(e33,'Informatics'). 224 | exam(e34,'Economy'). 225 | 226 | % Rooms: 227 | room(r1,'Small room'). 228 | room(r2,'Normal room'). 229 | room(r3,'Large room'). 230 | 231 | % Courses have exams: 232 | has_exam(c1,e1). 233 | has_exam(c2,e2). 234 | has_exam(c3,e3). 235 | has_exam(c4,e4). 236 | has_exam(c5,e5). 237 | has_exam(c6,e6). 238 | has_exam(c7,e7). 239 | has_exam(c8,e8). 240 | has_exam(c9,e9). 241 | has_exam(c10,e10). 242 | has_exam(c11,e11). 243 | has_exam(c12,e12). 244 | has_exam(c13,e13). 245 | has_exam(c14,e14). 246 | has_exam(c15,e15). 247 | has_exam(c16,e16). 248 | has_exam(c17,e17). 249 | has_exam(c18,e18). 250 | has_exam(c19,e19). 251 | has_exam(c20,e20). 252 | has_exam(c21,e21). 253 | has_exam(c22,e22). 254 | has_exam(c23,e23). 255 | has_exam(c24,e24). 256 | has_exam(c25,e25). 257 | has_exam(c26,e26). 258 | has_exam(c27,e27). 259 | has_exam(c28,e28). 260 | has_exam(c29,e29). 261 | has_exam(c30,e30). 262 | has_exam(c31,e31). 263 | has_exam(c32,e32). 264 | has_exam(c33,e33). 265 | has_exam(c34,e34). 266 | 267 | % Exams have durations: 268 | duration(e1,3). 269 | duration(e2,3). 270 | duration(e3,4). 271 | duration(e4,2). 272 | duration(e5,2). 273 | duration(e6,2). 274 | duration(e7,2). 275 | duration(e8,2). 276 | duration(e9,2). 277 | duration(e10,2). 278 | duration(e11,2). 279 | duration(e12,2). 280 | duration(e13,2). 281 | duration(e14,2). 282 | duration(e15,2). 283 | duration(e16,2). 284 | duration(e17,2). 285 | duration(e18,3). 286 | duration(e19,3). 287 | duration(e20,4). 288 | duration(e21,2). 289 | duration(e22,2). 290 | duration(e23,2). 291 | duration(e24,2). 292 | duration(e25,2). 293 | duration(e26,2). 294 | duration(e27,2). 295 | duration(e28,2). 296 | duration(e29,2). 297 | duration(e30,2). 298 | duration(e31,2). 299 | duration(e32,2). 300 | duration(e33,2). 301 | duration(e34,2). 302 | 303 | % Students follow courses: 304 | follows(s1,c1). 305 | follows(s2,c1). 306 | follows(s3,c1). 307 | follows(s6,c1). 308 | follows(s9,c1). 309 | follows(s10,c1). 310 | follows(s13,c1). 311 | follows(s15,c1). 312 | follows(s16,c1). 313 | follows(s17,c1). 314 | follows(s19,c1). 315 | follows(s20,c1). 316 | follows(s21,c1). 317 | follows(s22,c1). 318 | follows(s25,c1). 319 | follows(s26,c1). 320 | follows(s27,c1). 321 | follows(s30,c1). 322 | follows(s31,c1). 323 | follows(s33,c1). 324 | follows(s36,c1). 325 | follows(s46,c1). 326 | follows(s47,c1). 327 | follows(s50,c1). 328 | follows(s51,c1). 329 | follows(s55,c1). 330 | follows(s56,c1). 331 | follows(s58,c1). 332 | follows(s64,c1). 333 | follows(s67,c1). 334 | follows(s68,c1). 335 | follows(s69,c1). 336 | follows(s77,c1). 337 | follows(s79,c1). 338 | follows(s80,c1). 339 | follows(s82,c1). 340 | follows(s83,c1). 341 | follows(s84,c1). 342 | follows(s85,c1). 343 | follows(s86,c1). 344 | follows(s91,c1). 345 | follows(s92,c1). 346 | follows(s94,c1). 347 | follows(s96,c1). 348 | follows(s97,c1). 349 | follows(s99,c1). 350 | follows(s4,c2). 351 | follows(s5,c2). 352 | follows(s11,c2). 353 | follows(s28,c2). 354 | follows(s29,c2). 355 | follows(s32,c2). 356 | follows(s35,c2). 357 | follows(s37,c2). 358 | follows(s38,c2). 359 | follows(s39,c2). 360 | follows(s42,c2). 361 | follows(s44,c2). 362 | follows(s52,c2). 363 | follows(s54,c2). 364 | follows(s57,c2). 365 | follows(s59,c2). 366 | follows(s61,c2). 367 | follows(s71,c2). 368 | follows(s74,c2). 369 | follows(s75,c2). 370 | follows(s78,c2). 371 | follows(s88,c2). 372 | follows(s89,c2). 373 | follows(s90,c2). 374 | follows(s100,c2). 375 | follows(s7,c3). 376 | follows(s8,c3). 377 | follows(s12,c3). 378 | follows(s14,c3). 379 | follows(s18,c3). 380 | follows(s23,c3). 381 | follows(s24,c3). 382 | follows(s34,c3). 383 | follows(s40,c3). 384 | follows(s41,c3). 385 | follows(s43,c3). 386 | follows(s45,c3). 387 | follows(s48,c3). 388 | follows(s49,c3). 389 | follows(s53,c3). 390 | follows(s60,c3). 391 | follows(s62,c3). 392 | follows(s63,c3). 393 | follows(s65,c3). 394 | follows(s66,c3). 395 | follows(s70,c3). 396 | follows(s72,c3). 397 | follows(s73,c3). 398 | follows(s76,c3). 399 | follows(s81,c3). 400 | follows(s87,c3). 401 | follows(s93,c3). 402 | follows(s95,c3). 403 | follows(s98,c3). 404 | follows(s1,c4). 405 | follows(s2,c4). 406 | follows(s6,c4). 407 | follows(s15,c4). 408 | follows(s17,c4). 409 | follows(s19,c4). 410 | follows(s21,c4). 411 | follows(s22,c4). 412 | follows(s26,c4). 413 | follows(s30,c4). 414 | follows(s31,c4). 415 | follows(s33,c4). 416 | follows(s47,c4). 417 | follows(s56,c4). 418 | follows(s58,c4). 419 | follows(s68,c4). 420 | follows(s80,c4). 421 | follows(s82,c4). 422 | follows(s83,c4). 423 | follows(s86,c4). 424 | follows(s91,c4). 425 | follows(s92,c4). 426 | follows(s94,c4). 427 | follows(s99,c4). 428 | follows(s4,c5). 429 | follows(s5,c5). 430 | follows(s7,c5). 431 | follows(s11,c5). 432 | follows(s14,c5). 433 | follows(s23,c5). 434 | follows(s28,c5). 435 | follows(s29,c5). 436 | follows(s32,c5). 437 | follows(s34,c5). 438 | follows(s37,c5). 439 | follows(s38,c5). 440 | follows(s39,c5). 441 | follows(s41,c5). 442 | follows(s42,c5). 443 | follows(s44,c5). 444 | follows(s45,c5). 445 | follows(s49,c5). 446 | follows(s53,c5). 447 | follows(s54,c5). 448 | follows(s57,c5). 449 | follows(s59,c5). 450 | follows(s61,c5). 451 | follows(s62,c5). 452 | follows(s63,c5). 453 | follows(s66,c5). 454 | follows(s71,c5). 455 | follows(s72,c5). 456 | follows(s73,c5). 457 | follows(s74,c5). 458 | follows(s75,c5). 459 | follows(s76,c5). 460 | follows(s81,c5). 461 | follows(s88,c5). 462 | follows(s89,c5). 463 | follows(s90,c5). 464 | follows(s93,c5). 465 | follows(s95,c5). 466 | follows(s100,c5). 467 | follows(s3,c6). 468 | follows(s9,c6). 469 | follows(s10,c6). 470 | follows(s13,c6). 471 | follows(s16,c6). 472 | follows(s20,c6). 473 | follows(s25,c6). 474 | follows(s27,c6). 475 | follows(s36,c6). 476 | follows(s46,c6). 477 | follows(s50,c6). 478 | follows(s51,c6). 479 | follows(s55,c6). 480 | follows(s64,c6). 481 | follows(s67,c6). 482 | follows(s69,c6). 483 | follows(s77,c6). 484 | follows(s79,c6). 485 | follows(s84,c6). 486 | follows(s85,c6). 487 | follows(s96,c6). 488 | follows(s97,c6). 489 | follows(s8,c7). 490 | follows(s12,c7). 491 | follows(s18,c7). 492 | follows(s24,c7). 493 | follows(s35,c7). 494 | follows(s40,c7). 495 | follows(s43,c7). 496 | follows(s48,c7). 497 | follows(s52,c7). 498 | follows(s60,c7). 499 | follows(s65,c7). 500 | follows(s70,c7). 501 | follows(s78,c7). 502 | follows(s87,c7). 503 | follows(s98,c7). 504 | follows(s1,c8). 505 | follows(s2,c8). 506 | follows(s3,c8). 507 | follows(s6,c8). 508 | follows(s9,c8). 509 | follows(s10,c8). 510 | follows(s13,c8). 511 | follows(s15,c8). 512 | follows(s16,c8). 513 | follows(s17,c8). 514 | follows(s19,c8). 515 | follows(s20,c8). 516 | follows(s21,c8). 517 | follows(s22,c8). 518 | follows(s25,c8). 519 | follows(s26,c8). 520 | follows(s27,c8). 521 | follows(s30,c8). 522 | follows(s31,c8). 523 | follows(s33,c8). 524 | follows(s36,c8). 525 | follows(s46,c8). 526 | follows(s47,c8). 527 | follows(s50,c8). 528 | follows(s51,c8). 529 | follows(s55,c8). 530 | follows(s56,c8). 531 | follows(s58,c8). 532 | follows(s64,c8). 533 | follows(s67,c8). 534 | follows(s68,c8). 535 | follows(s69,c8). 536 | follows(s77,c8). 537 | follows(s79,c8). 538 | follows(s80,c8). 539 | follows(s82,c8). 540 | follows(s83,c8). 541 | follows(s84,c8). 542 | follows(s85,c8). 543 | follows(s86,c8). 544 | follows(s91,c8). 545 | follows(s92,c8). 546 | follows(s94,c8). 547 | follows(s96,c8). 548 | follows(s97,c8). 549 | follows(s99,c8). 550 | follows(s8,c9). 551 | follows(s11,c9). 552 | follows(s23,c9). 553 | follows(s24,c9). 554 | follows(s35,c9). 555 | follows(s37,c9). 556 | follows(s39,c9). 557 | follows(s43,c9). 558 | follows(s45,c9). 559 | follows(s52,c9). 560 | follows(s60,c9). 561 | follows(s63,c9). 562 | follows(s65,c9). 563 | follows(s70,c9). 564 | follows(s73,c9). 565 | follows(s76,c9). 566 | follows(s78,c9). 567 | follows(s81,c9). 568 | follows(s87,c9). 569 | follows(s88,c9). 570 | follows(s89,c9). 571 | follows(s95,c9). 572 | follows(s1,c10). 573 | follows(s2,c10). 574 | follows(s3,c10). 575 | follows(s6,c10). 576 | follows(s9,c10). 577 | follows(s10,c10). 578 | follows(s13,c10). 579 | follows(s15,c10). 580 | follows(s16,c10). 581 | follows(s17,c10). 582 | follows(s19,c10). 583 | follows(s20,c10). 584 | follows(s21,c10). 585 | follows(s22,c10). 586 | follows(s25,c10). 587 | follows(s26,c10). 588 | follows(s27,c10). 589 | follows(s30,c10). 590 | follows(s31,c10). 591 | follows(s33,c10). 592 | follows(s36,c10). 593 | follows(s46,c10). 594 | follows(s47,c10). 595 | follows(s50,c10). 596 | follows(s51,c10). 597 | follows(s55,c10). 598 | follows(s56,c10). 599 | follows(s58,c10). 600 | follows(s64,c10). 601 | follows(s67,c10). 602 | follows(s68,c10). 603 | follows(s69,c10). 604 | follows(s77,c10). 605 | follows(s79,c10). 606 | follows(s80,c10). 607 | follows(s82,c10). 608 | follows(s83,c10). 609 | follows(s84,c10). 610 | follows(s85,c10). 611 | follows(s86,c10). 612 | follows(s91,c10). 613 | follows(s92,c10). 614 | follows(s94,c10). 615 | follows(s96,c10). 616 | follows(s97,c10). 617 | follows(s99,c10). 618 | follows(s8,c11). 619 | follows(s23,c11). 620 | follows(s24,c11). 621 | follows(s43,c11). 622 | follows(s45,c11). 623 | follows(s60,c11). 624 | follows(s63,c11). 625 | follows(s65,c11). 626 | follows(s70,c11). 627 | follows(s73,c11). 628 | follows(s76,c11). 629 | follows(s81,c11). 630 | follows(s87,c11). 631 | follows(s95,c11). 632 | follows(s8,c12). 633 | follows(s23,c12). 634 | follows(s24,c12). 635 | follows(s43,c12). 636 | follows(s45,c12). 637 | follows(s60,c12). 638 | follows(s63,c12). 639 | follows(s65,c12). 640 | follows(s70,c12). 641 | follows(s73,c12). 642 | follows(s76,c12). 643 | follows(s81,c12). 644 | follows(s87,c12). 645 | follows(s95,c12). 646 | follows(s1,c13). 647 | follows(s2,c13). 648 | follows(s3,c13). 649 | follows(s6,c13). 650 | follows(s9,c13). 651 | follows(s10,c13). 652 | follows(s13,c13). 653 | follows(s15,c13). 654 | follows(s16,c13). 655 | follows(s17,c13). 656 | follows(s19,c13). 657 | follows(s20,c13). 658 | follows(s21,c13). 659 | follows(s22,c13). 660 | follows(s25,c13). 661 | follows(s26,c13). 662 | follows(s27,c13). 663 | follows(s30,c13). 664 | follows(s31,c13). 665 | follows(s33,c13). 666 | follows(s36,c13). 667 | follows(s46,c13). 668 | follows(s47,c13). 669 | follows(s50,c13). 670 | follows(s51,c13). 671 | follows(s55,c13). 672 | follows(s56,c13). 673 | follows(s58,c13). 674 | follows(s64,c13). 675 | follows(s67,c13). 676 | follows(s68,c13). 677 | follows(s69,c13). 678 | follows(s77,c13). 679 | follows(s79,c13). 680 | follows(s80,c13). 681 | follows(s82,c13). 682 | follows(s83,c13). 683 | follows(s84,c13). 684 | follows(s85,c13). 685 | follows(s86,c13). 686 | follows(s91,c13). 687 | follows(s92,c13). 688 | follows(s94,c13). 689 | follows(s96,c13). 690 | follows(s97,c13). 691 | follows(s99,c13). 692 | follows(s11,c14). 693 | follows(s35,c14). 694 | follows(s37,c14). 695 | follows(s39,c14). 696 | follows(s52,c14). 697 | follows(s78,c14). 698 | follows(s88,c14). 699 | follows(s89,c14). 700 | follows(s11,c15). 701 | follows(s35,c15). 702 | follows(s37,c15). 703 | follows(s39,c15). 704 | follows(s52,c15). 705 | follows(s78,c15). 706 | follows(s88,c15). 707 | follows(s89,c15). 708 | follows(s11,c16). 709 | follows(s35,c16). 710 | follows(s37,c16). 711 | follows(s39,c16). 712 | follows(s52,c16). 713 | follows(s78,c16). 714 | follows(s88,c16). 715 | follows(s89,c16). 716 | follows(s11,c17). 717 | follows(s35,c17). 718 | follows(s37,c17). 719 | follows(s39,c17). 720 | follows(s52,c17). 721 | follows(s78,c17). 722 | follows(s88,c17). 723 | follows(s89,c17). 724 | follows(s1,c18). 725 | follows(s2,c18). 726 | follows(s3,c18). 727 | follows(s6,c18). 728 | follows(s9,c18). 729 | follows(s10,c18). 730 | follows(s13,c18). 731 | follows(s15,c18). 732 | follows(s16,c18). 733 | follows(s17,c18). 734 | follows(s19,c18). 735 | follows(s20,c18). 736 | follows(s21,c18). 737 | follows(s22,c18). 738 | follows(s25,c18). 739 | follows(s26,c18). 740 | follows(s27,c18). 741 | follows(s30,c18). 742 | follows(s31,c18). 743 | follows(s33,c18). 744 | follows(s36,c18). 745 | follows(s46,c18). 746 | follows(s47,c18). 747 | follows(s50,c18). 748 | follows(s51,c18). 749 | follows(s55,c18). 750 | follows(s56,c18). 751 | follows(s58,c18). 752 | follows(s64,c18). 753 | follows(s67,c18). 754 | follows(s68,c18). 755 | follows(s69,c18). 756 | follows(s77,c18). 757 | follows(s79,c18). 758 | follows(s80,c18). 759 | follows(s82,c18). 760 | follows(s83,c18). 761 | follows(s84,c18). 762 | follows(s85,c18). 763 | follows(s86,c18). 764 | follows(s91,c18). 765 | follows(s92,c18). 766 | follows(s94,c18). 767 | follows(s96,c18). 768 | follows(s97,c18). 769 | follows(s99,c18). 770 | follows(s7,c19). 771 | follows(s8,c19). 772 | follows(s11,c19). 773 | follows(s12,c19). 774 | follows(s14,c19). 775 | follows(s18,c19). 776 | follows(s23,c19). 777 | follows(s24,c19). 778 | follows(s34,c19). 779 | follows(s35,c19). 780 | follows(s37,c19). 781 | follows(s39,c19). 782 | follows(s40,c19). 783 | follows(s41,c19). 784 | follows(s43,c19). 785 | follows(s45,c19). 786 | follows(s48,c19). 787 | follows(s49,c19). 788 | follows(s52,c19). 789 | follows(s53,c19). 790 | follows(s60,c19). 791 | follows(s62,c19). 792 | follows(s63,c19). 793 | follows(s65,c19). 794 | follows(s66,c19). 795 | follows(s70,c19). 796 | follows(s72,c19). 797 | follows(s73,c19). 798 | follows(s76,c19). 799 | follows(s78,c19). 800 | follows(s81,c19). 801 | follows(s87,c19). 802 | follows(s88,c19). 803 | follows(s89,c19). 804 | follows(s93,c19). 805 | follows(s95,c19). 806 | follows(s98,c19). 807 | follows(s4,c20). 808 | follows(s5,c20). 809 | follows(s28,c20). 810 | follows(s29,c20). 811 | follows(s32,c20). 812 | follows(s38,c20). 813 | follows(s42,c20). 814 | follows(s44,c20). 815 | follows(s54,c20). 816 | follows(s57,c20). 817 | follows(s59,c20). 818 | follows(s61,c20). 819 | follows(s71,c20). 820 | follows(s74,c20). 821 | follows(s75,c20). 822 | follows(s90,c20). 823 | follows(s100,c20). 824 | follows(s4,c21). 825 | follows(s5,c21). 826 | follows(s28,c21). 827 | follows(s29,c21). 828 | follows(s32,c21). 829 | follows(s38,c21). 830 | follows(s42,c21). 831 | follows(s44,c21). 832 | follows(s54,c21). 833 | follows(s57,c21). 834 | follows(s59,c21). 835 | follows(s61,c21). 836 | follows(s71,c21). 837 | follows(s74,c21). 838 | follows(s75,c21). 839 | follows(s90,c21). 840 | follows(s100,c21). 841 | follows(s4,c22). 842 | follows(s5,c22). 843 | follows(s28,c22). 844 | follows(s29,c22). 845 | follows(s32,c22). 846 | follows(s38,c22). 847 | follows(s42,c22). 848 | follows(s44,c22). 849 | follows(s54,c22). 850 | follows(s57,c22). 851 | follows(s59,c22). 852 | follows(s61,c22). 853 | follows(s71,c22). 854 | follows(s74,c22). 855 | follows(s75,c22). 856 | follows(s90,c22). 857 | follows(s100,c22). 858 | follows(s4,c23). 859 | follows(s5,c23). 860 | follows(s28,c23). 861 | follows(s29,c23). 862 | follows(s32,c23). 863 | follows(s38,c23). 864 | follows(s42,c23). 865 | follows(s44,c23). 866 | follows(s54,c23). 867 | follows(s57,c23). 868 | follows(s59,c23). 869 | follows(s61,c23). 870 | follows(s71,c23). 871 | follows(s74,c23). 872 | follows(s75,c23). 873 | follows(s90,c23). 874 | follows(s100,c23). 875 | follows(s29,c24). 876 | follows(s42,c24). 877 | follows(s54,c24). 878 | follows(s57,c24). 879 | follows(s59,c24). 880 | follows(s74,c24). 881 | follows(s4,c25). 882 | follows(s5,c25). 883 | follows(s71,c25). 884 | follows(s75,c25). 885 | follows(s100,c25). 886 | follows(s32,c26). 887 | follows(s28,c27). 888 | follows(s38,c27). 889 | follows(s44,c27). 890 | follows(s61,c27). 891 | follows(s90,c27). 892 | follows(s1,c28). 893 | follows(s2,c28). 894 | follows(s3,c28). 895 | follows(s6,c28). 896 | follows(s9,c28). 897 | follows(s10,c28). 898 | follows(s13,c28). 899 | follows(s15,c28). 900 | follows(s16,c28). 901 | follows(s17,c28). 902 | follows(s19,c28). 903 | follows(s20,c28). 904 | follows(s21,c28). 905 | follows(s22,c28). 906 | follows(s25,c28). 907 | follows(s26,c28). 908 | follows(s27,c28). 909 | follows(s30,c28). 910 | follows(s31,c28). 911 | follows(s33,c28). 912 | follows(s36,c28). 913 | follows(s46,c28). 914 | follows(s47,c28). 915 | follows(s50,c28). 916 | follows(s51,c28). 917 | follows(s55,c28). 918 | follows(s56,c28). 919 | follows(s58,c28). 920 | follows(s64,c28). 921 | follows(s67,c28). 922 | follows(s68,c28). 923 | follows(s69,c28). 924 | follows(s77,c28). 925 | follows(s79,c28). 926 | follows(s80,c28). 927 | follows(s82,c28). 928 | follows(s83,c28). 929 | follows(s84,c28). 930 | follows(s85,c28). 931 | follows(s86,c28). 932 | follows(s91,c28). 933 | follows(s92,c28). 934 | follows(s94,c28). 935 | follows(s96,c28). 936 | follows(s97,c28). 937 | follows(s99,c28). 938 | follows(s1,c29). 939 | follows(s2,c29). 940 | follows(s3,c29). 941 | follows(s6,c29). 942 | follows(s9,c29). 943 | follows(s10,c29). 944 | follows(s13,c29). 945 | follows(s15,c29). 946 | follows(s16,c29). 947 | follows(s17,c29). 948 | follows(s19,c29). 949 | follows(s20,c29). 950 | follows(s21,c29). 951 | follows(s22,c29). 952 | follows(s25,c29). 953 | follows(s26,c29). 954 | follows(s27,c29). 955 | follows(s30,c29). 956 | follows(s31,c29). 957 | follows(s33,c29). 958 | follows(s36,c29). 959 | follows(s46,c29). 960 | follows(s47,c29). 961 | follows(s50,c29). 962 | follows(s51,c29). 963 | follows(s55,c29). 964 | follows(s56,c29). 965 | follows(s58,c29). 966 | follows(s64,c29). 967 | follows(s67,c29). 968 | follows(s68,c29). 969 | follows(s69,c29). 970 | follows(s77,c29). 971 | follows(s79,c29). 972 | follows(s80,c29). 973 | follows(s82,c29). 974 | follows(s83,c29). 975 | follows(s84,c29). 976 | follows(s85,c29). 977 | follows(s86,c29). 978 | follows(s91,c29). 979 | follows(s92,c29). 980 | follows(s94,c29). 981 | follows(s96,c29). 982 | follows(s97,c29). 983 | follows(s99,c29). 984 | follows(s7,c30). 985 | follows(s12,c30). 986 | follows(s14,c30). 987 | follows(s18,c30). 988 | follows(s34,c30). 989 | follows(s40,c30). 990 | follows(s41,c30). 991 | follows(s48,c30). 992 | follows(s49,c30). 993 | follows(s53,c30). 994 | follows(s62,c30). 995 | follows(s66,c30). 996 | follows(s72,c30). 997 | follows(s93,c30). 998 | follows(s98,c30). 999 | follows(s7,c31). 1000 | follows(s12,c31). 1001 | follows(s14,c31). 1002 | follows(s18,c31). 1003 | follows(s34,c31). 1004 | follows(s40,c31). 1005 | follows(s41,c31). 1006 | follows(s48,c31). 1007 | follows(s49,c31). 1008 | follows(s53,c31). 1009 | follows(s62,c31). 1010 | follows(s66,c31). 1011 | follows(s72,c31). 1012 | follows(s93,c31). 1013 | follows(s98,c31). 1014 | follows(s7,c32). 1015 | follows(s12,c32). 1016 | follows(s14,c32). 1017 | follows(s18,c32). 1018 | follows(s34,c32). 1019 | follows(s40,c32). 1020 | follows(s41,c32). 1021 | follows(s48,c32). 1022 | follows(s49,c32). 1023 | follows(s53,c32). 1024 | follows(s62,c32). 1025 | follows(s66,c32). 1026 | follows(s72,c32). 1027 | follows(s93,c32). 1028 | follows(s98,c32). 1029 | follows(s7,c33). 1030 | follows(s12,c33). 1031 | follows(s14,c33). 1032 | follows(s18,c33). 1033 | follows(s34,c33). 1034 | follows(s40,c33). 1035 | follows(s41,c33). 1036 | follows(s48,c33). 1037 | follows(s49,c33). 1038 | follows(s53,c33). 1039 | follows(s62,c33). 1040 | follows(s66,c33). 1041 | follows(s72,c33). 1042 | follows(s93,c33). 1043 | follows(s98,c33). 1044 | follows(s8,c34). 1045 | follows(s23,c34). 1046 | follows(s24,c34). 1047 | follows(s43,c34). 1048 | follows(s45,c34). 1049 | follows(s60,c34). 1050 | follows(s63,c34). 1051 | follows(s65,c34). 1052 | follows(s70,c34). 1053 | follows(s73,c34). 1054 | follows(s76,c34). 1055 | follows(s81,c34). 1056 | follows(s87,c34). 1057 | follows(s95,c34). 1058 | 1059 | % Lectures teach courses: 1060 | teaches(l1,c1). 1061 | teaches(l2,c2). 1062 | teaches(l3,c3). 1063 | teaches(l4,c4). 1064 | teaches(l4,c5). 1065 | teaches(l5,c6). 1066 | teaches(l5,c7). 1067 | teaches(l6,c8). 1068 | teaches(l6,c9). 1069 | teaches(l7,c10). 1070 | teaches(l7,c11). 1071 | teaches(l8,c12). 1072 | teaches(l9,c13). 1073 | teaches(l6,c14). 1074 | teaches(l10,c15). 1075 | teaches(l9,c16). 1076 | teaches(l11,c17). 1077 | teaches(l12,c18). 1078 | teaches(l13,c19). 1079 | teaches(l13,c20). 1080 | teaches(l14,c21). 1081 | teaches(l12,c22). 1082 | teaches(l12,c23). 1083 | teaches(l14,c24). 1084 | teaches(l15,c25). 1085 | teaches(l16,c26). 1086 | teaches(l14,c27). 1087 | teaches(l1,c28). 1088 | teaches(l17,c29). 1089 | teaches(l17,c30). 1090 | teaches(l3,c31). 1091 | teaches(l18,c32). 1092 | teaches(l1,c33). 1093 | teaches(l2,c34). 1094 | 1095 | % Rooms have a capacity: 1096 | capacity(r1,10). 1097 | capacity(r2,30). 1098 | capacity(r3,50). 1099 | 1100 | %Exam/study period starts: 1101 | first_day(1). 1102 | 1103 | %Exam/correction period ends: 1104 | last_day(9). 1105 | 1106 | %Rooms have availabilities: 1107 | availability(Room,Day,9,17) :- room(Room,_), between(3,7,Day). 1108 | 1109 | %SOFT-CONSTRAINTS: 1110 | %lecturers 1111 | sc_lunch_break(L,1) :- lecturer(L,_). %Lecturers prefer a lunchbreak (12-13). 1112 | sc_b2b(L,2) :- lecturer(L,_). %lecturers prefer not to have exams back 2 back 1113 | %desired correction time (per exam): 1114 | sc_correction_time(e1,6). 1115 | sc_correction_time(e2,4). 1116 | sc_correction_time(e3,5). 1117 | sc_correction_time(e4,2). 1118 | sc_correction_time(e5,4). 1119 | sc_correction_time(e6,2). 1120 | sc_correction_time(e7,2). 1121 | sc_correction_time(e8,4). 1122 | sc_correction_time(e9,2). 1123 | sc_correction_time(e10,4). 1124 | sc_correction_time(e11,2). 1125 | sc_correction_time(e12,2). 1126 | sc_correction_time(e13,4). 1127 | sc_correction_time(e14,1). 1128 | sc_correction_time(e15,1). 1129 | sc_correction_time(e16,1). 1130 | sc_correction_time(e17,1). 1131 | sc_correction_time(e18,6). 1132 | sc_correction_time(e19,5). 1133 | sc_correction_time(e20,3). 1134 | sc_correction_time(e21,2). 1135 | sc_correction_time(e22,2). 1136 | sc_correction_time(e23,2). 1137 | sc_correction_time(e24,1). 1138 | sc_correction_time(e25,1). 1139 | sc_correction_time(e26,1). 1140 | sc_correction_time(e27,1). 1141 | sc_correction_time(e28,4). 1142 | sc_correction_time(e29,4). 1143 | sc_correction_time(e30,2). 1144 | sc_correction_time(e31,2). 1145 | sc_correction_time(e32,2). 1146 | sc_correction_time(e33,2). 1147 | sc_correction_time(e34,2). 1148 | sc_correction_penalty(L,2) :- lecturer(L,_). %Lecturers prefer sufficient correction time. 1149 | %Some exams shouldn't fall on the last days of the exam period 1150 | sc_not_in_period(l1,e1,7,0,24,10). 1151 | sc_not_in_period(l12,e18,7,0,24,10). 1152 | sc_not_in_period(l3,e3,7,0,24,5). 1153 | sc_not_in_period(l13,e19,7,0,24,5). 1154 | sc_not_in_period(l1,e1,6,0,24,5). 1155 | sc_not_in_period(l12,e18,6,0,24,5). 1156 | %Lecturer time preferences/unavailabilities 1157 | sc_no_exam_in_period(l3,Day,0,10,4) :- between(3,7,Day). %Morgan Nosek prefers to have no exam before 10h. 1158 | sc_no_exam_in_period(l4,Day,0,13,1) :- between(3,7,Day). %Glenn Janson prefers to have no exam before 13h. 1159 | sc_no_exam_in_period(l12,5,0,24,5). %Shalon Stains prefers to have no exam day 5. 1160 | sc_no_exam_in_period(l12,7,12,24,5). %Shalon Stains prefers to have no exam in the afternoon, day 7. 1161 | sc_no_exam_in_period(l14,7,12,24,5). %Wanda Griffins prefers to have no exam in the afternoon, day 7. 1162 | sc_no_exam_in_period(l15,5,0,24,5). %Oswaldo Bardo prefers to have no exam day 5. 1163 | sc_no_exam_in_period(l16,5,12,24,2). %Jama Nguyn prefers to have no exam in the afternoon, day 5. 1164 | sc_no_exam_in_period(l17,6,12,24,5). %Charleen Mellema prefers to have no exam in the afternoon, day 6. 1165 | sc_no_exam_in_period(l17,7,0,24,5). %Charleen Mellema prefers to have no exam day 7. 1166 | 1167 | %students 1168 | sc_lunch_break(S,1) :- student(S,_). %Students prefer a lunchbreak (12-13). 1169 | sc_same_day(S,3) :- student(S,_). %students prefer not to have multiple exams on the same day 1170 | sc_b2b(S,5) :- student(S,_). %students prefer not to have exams back 2 back 1171 | %desired study time (per exam): 1172 | sc_study_time(e1,3). 1173 | sc_study_time(e2,3). 1174 | sc_study_time(e3,5). 1175 | sc_study_time(e4,2). 1176 | sc_study_time(e5,2). 1177 | sc_study_time(e6,2). 1178 | sc_study_time(e7,2). 1179 | sc_study_time(e8,2). 1180 | sc_study_time(e9,2). 1181 | sc_study_time(e10,2). 1182 | sc_study_time(e11,2). 1183 | sc_study_time(e12,2). 1184 | sc_study_time(e13,2). 1185 | sc_study_time(e14,2). 1186 | sc_study_time(e15,2). 1187 | sc_study_time(e16,2). 1188 | sc_study_time(e17,2). 1189 | sc_study_time(e18,3). 1190 | sc_study_time(e19,3). 1191 | sc_study_time(e20,5). 1192 | sc_study_time(e21,2). 1193 | sc_study_time(e22,2). 1194 | sc_study_time(e23,2). 1195 | sc_study_time(e24,2). 1196 | sc_study_time(e25,2). 1197 | sc_study_time(e26,2). 1198 | sc_study_time(e27,2). 1199 | sc_study_time(e28,2). 1200 | sc_study_time(e29,2). 1201 | sc_study_time(e30,2). 1202 | sc_study_time(e31,2). 1203 | sc_study_time(e32,2). 1204 | sc_study_time(e33,2). 1205 | sc_study_time(e34,2). 1206 | sc_study_penalty(S,2) :- student(S,_). %Students prefer sufficient study time. 1207 | %Some exams shouldn't fall on the first days of the exam period 1208 | sc_not_in_period(S,e3,3,0,24,8) :- student(S,_),follows(S,C),has_exam(C,e3). 1209 | sc_not_in_period(S,e19,3,0,24,8) :- student(S,_),follows(S,C),has_exam(C,e19). 1210 | sc_not_in_period(S,e3,4,0,24,4) :- student(S,_),follows(S,C),has_exam(C,e3). 1211 | sc_not_in_period(S,e19,4,0,24,4) :- student(S,_),follows(S,C),has_exam(C,e19). 1212 | -------------------------------------------------------------------------------- /print.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % pretty_print(+S) % 6 | % pretty_print(+SID, +S) % 7 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 8 | 9 | :- module(print, [pretty_print/1, 10 | pretty_print/2]). 11 | 12 | :- use_module(small_instance). 13 | %:- use_module(large_short_instance). 14 | %:- use_module(large_long_instance). 15 | 16 | :- use_module(utils). 17 | 18 | % pretty_print(+SID, +Schedule) 19 | % +SID: Student ID 20 | % +Schedule: schedule/1 functor that contains a list 21 | % of event/4 functors. 22 | % 23 | % The events in the given schedule are filtered by 24 | % filter_events/3, based on the given SID. The 25 | % resulting list is passed to print_day/1, via findall, 26 | % so all alternatives are tried. 27 | pretty_print(PID, schedule(Events)) :- 28 | filter_events(Events, PID, FilteredEvents), 29 | findall(_, print_day(FilteredEvents), _). 30 | 31 | % filter_events(+Events, +SID, -FilteredEvents) 32 | % +Events: List of event/4 functors 33 | % +SID: Student ID 34 | % -FilteredEvents: +Events filtered by +SID 35 | % 36 | % Loops through the list of given events and add all 37 | % elements of Events to FilteredEvents when the student 38 | % with SID follows the course associated with Event. 39 | filter_events(Events, PID, Filtered) :- 40 | filter_events_acc(Events, PID, [], Filtered). 41 | 42 | filter_events_acc([], _, Filtered, Filtered). 43 | 44 | filter_events_acc([event(EID,RID,Day,Start)|RestEvents], PID, Filtered0, Filtered) :- 45 | student(PID,_), 46 | has_exam(CID,EID), 47 | findall(SID, follows(SID,CID), Students), 48 | member(PID, Students), 49 | append([event(EID,RID,Day,Start)], Filtered0, NewFiltered), 50 | !, 51 | filter_events_acc(RestEvents, PID, NewFiltered, Filtered). 52 | 53 | filter_events_acc([event(EID,RID,Day,Start)|RestEvents], PID, Filtered0, Filtered) :- 54 | lecturer(PID,_), 55 | has_exam(CID,EID), 56 | teaches(PID,CID), 57 | append([event(EID,RID,Day,Start)], Filtered0, NewFiltered), 58 | !, 59 | filter_events_acc(RestEvents, PID, NewFiltered, Filtered). 60 | 61 | filter_events_acc([_|RestEvents], PID, Filtered0, Filtered) :- 62 | filter_events_acc(RestEvents, PID, Filtered0, Filtered). 63 | 64 | % pretty_print(+Schedule) 65 | % +Schedule: schedule/1 functor that contains a list of 66 | % event/4 functors. 67 | % 68 | % The events are passed to print_day/1 69 | % via findall, so all alternatives are tried. This means 70 | % that the events are grouped together based on all possible 71 | % values for Days. 72 | pretty_print(schedule(Events)) :- 73 | findall(_, print_day(Events), _). 74 | 75 | % print_day(+Events) 76 | % +Events: List of event/4 functors 77 | % 78 | % The setof groups the given events together 79 | % based on Day. RID and Start are not bound in the member-predicate, 80 | % but are bound in the template. The Day is printed to output 81 | % and the resulting list is passed to print_event/1. Since this is 82 | % done via findall, all alternatives are tried, i.e. for each day, 83 | % the resulting list of events is grouped on all possible rooms 84 | % that still occur in the list. 85 | print_day(Events) :- 86 | setof(event(EID,RID,_,Start), RID^Start^member(event(EID,RID,Day,Start),Events), Result), 87 | format("~n ~n*** DAY ~d *** ~n ~n", Day), 88 | findall(_, print_event(Result), _). 89 | 90 | % print_event(+Events) 91 | % +Events: List of event/4 functors 92 | % 93 | % The setof groups the given events together 94 | % based on RID. Start is not bound in the member-predicate, 95 | % but is bound in the template. Afterwards, the name of 96 | % the room is printed to output, the resulting list is 97 | % sorted based on Start-hour and passed on to print/1. 98 | print_event(Events) :- 99 | setof(event(EID,_,Day,Start), Start^member(event(EID,RID,Day,Start),Events), Result), 100 | room(RID, RoomName), 101 | format("~a:~n", RoomName), 102 | sort_functors_asc(4, Result, Sorted), 103 | print(Sorted). 104 | 105 | % print(+Events) 106 | % +Events: List of event/4 functors 107 | % 108 | % Loops through the list of given events 109 | % gets extra information about the event, such as 110 | % exam name, lecturer name, ..., and prints this 111 | % information to output using format. 112 | print([]). 113 | 114 | print([event(EID,_,_,Start)|RestEvents]) :- 115 | exam(EID,ExamName), 116 | duration(EID,Duration), 117 | End is Start + Duration, 118 | has_exam(CID,EID), 119 | teaches(LID,CID), 120 | lecturer(LID, LecturerName), 121 | format("~d:00 - ", Start), 122 | format("~d:00: ", End), 123 | format("~a ", ExamName), 124 | format("(~a).~n", LecturerName), 125 | print(RestEvents). 126 | -------------------------------------------------------------------------------- /small_instance.pl: -------------------------------------------------------------------------------- 1 | :- module(small_instance, [lecturer/2, 2 | student/2, 3 | course/2, 4 | exam/2, 5 | room/2, 6 | has_exam/2, 7 | duration/2, 8 | follows/2, 9 | teaches/2, 10 | capacity/2, 11 | first_day/1, 12 | last_day/1, 13 | availability/4, 14 | sc_lunch_break/2, 15 | sc_b2b/2, 16 | sc_same_day/2, 17 | sc_no_exam_in_period/5, 18 | sc_not_in_period/6, 19 | sc_correction_time/2, 20 | sc_correction_penalty/2, 21 | sc_study_time/2, 22 | sc_study_penalty/2]). 23 | 24 | %Allow grouping constraints per students/lecturers 25 | :- discontiguous 26 | sc_lunch_break/2, 27 | sc_not_in_period/6, 28 | sc_same_day/2, 29 | sc_b2b/2. 30 | 31 | lecturer(l1,'Mr John'). 32 | lecturer(l2,'Mr Francis'). 33 | lecturer(l3,'Mr Josef'). 34 | lecturer(l4,'Ms Ann'). 35 | 36 | student(s1,'Anna'). 37 | student(s2,'Max'). 38 | student(s3,'Bill'). 39 | student(s4,'Carla'). 40 | 41 | course(c1,'Math'). 42 | course(c2,'Science & Technology'). 43 | course(c3,'Philosophy'). 44 | course(c4,'Religion'). 45 | course(c5,'English'). 46 | 47 | exam(e1,'Math'). 48 | exam(e2,'Science & Technology'). 49 | exam(e3,'Philosophy'). 50 | exam(e4,'Religion'). 51 | exam(e5,'English'). 52 | 53 | room(r1,'Small room'). 54 | room(r2,'Large room'). 55 | 56 | has_exam(c1,e1). 57 | has_exam(c2,e2). 58 | has_exam(c3,e3). 59 | has_exam(c4,e4). 60 | has_exam(c5,e5). 61 | 62 | duration(Exam,2) :- exam(Exam,_). %every exam takes 2 hours 63 | 64 | follows(Student,c1) :- student(Student,_). %every student follows Math 65 | follows(Student,c2) :- student(Student,_). %every student follows Science & Technology 66 | follows(Student,c5) :- student(Student,_). %every student follows Languages 67 | follows(s2,c3). %Max follows philosophy 68 | follows(s3,c3). %Bill follows philosophy 69 | follows(s1,c4). %Anna follows religion 70 | follows(s4,c4). %Carla follows religion 71 | 72 | teaches(l1,c1). 73 | teaches(l1,c2). 74 | teaches(l2,c3). 75 | teaches(l3,c4). 76 | teaches(l4,c5). 77 | 78 | capacity(r1,2). 79 | capacity(r2,4). 80 | 81 | %first and last day of exam period 82 | first_day(1). 83 | last_day(5). 84 | 85 | %Rooms are available 86 | availability(Room,1,10,12) :- room(Room,_). %Day 1, all rooms are available from 10 to 12 87 | availability(Room,2,10,12) :- room(Room,_). %Day 2, all rooms are available from 10 to 12 88 | availability(Room,3,10,15) :- room(Room,_). %Day 3, all rooms are available from 10 to 15 89 | availability(Room,4,10,12) :- room(Room,_). %Day 4, all rooms are available from 10 to 12 90 | availability(Room,5,10,12) :- room(Room,_). %Day 5, all rooms are available from 10 to 12 91 | 92 | %soft-constraints 93 | %lecturer 94 | sc_lunch_break(L,1) :- lecturer(L,_). %lecturers prefer a lunchbreak 95 | sc_b2b(L,2) :- lecturer(L,_). %lecturers prefer not to have exams back 2 back 96 | sc_no_exam_in_period(l3,3,0,24,5). %Josef prefers no exams at day 3 97 | sc_no_exam_in_period(l4,Day,0,12,1) :- first_day(FirstDay),last_day(LastDay),between(FirstDay,LastDay,Day). %Ann prefers no exams before noon 98 | sc_no_exam_in_period(l1,Day,14,24,5) :- first_day(FirstDay),last_day(LastDay),between(FirstDay,LastDay,Day). %John prefers no exams after 14h 99 | sc_not_in_period(l1,e2,1,0,24,3). %Science & technology preferably not day 1 100 | sc_correction_time(e1,2). 101 | sc_correction_time(e2,1). 102 | sc_correction_time(e3,1). 103 | sc_correction_time(e4,1). 104 | sc_correction_time(e5,2). 105 | sc_correction_penalty(L,3) :- lecturer(L,_). %guarantee enough correction time 106 | 107 | %student 108 | sc_lunch_break(S,1) :- student(S,_). %students prefer a lunchbreak 109 | sc_same_day(S,2) :- student(S,_). %students prefer not to have multiple exams on the same day 110 | sc_b2b(S,5) :- student(S,_). %students prefer not to have exams back 2 back 111 | sc_study_time(e1,2). 112 | sc_study_time(e2,1). 113 | sc_study_time(e3,1). 114 | sc_study_time(e4,1). 115 | sc_study_time(e5,1). 116 | sc_study_penalty(S,3) :- student(S,_). %guarantee enough study time 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /utils.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % utils % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | :- module(utils, [do_preprocess/1, 9 | list_overlap/2, 10 | delete_first/3, 11 | clean/0, 12 | sort_functors_asc/3, 13 | sort_functors_dec/3, 14 | follows_course/2, 15 | student_overlap/2, 16 | teacher_overlap/2, 17 | preprocess_done/0, 18 | link_to_exam/2]). 19 | 20 | %:- use_module(small_instance). 21 | %:- use_module(large_short_instance). 22 | %:- use_module(large_long_instance). 23 | 24 | :- dynamic follows_course/2. 25 | :- dynamic student_overlap/2. 26 | :- dynamic teacher_overlap/2. 27 | :- dynamic preprocess_done/0. 28 | 29 | % do_preprocess(+ExamIDs) 30 | % +ExamIDs: IDs of all exams 31 | % 32 | % Invokes preprocessing. This executes and asserts 33 | % predicates which are used a lot later on. When 34 | % preprocess is done, the preprocess_done/0 predicate 35 | % is asserted, so it is only done once. 36 | do_preprocess(_) :- 37 | preprocess_done, 38 | !. 39 | 40 | do_preprocess(ExamIDs) :- 41 | preprocess(ExamIDs), 42 | assert(preprocess_done), 43 | !. 44 | 45 | % preprocess(+ExamIDs) 46 | % +ExamIDs: IDs of all exams 47 | % 48 | % Does the actual preprocessing. Three predicates 49 | % are asserted: follows_course/2, teacher_overlap/2 50 | % and student_overlap/2. This predicate loops through 51 | % the list of exam IDs and calls has_teacher_overlap/2 52 | % and has_student_overlap/3 for each CID associated 53 | % with the EID. 54 | preprocess([]). 55 | 56 | preprocess([EID|RestExams]) :- 57 | has_exam(CID,EID), 58 | findall(SID, follows(SID,CID), Students), 59 | asserta(follows_course(CID,Students)), 60 | has_teacher_overlap(CID, RestExams), 61 | has_student_overlap(CID, Students, RestExams), 62 | preprocess(RestExams). 63 | 64 | % has_teacher_overlap(+CID, +EIDs) 65 | % +CID: Course ID 66 | % +EIDs: List of Exam IDs 67 | % 68 | % Checks if the lecturer of course CID is 69 | % associated with any of the courses linked 70 | % to the exams in EIDs. If yes, teacher_overlap/2 71 | % is asserted. 72 | has_teacher_overlap(_, []). 73 | 74 | has_teacher_overlap(CID, [OtherEID|RestExams]) :- 75 | has_exam(OtherCID, OtherEID), 76 | teaches(LID, CID), 77 | teaches(LID, OtherCID), 78 | asserta(teacher_overlap(CID, OtherCID)), 79 | asserta(teacher_overlap(OtherCID, CID)), 80 | has_teacher_overlap(CID,RestExams). 81 | 82 | has_teacher_overlap(CID, [_|RestExams]) :- 83 | has_teacher_overlap(CID, RestExams). 84 | 85 | % has_student_overlap(+CID, +Students, +EIDs) 86 | % +CID: Course ID 87 | % +Students: Students following this course 88 | % +EIDs: List of Exam IDs 89 | % 90 | % Checks if any of the Students following course 91 | % with CID are associated with any of the courses 92 | % linked to the exam in EIDs. If yes, student_overlap/2 93 | % is asserted. 94 | has_student_overlap(_, _, []). 95 | 96 | has_student_overlap(CID, Students, [OtherEID|RestExams]) :- 97 | has_exam(OtherCID,OtherEID), 98 | findall(SID, follows(SID,OtherCID), OtherStudents), 99 | list_overlap(Students, OtherStudents), 100 | asserta(student_overlap(CID, OtherCID)), 101 | asserta(student_overlap(OtherCID,CID)), 102 | has_student_overlap(CID, Students, RestExams). 103 | 104 | has_student_overlap(CID, Students, [_|RestExams]) :- 105 | has_student_overlap(CID, Students, RestExams). 106 | 107 | % list_overlap(+List1, +List2) 108 | % +List1: Any list 109 | % +List2: Any list 110 | % 111 | % Checks if any member of List1 is also a 112 | % member of List2. When a member is found, 113 | % no backtracking is needed. It could also find 114 | % the other members, but this is not necessary. 115 | list_overlap([],_) :- 116 | false. 117 | 118 | list_overlap([First|_],OtherList) :- 119 | member(First, OtherList), 120 | !. 121 | 122 | list_overlap([_|Rest],OtherList) :- 123 | list_overlap(Rest,OtherList). 124 | 125 | % clean 126 | % Retract all predicates asserted 127 | % by the preprocessing 128 | clean :- 129 | retractall(follows_course(_,_)), 130 | retractall(student_overlap(_,_)), 131 | retractall(teacher_overlap(_,_)), 132 | retractall(preprocess_done). 133 | 134 | % delete_first(?Elem, ?List, ?ResultList) 135 | % ?Elem: Any ground term 136 | % ?List: Any List 137 | % ?ResultList: Same as List but without Elem 138 | % 139 | % ResultList is the same as List but with the 140 | % first occurence of Elem removed. 141 | delete_first(E,[E|T],T) :- !. 142 | 143 | delete_first(E,[H|T1],[H|T2]) :- 144 | delete_first(E,T1,T2). 145 | 146 | % sort_functors_asc(+Arg, +Functors, -SortedFunctors) 147 | % sort_functors_dec(+Arg, +Functors, -SortedFunctors) 148 | % +Arg: i'th element of functor on which to sort 149 | % +Functors: List of functors 150 | % -SortedFunctors: List where Functors is sorted 151 | % based on the Arg'th element of the functor. 152 | % 153 | % Sorts list on functors Functors based on the 154 | % Arg'th element of the functor. Results in 155 | % SortedFunctors. Duplicates are kept. 156 | sort_functors_asc(Arg, Functors, SortedFunctors) :- 157 | sort(Arg, @=<, Functors, SortedFunctors). 158 | 159 | sort_functors_dec(Arg, Functors, SortedFunctors) :- 160 | sort(Arg, @>=, Functors, SortedFunctors). 161 | 162 | % link_to_exam(+PID, +EID) 163 | % +PID: ID of student or lecturer 164 | % +EID: ID of exam 165 | % 166 | % Checks whether person with PID is linked to exam 167 | % with EID. If PID is a lecturer, PID needs to teach 168 | % CID associated with EID. If PID is a student, 169 | % PID needs to follow course CID associated with EID. 170 | link_to_exam(PID, EID) :- 171 | lecturer(PID,_), 172 | has_exam(CID,EID), 173 | teaches(PID,CID), 174 | !. 175 | 176 | link_to_exam(PID, EID) :- 177 | student(PID,_), 178 | has_exam(CID,EID), 179 | follows_course(CID, Students), 180 | member(PID, Students), 181 | !. 182 | 183 | link_to_exam(_, _) :- 184 | fail. 185 | 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /valid.pl: -------------------------------------------------------------------------------- 1 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2 | % Project Declarative Programming % 3 | % Jens Nevens % 4 | % % 5 | % is_valid(?S) % 6 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 7 | 8 | :- module(valid, [is_valid/1, 9 | conflict/2]). 10 | 11 | %:- use_module(small_instance). 12 | %:- use_module(large_short_instance). 13 | %:- use_module(large_long_instance). 14 | 15 | :- use_module(utils). 16 | 17 | % is_valid(?Schedule) 18 | % ?Schedule: A schedule/1 functor that contains a 19 | % list of event/4 functors. 20 | % 21 | % is_valid/1 will trigger preprocessing and then call 22 | % is_valid/2. This will return a valid schedule if 23 | % ?Schedule was not bound. If ?Schedule was bound, it 24 | % will return true or false. 25 | is_valid(schedule(Events)) :- 26 | findall(EID, exam(EID,_), ExamIDs), 27 | do_preprocess(ExamIDs), 28 | is_valid(schedule(Events), ExamIDs). 29 | 30 | % is_valid(?Schedule, +ExamIDs) 31 | % ?Schedule: A schedule/1 functor that contains a 32 | % list of event/4 functors. 33 | % +ExamIDs: IDs of all exams 34 | % 35 | % is_valid/2 will loop through all ExamIDs. If ?Schedule 36 | % is bound, it will check if the room is large enough, if 37 | % the room is available during the exam and if there are 38 | % no conflicts with other (already checked) exams. If ?Schedule 39 | % is not bound, it will generate exams in this manner. is_valid/2 40 | % can only end when all exams are scheduled. 41 | is_valid(schedule([]), []). 42 | 43 | is_valid(schedule([event(EID,RID,Day,Start)|RestEvents]), ExamIDs) :- 44 | delete_first(EID,ExamIDs,NewExamIDs), 45 | is_valid(schedule(RestEvents), NewExamIDs), 46 | exam(EID,_), 47 | has_exam(CID,EID), 48 | follows_course(CID,Students), 49 | length(Students, Size), 50 | room(RID,_), 51 | capacity(RID,Capacity), 52 | Capacity >= Size, 53 | availability(RID,Day,StartHour,EndHour), 54 | between(StartHour,EndHour,Start), 55 | duration(EID,Duration), 56 | End is Start + Duration, 57 | End =< EndHour, 58 | not(conflict(event(EID,RID,Day,Start), RestEvents)). 59 | 60 | % conflict(+Event, +OtherEvents) 61 | % +Event: An event/4 functor 62 | % +OtherEvents: List of event/4 functors 63 | % 64 | % conflict/2 will loop through the list of OtherEvents 65 | % and check if Event conflicts with these. There is a 66 | % conflict when two exams are on the same day in the 67 | % same room, on the same day and with overlapping hours 68 | % and overlapping students or on the same day and with 69 | % overlapping hours and overlapping lecturer. 70 | conflict(_, []) :- 71 | fail. 72 | 73 | conflict(event(EID1,RID,Day,Start1), [event(EID2,RID,Day,Start2)|_]) :- 74 | collision(EID1, Start1, EID2, Start2). 75 | 76 | conflict(event(EID1,_,Day,Start1), [event(EID2,_,Day,Start2)|_]) :- 77 | has_exam(CID1,EID1), 78 | has_exam(CID2,EID2), 79 | student_overlap(CID1,CID2), 80 | collision(EID1, Start1, EID2, Start2). 81 | 82 | conflict(event(EID1,_,Day,Start1), [event(EID2,_,Day,Start2)|_]) :- 83 | has_exam(CID1,EID1), 84 | has_exam(CID2,EID2), 85 | teacher_overlap(CID1,CID2), 86 | collision(EID1, Start1, EID2, Start2). 87 | 88 | conflict(Event, [_|RestEvents]) :- 89 | conflict(Event,RestEvents). 90 | 91 | % collision(+EID1, +Start1, +EID2, +Start2) 92 | % +EID1, +EID2: Exam IDs 93 | % +Start1, +Start2: Start hours of these EIDs 94 | % 95 | % collision/4 will check if exams EID1 and EID2 overlap. 96 | % This can be in 2 cases: Start2 < Start1 =< End2 97 | % or Start2 =< End1 < End2 98 | collision(_, Start1, EID2, Start2) :- 99 | duration(EID2, Duration2), 100 | End2 is (Start2 + Duration2) - 1, 101 | between(Start2, End2, Start1). 102 | 103 | collision(EID1, Start1, EID2, Start2) :- 104 | duration(EID1, Duration1), 105 | duration(EID2, Duration2), 106 | End1 is Start1 + Duration1, 107 | End2 is Start2 + Duration2, 108 | StartPlus is Start2 + 1, 109 | between(StartPlus, End2, End1). 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | --------------------------------------------------------------------------------