1 /*File generate_pre.cpp
2 */
3
4 /***************************************************************************
5 generate_pre.cpp - description
6 -------------------
7 begin : 2002
8 copyright : (C) 2002 by Lalescu Liviu
9 email : Please see https://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
10 ***************************************************************************/
11
12 /***************************************************************************
13 * *
14 * This program is free software: you can redistribute it and/or modify *
15 * it under the terms of the GNU Affero General Public License as *
16 * published by the Free Software Foundation, either version 3 of the *
17 * License, or (at your option) any later version. *
18 * *
19 ***************************************************************************/
20
21 #include "timetable_defs.h"
22 #include "rules.h"
23 #include "timetable.h"
24
25 #include "generate_pre.h"
26
27 #include "matrix.h"
28
29 #include <iostream>
30 #include <algorithm>
31 #include <cmath>
32 using namespace std;
33
34 #include "messageboxes.h"
35
36 #include <QtAlgorithms>
37 #include <QtGlobal>
38
39 #include <QPair>
40 #include <QSet>
41 #include <QHash>
42 #include <QMultiHash>
43 #include <QQueue>
44 #include <QList>
45
46 #include <list>
47
48 extern Timetable gt;
49
50 //#include <QApplication>
51 #ifndef FET_COMMAND_LINE
52 #include <QProgressDialog>
53 #include <QMessageBox>
54 #endif
55
56
57 #ifndef FET_COMMAND_LINE
58 extern QString initialOrderOfActivities;
59 #else
60 QString initialOrderOfActivities;
61 #endif
62
63
64 bool haveStudentsMinHoursDailyAllowEmptyDays;
65
66 Matrix1D<QSet<int>> tmpPreferredRealRooms;
67 Matrix1D<bool> tmpFoundNonEmpty;
68
69 QSet<int> fixedVirtualSpaceNonZeroButNotTimeActivities;
70
71 //bool thereAreTeachersWithMaxHoursDailyWithUnder100Weight;
72 bool thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight;
73 //bool thereAreSubgroupsWithMaxHoursDailyWithUnder100Weight;
74 bool thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight;
75
76 Matrix1D<QList<SpaceConstraint*>> constraintsForActivity;
77
78 Matrix1D<bool> visitedActivityResultantRealRooms;
79 ////////end rooms
80
81 //extern Matrix1D<int> initialOrderOfActivitiesIndices;
82 Matrix1D<int> initialOrderOfActivitiesIndices;
83
84 Matrix1D<int> daysTeacherIsAvailable;
85 Matrix1D<int> daysSubgroupIsAvailable;
86 Matrix1D<int> requestedDaysForTeachers;
87 Matrix1D<int> requestedDaysForSubgroups;
88 Matrix1D<int> nReqForTeacher;
89 Matrix1D<int> nReqForSubgroup;
90
91 //used only in homeRoomsAreOk
92 Matrix1D<int> nHoursRequiredForRoom;
93 Matrix1D<int> nHoursAvailableForRoom;
94 /////////////////////////////
95
96 /////////used only in sortActivities
97 Matrix1D<int> nIncompatible;
98 Matrix1D<double> nMinDaysConstraintsBroken;
99 Matrix1D<int> nRoomsIncompat;
100 Matrix1D<double> nHoursForRoom;
101 Matrix1D<PreferredRoomsItem> maxPercentagePrefRooms;
102 Matrix1D<int> reprNInc;
103 ////////////////////////////////////
104
105 Matrix1D<int> nIncompatibleFromFather;
106 Matrix1D<int> fatherActivityInInitialOrder;
107 ////////////////////////////////////
108
109 //Matrix1D<int> permutation;
110 Matrix1D<int> copyOfInitialPermutation;
111 //the permutation matrix to obtain activities in decreasing difficulty order
112
113 //bool processTimeSpaceConstraints(QWidget* parent, QTextStream* initialOrderStream=nullptr);
114
115
116 ////////BEGIN BASIC TIME CONSTRAINTS
117 //a value >=0 equal with the weight of the maximum weightPercentage of a basic time constraint
118 Matrix1D<QHash<int, int>> activitiesConflictingPercentage;
119
120 //bool computeActivitiesConflictingPercentage(QWidget* parent);
121
122 //void sortActivities(QWidget* parent, const QHash<int, int>& reprSameStartingTime, const QHash<int, QSet<int>>& reprSameActivitiesSet, QTextStream* initialOrderStream=nullptr);
123 ////////END BASIC TIME CONSTRAINTS
124
125
126 ////////BEGIN MIN DAYS TIME CONSTRAINTS
127 Matrix1D<QList<int>> minDaysListOfActivities;
128 Matrix1D<QList<int>> minDaysListOfMinDays;
129 Matrix1D<QList<double>> minDaysListOfWeightPercentages;
130 Matrix1D<QList<bool>> minDaysListOfConsecutiveIfSameDay;
131
132 //bool computeMinDays(QWidget* parent);
133 ////////END MIN DAYS TIME CONSTRAINTS
134
135
136 ////////BEGIN MAX DAYS TIME CONSTRAINTS
137 Matrix1D<QList<int>> maxDaysListOfActivities;
138 Matrix1D<QList<int>> maxDaysListOfMaxDays;
139 Matrix1D<QList<double>> maxDaysListOfWeightPercentages;
140
141 //bool computeMaxDays(QWidget* parent);
142 ////////END MAX DAYS TIME CONSTRAINTS
143
144
145 ////////BEGIN MIN GAPS between activities TIME CONSTRAINTS
146 Matrix1D<QList<int>> minGapsBetweenActivitiesListOfActivities;
147 Matrix1D<QList<int>> minGapsBetweenActivitiesListOfMinGaps;
148 Matrix1D<QList<double>> minGapsBetweenActivitiesListOfWeightPercentages;
149
150 //bool computeMinGapsBetweenActivities(QWidget* parent);
151 ////////END MIN GAPS between activities TIME CONSTRAINTS
152
153 //MAX GAPS BETWEEN ACTIVITIES
154 Matrix1D<QList<int> > maxGapsBetweenActivitiesListOfActivities;
155 Matrix1D<QList<int> > maxGapsBetweenActivitiesListOfMaxGaps;
156 Matrix1D<QList<double> > maxGapsBetweenActivitiesListOfWeightPercentages;
157
158 ////////BEGIN st. not available, tch not avail., break, activity preferred time,
159 ////////activity preferred times, activities preferred times
160 //percentage of allowed time, -1 if no restriction
161 Matrix2D<double> notAllowedTimesPercentages;
162
163 //break, which is not considered gap, false means no break, true means 100% break
164 //break can only be 100% or none
165 Matrix2D<bool> breakDayHour;
166
167 //students set not available, which is not considered gap, false means available, true means 100% not available
168 //students set not available can only be 100% or none
169 Matrix3D<bool> subgroupNotAvailableDayHour;
170
171 //used in students timetable view time horizontal dialog
172 QHash<QString, QSet<QPair<int, int>>> studentsSetNotAvailableDayHour;
173
174 //teacher not available, which is not considered gap, false means available, true means 100% not available
175 //teacher not available can only be 100% or none
176 Matrix3D<bool> teacherNotAvailableDayHour;
177
178 //bool computeNotAllowedTimesPercentages(QWidget* parent);
179 ////////END st. not available, tch not avail., break, activity preferred time,
180 ////////activity preferred time, activities preferred times
181
182
183 ////////BEGIN students max gaps and early
184 //bool computeNHoursPerSubgroup(QWidget* parent);
185 //bool computeSubgroupsEarlyAndMaxGapsPercentages(QWidget* parent);
186
187 Matrix1D<double> subgroupsEarlyMaxBeginningsAtSecondHourPercentage;
188 Matrix1D<int> subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings;
189 Matrix1D<double> subgroupsMaxGapsPerWeekPercentage;
190 Matrix1D<int> subgroupsMaxGapsPerWeekMaxGaps;
191
192 Matrix1D<int> nHoursPerSubgroup; //used also for students min hours daily
193
194 //max gaps per day (not perfect!!!)
195 //bool computeSubgroupsMaxGapsPerDayPercentages(QWidget* parent);
196
197 Matrix1D<double> subgroupsMaxGapsPerDayPercentage;
198 Matrix1D<int> subgroupsMaxGapsPerDayMaxGaps;
199 bool haveStudentsMaxGapsPerDay;
200
201
202 Matrix1D<double> subgroupsMaxGapsPerRealDayPercentage;
203 Matrix1D<int> subgroupsMaxGapsPerRealDayMaxGaps;
204 bool haveStudentsMaxGapsPerRealDay;
205
206 //2020-07-29
207 Matrix1D<double> subgroupsMaxGapsPerWeekForRealDaysPercentage;
208 Matrix1D<int> subgroupsMaxGapsPerWeekForRealDaysMaxGaps;
209 //bool haveStudentsMaxGapsPerRealDay;
210
211 ////////END students max gaps and early
212
213 //STUDENTS MAX REAL DAYS PER WEEK
214 Matrix1D<int> subgroupsMaxRealDaysPerWeekMaxDays;
215 Matrix1D<double> subgroupsMaxRealDaysPerWeekWeightPercentages;
216 Matrix1D<QList<int>> subgroupsWithMaxRealDaysPerWeekForActivities;
217
218
219 //TEACHERS MAX REAL DAYS PER WEEK
220 Matrix1D<int> teachersMaxRealDaysPerWeekMaxDays;
221 Matrix1D<double> teachersMaxRealDaysPerWeekWeightPercentages;
222 Matrix1D<QList<int>> teachersWithMaxRealDaysPerWeekForActivities;
223
224 //TEACHERS MAX AFTERNOONS PER WEEK
225 Matrix1D<int> teachersMaxAfternoonsPerWeekMaxAfternoons;
226 Matrix1D<double> teachersMaxAfternoonsPerWeekWeightPercentages;
227 Matrix1D<QList<int>> teachersWithMaxAfternoonsPerWeekForActivities;
228
229 //TEACHERS MAX MORNINGS PER WEEK
230 Matrix1D<int> teachersMaxMorningsPerWeekMaxMornings;
231 Matrix1D<double> teachersMaxMorningsPerWeekWeightPercentages;
232 Matrix1D<QList<int>> teachersWithMaxMorningsPerWeekForActivities;
233
234
235 //2020-06-25
236 ////////BEGIN students max afternoons per week
237 //activities indices (in 0..gt.rules.nInternalActivities-1) for each subgroup
238 Matrix1D<int> subgroupsMaxAfternoonsPerWeekMaxAfternoons; //-1 for not existing
239 Matrix1D<double> subgroupsMaxAfternoonsPerWeekWeightPercentages; //-1 for not existing
240 //it is practically better to use the variable below and to put it exactly like in generate.cpp,
241 //the order of activities changes
242 Matrix1D<QList<int>> subgroupsWithMaxAfternoonsPerWeekForActivities;
243
244 ////////BEGIN students max mornings per week
245 //activities indices (in 0..gt.rules.nInternalActivities-1) for each subgroup
246 Matrix1D<int> subgroupsMaxMorningsPerWeekMaxMornings; //-1 for not existing
247 Matrix1D<double> subgroupsMaxMorningsPerWeekWeightPercentages; //-1 for not existing
248 //it is practically better to use the variable below and to put it exactly like in generate.cpp,
249 //the order of activities changes
250 Matrix1D<QList<int>> subgroupsWithMaxMorningsPerWeekForActivities;
251 ////////END students max mornings per week
252
253
254 ////////BEGIN students max days per week
255 //activities indices (in 0..gt.rules.nInternalActivities-1) for each subgroup
256 Matrix1D<int> subgroupsMaxDaysPerWeekMaxDays; //-1 for not existing
257 Matrix1D<double> subgroupsMaxDaysPerWeekWeightPercentages; //-1 for not existing
258 //it is practically better to use the variable below and to put it exactly like in generate.cpp,
259 //the order of activities changes
260 Matrix1D<QList<int>> subgroupsWithMaxDaysPerWeekForActivities;
261
262 ////////BEGIN teachers max days per week
263 //activities indices (in 0..gt.rules.nInternalActivities-1) for each teacher
264 Matrix1D<int> teachersMaxDaysPerWeekMaxDays; //-1 for not existing
265 Matrix1D<double> teachersMaxDaysPerWeekWeightPercentages; //-1 for not existing
266 //it is practically better to use the variable below and to put it exactly like in generate.cpp,
267 //the order of activities changes
268 Matrix1D<QList<int>> teachersWithMaxDaysPerWeekForActivities;
269
270 //bool computeMaxDaysPerWeekForTeachers(QWidget* parent);
271
272 //bool computeMaxDaysPerWeekForStudents(QWidget* parent);
273 ////////END teachers max days per week
274
275
276 ////////BEGIN teachers max three consecutive days
277 //activities indices (in 0..gt.rules.nInternalActivities-1) for each teacher
278 Matrix1D<bool> teachersMaxThreeConsecutiveDaysAllowAMAMException;
279 Matrix1D<double> teachersMaxThreeConsecutiveDaysPercentages; //-1 for not existing
280 //it is practically better to use the variable below and to put it exactly like in generate.cpp,
281 //the order of activities changes
282 Matrix1D<QList<int>> teachersWithMaxThreeConsecutiveDaysForActivities;
283
284 //bool computeMaxThreeDaysConsecutiveForTeachers(QWidget* parent);
285 ////////END teachers max three consecutive days
286
287
288 Matrix1D<double> teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage;
289 Matrix1D<int> teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings;
290
291 Matrix1D<double> subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage;
292 Matrix1D<int> subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings;
293
294
295 Matrix1D<double> teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage;
296 Matrix1D<int> teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings;
297
298 Matrix1D<double> subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage;
299 Matrix1D<int> subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings;
300
301
302 ////////BEGIN teachers max gaps per week and per day and per morning and afternoon
303 Matrix1D<double> teachersMaxGapsPerWeekPercentage;
304 Matrix1D<int> teachersMaxGapsPerWeekMaxGaps;
305
306 Matrix1D<double> teachersMaxGapsPerDayPercentage;
307 Matrix1D<int> teachersMaxGapsPerDayMaxGaps;
308
309 Matrix1D<double> teachersMaxGapsPerMorningAndAfternoonPercentage;
310 Matrix1D<int> teachersMaxGapsPerMorningAndAfternoonMaxGaps;
311
312 Matrix1D<int> nHoursPerTeacher;
313 //bool computeNHoursPerTeacher(QWidget* parent);
314 //bool computeTeachersMaxGapsPerWeekPercentage(QWidget* parent);
315 //bool computeTeachersMaxGapsPerDayPercentage(QWidget* parent);
316 //bool computeTeachersMaxGapsPerMorningAndAfternoonPercentage(QWidget* parent);
317
318
319 Matrix1D<double> teachersMaxGapsPerRealDayPercentage;
320 Matrix1D<int> teachersMaxGapsPerRealDayMaxGaps;
321 Matrix1D<bool> teachersMaxGapsPerRealDayAllowException;
322 bool haveTeachersMaxGapsPerRealDay;
323
324 //2020-07-29
325 Matrix1D<double> teachersMaxGapsPerWeekForRealDaysPercentage;
326 Matrix1D<int> teachersMaxGapsPerWeekForRealDaysMaxGaps;
327 //bool haveTeachersMaxGapsPerRealDay;
328
329 ////////END teachers max gaps per week and per day and per morning and afternoon
330
331 bool haveTeachersAfternoonsEarly;
332 bool haveStudentsAfternoonsEarly;
333
334 bool haveTeachersMorningsEarly;
335 bool haveStudentsMorningsEarly;
336
337 Matrix1D<bool> teacherConstrainedToZeroGapsPerAfternoon;
338
339
340 ////////BEGIN activities same starting time
341 Matrix1D<QList<int>> activitiesSameStartingTimeActivities;
342 Matrix1D<QList<double>> activitiesSameStartingTimePercentages;
343 //bool computeActivitiesSameStartingTime(QWidget* parent, QHash<int, int> & reprSameStartingTime, QHash<int, QSet<int>> & reprSameActivitiesSet);
344 ////////END activities same starting time
345
346
347 ////////BEGIN activities same starting hour
348 Matrix1D<QList<int>> activitiesSameStartingHourActivities;
349 Matrix1D<QList<double>> activitiesSameStartingHourPercentages;
350 //void computeActivitiesSameStartingHour();
351 ////////END activities same starting hour
352
353
354 ////////BEGIN activities same starting day
355 Matrix1D<QList<int>> activitiesSameStartingDayActivities;
356 Matrix1D<QList<double>> activitiesSameStartingDayPercentages;
357 //void computeActivitiesSameStartingDay();
358 ////////END activities same starting hour
359
360
361 ////////BEGIN activities not overlapping
362 Matrix1D<QList<int>> activitiesNotOverlappingActivities;
363 Matrix1D<QList<double>> activitiesNotOverlappingPercentages;
364 //void computeActivitiesNotOverlapping();
365 ////////END activities not overlapping
366
367
368 ////////BEGIN teacher(s) max hours daily
369 Matrix1D<double> teachersMaxHoursDailyPercentages1;
370 Matrix1D<int> teachersMaxHoursDailyMaxHours1;
371
372 Matrix1D<double> teachersMaxHoursDailyPercentages2;
373 Matrix1D<int> teachersMaxHoursDailyMaxHours2;
374
375 //bool computeTeachersMaxHoursDaily(QWidget* parent);
376 ////////END teacher(s) max hours daily
377
378
379 Matrix1D<double> teachersMaxHoursDailyRealDaysPercentages1;
380 Matrix1D<int> teachersMaxHoursDailyRealDaysMaxHours1;
381
382 Matrix1D<double> teachersMaxHoursDailyRealDaysPercentages2;
383 Matrix1D<int> teachersMaxHoursDailyRealDaysMaxHours2;
384
385
386 ////////BEGIN teacher(s) max hours continuously
387 Matrix1D<double> teachersMaxHoursContinuouslyPercentages1;
388 Matrix1D<int> teachersMaxHoursContinuouslyMaxHours1;
389
390 Matrix1D<double> teachersMaxHoursContinuouslyPercentages2;
391 Matrix1D<int> teachersMaxHoursContinuouslyMaxHours2;
392
393 //bool computeTeachersMaxHoursContinuously(QWidget* parent);
394 ////////END teacher(s) max hours continuously
395
396
397 ///////BEGIN teacher(s) activity tag max hours daily
398 bool haveTeachersActivityTagMaxHoursDaily;
399
400 Matrix1D<QList<int>> teachersActivityTagMaxHoursDailyMaxHours;
401 Matrix1D<QList<int>> teachersActivityTagMaxHoursDailyActivityTag;
402 Matrix1D<QList<double>> teachersActivityTagMaxHoursDailyPercentage;
403
404 //bool computeTeachersActivityTagMaxHoursDaily(QWidget* parent);
405 ///////END teacher(s) activity tag max hours daily
406
407
408 //teacher(s) activity tag max hours daily real days
409 bool haveTeachersActivityTagMaxHoursDailyRealDays;
410
411 Matrix1D<QList<int>> teachersActivityTagMaxHoursDailyRealDaysMaxHours;
412 Matrix1D<QList<int>> teachersActivityTagMaxHoursDailyRealDaysActivityTag;
413 Matrix1D<QList<double>> teachersActivityTagMaxHoursDailyRealDaysPercentage;
414
415
416 ///////BEGIN teacher(s) activity tag max hours continuously
417 bool haveTeachersActivityTagMaxHoursContinuously;
418
419 Matrix1D<QList<int>> teachersActivityTagMaxHoursContinuouslyMaxHours;
420 Matrix1D<QList<int>> teachersActivityTagMaxHoursContinuouslyActivityTag;
421 Matrix1D<QList<double>> teachersActivityTagMaxHoursContinuouslyPercentage;
422
423 //bool computeTeachersActivityTagMaxHoursContinuously(QWidget* parent);
424 ///////END teacher(s) activity tag max hours continuously
425
426
427 ////////BEGIN teacher(s) min hours daily
428 Matrix2D<double> teachersMinHoursDailyPercentages;
429 Matrix2D<int> teachersMinHoursDailyMinHours;
430
431 //bool computeTeachersMinHoursDaily(QWidget* parent);
432 ////////END teacher(s) min hours daily
433
434
435 ////////BEGIN teacher(s) min days per week
436 Matrix1D<double> teachersMinDaysPerWeekPercentages;
437 Matrix1D<int> teachersMinDaysPerWeekMinDays;
438
439 //bool computeTeachersMinDaysPerWeek(QWidget* parent);
440 ////////END teacher(s) min days per week
441
442
443 ////////BEGIN students (set) max hours daily
444 Matrix1D<double> subgroupsMaxHoursDailyPercentages1;
445 Matrix1D<int> subgroupsMaxHoursDailyMaxHours1;
446
447 Matrix1D<double> subgroupsMaxHoursDailyPercentages2;
448 Matrix1D<int> subgroupsMaxHoursDailyMaxHours2;
449
450 //bool computeSubgroupsMaxHoursDaily(QWidget* parent);
451 ////////END students (set) max hours daily
452
453
454 //2020-06-28
455 //teacher(s) max hours per all afternoons
456 Matrix1D<double> teachersMaxHoursPerAllAfternoonsPercentages;
457 Matrix1D<int> teachersMaxHoursPerAllAfternoonsMaxHours;
458
459 //2020-06-28
460 //students (set) max hours per all afternoons
461 Matrix1D<double> subgroupsMaxHoursPerAllAfternoonsPercentages;
462 Matrix1D<int> subgroupsMaxHoursPerAllAfternoonsMaxHours;
463
464 //real day
465 Matrix1D<double> teachersMinHoursDailyRealDaysPercentages;
466 Matrix1D<int> teachersMinHoursDailyRealDaysMinHours;
467
468 //teacher(s) min days per week
469 Matrix1D<double> teachersMinRealDaysPerWeekPercentages;
470 Matrix1D<int> teachersMinRealDaysPerWeekMinDays;
471
472 //teacher(s) min mornings and afternoons per week
473 Matrix1D<double> teachersMinMorningsPerWeekPercentages;
474 Matrix1D<int> teachersMinMorningsPerWeekMinMornings;
475 Matrix1D<double> teachersMinAfternoonsPerWeekPercentages;
476 Matrix1D<int> teachersMinAfternoonsPerWeekMinAfternoons;
477
478 //students min mornings and afternoons per week
479 Matrix1D<double> subgroupsMinMorningsPerWeekPercentages;
480 Matrix1D<int> subgroupsMinMorningsPerWeekMinMornings;
481 Matrix1D<double> subgroupsMinAfternoonsPerWeekPercentages;
482 Matrix1D<int> subgroupsMinAfternoonsPerWeekMinAfternoons;
483
484
485 ////////BEGIN students (set) max hours continuously
486 Matrix1D<double> subgroupsMaxHoursContinuouslyPercentages1;
487 Matrix1D<int> subgroupsMaxHoursContinuouslyMaxHours1;
488
489 Matrix1D<double> subgroupsMaxHoursContinuouslyPercentages2;
490 Matrix1D<int> subgroupsMaxHoursContinuouslyMaxHours2;
491
492 //bool computeStudentsMaxHoursContinuously(QWidget* parent);
493 ////////END students (set) max hours continuously
494
495
496 ///////BEGIN students (set) activity tag max hours daily
497 bool haveStudentsActivityTagMaxHoursDaily;
498
499 Matrix1D<QList<int>> subgroupsActivityTagMaxHoursDailyMaxHours;
500 Matrix1D<QList<int>> subgroupsActivityTagMaxHoursDailyActivityTag;
501 Matrix1D<QList<double>> subgroupsActivityTagMaxHoursDailyPercentage;
502
503 //bool computeStudentsActivityTagMaxHoursDaily(QWidget* parent);
504 ///////END students (set) activity tag max hours daily
505
506
507 //students (set) activity tag max hours daily real days
508 bool haveStudentsActivityTagMaxHoursDailyRealDays;
509
510 Matrix1D<QList<int>> subgroupsActivityTagMaxHoursDailyRealDaysMaxHours;
511 Matrix1D<QList<int>> subgroupsActivityTagMaxHoursDailyRealDaysActivityTag;
512 Matrix1D<QList<double>> subgroupsActivityTagMaxHoursDailyRealDaysPercentage;
513
514
515 ///////BEGIN students (set) activity tag max hours continuously
516 bool haveStudentsActivityTagMaxHoursContinuously;
517
518 Matrix1D<QList<int>> subgroupsActivityTagMaxHoursContinuouslyMaxHours;
519 Matrix1D<QList<int>> subgroupsActivityTagMaxHoursContinuouslyActivityTag;
520 Matrix1D<QList<double>> subgroupsActivityTagMaxHoursContinuouslyPercentage;
521
522 //bool computeStudentsActivityTagMaxHoursContinuously(QWidget* parent);
523 ///////END students (set) activity tag max hours continuously
524
525
526 //students (set) max hours daily real days
527 Matrix1D<double> subgroupsMaxHoursDailyRealDaysPercentages1;
528 Matrix1D<int> subgroupsMaxHoursDailyRealDaysMaxHours1;
529
530 Matrix1D<double> subgroupsMaxHoursDailyRealDaysPercentages2;
531 Matrix1D<int> subgroupsMaxHoursDailyRealDaysMaxHours2;
532
533
534 ////////BEGIN students (set) min hours daily
535 Matrix2D<double> subgroupsMinHoursDailyPercentages;
536 Matrix2D<int> subgroupsMinHoursDailyMinHours;
537 Matrix1D<bool> subgroupsMinHoursDailyAllowEmptyDays;
538 Matrix1D<bool> subgroupsMinHoursPerMorningAllowEmptyMornings;
539 bool haveStudentsMinHoursDailyMorningsAllowEmptyDays;
540 //bool computeSubgroupsMinHoursDaily(QWidget* parent);
541 ////////END students (set) min hours daily
542
543
544 //////////////BEGIN 2 activities consecutive
545 //index represents the first activity, value in array represents the second activity
546 Matrix1D<QList<double>> constrTwoActivitiesConsecutivePercentages;
547 Matrix1D<QList<int>> constrTwoActivitiesConsecutiveActivities;
548 //void computeConstrTwoActivitiesConsecutive();
549
550 //index represents the second activity, value in array represents the first activity
551 Matrix1D<QList<double>> inverseConstrTwoActivitiesConsecutivePercentages;
552 Matrix1D<QList<int>> inverseConstrTwoActivitiesConsecutiveActivities;
553 //////////////END 2 activities consecutive
554
555
556 //////////////BEGIN 2 activities grouped
557 //index represents the first activity, value in array represents the second activity
558 Matrix1D<QList<double>> constrTwoActivitiesGroupedPercentages;
559 Matrix1D<QList<int>> constrTwoActivitiesGroupedActivities;
560 //void computeConstrTwoActivitiesGrouped();
561
562
563 //////////////BEGIN 3 activities grouped
564 //index represents the first activity, value in array represents the second and third activities
565 Matrix1D<QList<double>> constrThreeActivitiesGroupedPercentages;
566 Matrix1D<QList<QPair<int, int>>> constrThreeActivitiesGroupedActivities;
567 //void computeConstrThreeActivitiesGrouped();
568
569
570 //////////////BEGIN 2 activities ordered
571 //index represents the first activity, value in array represents the second activity
572 Matrix1D<QList<double>> constrTwoActivitiesOrderedPercentages;
573 Matrix1D<QList<int>> constrTwoActivitiesOrderedActivities;
574 //void computeConstrTwoActivitiesOrdered();
575
576 //index represents the second activity, value in array represents the first activity
577 Matrix1D<QList<double>> inverseConstrTwoActivitiesOrderedPercentages;
578 Matrix1D<QList<int>> inverseConstrTwoActivitiesOrderedActivities;
579 //////////////END 2 activities ordered
580
581 //////////////BEGIN 2 activities ordered if same day
582 //index represents the first activity, value in array represents the second activity
583 Matrix1D<QList<double>> constrTwoActivitiesOrderedIfSameDayPercentages;
584 Matrix1D<QList<int>> constrTwoActivitiesOrderedIfSameDayActivities;
585 //void computeConstrTwoActivitiesOrderedIfSameDay();
586
587 //index represents the second activity, value in array represents the first activity
588 Matrix1D<QList<double>> inverseConstrTwoActivitiesOrderedIfSameDayPercentages;
589 Matrix1D<QList<int>> inverseConstrTwoActivitiesOrderedIfSameDayActivities;
590 //////////////END 2 activities ordered if same day
591
592
593 ////////////BEGIN activity ends students day
594 Matrix1D<double> activityEndsStudentsDayPercentages; //-1 for not existing
595 //bool computeActivityEndsStudentsDayPercentages(QWidget* parent);
596 bool haveActivityEndsStudentsDay;
597 ////////////END activity ends students day
598
599 ////////////BEGIN activity ends teachers day
600 Matrix1D<double> activityEndsTeachersDayPercentages; //-1 for not existing
601 //bool computeActivityEndsTeachersDayPercentages(QWidget* parent);
602 bool haveActivityEndsTeachersDay;
603 ////////////END activity ends teachers day
604
605
606 bool checkMinDays100Percent(QWidget* parent);
607 bool checkMinDaysConsecutiveIfSameDay(QWidget* parent);
608
609
610 bool checkMaxHoursForActivityDuration(QWidget* parent);
611
612
613 ///////BEGIN teachers interval max days per week
614 Matrix1D<QList<double>> teachersIntervalMaxDaysPerWeekPercentages;
615 Matrix1D<QList<int>> teachersIntervalMaxDaysPerWeekMaxDays;
616 Matrix1D<QList<int>> teachersIntervalMaxDaysPerWeekIntervalStart;
617 Matrix1D<QList<int>> teachersIntervalMaxDaysPerWeekIntervalEnd;
618
619 //bool computeTeachersIntervalMaxDaysPerWeek(QWidget* parent);
620
621
622 //morning
623 Matrix1D<QList<double>> teachersMorningIntervalMaxDaysPerWeekPercentages;
624 Matrix1D<QList<int>> teachersMorningIntervalMaxDaysPerWeekMaxDays;
625 Matrix1D<QList<int>> teachersMorningIntervalMaxDaysPerWeekIntervalStart;
626 Matrix1D<QList<int>> teachersMorningIntervalMaxDaysPerWeekIntervalEnd;
627
628 //bool computeTeachersMorningIntervalMaxDaysPerWeek();
629
630 //afternoon
631 Matrix1D<QList<double>> teachersAfternoonIntervalMaxDaysPerWeekPercentages;
632 Matrix1D<QList<int>> teachersAfternoonIntervalMaxDaysPerWeekMaxDays;
633 Matrix1D<QList<int>> teachersAfternoonIntervalMaxDaysPerWeekIntervalStart;
634 Matrix1D<QList<int>> teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd;
635
636 //bool computeTeachersAfternoonIntervalMaxDaysPerWeek();
637
638 ///////END teachers interval max days per week
639
640
641 ///////BEGIN subgroups interval max days per week
642 Matrix1D<QList<double>> subgroupsIntervalMaxDaysPerWeekPercentages;
643 Matrix1D<QList<int>> subgroupsIntervalMaxDaysPerWeekMaxDays;
644 Matrix1D<QList<int>> subgroupsIntervalMaxDaysPerWeekIntervalStart;
645 Matrix1D<QList<int>> subgroupsIntervalMaxDaysPerWeekIntervalEnd;
646
647 //bool computeSubgroupsIntervalMaxDaysPerWeek(QWidget* parent);
648 ///////END subgroups interval max days per week
649
650
651
652 ///////BEGIN students morning interval max days per week
653 Matrix1D<QList<double>> subgroupsMorningIntervalMaxDaysPerWeekPercentages;
654 Matrix1D<QList<int>> subgroupsMorningIntervalMaxDaysPerWeekMaxDays;
655 Matrix1D<QList<int>> subgroupsMorningIntervalMaxDaysPerWeekIntervalStart;
656 Matrix1D<QList<int>> subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd;
657
658 //bool computeSubgroupsMorningIntervalMaxDaysPerWeek();
659 ///////END subgroups morning interval max days per week
660
661 ///////BEGIN students afternoon interval max days per week
662 Matrix1D<QList<double>> subgroupsAfternoonIntervalMaxDaysPerWeekPercentages;
663 Matrix1D<QList<int>> subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays;
664 Matrix1D<QList<int>> subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart;
665 Matrix1D<QList<int>> subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd;
666
667 //bool computeSubgroupsAfternoonIntervalMaxDaysPerWeek();
668 ///////END subgroups afternoon interval max days per week
669
670
671 //2017-02-06
672 Matrix1D<int> teachersMaxSpanPerDayMaxSpan; //-1 for not existing
673 Matrix1D<double> teachersMaxSpanPerDayPercentages; //-1 for not existing
674 Matrix1D<bool> teachersMaxSpanPerDayAllowOneDayExceptionPlusOne;
675
676
677 ////////////
678 Matrix1D<int> teachersMaxSpanPerRealDayMaxSpan; //-1 for not existing
679 Matrix1D<double> teachersMaxSpanPerRealDayPercentages; //-1 for not existing
680 Matrix1D<bool> teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne; //for Luca
681
682 Matrix1D<int> subgroupsMaxSpanPerRealDayMaxSpan; //-1 for not existing
683 Matrix1D<double> subgroupsMaxSpanPerRealDayPercentages; //-1 for not existing
684 ////////////
685
686
687 Matrix1D<int> teachersMinRestingHoursCircularMinHours; //-1 for not existing
688 Matrix1D<double> teachersMinRestingHoursCircularPercentages; //-1 for not existing
689 Matrix1D<int> teachersMinRestingHoursNotCircularMinHours; //-1 for not existing
690 Matrix1D<double> teachersMinRestingHoursNotCircularPercentages; //-1 for not existing
691
692 Matrix1D<int> subgroupsMaxSpanPerDayMaxSpan; //-1 for not existing
693 Matrix1D<double> subgroupsMaxSpanPerDayPercentages; //-1 for not existing
694
695 Matrix1D<int> subgroupsMinRestingHoursCircularMinHours; //-1 for not existing
696 Matrix1D<double> subgroupsMinRestingHoursCircularPercentages; //-1 for not existing
697 Matrix1D<int> subgroupsMinRestingHoursNotCircularMinHours; //-1 for not existing
698 Matrix1D<double> subgroupsMinRestingHoursNotCircularPercentages; //-1 for not existing
699
700 //bool computeTeachersMaxSpanPerDay(QWidget* parent);
701 //bool computeTeachersMinRestingHours(QWidget* parent);
702 //bool computeSubgroupsMaxSpanPerDay(QWidget* parent);
703 //bool computeSubgroupsMinRestingHours(QWidget* parent);
704 ////////////
705
706
707 //2020-07-20
708 ///////////////
709 Matrix1D<int> teachersMinRestingHoursBetweenMorningAndAfternoonMinHours; //-1 for not existing
710 Matrix1D<double> teachersMinRestingHoursBetweenMorningAndAfternoonPercentages; //-1 for not existing
711
712 Matrix1D<int> subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours; //-1 for not existing
713 Matrix1D<double> subgroupsMinRestingHoursBetweenMorningAndAfternoonPercentages; //-1 for not existing
714 //bool computeTeachersMinRestingHoursBetweenMorningAndAfternoon(QWidget* parent);
715 //bool computeSubgroupsMinRestingHoursBetweenMorningAndAfternoon(QWidget* parent);
716 ///////////////
717
718
719 Matrix1D<double> teachersMaxTwoConsecutiveMorningsPercentage;
720 Matrix1D<double> teachersMaxTwoConsecutiveAfternoonsPercentage;
721
722
723 Matrix1D<double> teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages;
724 Matrix1D<int> activityTagN1N2N3;
725 Matrix1D<QList<int>> teachersWithN1N2N3ForActivities;
726
727
728 ////////BEGIN rooms
729 //bool computeBasicSpace(QWidget* parent);
730
731 Matrix2D<double> notAllowedRoomTimePercentages; //-1 for available
732 //bool computeNotAllowedRoomTimePercentages();
733
734 bool haveTeacherRoomNotAllowedTimesConstraints;
735 QHash<QPair<qint64, qint64>, double> notAllowedTeacherRoomTimePercentages;
736 //first qint64 is (teacher, room), second qint64 is (day, hour)
737 //bool computeNotAllowedTeacherRoomTimePercentages();
738
739 Matrix1D<QList<PreferredRoomsItem>> activitiesPreferredRoomsList;
740 Matrix1D<bool> unspecifiedPreferredRoom;
741
742 Matrix1D<QList<int>> activitiesHomeRoomsHomeRooms;
743 Matrix1D<double> activitiesHomeRoomsPercentage;
744 Matrix1D<bool> unspecifiedHomeRoom;
745
746 Matrix1D<QSet<int>> preferredRealRooms;
747
748 //bool computeActivitiesRoomsPreferences(QWidget* parent);
749 ////////END rooms
750
751
752 ////////BEGIN building changes
753 Matrix1D<double> maxBuildingChangesPerWeekForStudentsPercentages;
754 Matrix1D<int> maxBuildingChangesPerWeekForStudentsMaxChanges;
755 //bool computeMaxBuildingChangesPerWeekForStudents(QWidget* parent);
756
757 Matrix1D<double> maxBuildingChangesPerDayForStudentsPercentages;
758 Matrix1D<int> maxBuildingChangesPerDayForStudentsMaxChanges;
759 //bool computeMaxBuildingChangesPerDayForStudents(QWidget* parent);
760
761 Matrix1D<double> minGapsBetweenBuildingChangesForStudentsPercentages;
762 Matrix1D<int> minGapsBetweenBuildingChangesForStudentsMinGaps;
763 //bool computeMinGapsBetweenBuildingChangesForStudents(QWidget* parent);
764
765 Matrix1D<double> maxBuildingChangesPerWeekForTeachersPercentages;
766 Matrix1D<int> maxBuildingChangesPerWeekForTeachersMaxChanges;
767 //bool computeMaxBuildingChangesPerWeekForTeachers(QWidget* parent);
768
769 Matrix1D<double> maxBuildingChangesPerDayForTeachersPercentages;
770 Matrix1D<int> maxBuildingChangesPerDayForTeachersMaxChanges;
771 //bool computeMaxBuildingChangesPerDayForTeachers(QWidget* parent);
772
773 Matrix1D<double> minGapsBetweenBuildingChangesForTeachersPercentages;
774 Matrix1D<int> minGapsBetweenBuildingChangesForTeachersMinGaps;
775 //bool computeMinGapsBetweenBuildingChangesForTeachers(QWidget* parent);
776 ////////END building changes
777
778
779 ////////BEGIN room changes
780 Matrix1D<double> maxRoomChangesPerWeekForStudentsPercentages;
781 Matrix1D<int> maxRoomChangesPerWeekForStudentsMaxChanges;
782 //bool computeMaxRoomChangesPerWeekForStudents(QWidget* parent);
783
784 Matrix1D<double> maxRoomChangesPerDayForStudentsPercentages;
785 Matrix1D<int> maxRoomChangesPerDayForStudentsMaxChanges;
786 //bool computeMaxRoomChangesPerDayForStudents(QWidget* parent);
787
788 Matrix1D<double> minGapsBetweenRoomChangesForStudentsPercentages;
789 Matrix1D<int> minGapsBetweenRoomChangesForStudentsMinGaps;
790 //bool computeMinGapsBetweenRoomChangesForStudents(QWidget* parent);
791
792 Matrix1D<double> maxRoomChangesPerWeekForTeachersPercentages;
793 Matrix1D<int> maxRoomChangesPerWeekForTeachersMaxChanges;
794 //bool computeMaxRoomChangesPerWeekForTeachers(QWidget* parent);
795
796 Matrix1D<double> maxRoomChangesPerDayForTeachersPercentages;
797 Matrix1D<int> maxRoomChangesPerDayForTeachersMaxChanges;
798 //bool computeMaxRoomChangesPerDayForTeachers(QWidget* parent);
799
800 Matrix1D<double> minGapsBetweenRoomChangesForTeachersPercentages;
801 Matrix1D<int> minGapsBetweenRoomChangesForTeachersMinGaps;
802 //bool computeMinGapsBetweenRoomChangesForTeachers(QWidget* parent);
803
804
805 //BEGIN room changes per real day for teachers
806 Matrix1D<double> maxRoomChangesPerRealDayForTeachersPercentages;
807 Matrix1D<int> maxRoomChangesPerRealDayForTeachersMaxChanges;
808 //END room changes per real day for teachers
809
810 //BEGIN room changes per real day for students
811 Matrix1D<double> maxRoomChangesPerRealDayForSubgroupsPercentages;
812 Matrix1D<int> maxRoomChangesPerRealDayForSubgroupsMaxChanges;
813 //END room changes per real day for students
814
815 ////////END room changes
816
817
818 Matrix1D<QList<int>> mustComputeTimetableSubgroups;
819 Matrix1D<QList<int>> mustComputeTimetableTeachers;
820 Matrix1D<bool> mustComputeTimetableSubgroup;
821 Matrix1D<bool> mustComputeTimetableTeacher;
822
823 //void computeMustComputeTimetableSubgroups();
824 //void computeMustComputeTimetableTeachers();
825
826
827 //bool homeRoomsAreOk(QWidget* parent);
828
829
830 //2011-09-25 - Constraint activities occupy max time slots from selection
831
832 //We need the references to the elements to be valid, so we need this to be a std::list
833 std::list<ActivitiesOccupyMaxTimeSlotsFromSelection_item> aomtsList;
834 Matrix1D<QList<ActivitiesOccupyMaxTimeSlotsFromSelection_item*>> aomtsListForActivity;
835
836 //bool computeActivitiesOccupyMaxTimeSlotsFromSelection(QWidget* parent);
837
838 //2019-11-16 - Constraint activities occupy min time slots from selection
839
840 //We need the references to the elements to be valid, so we need this to be a std::list
841 std::list<ActivitiesOccupyMinTimeSlotsFromSelection_item> aomintsList;
842 Matrix1D<QList<ActivitiesOccupyMinTimeSlotsFromSelection_item*>> aomintsListForActivity;
843
844 //bool computeActivitiesOccupyMinTimeSlotsFromSelection(QWidget* parent);
845
846 //2011-09-30 - Constraint activities max simultaneous in selected time slots
847
848 //We need the references to the elements to be valid, so we need this to be a std::list
849 std::list<ActivitiesMaxSimultaneousInSelectedTimeSlots_item> amsistsList;
850 Matrix1D<QList<ActivitiesMaxSimultaneousInSelectedTimeSlots_item*>> amsistsListForActivity;
851
852 //bool computeActivitiesMaxSimultaneousInSelectedTimeSlots(QWidget* parent);
853
854 //2019-11-16 - Constraint activities min simultaneous in selected time slots
855
856 //We need the references to the elements to be valid, so we need this to be a std::list
857 std::list<ActivitiesMinSimultaneousInSelectedTimeSlots_item> aminsistsList;
858 Matrix1D<QList<ActivitiesMinSimultaneousInSelectedTimeSlots_item*>> aminsistsListForActivity;
859
860 //bool computeActivitiesMinSimultaneousInSelectedTimeSlots(QWidget* parent);
861
862 bool haveActivitiesOccupyMaxConstraints;
863 Matrix1D<bool> activityHasOccupyMaxConstraints;
864
865 bool haveActivitiesMaxSimultaneousConstraints;
866 Matrix1D<bool> activityHasMaxSimultaneousConstraints;
867
868 //2020-05-01 - Constraint max total activities from set in selected time slots
869 std::list<ActivitiesMaxTotalFromSetInSelectedTimeSlots_item> amtfsistsList;
870 Matrix1D<QList<ActivitiesMaxTotalFromSetInSelectedTimeSlots_item*>> amtfsistsListForActivity;
871 //bool computeActivitiesMaxTotalFromSetInSelectedTimeSlots(QWidget* parent);
872
873 //for the terms mode
874 //2020-01-14 - Constraint activities max in a term
875 std::list<ActivitiesMaxInATerm_item> amiatList;
876 Matrix1D<QList<ActivitiesMaxInATerm_item*>> amiatListForActivity;
877 //bool computeActivitiesMaxInATerm(QWidget* parent);
878
879 //2020-01-14 - Constraint activities occupy max terms
880 std::list<ActivitiesOccupyMaxTerms_item> aomtList;
881 Matrix1D<QList<ActivitiesOccupyMaxTerms_item*>> aomtListForActivity;
882 //bool computeActivitiesOccupyMaxTerms(QWidget* parent);
883
884 //2019-06-08 - Constraint students (set) min gaps between ordered pair of activity tags
885
886 //We need the references to the elements to be valid, so we need this to be a std::list
887 std::list<StudentsMinGapsBetweenOrderedPairOfActivityTags_item> smgbopoatList;
888 Matrix1D<QList<StudentsMinGapsBetweenOrderedPairOfActivityTags_item*>> smgbopoatListForActivity;
889
890 //bool computeStudentsMinGapsBetweenOrderedPairOfActivityTags(QWidget* parent);
891
892 //2019-06-08 - Constraint teacher(s) min gaps between ordered pair of activity tags
893
894 //We need the references to the elements to be valid, so we need this to be a std::list
895 std::list<TeachersMinGapsBetweenOrderedPairOfActivityTags_item> tmgbopoatList;
896 Matrix1D<QList<TeachersMinGapsBetweenOrderedPairOfActivityTags_item*>> tmgbopoatListForActivity;
897
898 //bool computeTeachersMinGapsBetweenOrderedPairOfActivityTags(QWidget* parent);
899
900 //2012-04-29 - Constraint activities occupy max different rooms
901
902 //We need the references to the elements to be valid, so we need this to be a std::list
903 std::list<ActivitiesOccupyMaxDifferentRooms_item> aomdrList;
904 Matrix1D<QList<ActivitiesOccupyMaxDifferentRooms_item*>> aomdrListForActivity;
905
906 //bool computeActivitiesOccupyMaxDifferentRooms(QWidget* parent);
907
908 //2013-09-14 - Constraint activities same room if consecutive
909
910 //We need the references to the elements to be valid, so we need this to be a std::list
911 std::list<ActivitiesSameRoomIfConsecutive_item> asricList;
912 Matrix1D<QList<ActivitiesSameRoomIfConsecutive_item*>> asricListForActivity;
913
914 //bool computeActivitiesSameRoomIfConsecutive(QWidget* parent);
915
916 /////////////////////////////////////////////////////////////////////////
917
918 //2019-11-20
919 //We need the references to the elements to be valid, so we need this to be a std::list
920 std::list<SubgroupActivityTagMinHoursDaily_item> satmhdList;
921 Matrix1D<QList<SubgroupActivityTagMinHoursDaily_item*>> satmhdListForSubgroup;
922 bool haveStudentsActivityTagMinHoursDaily;
923
924 //bool computeStudentsActivityTagMinHoursDaily(QWidget* parent);
925
926 //2019-11-20
927
928 //We need the references to the elements to be valid, so we need this to be a std::list
929 std::list<TeacherActivityTagMinHoursDaily_item> tatmhdList;
930 Matrix1D<QList<TeacherActivityTagMinHoursDaily_item*>> tatmhdListForTeacher;
931 bool haveTeachersActivityTagMinHoursDaily;
932
933 //bool computeTeachersActivityTagMinHoursDaily(QWidget* parent);
934
935 /////////////////////////////////////////////////////////////////////////
936
937 Matrix1D<bool> fixedTimeActivity;
938 Matrix1D<bool> fixedSpaceActivity;
939 //bool computeFixedActivities(QWidget* parent);
940
941 //The following two functions are used in teacher room not available time constraints.
teacherRoomQInt64Combination(int teacher,int room)942 qint64 teacherRoomQInt64Combination(int teacher, int room)
943 {
944 assert(teacher>=0);
945 assert(teacher<gt.rules.nInternalTeachers);
946 assert(room>=0);
947 assert(room<gt.rules.nInternalRooms);
948
949 return qint64(teacher)*qint64(gt.rules.nInternalRooms)+qint64(room);
950 }
951
dayHourQInt64Combination(int day,int hour)952 qint64 dayHourQInt64Combination(int day, int hour)
953 {
954 assert(hour>=0);
955 assert(hour<gt.rules.nHoursPerDay);
956 assert(day>=0);
957 assert(day<gt.rules.nDaysPerWeek);
958
959 return qint64(hour)*qint64(gt.rules.nDaysPerWeek)+qint64(day);
960 }
961
findEquivalentSubgroupsCompareFunction(int i1,int i2)962 inline bool findEquivalentSubgroupsCompareFunction(int i1, int i2)
963 {
964 const QList<int>& a1=gt.rules.internalSubgroupsList[i1]->activitiesForSubgroup;
965 const QList<int>& a2=gt.rules.internalSubgroupsList[i2]->activitiesForSubgroup;
966
967 if(a1.count()<a2.count()){
968 return true;
969 }
970 else if(a1.count()>a2.count()){
971 return false;
972 }
973 else{
974 assert(a1.count()==a2.count());
975 for(int i=0; i<a1.count(); i++){
976 if(a1.at(i)<a2.at(i)){
977 return true;
978 }
979 else if(a1.at(i)>a2.at(i)){
980 return false;
981 }
982 }
983 }
984 return false;
985 }
986
987 ////////////////////////////////////
988
compareFunctionGeneratePre(int i,int j)989 inline bool compareFunctionGeneratePre(int i, int j)
990 {
991 if(nIncompatible[i]>nIncompatible[j] || (nIncompatible[i]==nIncompatible[j] && nMinDaysConstraintsBroken[i]>nMinDaysConstraintsBroken[j]))
992 return true;
993
994 return false;
995 }
996
compareFunctionGeneratePreWithGroupedActivities(int i,int j)997 inline bool compareFunctionGeneratePreWithGroupedActivities(int i, int j)
998 {
999 //nMinDaysBroken is different from 0.0 only if the activity is fixed
1000 if( nIncompatibleFromFather[i]>nIncompatibleFromFather[j]
1001 || (nIncompatibleFromFather[i]==nIncompatibleFromFather[j] && nMinDaysConstraintsBroken[i]>nMinDaysConstraintsBroken[j])
1002 || (nIncompatibleFromFather[i]==nIncompatibleFromFather[j] && nMinDaysConstraintsBroken[i]==nMinDaysConstraintsBroken[j] && nIncompatible[i]>nIncompatible[j] ) )
1003 return true;
1004
1005 return false;
1006 }
1007
1008
processTimeSpaceConstraints(QWidget * parent,QTextStream * initialOrderStream)1009 bool processTimeSpaceConstraints(QWidget* parent, QTextStream* initialOrderStream)
1010 {
1011 assert(gt.rules.internalStructureComputed);
1012
1013 if(gt.rules.mode==MORNINGS_AFTERNOONS && gt.rules.nDaysPerWeek%2 != 0){
1014 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
1015 GeneratePreTranslate::tr("Cannot generate the timetable in the mornings-afternoons mode if the number of FET days per week is odd. "
1016 "Please make it an even number and try again."));
1017 return false;
1018 }
1019 else if(gt.rules.mode==TERMS && gt.rules.nDaysPerWeek != gt.rules.nTerms * gt.rules.nDaysPerTerm){
1020 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
1021 GeneratePreTranslate::tr("You are working in the Terms mode and the number of"
1022 " days per week (%1) is not equal to the number of terms (%2) x the number of days per term (%3) - please correct this before generating.")
1023 .arg(gt.rules.nDaysPerWeek).arg(gt.rules.nTerms).arg(gt.rules.nDaysPerTerm));
1024 return false;
1025 }
1026
1027 QList<TimeConstraint*> incompatibleModeTimeConstraints;
1028 for(TimeConstraint* tc : qAsConst(gt.rules.timeConstraintsList))
1029 if((gt.rules.mode==OFFICIAL && !tc->canBeUsedInOfficialMode()) ||
1030 (gt.rules.mode==MORNINGS_AFTERNOONS && !tc->canBeUsedInMorningsAfternoonsMode()) ||
1031 (gt.rules.mode==BLOCK_PLANNING && !tc->canBeUsedInBlockPlanningMode()) ||
1032 (gt.rules.mode==TERMS && !tc->canBeUsedInTermsMode()))
1033 incompatibleModeTimeConstraints.append(tc);
1034
1035 QList<SpaceConstraint*> incompatibleModeSpaceConstraints;
1036 for(SpaceConstraint* sc : qAsConst(gt.rules.spaceConstraintsList))
1037 if((gt.rules.mode==OFFICIAL && !sc->canBeUsedInOfficialMode()) ||
1038 (gt.rules.mode==MORNINGS_AFTERNOONS && !sc->canBeUsedInMorningsAfternoonsMode()) ||
1039 (gt.rules.mode==BLOCK_PLANNING && !sc->canBeUsedInBlockPlanningMode()) ||
1040 (gt.rules.mode==TERMS && !sc->canBeUsedInTermsMode()))
1041 incompatibleModeSpaceConstraints.append(sc);
1042
1043 if(!incompatibleModeTimeConstraints.isEmpty() || !incompatibleModeSpaceConstraints.isEmpty()){
1044 QString s=GeneratePreTranslate::tr("You have constraints which are incompatible with the current mode. Please remove them"
1045 " from the all time/space constraint dialogs or change the mode."
1046 " If this is a FET bug, please report it. These constraints are listed below:");
1047 s+="\n\n";
1048 for(TimeConstraint* tc : qAsConst(incompatibleModeTimeConstraints)){
1049 s+=tc->getDetailedDescription(gt.rules);
1050 s+="\n";
1051 }
1052 for(SpaceConstraint* sc : qAsConst(incompatibleModeSpaceConstraints)){
1053 s+=sc->getDetailedDescription(gt.rules);
1054 s+="\n";
1055 }
1056
1057 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"), s);
1058 return false;
1059 }
1060
1061 ////////////Compute equivalent subgroups
1062 if(SHOW_WARNING_FOR_SUBGROUPS_WITH_THE_SAME_ACTIVITIES){
1063 QList<int> tmpSortedSubgroupsList;
1064 Matrix1D<bool> isSignificantSubgroup;
1065
1066 isSignificantSubgroup.resize(gt.rules.nInternalSubgroups);
1067
1068 tmpSortedSubgroupsList.clear();
1069 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
1070 tmpSortedSubgroupsList.append(i);
1071
1072 std::stable_sort(tmpSortedSubgroupsList.begin(), tmpSortedSubgroupsList.end(), findEquivalentSubgroupsCompareFunction);
1073
1074 QStringList s;
1075
1076 if(gt.rules.nInternalSubgroups>0)
1077 isSignificantSubgroup[tmpSortedSubgroupsList.at(0)]=true;
1078 for(int i=1; i<gt.rules.nInternalSubgroups; i++){
1079 int s1=tmpSortedSubgroupsList.at(i-1);
1080 int s2=tmpSortedSubgroupsList.at(i);
1081
1082 isSignificantSubgroup[s2]=true;
1083
1084 const QList<int>& l1=gt.rules.internalSubgroupsList[s1]->activitiesForSubgroup;
1085 const QList<int>& l2=gt.rules.internalSubgroupsList[s2]->activitiesForSubgroup;
1086 if(l1.count()==l2.count()){
1087 int i;
1088 for(i=0; i<l1.count(); i++)
1089 if(l1.at(i)!=l2.at(i))
1090 break;
1091 if(i==l1.count()){
1092 isSignificantSubgroup[s2]=false;
1093
1094 s.append(GeneratePreTranslate::tr("Subgroup %1 has the same activities as subgroup %2.").arg(gt.rules.internalSubgroupsList[s2]->name).arg(gt.rules.internalSubgroupsList[s1]->name));
1095 }
1096 }
1097 }
1098
1099 int cnt=0;
1100 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
1101 if(!isSignificantSubgroup[i])
1102 cnt++;
1103
1104 if(cnt>0){
1105 QString s0=GeneratePreTranslate::tr("Optimization tip:");
1106 s0+=" ";
1107 s0+=GeneratePreTranslate::tr("There are %1 subgroups (from the total of %2 subgroups) which have the same activities as other subgroups. They are listed below."
1108 " If the constraints relating to these subgroups are also the same, you can make the generation (directly proportional) faster by completely removing the subgroups"
1109 " which are equivalent to other subgroups (leaving only one representant for each equivalence set). (The generation algorithm will not completely remove the equivalent"
1110 " subgroups automatically.)").arg(cnt).arg(gt.rules.nInternalSubgroups);
1111 s0+="\n\n";
1112 s0+=GeneratePreTranslate::tr("If you did not add all the activities yet or if the number of equivalent subgroups compared to the total number of subgroups"
1113 " is small, probably you can safely ignore this message.");
1114 s0+="\n\n";
1115 s0+=GeneratePreTranslate::tr("You can deactivate this message from the 'Settings' menu.");
1116
1117 GeneratePreReconcilableMessage::largeInformation(parent, GeneratePreTranslate::tr("FET warning"), s0+QString("\n\n")+s.join("\n"));
1118 }
1119 }
1120 //////////////////////////////////
1121
1122 //////////////////begin resizing
1123
1124 //2021-03-18
1125 //permutation.resize(gt.rules.nInternalActivities);
1126 copyOfInitialPermutation.resize(gt.rules.nInternalActivities);
1127 //
1128 subgroupsEarlyMaxBeginningsAtSecondHourPercentage.resize(gt.rules.nInternalSubgroups);
1129 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings.resize(gt.rules.nInternalSubgroups);
1130 subgroupsMaxGapsPerWeekPercentage.resize(gt.rules.nInternalSubgroups);
1131 subgroupsMaxGapsPerWeekMaxGaps.resize(gt.rules.nInternalSubgroups);
1132 //
1133 nHoursPerSubgroup.resize(gt.rules.nInternalSubgroups);
1134 //
1135 subgroupsMaxGapsPerDayPercentage.resize(gt.rules.nInternalSubgroups);
1136 subgroupsMaxGapsPerDayMaxGaps.resize(gt.rules.nInternalSubgroups);
1137 //
1138 subgroupsMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalSubgroups);
1139 subgroupsMaxDaysPerWeekWeightPercentages.resize(gt.rules.nInternalSubgroups);
1140 //
1141 teachersMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalTeachers);
1142 teachersMaxDaysPerWeekWeightPercentages.resize(gt.rules.nInternalTeachers);
1143 //
1144 teachersMaxThreeConsecutiveDaysAllowAMAMException.resize(gt.rules.nInternalTeachers);
1145 teachersMaxThreeConsecutiveDaysPercentages.resize(gt.rules.nInternalTeachers); //-1 for not existing
1146 //
1147 teachersMaxGapsPerWeekPercentage.resize(gt.rules.nInternalTeachers);
1148 teachersMaxGapsPerWeekMaxGaps.resize(gt.rules.nInternalTeachers);
1149 teachersMaxGapsPerDayPercentage.resize(gt.rules.nInternalTeachers);
1150 teachersMaxGapsPerDayMaxGaps.resize(gt.rules.nInternalTeachers);
1151 teachersMaxGapsPerMorningAndAfternoonPercentage.resize(gt.rules.nInternalTeachers);
1152 teachersMaxGapsPerMorningAndAfternoonMaxGaps.resize(gt.rules.nInternalTeachers);
1153 nHoursPerTeacher.resize(gt.rules.nInternalTeachers);
1154 //
1155 teachersMaxHoursDailyPercentages1.resize(gt.rules.nInternalTeachers);
1156 teachersMaxHoursDailyMaxHours1.resize(gt.rules.nInternalTeachers);
1157 teachersMaxHoursDailyPercentages2.resize(gt.rules.nInternalTeachers);
1158 teachersMaxHoursDailyMaxHours2.resize(gt.rules.nInternalTeachers);
1159 //
1160 teachersMaxHoursContinuouslyPercentages1.resize(gt.rules.nInternalTeachers);
1161 teachersMaxHoursContinuouslyMaxHours1.resize(gt.rules.nInternalTeachers);
1162 teachersMaxHoursContinuouslyPercentages2.resize(gt.rules.nInternalTeachers);
1163 teachersMaxHoursContinuouslyMaxHours2.resize(gt.rules.nInternalTeachers);
1164 //
1165 teachersMinHoursDailyPercentages.resize(gt.rules.nInternalTeachers, 2);
1166 teachersMinHoursDailyMinHours.resize(gt.rules.nInternalTeachers, 2);
1167 teachersMinHoursDailyRealDaysPercentages.resize(gt.rules.nInternalTeachers);
1168 teachersMinHoursDailyRealDaysMinHours.resize(gt.rules.nInternalTeachers);
1169 //
1170 teachersMinDaysPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1171 teachersMinDaysPerWeekMinDays.resize(gt.rules.nInternalTeachers);
1172 //
1173 teachersMaxRealDaysPerWeekMaxDays.resize(gt.rules.nInternalTeachers);
1174 teachersMaxRealDaysPerWeekWeightPercentages.resize(gt.rules.nInternalTeachers);
1175 //
1176 teachersMaxGapsPerRealDayPercentage.resize(gt.rules.nInternalTeachers);
1177 teachersMaxGapsPerRealDayMaxGaps.resize(gt.rules.nInternalTeachers);
1178 teachersMaxGapsPerRealDayAllowException.resize(gt.rules.nInternalTeachers);
1179 teachersMaxGapsPerWeekForRealDaysPercentage.resize(gt.rules.nInternalTeachers);
1180 teachersMaxGapsPerWeekForRealDaysMaxGaps.resize(gt.rules.nInternalTeachers);
1181 teacherConstrainedToZeroGapsPerAfternoon.resize(gt.rules.nInternalTeachers);
1182 //
1183 teachersMaxAfternoonsPerWeekMaxAfternoons.resize(gt.rules.nInternalTeachers);
1184 teachersMaxAfternoonsPerWeekWeightPercentages.resize(gt.rules.nInternalTeachers);
1185 teachersMaxMorningsPerWeekMaxMornings.resize(gt.rules.nInternalTeachers);
1186 teachersMaxMorningsPerWeekWeightPercentages.resize(gt.rules.nInternalTeachers);
1187 //
1188 teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage.resize(gt.rules.nInternalTeachers);
1189 teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings.resize(gt.rules.nInternalTeachers);
1190 //
1191 teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage.resize(gt.rules.nInternalTeachers);
1192 teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings.resize(gt.rules.nInternalTeachers);
1193 //
1194 teachersMaxHoursDailyRealDaysPercentages1.resize(gt.rules.nInternalTeachers);
1195 teachersMaxHoursDailyRealDaysMaxHours1.resize(gt.rules.nInternalTeachers);
1196 teachersMaxHoursDailyRealDaysPercentages2.resize(gt.rules.nInternalTeachers);
1197 teachersMaxHoursDailyRealDaysMaxHours2.resize(gt.rules.nInternalTeachers);
1198 //
1199 teachersMinRealDaysPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1200 teachersMinRealDaysPerWeekMinDays.resize(gt.rules.nInternalTeachers);
1201 teachersMinMorningsPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1202 teachersMinMorningsPerWeekMinMornings.resize(gt.rules.nInternalTeachers);
1203 teachersMinAfternoonsPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1204 teachersMinAfternoonsPerWeekMinAfternoons.resize(gt.rules.nInternalTeachers);
1205 teachersMaxHoursPerAllAfternoonsPercentages.resize(gt.rules.nInternalTeachers);
1206 teachersMaxHoursPerAllAfternoonsMaxHours.resize(gt.rules.nInternalTeachers);
1207 //
1208 subgroupsMaxAfternoonsPerWeekMaxAfternoons.resize(gt.rules.nInternalSubgroups);
1209 subgroupsMaxAfternoonsPerWeekWeightPercentages.resize(gt.rules.nInternalSubgroups);
1210 subgroupsMaxMorningsPerWeekMaxMornings.resize(gt.rules.nInternalSubgroups);
1211 subgroupsMaxMorningsPerWeekWeightPercentages.resize(gt.rules.nInternalSubgroups);
1212 //
1213 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage.resize(gt.rules.nInternalSubgroups);
1214 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings.resize(gt.rules.nInternalSubgroups);
1215 //
1216 subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage.resize(gt.rules.nInternalSubgroups);
1217 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings.resize(gt.rules.nInternalSubgroups);
1218 //
1219 subgroupsMaxHoursDailyPercentages1.resize(gt.rules.nInternalSubgroups);
1220 subgroupsMaxHoursDailyMaxHours1.resize(gt.rules.nInternalSubgroups);
1221 subgroupsMaxHoursDailyPercentages2.resize(gt.rules.nInternalSubgroups);
1222 subgroupsMaxHoursDailyMaxHours2.resize(gt.rules.nInternalSubgroups);
1223 //
1224 subgroupsMaxHoursContinuouslyPercentages1.resize(gt.rules.nInternalSubgroups);
1225 subgroupsMaxHoursContinuouslyMaxHours1.resize(gt.rules.nInternalSubgroups);
1226 subgroupsMaxHoursContinuouslyPercentages2.resize(gt.rules.nInternalSubgroups);
1227 subgroupsMaxHoursContinuouslyMaxHours2.resize(gt.rules.nInternalSubgroups);
1228 //
1229 subgroupsMinHoursDailyPercentages.resize(gt.rules.nInternalSubgroups, 2);
1230 subgroupsMinHoursDailyMinHours.resize(gt.rules.nInternalSubgroups, 2);
1231 subgroupsMinHoursDailyAllowEmptyDays.resize(gt.rules.nInternalSubgroups);
1232 subgroupsMinHoursPerMorningAllowEmptyMornings.resize(gt.rules.nInternalSubgroups);
1233 //
1234 subgroupsMaxGapsPerRealDayPercentage.resize(gt.rules.nInternalSubgroups);
1235 subgroupsMaxGapsPerRealDayMaxGaps.resize(gt.rules.nInternalSubgroups);
1236 //
1237 subgroupsMaxGapsPerWeekForRealDaysPercentage.resize(gt.rules.nInternalSubgroups);
1238 subgroupsMaxGapsPerWeekForRealDaysMaxGaps.resize(gt.rules.nInternalSubgroups);
1239 //
1240 subgroupsMaxRealDaysPerWeekMaxDays.resize(gt.rules.nInternalSubgroups);
1241 subgroupsMaxRealDaysPerWeekWeightPercentages.resize(gt.rules.nInternalSubgroups);
1242 //
1243 subgroupsMaxHoursPerAllAfternoonsPercentages.resize(gt.rules.nInternalSubgroups);
1244 subgroupsMaxHoursPerAllAfternoonsMaxHours.resize(gt.rules.nInternalSubgroups);
1245 subgroupsMinMorningsPerWeekPercentages.resize(gt.rules.nInternalSubgroups);
1246 subgroupsMinMorningsPerWeekMinMornings.resize(gt.rules.nInternalSubgroups);
1247 subgroupsMinAfternoonsPerWeekPercentages.resize(gt.rules.nInternalSubgroups);
1248 subgroupsMinAfternoonsPerWeekMinAfternoons.resize(gt.rules.nInternalSubgroups);
1249 //
1250 subgroupsMaxHoursDailyRealDaysPercentages1.resize(gt.rules.nInternalSubgroups);
1251 subgroupsMaxHoursDailyRealDaysMaxHours1.resize(gt.rules.nInternalSubgroups);
1252 subgroupsMaxHoursDailyRealDaysPercentages2.resize(gt.rules.nInternalSubgroups);
1253 subgroupsMaxHoursDailyRealDaysMaxHours2.resize(gt.rules.nInternalSubgroups);
1254 //
1255 activityEndsStudentsDayPercentages.resize(gt.rules.nInternalActivities);
1256 activityEndsTeachersDayPercentages.resize(gt.rules.nInternalActivities);
1257 //
1258 teachersMaxSpanPerDayMaxSpan.resize(gt.rules.nInternalTeachers);
1259 teachersMaxSpanPerDayPercentages.resize(gt.rules.nInternalTeachers);
1260 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne.resize(gt.rules.nInternalTeachers);
1261 teachersMinRestingHoursCircularMinHours.resize(gt.rules.nInternalTeachers);
1262 teachersMinRestingHoursCircularPercentages.resize(gt.rules.nInternalTeachers);
1263 teachersMinRestingHoursNotCircularMinHours.resize(gt.rules.nInternalTeachers);
1264 teachersMinRestingHoursNotCircularPercentages.resize(gt.rules.nInternalTeachers);
1265 //
1266 teachersMaxTwoConsecutiveMorningsPercentage.resize(gt.rules.nInternalTeachers);
1267 teachersMaxTwoConsecutiveAfternoonsPercentage.resize(gt.rules.nInternalTeachers);
1268 //
1269 teachersMaxSpanPerRealDayMaxSpan.resize(gt.rules.nInternalTeachers);
1270 teachersMaxSpanPerRealDayPercentages.resize(gt.rules.nInternalTeachers);
1271 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne.resize(gt.rules.nInternalTeachers);
1272 //
1273 teachersMinRestingHoursBetweenMorningAndAfternoonMinHours.resize(gt.rules.nInternalTeachers);
1274 teachersMinRestingHoursBetweenMorningAndAfternoonPercentages.resize(gt.rules.nInternalTeachers);
1275 //
1276 teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages.resize(gt.rules.nInternalTeachers);
1277 //
1278 subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours.resize(gt.rules.nInternalSubgroups);
1279 subgroupsMinRestingHoursBetweenMorningAndAfternoonPercentages.resize(gt.rules.nInternalSubgroups);
1280 //
1281 subgroupsMaxSpanPerDayMaxSpan.resize(gt.rules.nInternalSubgroups);
1282 subgroupsMaxSpanPerDayPercentages.resize(gt.rules.nInternalSubgroups);
1283 subgroupsMinRestingHoursCircularMinHours.resize(gt.rules.nInternalSubgroups);
1284 subgroupsMinRestingHoursCircularPercentages.resize(gt.rules.nInternalSubgroups);
1285 subgroupsMinRestingHoursNotCircularMinHours.resize(gt.rules.nInternalSubgroups);
1286 subgroupsMinRestingHoursNotCircularPercentages.resize(gt.rules.nInternalSubgroups);
1287 //
1288 subgroupsMaxSpanPerRealDayMaxSpan.resize(gt.rules.nInternalSubgroups);
1289 subgroupsMaxSpanPerRealDayPercentages.resize(gt.rules.nInternalSubgroups);
1290 //
1291 unspecifiedPreferredRoom.resize(gt.rules.nInternalActivities);
1292 activitiesHomeRoomsPercentage.resize(gt.rules.nInternalActivities);
1293 unspecifiedHomeRoom.resize(gt.rules.nInternalActivities);
1294 //
1295 maxBuildingChangesPerWeekForStudentsPercentages.resize(gt.rules.nInternalSubgroups);
1296 maxBuildingChangesPerWeekForStudentsMaxChanges.resize(gt.rules.nInternalSubgroups);
1297 maxBuildingChangesPerDayForStudentsPercentages.resize(gt.rules.nInternalSubgroups);
1298 maxBuildingChangesPerDayForStudentsMaxChanges.resize(gt.rules.nInternalSubgroups);
1299 minGapsBetweenBuildingChangesForStudentsPercentages.resize(gt.rules.nInternalSubgroups);
1300 minGapsBetweenBuildingChangesForStudentsMinGaps.resize(gt.rules.nInternalSubgroups);
1301 //
1302 maxBuildingChangesPerWeekForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1303 maxBuildingChangesPerWeekForTeachersMaxChanges.resize(gt.rules.nInternalTeachers);
1304 maxBuildingChangesPerDayForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1305 maxBuildingChangesPerDayForTeachersMaxChanges.resize(gt.rules.nInternalTeachers);
1306 minGapsBetweenBuildingChangesForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1307 minGapsBetweenBuildingChangesForTeachersMinGaps.resize(gt.rules.nInternalTeachers);
1308 //
1309 maxRoomChangesPerRealDayForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1310 maxRoomChangesPerRealDayForTeachersMaxChanges.resize(gt.rules.nInternalTeachers);
1311 //
1312 maxRoomChangesPerWeekForStudentsPercentages.resize(gt.rules.nInternalSubgroups);
1313 maxRoomChangesPerWeekForStudentsMaxChanges.resize(gt.rules.nInternalSubgroups);
1314 maxRoomChangesPerDayForStudentsPercentages.resize(gt.rules.nInternalSubgroups);
1315 maxRoomChangesPerDayForStudentsMaxChanges.resize(gt.rules.nInternalSubgroups);
1316 minGapsBetweenRoomChangesForStudentsPercentages.resize(gt.rules.nInternalSubgroups);
1317 minGapsBetweenRoomChangesForStudentsMinGaps.resize(gt.rules.nInternalSubgroups);
1318 //
1319 maxRoomChangesPerRealDayForSubgroupsPercentages.resize(gt.rules.nInternalSubgroups);
1320 maxRoomChangesPerRealDayForSubgroupsMaxChanges.resize(gt.rules.nInternalSubgroups);
1321 //
1322 maxRoomChangesPerWeekForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1323 maxRoomChangesPerWeekForTeachersMaxChanges.resize(gt.rules.nInternalTeachers);
1324 maxRoomChangesPerDayForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1325 maxRoomChangesPerDayForTeachersMaxChanges.resize(gt.rules.nInternalTeachers);
1326 minGapsBetweenRoomChangesForTeachersPercentages.resize(gt.rules.nInternalTeachers);
1327 minGapsBetweenRoomChangesForTeachersMinGaps.resize(gt.rules.nInternalTeachers);
1328 //
1329 mustComputeTimetableSubgroup.resize(gt.rules.nInternalSubgroups);
1330 mustComputeTimetableTeacher.resize(gt.rules.nInternalTeachers);
1331 //
1332 activityTagN1N2N3.resize(gt.rules.nInternalActivities);
1333 //
1334 activityHasOccupyMaxConstraints.resize(gt.rules.nInternalActivities);
1335 activityHasMaxSimultaneousConstraints.resize(gt.rules.nInternalActivities);
1336 //
1337 fixedTimeActivity.resize(gt.rules.nInternalActivities);
1338 fixedSpaceActivity.resize(gt.rules.nInternalActivities);
1339 //
1340 initialOrderOfActivitiesIndices.resize(gt.rules.nInternalActivities);
1341 //
1342 daysTeacherIsAvailable.resize(gt.rules.nInternalTeachers);
1343 daysSubgroupIsAvailable.resize(gt.rules.nInternalSubgroups);
1344 requestedDaysForTeachers.resize(gt.rules.nInternalTeachers);
1345 requestedDaysForSubgroups.resize(gt.rules.nInternalSubgroups);
1346 nReqForTeacher.resize(gt.rules.nInternalTeachers);
1347 nReqForSubgroup.resize(gt.rules.nInternalSubgroups);
1348 //
1349 nHoursRequiredForRoom.resize(gt.rules.nInternalRooms);
1350 nHoursAvailableForRoom.resize(gt.rules.nInternalRooms);
1351 //
1352 nIncompatible.resize(gt.rules.nInternalActivities);
1353 nMinDaysConstraintsBroken.resize(gt.rules.nInternalActivities);
1354 nRoomsIncompat.resize(gt.rules.nInternalRooms);
1355 nHoursForRoom.resize(gt.rules.nInternalRooms);
1356 maxPercentagePrefRooms.resize(gt.rules.nInternalActivities);
1357 reprNInc.resize(gt.rules.nInternalActivities);
1358 //
1359 nIncompatibleFromFather.resize(gt.rules.nInternalActivities);
1360 fatherActivityInInitialOrder.resize(gt.rules.nInternalActivities);
1361
1362 //MIN DAYS BETWEEN ACTIVITIES
1363 minDaysListOfActivities.resize(gt.rules.nInternalActivities);
1364 minDaysListOfMinDays.resize(gt.rules.nInternalActivities);
1365 minDaysListOfWeightPercentages.resize(gt.rules.nInternalActivities);
1366 minDaysListOfConsecutiveIfSameDay.resize(gt.rules.nInternalActivities);
1367
1368 //MAX DAYS BETWEEN ACTIVITIES
1369 maxDaysListOfActivities.resize(gt.rules.nInternalActivities);
1370 maxDaysListOfMaxDays.resize(gt.rules.nInternalActivities);
1371 maxDaysListOfWeightPercentages.resize(gt.rules.nInternalActivities);
1372
1373 //MIN GAPS BETWEEN ACTIVITIES
1374 minGapsBetweenActivitiesListOfActivities.resize(gt.rules.nInternalActivities);
1375 minGapsBetweenActivitiesListOfMinGaps.resize(gt.rules.nInternalActivities);
1376 minGapsBetweenActivitiesListOfWeightPercentages.resize(gt.rules.nInternalActivities);
1377
1378 //MAX GAPS BETWEEN ACTIVITIES
1379 maxGapsBetweenActivitiesListOfActivities.resize(gt.rules.nInternalActivities);
1380 maxGapsBetweenActivitiesListOfMaxGaps.resize(gt.rules.nInternalActivities);
1381 maxGapsBetweenActivitiesListOfWeightPercentages.resize(gt.rules.nInternalActivities);
1382
1383 teachersWithMaxDaysPerWeekForActivities.resize(gt.rules.nInternalActivities);
1384 subgroupsWithMaxDaysPerWeekForActivities.resize(gt.rules.nInternalActivities);
1385
1386 teachersWithMaxThreeConsecutiveDaysForActivities.resize(gt.rules.nInternalActivities);
1387
1388 teachersWithMaxRealDaysPerWeekForActivities.resize(gt.rules.nInternalActivities);
1389
1390 teachersWithMaxAfternoonsPerWeekForActivities.resize(gt.rules.nInternalActivities);
1391 teachersWithMaxMorningsPerWeekForActivities.resize(gt.rules.nInternalActivities);
1392
1393 subgroupsWithMaxAfternoonsPerWeekForActivities.resize(gt.rules.nInternalActivities);
1394 subgroupsWithMaxMorningsPerWeekForActivities.resize(gt.rules.nInternalActivities);
1395
1396 subgroupsWithMaxRealDaysPerWeekForActivities.resize(gt.rules.nInternalActivities);
1397
1398
1399 //activities same starting time
1400 activitiesSameStartingTimeActivities.resize(gt.rules.nInternalActivities);
1401 activitiesSameStartingTimePercentages.resize(gt.rules.nInternalActivities);
1402
1403 //activities same starting hour
1404 activitiesSameStartingHourActivities.resize(gt.rules.nInternalActivities);
1405 activitiesSameStartingHourPercentages.resize(gt.rules.nInternalActivities);
1406
1407 //activities same starting day
1408 activitiesSameStartingDayActivities.resize(gt.rules.nInternalActivities);
1409 activitiesSameStartingDayPercentages.resize(gt.rules.nInternalActivities);
1410
1411 //activities not overlapping
1412 activitiesNotOverlappingActivities.resize(gt.rules.nInternalActivities);
1413 activitiesNotOverlappingPercentages.resize(gt.rules.nInternalActivities);
1414
1415 // 2 activities consecutive
1416 //index represents the first activity, value in array represents the second activity
1417 constrTwoActivitiesConsecutivePercentages.resize(gt.rules.nInternalActivities);
1418 constrTwoActivitiesConsecutiveActivities.resize(gt.rules.nInternalActivities);
1419
1420 //index represents the second activity, value in array represents the first activity
1421 inverseConstrTwoActivitiesConsecutivePercentages.resize(gt.rules.nInternalActivities);
1422 inverseConstrTwoActivitiesConsecutiveActivities.resize(gt.rules.nInternalActivities);
1423 // 2 activities consecutive
1424
1425 // 2 activities grouped
1426 //index represents the first activity, value in array represents the second activity
1427 constrTwoActivitiesGroupedPercentages.resize(gt.rules.nInternalActivities);
1428 constrTwoActivitiesGroupedActivities.resize(gt.rules.nInternalActivities);
1429
1430 // 3 activities grouped
1431 //index represents the first activity, value in array represents the second activity
1432 constrThreeActivitiesGroupedPercentages.resize(gt.rules.nInternalActivities);
1433 constrThreeActivitiesGroupedActivities.resize(gt.rules.nInternalActivities);
1434
1435 // 2 activities ordered
1436 //index represents the first activity, value in array represents the second activity
1437 constrTwoActivitiesOrderedPercentages.resize(gt.rules.nInternalActivities);
1438 constrTwoActivitiesOrderedActivities.resize(gt.rules.nInternalActivities);
1439
1440 //index represents the second activity, value in array represents the first activity
1441 inverseConstrTwoActivitiesOrderedPercentages.resize(gt.rules.nInternalActivities);
1442 inverseConstrTwoActivitiesOrderedActivities.resize(gt.rules.nInternalActivities);
1443 // 2 activities ordered
1444
1445 // 2 activities ordered if same day
1446 //index represents the first activity, value in array represents the second activity
1447 constrTwoActivitiesOrderedIfSameDayPercentages.resize(gt.rules.nInternalActivities);
1448 constrTwoActivitiesOrderedIfSameDayActivities.resize(gt.rules.nInternalActivities);
1449
1450 //index represents the second activity, value in array represents the first activity
1451 inverseConstrTwoActivitiesOrderedIfSameDayPercentages.resize(gt.rules.nInternalActivities);
1452 inverseConstrTwoActivitiesOrderedIfSameDayActivities.resize(gt.rules.nInternalActivities);
1453 // 2 activities ordered if same day
1454
1455 //rooms
1456 activitiesPreferredRoomsList.resize(gt.rules.nInternalActivities);
1457
1458 activitiesHomeRoomsHomeRooms.resize(gt.rules.nInternalActivities);
1459 ////////rooms
1460
1461 mustComputeTimetableSubgroups.resize(gt.rules.nInternalActivities);
1462 mustComputeTimetableTeachers.resize(gt.rules.nInternalActivities);
1463
1464 //2021-02-20
1465 teachersIntervalMaxDaysPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1466 teachersIntervalMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalTeachers);
1467 teachersIntervalMaxDaysPerWeekIntervalStart.resize(gt.rules.nInternalTeachers);
1468 teachersIntervalMaxDaysPerWeekIntervalEnd.resize(gt.rules.nInternalTeachers);
1469
1470 teachersMorningIntervalMaxDaysPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1471 teachersMorningIntervalMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalTeachers);
1472 teachersMorningIntervalMaxDaysPerWeekIntervalStart.resize(gt.rules.nInternalTeachers);
1473 teachersMorningIntervalMaxDaysPerWeekIntervalEnd.resize(gt.rules.nInternalTeachers);
1474
1475 teachersAfternoonIntervalMaxDaysPerWeekPercentages.resize(gt.rules.nInternalTeachers);
1476 teachersAfternoonIntervalMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalTeachers);
1477 teachersAfternoonIntervalMaxDaysPerWeekIntervalStart.resize(gt.rules.nInternalTeachers);
1478 teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd.resize(gt.rules.nInternalTeachers);
1479
1480 subgroupsIntervalMaxDaysPerWeekPercentages.resize(gt.rules.nInternalSubgroups);
1481 subgroupsIntervalMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalSubgroups);
1482 subgroupsIntervalMaxDaysPerWeekIntervalStart.resize(gt.rules.nInternalSubgroups);
1483 subgroupsIntervalMaxDaysPerWeekIntervalEnd.resize(gt.rules.nInternalSubgroups);
1484
1485 subgroupsMorningIntervalMaxDaysPerWeekPercentages.resize(gt.rules.nInternalSubgroups);
1486 subgroupsMorningIntervalMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalSubgroups);
1487 subgroupsMorningIntervalMaxDaysPerWeekIntervalStart.resize(gt.rules.nInternalSubgroups);
1488 subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd.resize(gt.rules.nInternalSubgroups);
1489
1490 subgroupsAfternoonIntervalMaxDaysPerWeekPercentages.resize(gt.rules.nInternalSubgroups);
1491 subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays.resize(gt.rules.nInternalSubgroups);
1492 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart.resize(gt.rules.nInternalSubgroups);
1493 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd.resize(gt.rules.nInternalSubgroups);
1494
1495 //////teachers and subgroups activity tag max hours daily and continuously
1496 teachersActivityTagMaxHoursDailyMaxHours.resize(gt.rules.nInternalTeachers);
1497 teachersActivityTagMaxHoursDailyActivityTag.resize(gt.rules.nInternalTeachers);
1498 teachersActivityTagMaxHoursDailyPercentage.resize(gt.rules.nInternalTeachers);
1499
1500 teachersActivityTagMaxHoursDailyRealDaysMaxHours.resize(gt.rules.nInternalTeachers);
1501 teachersActivityTagMaxHoursDailyRealDaysActivityTag.resize(gt.rules.nInternalTeachers);
1502 teachersActivityTagMaxHoursDailyRealDaysPercentage.resize(gt.rules.nInternalTeachers);
1503
1504 teachersActivityTagMaxHoursContinuouslyMaxHours.resize(gt.rules.nInternalTeachers);
1505 teachersActivityTagMaxHoursContinuouslyActivityTag.resize(gt.rules.nInternalTeachers);
1506 teachersActivityTagMaxHoursContinuouslyPercentage.resize(gt.rules.nInternalTeachers);
1507
1508 teachersWithN1N2N3ForActivities.resize(gt.rules.nInternalActivities);
1509
1510 subgroupsActivityTagMaxHoursDailyMaxHours.resize(gt.rules.nInternalSubgroups);
1511 subgroupsActivityTagMaxHoursDailyActivityTag.resize(gt.rules.nInternalSubgroups);
1512 subgroupsActivityTagMaxHoursDailyPercentage.resize(gt.rules.nInternalSubgroups);
1513
1514 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours.resize(gt.rules.nInternalSubgroups);
1515 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag.resize(gt.rules.nInternalSubgroups);
1516 subgroupsActivityTagMaxHoursDailyRealDaysPercentage.resize(gt.rules.nInternalSubgroups);
1517
1518 subgroupsActivityTagMaxHoursContinuouslyMaxHours.resize(gt.rules.nInternalSubgroups);
1519 subgroupsActivityTagMaxHoursContinuouslyActivityTag.resize(gt.rules.nInternalSubgroups);
1520 subgroupsActivityTagMaxHoursContinuouslyPercentage.resize(gt.rules.nInternalSubgroups);
1521
1522 satmhdListForSubgroup.resize(gt.rules.nInternalSubgroups);
1523 tatmhdListForTeacher.resize(gt.rules.nInternalTeachers);
1524
1525 //2011-09-25
1526 aomtsListForActivity.resize(gt.rules.nInternalActivities);
1527 //2019-11-16
1528 aomintsListForActivity.resize(gt.rules.nInternalActivities);
1529 //2011-09-30
1530 amsistsListForActivity.resize(gt.rules.nInternalActivities);
1531 //2019-11-16
1532 aminsistsListForActivity.resize(gt.rules.nInternalActivities);
1533
1534 //2020-05-02
1535 amtfsistsListForActivity.resize(gt.rules.nInternalActivities);
1536
1537 //for terms
1538 //2020-01-14
1539 amiatListForActivity.resize(gt.rules.nInternalActivities);
1540 //2020-01-14
1541 aomtListForActivity.resize(gt.rules.nInternalActivities);
1542
1543 //2019-06-08
1544 smgbopoatListForActivity.resize(gt.rules.nInternalActivities);
1545 //2019-06-08
1546 tmgbopoatListForActivity.resize(gt.rules.nInternalActivities);
1547
1548 //2012-04-29
1549 aomdrListForActivity.resize(gt.rules.nInternalActivities);
1550
1551 //2013-09-14
1552 asricListForActivity.resize(gt.rules.nInternalActivities);
1553
1554 //////////////////end resizing - new feature
1555
1556 QHash<int, int> reprSameStartingTime;
1557 QHash<int, QSet<int>> reprSameActivitiesSet;
1558
1559 /////1. BASIC TIME CONSTRAINTS
1560 bool t=computeActivitiesConflictingPercentage(parent);
1561 if(!t)
1562 return false;
1563 //////////////////////////////
1564
1565 /////2. min days between activities
1566 t=computeMinDays(parent);
1567 if(!t)
1568 return false;
1569 /////////////////////////////////////
1570
1571 /////2.3. max days between activities
1572 t=computeMaxDays(parent);
1573 if(!t)
1574 return false;
1575 /////////////////////////////////////
1576
1577 /////2.5. min gaps between activities
1578 t=computeMinGapsBetweenActivities(parent);
1579 if(!t)
1580 return false;
1581 /////////////////////////////////////
1582
1583 /////2.6. max gaps between activities
1584 t=computeMaxGapsBetweenActivities(parent);
1585 if(!t)
1586 return false;
1587 /////////////////////////////////////
1588
1589 /////3. students not available, teachers not available, break, activity preferred time,
1590 ///// activity preferred times, activities preferred times
1591 t=computeNotAllowedTimesPercentages(parent);
1592 if(!t)
1593 return false;
1594 ///////////////////////////////////////////////////////////////
1595
1596 /////3.5. STUDENTS MAX DAYS PER WEEK
1597 t=computeMaxDaysPerWeekForStudents(parent);
1598 if(!t)
1599 return false;
1600
1601 t=computeMaxRealDaysPerWeekForStudents(parent);
1602 if(!t)
1603 return false;
1604 //////////////////////////////////
1605
1606 //3.6. students max afternoons/mornings per week
1607 t=computeMaxAfternoonsPerWeekForStudents(parent);
1608 if(!t)
1609 return false;
1610 t=computeMaxMorningsPerWeekForStudents(parent);
1611 if(!t)
1612 return false;
1613 //////////////////////////////////
1614
1615 /////4. students max gaps and early
1616 t=computeNHoursPerSubgroup(parent);
1617 if(!t)
1618 return false;
1619 t=computeSubgroupsEarlyAndMaxGapsPercentages(parent);
1620 if(!t)
1621 return false;
1622 t=computeSubgroupsMaxGapsPerDayPercentages(parent); //!!!after max gaps per week
1623 if(!t)
1624 return false;
1625 t=computeSubgroupsMaxGapsPerRealDayPercentages(parent); //Old useless comment? !!!after max gaps per week
1626 if(!t)
1627 return false;
1628
1629 //!!!After subgroups early
1630 t=computeSubgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentages(parent);
1631 if(!t)
1632 return false;
1633 //!!!After subgroups early and subgroups afternoons early
1634 t=computeSubgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentages(parent);
1635 if(!t)
1636 return false;
1637 //////////////////////////////////
1638
1639 /////5. TEACHERS MAX DAYS PER WEEK (and max three days consecutive)
1640 t=computeMaxDaysPerWeekForTeachers(parent);
1641 if(!t)
1642 return false;
1643 t=computeMaxThreeConsecutiveDaysForTeachers(parent);
1644 if(!t)
1645 return false;
1646 t=computeMaxRealDaysPerWeekForTeachers(parent);
1647 if(!t)
1648 return false;
1649
1650 t=computeMaxAfternoonsPerWeekForTeachers(parent);
1651 if(!t)
1652 return false;
1653 t=computeMaxMorningsPerWeekForTeachers(parent);
1654 if(!t)
1655 return false;
1656 //////////////////////////////////
1657
1658
1659 /////6. TEACHERS MAX GAPS PER WEEK/DAY
1660 t=computeNHoursPerTeacher(parent);
1661 if(!t)
1662 return false;
1663 t=computeTeachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentages(parent);
1664 if(!t)
1665 return false;
1666 t=computeTeachersMorningsEarlyMaxBeginningsAtSecondHourPercentages(parent);
1667 if(!t)
1668 return false;
1669 t=computeTeachersMaxGapsPerWeekPercentage(parent);
1670 if(!t)
1671 return false;
1672 t=computeTeachersMaxGapsPerDayPercentage(parent);
1673 if(!t)
1674 return false;
1675 //!!!After max gaps per week and per day
1676 t=computeTeachersMaxGapsPerMorningAndAfternoonPercentage(parent);
1677 if(!t)
1678 return false;
1679 t=computeTeachersMaxGapsPerRealDayPercentage(parent);
1680 if(!t)
1681 return false;
1682 t=computeTeachersConstrainedToZeroGapsPerAfternoon(parent);
1683 if(!t)
1684 return false;
1685 //////////////////////////////////
1686
1687 //must be AFTER basic time constraints (computeActivitiesConflictingPercentage)
1688 t=computeActivitiesSameStartingTime(parent, reprSameStartingTime, reprSameActivitiesSet);
1689 if(!t)
1690 return false;
1691
1692 computeActivitiesSameStartingHour();
1693
1694 computeActivitiesSameStartingDay();
1695
1696 computeActivitiesNotOverlapping();
1697
1698 //must be after allowed times, after n hours per teacher and after max days per week for teachers
1699 thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight=false;
1700 //deprecated comment below
1701 //after teachers max hours daily, because of initializing with false in mhd of the variable which represents true/false <100.0% constraints of this type.
1702 t=computeTeachersMaxHoursDaily(parent);
1703 if(!t)
1704 return false;
1705 t=computeTeachersMaxHoursDailyRealDays(parent);
1706 if(!t)
1707 return false;
1708
1709 t=computeTeachersMaxHoursContinuously(parent);
1710 if(!t)
1711 return false;
1712
1713 t=computeTeachersActivityTagMaxHoursDaily(parent);
1714 if(!t)
1715 return false;
1716 t=computeTeachersActivityTagMaxHoursDailyRealDays(parent);
1717 if(!t)
1718 return false;
1719
1720
1721 t=computeTeachersActivityTagMaxHoursContinuously(parent);
1722 if(!t)
1723 return false;
1724
1725 //must be after n hours per teacher
1726 t=computeTeachersMinHoursDaily(parent);
1727 if(!t)
1728 return false;
1729 t=computeTeachersMinHoursDailyRealDays(parent);
1730 if(!t)
1731 return false;
1732
1733 //must be after teachers min hours daily
1734 t=computeTeachersMinDaysPerWeek(parent);
1735 if(!t)
1736 return false;
1737 t=computeTeachersMinRealDaysPerWeek(parent);
1738 if(!t)
1739 return false;
1740
1741 //must be after teachers min hours daily (I think not), teachers max gaps per day and teachers max gaps per week
1742 t=computeTeachersMinMorningsAfternoonsPerWeek(parent);
1743 if(!t)
1744 return false;
1745
1746 //2020-06-28
1747 //must be after n hours per teacher
1748 t=computeTeachersMaxHoursPerAllAfternoons(parent);
1749 if(!t)
1750 return false;
1751
1752 //must be after allowed times, after n hours per subgroup and after max days per week for subgroups
1753 //thereAreSubgroupsWithMaxHoursDailyWithUnder100Weight=false;
1754 thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight=false;
1755 t=computeSubgroupsMaxHoursDaily(parent);
1756 if(!t)
1757 return false;
1758 //must be after allowed times and after n hours per subgroup
1759 t=computeSubgroupsMaxHoursDailyRealDays(parent);
1760 if(!t)
1761 return false;
1762
1763 t=computeStudentsMaxHoursContinuously(parent);
1764 if(!t)
1765 return false;
1766
1767 t=computeStudentsMaxHoursContinuously(parent);
1768 if(!t)
1769 return false;
1770
1771 t=computeStudentsActivityTagMaxHoursDaily(parent);
1772 if(!t)
1773 return false;
1774
1775 t=computeStudentsActivityTagMaxHoursDailyRealDays(parent);
1776 if(!t)
1777 return false;
1778
1779 t=computeStudentsActivityTagMaxHoursContinuously(parent);
1780 if(!t)
1781 return false;
1782
1783 //after max hours daily/continuously without/with an activity tag
1784 t=checkMaxHoursForActivityDuration(parent);
1785 if(!t)
1786 return false;
1787
1788 t=computeSubgroupsMinHoursDaily(parent);
1789 if(!t)
1790 return false;
1791
1792 //must be after students min hours daily (I think not), students max gaps per day and students max gaps per week (I think not)
1793 t=computeStudentsMinMorningsAfternoonsPerWeek(parent);
1794 if(!t)
1795 return false;
1796
1797 //2020-06-28
1798 //must be after n hours per subgroup
1799 t=computeStudentsMaxHoursPerAllAfternoons(parent);
1800 if(!t)
1801 return false;
1802
1803 t=computeStudentsActivityTagMinHoursDaily(parent);
1804 if(!t)
1805 return false;
1806
1807 t=computeTeachersActivityTagMinHoursDaily(parent);
1808 if(!t)
1809 return false;
1810
1811 computeConstrTwoActivitiesConsecutive();
1812
1813 computeConstrTwoActivitiesGrouped();
1814
1815 computeConstrThreeActivitiesGrouped();
1816
1817 computeConstrTwoActivitiesOrdered();
1818
1819 computeConstrTwoActivitiesOrderedIfSameDay();
1820
1821 t=computeActivityEndsStudentsDayPercentages(parent);
1822 if(!t)
1823 return false;
1824
1825 t=computeActivityEndsTeachersDayPercentages(parent);
1826 if(!t)
1827 return false;
1828
1829 //check for impossible min days
1830 t=checkMinDays100Percent(parent);
1831 if(!t)
1832 return false;
1833 t=checkMinDaysConsecutiveIfSameDay(parent);
1834 if(!t)
1835 return false;
1836
1837 //check teachers interval max days per week
1838 t=computeTeachersIntervalMaxDaysPerWeek(parent);
1839 if(!t)
1840 return false;
1841
1842 //check teachers morning interval max days per week
1843 t=computeTeachersMorningIntervalMaxDaysPerWeek(parent);
1844 if(!t)
1845 return false;
1846
1847 //check teachers afternoon interval max days per week
1848 t=computeTeachersAfternoonIntervalMaxDaysPerWeek(parent);
1849 if(!t)
1850 return false;
1851
1852 t=computeTeachersMaxTwoConsecutiveMornings(parent);
1853 if(!t)
1854 return false;
1855 t=computeTeachersMaxTwoConsecutiveAfternoons(parent);
1856 if(!t)
1857 return false;
1858
1859 //2017-02-06
1860 t=computeTeachersMaxSpanPerDay(parent);
1861 if(!t)
1862 return false;
1863
1864 //2017-02-06
1865 t=computeTeachersMaxSpanPerRealDay(parent);
1866 if(!t)
1867 return false;
1868
1869 //check subgroups interval max days per week
1870 t=computeSubgroupsIntervalMaxDaysPerWeek(parent);
1871 if(!t)
1872 return false;
1873
1874 t=computeSubgroupsMorningIntervalMaxDaysPerWeek(parent);
1875 if(!t)
1876 return false;
1877 t=computeSubgroupsAfternoonIntervalMaxDaysPerWeek(parent);
1878 if(!t)
1879 return false;
1880
1881 /////////
1882 t=computeSubgroupsMaxSpanPerDay(parent);
1883 if(!t)
1884 return false;
1885
1886 t=computeSubgroupsMaxSpanPerRealDay(parent);
1887 if(!t)
1888 return false;
1889 /////////
1890
1891 t=computeTeachersMinRestingHours(parent);
1892 if(!t)
1893 return false;
1894
1895 t=computeSubgroupsMinRestingHours(parent);
1896 if(!t)
1897 return false;
1898
1899 t=computeTeachersMinRestingHoursBetweenMorningAndAfternoon(parent);
1900 if(!t)
1901 return false;
1902
1903 t=computeSubgroupsMinRestingHoursBetweenMorningAndAfternoon(parent);
1904 if(!t)
1905 return false;
1906
1907 t=computeN1N2N3(parent);
1908 if(!t)
1909 return false;
1910
1911 ////////////////
1912 //2011-09-25
1913 t=computeActivitiesOccupyMaxTimeSlotsFromSelection(parent);
1914 if(!t)
1915 return false;
1916
1917 ////////////////
1918 //2019-11-16
1919 t=computeActivitiesOccupyMinTimeSlotsFromSelection(parent);
1920 if(!t)
1921 return false;
1922
1923 //2011-09-30
1924 t=computeActivitiesMaxSimultaneousInSelectedTimeSlots(parent);
1925 if(!t)
1926 return false;
1927 ////////////////
1928
1929 //2019-11-16
1930 t=computeActivitiesMinSimultaneousInSelectedTimeSlots(parent);
1931 if(!t)
1932 return false;
1933 ////////////////
1934
1935 //2020-05-02
1936 t=computeActivitiesMaxTotalFromSetInSelectedTimeSlots(parent);
1937 if(!t)
1938 return false;
1939 ////////////////
1940
1941 //for terms
1942 ////////////////
1943 //2020-01-14
1944 t=computeActivitiesMaxInATerm(parent);
1945 if(!t)
1946 return false;
1947
1948 ////////////////
1949 //2020-01-14
1950 t=computeActivitiesOccupyMaxTerms(parent);
1951 if(!t)
1952 return false;
1953
1954 //2019-06-08
1955 t=computeStudentsMinGapsBetweenOrderedPairOfActivityTags(parent);
1956 if(!t)
1957 return false;
1958 ////////////////
1959
1960 //2019-06-08
1961 t=computeTeachersMinGapsBetweenOrderedPairOfActivityTags(parent);
1962 if(!t)
1963 return false;
1964 ////////////////
1965
1966 //2012-04-29
1967 t=computeActivitiesOccupyMaxDifferentRooms(parent);
1968 if(!t)
1969 return false;
1970
1971 ////////////////
1972
1973 //2013-09-14
1974 t=computeActivitiesSameRoomIfConsecutive(parent);
1975 if(!t)
1976 return false;
1977
1978 ////////////////
1979
1980 /////////////rooms
1981 t=computeBasicSpace(parent);
1982 if(!t)
1983 return false;
1984 t=computeNotAllowedRoomTimePercentages();
1985 if(!t)
1986 return false;
1987
1988 t=computeNotAllowedTeacherRoomTimePercentages();
1989 if(!t)
1990 return false;
1991 //QHash<QPair<QPair<int, int>, QPair<int, int>>, double > notAllowedTeacherRoomTimePercentages;
1992
1993 //compute below !before computeFixedActivities!
1994 t=computeActivitiesRoomsPreferences(parent);
1995 if(!t)
1996 return false;
1997 //////////////////
1998
1999 /////////buildings
2000 t=computeMaxBuildingChangesPerWeekForStudents(parent);
2001 if(!t)
2002 return false;
2003 t=computeMaxBuildingChangesPerDayForStudents(parent);
2004 if(!t)
2005 return false;
2006 t=computeMinGapsBetweenBuildingChangesForStudents(parent);
2007 if(!t)
2008 return false;
2009
2010 t=computeMaxBuildingChangesPerWeekForTeachers(parent);
2011 if(!t)
2012 return false;
2013 t=computeMaxBuildingChangesPerDayForTeachers(parent);
2014 if(!t)
2015 return false;
2016 t=computeMinGapsBetweenBuildingChangesForTeachers(parent);
2017 if(!t)
2018 return false;
2019 //////////////////
2020
2021 /////////rooms
2022 t=computeMaxRoomChangesPerWeekForStudents(parent);
2023 if(!t)
2024 return false;
2025 t=computeMaxRoomChangesPerDayForStudents(parent);
2026 if(!t)
2027 return false;
2028 t=computeMinGapsBetweenRoomChangesForStudents(parent);
2029 if(!t)
2030 return false;
2031
2032 t=computeMaxRoomChangesPerWeekForTeachers(parent);
2033 if(!t)
2034 return false;
2035 t=computeMaxRoomChangesPerDayForTeachers(parent);
2036 if(!t)
2037 return false;
2038 t=computeMinGapsBetweenRoomChangesForTeachers(parent);
2039 if(!t)
2040 return false;
2041 //////////////////
2042
2043 t=computeMaxRoomChangesPerRealDayForTeachers(parent);
2044 if(!t)
2045 return false;
2046 t=computeMaxRoomChangesPerRealDayForStudents(parent);
2047 if(!t)
2048 return false;
2049 //////////////////
2050
2051 t=homeRoomsAreOk(parent);
2052 if(!t)
2053 return false;
2054
2055 computeMustComputeTimetableSubgroups();
2056 computeMustComputeTimetableTeachers();
2057
2058 //!after computeActivitiesRoomsPreferences!
2059 t=computeFixedActivities(parent);
2060 if(!t)
2061 return false;
2062
2063 //must have here repr computed correctly
2064 sortActivities(parent, reprSameStartingTime, reprSameActivitiesSet, initialOrderStream);
2065
2066 if(SHOW_WARNING_FOR_MAX_HOURS_DAILY_WITH_UNDER_100_WEIGHT && (thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight || thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight)){
2067 QString s=GeneratePreTranslate::tr("Your file contains constraints of type teacher(s)/students (set) max hours daily or per real day (where applicable)"
2068 " with a weight less than 100%. This is not recommended, because in this case the algorithm is not implemented perfectly"
2069 " (even if it might work well in practice). You are advised to use constraints of this type only with weight 100%.");
2070 s+="\n\n";
2071 s+=GeneratePreTranslate::tr("Are you sure you want to continue?");
2072 s+="\n\n";
2073 s+=GeneratePreTranslate::tr("Note: You can deactivate this warning from the Settings menu.");
2074
2075 int t=GeneratePreReconcilableMessage::largeConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2076 GeneratePreTranslate::tr("Continue"), GeneratePreTranslate::tr("Cancel"), QString(), 0, 1);
2077
2078 if(t!=0)
2079 return false;
2080 }
2081
2082 if(SHOW_WARNING_FOR_NOT_PERFECT_CONSTRAINTS){
2083 if(haveStudentsMaxGapsPerDay || haveTeachersActivityTagMaxHoursDailyRealDays || haveStudentsActivityTagMaxHoursDailyRealDays
2084 || haveStudentsMaxGapsPerRealDay || haveTeachersMaxGapsPerRealDay /* || haveStudentsMaxGapsPerWeekForRealDays || haveTeachersMaxGapsPerWeekForRealDays */
2085 || haveTeachersActivityTagMinHoursDaily || haveStudentsActivityTagMinHoursDaily
2086 || haveTeachersActivityTagMaxHoursDaily || haveStudentsActivityTagMaxHoursDaily){
2087 QString s=GeneratePreTranslate::tr("Your data contains constraints students max gaps per day"
2088 " and/or students max gaps per real day and/or teachers max gaps per real day"
2089 " and/or students max gaps per week for real days and/or teachers max gaps per week for real days"
2090 " and/or activity tag max/min hours daily/per real day (where applicable).");
2091 s+="\n\n";
2092 s+=GeneratePreTranslate::tr("These constraints are good, but they are not perfectly optimized for speed. You may obtain a long generation time or even impossible timetables.");
2093 s+=" ";
2094 s+=GeneratePreTranslate::tr("It is recommended to use such constraints with caution.");
2095 s+="\n\n";
2096 s+=GeneratePreTranslate::tr("Are you sure you want to continue?");
2097
2098 #ifdef FET_COMMAND_LINE
2099 int b=GeneratePreReconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s, GeneratePreTranslate::tr("Yes"), GeneratePreTranslate::tr("No"), QString(), 0, 1);
2100 if(b!=0)
2101 return false;
2102 #else
2103 QMessageBox::StandardButton b=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"), s, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
2104 if(b!=QMessageBox::Yes)
2105 return false;
2106 #endif
2107 }
2108 }
2109
2110 if(gt.rules.mode!=MORNINGS_AFTERNOONS && SHOW_WARNING_FOR_STUDENTS_MIN_HOURS_DAILY_WITH_ALLOW_EMPTY_DAYS){
2111 if(haveStudentsMinHoursDailyAllowEmptyDays || haveStudentsMinHoursDailyMorningsAllowEmptyDays){
2112 QString s=GeneratePreTranslate::tr("Your data contains constraints students min hours daily/per morning which allow empty days/mornings.");
2113 s+="\n\n";
2114 s+=GeneratePreTranslate::tr("These constraints are nonstandard. They are recommended only if the students can have free days and a solution with free days for students exists."
2115 " Otherwise the solution might be impossible for FET to find.");
2116 s+=" ";
2117 s+=GeneratePreTranslate::tr("It is recommended to use such constraints with caution.");
2118 s+="\n\n";
2119 s+=GeneratePreTranslate::tr("Are you sure you want to continue?");
2120
2121 #ifdef FET_COMMAND_LINE
2122 int b=GeneratePreReconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s, GeneratePreTranslate::tr("Yes"), GeneratePreTranslate::tr("No"), QString(), 0, 1);
2123 if(b!=0)
2124 return false;
2125 #else
2126 QMessageBox::StandardButton b=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"), s, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
2127 if(b!=QMessageBox::Yes)
2128 return false;
2129 #endif
2130 }
2131 }
2132
2133 if(SHOW_WARNING_FOR_GROUP_ACTIVITIES_IN_INITIAL_ORDER){
2134 if(gt.rules.groupActivitiesInInitialOrderList.count()>0){
2135 QString s=GeneratePreTranslate::tr("Your data contains the option to group activities in the initial order.");
2136 s+="\n\n";
2137 s+=GeneratePreTranslate::tr("This option is nonstandard. It is recommended only if you know what you are doing,"
2138 " otherwise the solution might be impossible for FET to find.");
2139 s+=" ";
2140 s+=GeneratePreTranslate::tr("Use with caution.");
2141 s+="\n\n";
2142 s+=GeneratePreTranslate::tr("Are you sure you want to continue?");
2143
2144 #ifdef FET_COMMAND_LINE
2145 int b=GeneratePreReconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s, GeneratePreTranslate::tr("Yes"), GeneratePreTranslate::tr("No"), QString(), 0, 1);
2146 if(b!=0)
2147 return false;
2148 #else
2149 QMessageBox::StandardButton b=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"), s, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
2150 if(b!=QMessageBox::Yes)
2151 return false;
2152 #endif
2153 }
2154 }
2155
2156 if(SHOW_WARNING_FOR_ACTIVITIES_FIXED_SPACE_VIRTUAL_REAL_ROOMS_BUT_NOT_FIXED_TIME && !fixedVirtualSpaceNonZeroButNotTimeActivities.isEmpty()){
2157 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
2158 QList<int> tl=QList<int>(fixedVirtualSpaceNonZeroButNotTimeActivities.begin(), fixedVirtualSpaceNonZeroButNotTimeActivities.end());
2159 #else
2160 QList<int> tl=fixedVirtualSpaceNonZeroButNotTimeActivities.toList();
2161 #endif
2162 std::stable_sort(tl.begin(), tl.end());
2163
2164 QStringList tlids;
2165 for(int i : qAsConst(tl))
2166 tlids.append(CustomFETString::number(gt.rules.internalActivitiesList[i].id));
2167
2168 QString s=GeneratePreTranslate::tr("You have a number of %1 activities (listed below) which are not locked in time, but are locked in space"
2169 " into a virtual room (having specified also a nonempty list of selected real rooms). This might lead to impossible, cycling timetables (FET might"
2170 " not be able to find a timetable, even if one exists). It is recommended either to lock these activities also in time, or to"
2171 " remove the specified real rooms and leave only the preferred virtual room. This problematic situation was discovered when"
2172 " generating on a crafted file derived from a German example (the exact file name is %2). If after an initial successful generation"
2173 " you only lock the activities in space (but not also in time), FET seems to cycle indefinitely when trying to generate again on the newly obtained file.")
2174 .arg(tl.count())
2175 .arg("fet-v.v.v/examples/Germany/secondary-school-1/test-virtual-rooms-1/German-test-virtual-rooms-1.fet");
2176 s+="\n\n";
2177 s+=GeneratePreTranslate::tr("Are you sure you want to continue?");
2178 s+="\n\n";
2179 s+=GeneratePreTranslate::tr("Note: If an activity is fixed in a virtual room with a constraint activity preferred room with a 100% weight,"
2180 " it is considered locked in space only if the constraint also specifies a nonempty list of real rooms assigned for this activity"
2181 " (chosen from the list of sets of real rooms of the virtual room).");
2182 s+="\n\n";
2183 s+=GeneratePreTranslate::tr("Note: You can deactivate this warning from the Settings menu.");
2184 s+="\n\n";
2185 s+=GeneratePreTranslate::tr("The ids of the activities are: %1.")
2186 .arg(tlids.join(", "));
2187
2188 int t=GeneratePreReconcilableMessage::largeConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2189 GeneratePreTranslate::tr("Continue"), GeneratePreTranslate::tr("Cancel"), QString(), 0, 1);
2190
2191 if(t!=0)
2192 return false;
2193 }
2194
2195 bool ok=true;
2196
2197 return ok;
2198 }
2199
2200 //must be after allowed times, after n hours per subgroup and after max days per week for subgroups
computeSubgroupsMaxHoursDaily(QWidget * parent)2201 bool computeSubgroupsMaxHoursDaily(QWidget* parent)
2202 {
2203 thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight=false;
2204
2205 bool ok=true;
2206
2207 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
2208 subgroupsMaxHoursDailyMaxHours1[i]=-1;
2209 subgroupsMaxHoursDailyPercentages1[i]=-1;
2210
2211 subgroupsMaxHoursDailyMaxHours2[i]=-1;
2212 subgroupsMaxHoursDailyPercentages2[i]=-1;
2213 }
2214
2215 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
2216 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_HOURS_DAILY){
2217 ConstraintStudentsMaxHoursDaily* smd=(ConstraintStudentsMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
2218
2219 if(smd->weightPercentage<100.0)
2220 thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
2221
2222 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2223 if(subgroupsMaxHoursDailyMaxHours1[sb]==-1 ||
2224 (subgroupsMaxHoursDailyMaxHours1[sb] >= smd->maxHoursDaily &&
2225 subgroupsMaxHoursDailyPercentages1[sb] <= smd->weightPercentage)){
2226 subgroupsMaxHoursDailyMaxHours1[sb] = smd->maxHoursDaily;
2227 subgroupsMaxHoursDailyPercentages1[sb] = smd->weightPercentage;
2228 }
2229 else if(subgroupsMaxHoursDailyMaxHours1[sb] <= smd->maxHoursDaily &&
2230 subgroupsMaxHoursDailyPercentages1[sb] >= smd->weightPercentage){
2231 //nothing
2232 }
2233 else{
2234 if(subgroupsMaxHoursDailyMaxHours2[sb]==-1 ||
2235 (subgroupsMaxHoursDailyMaxHours2[sb] >= smd->maxHoursDaily &&
2236 subgroupsMaxHoursDailyPercentages2[sb] <= smd->weightPercentage)){
2237 subgroupsMaxHoursDailyMaxHours2[sb] = smd->maxHoursDaily;
2238 subgroupsMaxHoursDailyPercentages2[sb] = smd->weightPercentage;
2239 }
2240 else if(subgroupsMaxHoursDailyMaxHours2[sb] <= smd->maxHoursDaily &&
2241 subgroupsMaxHoursDailyPercentages2[sb] >= smd->weightPercentage){
2242 //nothing
2243 }
2244 else{
2245 //cannot proceed
2246 ok=false;
2247
2248 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2249 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are too many constraints"
2250 " of type max hours daily relating to it, which cannot be compressed in 2 constraints of this type."
2251 " Two constraints max hours can be compressed into a single one if the max hours are lower"
2252 " in the first one and the weight percentage is higher on the first one."
2253 " It is possible to use any number of such constraints for a subgroup, but their resultant must"
2254 " be maximum 2 constraints of type max hours daily.\n\n"
2255 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
2256 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
2257 " Please modify your data accordingly and try again.")
2258 .arg(gt.rules.internalSubgroupsList[sb]->name),
2259 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2260 1, 0 );
2261
2262 if(t==0)
2263 return false;
2264 }
2265 }
2266 }
2267 }
2268 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_DAILY){
2269 ConstraintStudentsSetMaxHoursDaily* smd=(ConstraintStudentsSetMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
2270
2271 if(smd->weightPercentage<100.0)
2272 thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
2273
2274 for(int q=0; q<smd->iSubgroupsList.count(); q++){
2275 int sb=smd->iSubgroupsList.at(q);
2276 //for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2277 if(subgroupsMaxHoursDailyMaxHours1[sb]==-1 ||
2278 (subgroupsMaxHoursDailyMaxHours1[sb] >= smd->maxHoursDaily &&
2279 subgroupsMaxHoursDailyPercentages1[sb] <= smd->weightPercentage)){
2280 subgroupsMaxHoursDailyMaxHours1[sb] = smd->maxHoursDaily;
2281 subgroupsMaxHoursDailyPercentages1[sb] = smd->weightPercentage;
2282 }
2283 else if(subgroupsMaxHoursDailyMaxHours1[sb] <= smd->maxHoursDaily &&
2284 subgroupsMaxHoursDailyPercentages1[sb] >= smd->weightPercentage){
2285 //nothing
2286 }
2287 else{
2288 if(subgroupsMaxHoursDailyMaxHours2[sb]==-1 ||
2289 (subgroupsMaxHoursDailyMaxHours2[sb] >= smd->maxHoursDaily &&
2290 subgroupsMaxHoursDailyPercentages2[sb] <= smd->weightPercentage)){
2291 subgroupsMaxHoursDailyMaxHours2[sb] = smd->maxHoursDaily;
2292 subgroupsMaxHoursDailyPercentages2[sb] = smd->weightPercentage;
2293 }
2294 else if(subgroupsMaxHoursDailyMaxHours2[sb] <= smd->maxHoursDaily &&
2295 subgroupsMaxHoursDailyPercentages2[sb] >= smd->weightPercentage){
2296 //nothing
2297 }
2298 else{
2299 //cannot proceed
2300 ok=false;
2301
2302 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2303 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are too many constraints"
2304 " of type max hours daily relating to it, which cannot be compressed in 2 constraints of this type."
2305 " Two constraints max hours can be compressed into a single one if the max hours are lower"
2306 " in the first one and the weight percentage is higher on the first one."
2307 " It is possible to use any number of such constraints for a subgroup, but their resultant must"
2308 " be maximum 2 constraints of type max hours daily.\n\n"
2309 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
2310 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
2311 " Please modify your data accordingly and try again.")
2312 .arg(gt.rules.internalSubgroupsList[sb]->name),
2313 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2314 1, 0 );
2315
2316 if(t==0)
2317 return false;
2318 }
2319 }
2320 }
2321 }
2322 }
2323
2324 Matrix1D<int> nAllowedSlotsPerDay;
2325 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
2326
2327 Matrix1D<int> dayAvailable;
2328 dayAvailable.resize(gt.rules.nDaysPerWeek);
2329
2330 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2331 if(subgroupsMaxHoursDailyPercentages1[sb]==100){
2332 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
2333 nAllowedSlotsPerDay[d]=0;
2334 for(int h=0; h<gt.rules.nHoursPerDay; h++)
2335 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sb][d][h])
2336 nAllowedSlotsPerDay[d]++;
2337 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],subgroupsMaxHoursDailyMaxHours1[sb]);
2338 }
2339
2340 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2341 dayAvailable[d]=1;
2342 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){
2343 //n days per week has 100% weight
2344 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2345 dayAvailable[d]=0;
2346 assert(subgroupsMaxDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek);
2347 for(int k=0; k<subgroupsMaxDaysPerWeekMaxDays[sb]; k++){
2348 int maxPos=-1, maxVal=-1;
2349 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2350 if(dayAvailable[d]==0)
2351 if(maxVal<nAllowedSlotsPerDay[d]){
2352 maxVal=nAllowedSlotsPerDay[d];
2353 maxPos=d;
2354 }
2355 assert(maxPos>=0);
2356 assert(dayAvailable[maxPos]==0);
2357 dayAvailable[maxPos]=1;
2358 }
2359 }
2360
2361 int total=0;
2362 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2363 if(dayAvailable[d]==1)
2364 total+=nAllowedSlotsPerDay[d];
2365 if(total<nHoursPerSubgroup[sb]){
2366 ok=false;
2367
2368 QString s;
2369 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
2370 " max %2 hours daily with 100% weight which cannot be respected because of number of days per week,"
2371 " number of hours per day, students (set) max days per week, students set not available and/or breaks."
2372 " The number of total hours for this subgroup is"
2373 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
2374 .arg(gt.rules.internalSubgroupsList[sb]->name)
2375 .arg(subgroupsMaxHoursDailyMaxHours1[sb])
2376 .arg(nHoursPerSubgroup[sb])
2377 .arg(total);
2378 s+="\n\n";
2379 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
2380
2381 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2382 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2383 1, 0 );
2384
2385 if(t==0)
2386 return false;
2387 }
2388 }
2389 }
2390
2391 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2392 if(subgroupsMaxHoursDailyPercentages2[sb]==100){
2393 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
2394 nAllowedSlotsPerDay[d]=0;
2395 for(int h=0; h<gt.rules.nHoursPerDay; h++)
2396 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sb][d][h])
2397 nAllowedSlotsPerDay[d]++;
2398 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],subgroupsMaxHoursDailyMaxHours2[sb]);
2399 }
2400
2401 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2402 dayAvailable[d]=1;
2403 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){
2404 //n days per week has 100% weight
2405 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2406 dayAvailable[d]=0;
2407 assert(subgroupsMaxDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek);
2408 for(int k=0; k<subgroupsMaxDaysPerWeekMaxDays[sb]; k++){
2409 int maxPos=-1, maxVal=-1;
2410 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2411 if(dayAvailable[d]==0)
2412 if(maxVal<nAllowedSlotsPerDay[d]){
2413 maxVal=nAllowedSlotsPerDay[d];
2414 maxPos=d;
2415 }
2416 assert(maxPos>=0);
2417 assert(dayAvailable[maxPos]==0);
2418 dayAvailable[maxPos]=1;
2419 }
2420 }
2421
2422 int total=0;
2423 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2424 if(dayAvailable[d]==1)
2425 total+=nAllowedSlotsPerDay[d];
2426 if(total<nHoursPerSubgroup[sb]){
2427 ok=false;
2428
2429 QString s;
2430 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
2431 " max %2 hours daily with 100% weight which cannot be respected because of number of days per week,"
2432 " number of hours per day, students (set) max days per week, students set not available and/or breaks."
2433 " The number of total hours for this subgroup is"
2434 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
2435 .arg(gt.rules.internalSubgroupsList[sb]->name)
2436 .arg(subgroupsMaxHoursDailyMaxHours2[sb])
2437 .arg(nHoursPerSubgroup[sb])
2438 .arg(total);
2439 s+="\n\n";
2440 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
2441
2442 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2443 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2444 1, 0 );
2445
2446 if(t==0)
2447 return false;
2448 }
2449 }
2450 }
2451
2452 return ok;
2453 }
2454
2455 //must be after allowed times and after n hours per subgroup
computeSubgroupsMaxHoursDailyRealDays(QWidget * parent)2456 bool computeSubgroupsMaxHoursDailyRealDays(QWidget* parent)
2457 {
2458 bool ok=true;
2459
2460 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
2461 subgroupsMaxHoursDailyRealDaysMaxHours1[i]=-1;
2462 subgroupsMaxHoursDailyRealDaysPercentages1[i]=-1;
2463
2464 subgroupsMaxHoursDailyRealDaysMaxHours2[i]=-1;
2465 subgroupsMaxHoursDailyRealDaysPercentages2[i]=-1;
2466 }
2467
2468 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
2469 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_HOURS_DAILY_REAL_DAYS){
2470 ConstraintStudentsMaxHoursDailyRealDays* smd=(ConstraintStudentsMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
2471
2472 if(smd->weightPercentage<100.0)
2473 thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
2474
2475 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2476 if(subgroupsMaxHoursDailyRealDaysMaxHours1[sb]==-1 ||
2477 (subgroupsMaxHoursDailyRealDaysMaxHours1[sb] >= smd->maxHoursDaily &&
2478 subgroupsMaxHoursDailyRealDaysPercentages1[sb] <= smd->weightPercentage)){
2479 subgroupsMaxHoursDailyRealDaysMaxHours1[sb] = smd->maxHoursDaily;
2480 subgroupsMaxHoursDailyRealDaysPercentages1[sb] = smd->weightPercentage;
2481 }
2482 else if(subgroupsMaxHoursDailyRealDaysMaxHours1[sb] <= smd->maxHoursDaily &&
2483 subgroupsMaxHoursDailyRealDaysPercentages1[sb] >= smd->weightPercentage){
2484 //nothing
2485 }
2486 else{
2487 if(subgroupsMaxHoursDailyRealDaysMaxHours2[sb]==-1 ||
2488 (subgroupsMaxHoursDailyRealDaysMaxHours2[sb] >= smd->maxHoursDaily &&
2489 subgroupsMaxHoursDailyRealDaysPercentages2[sb] <= smd->weightPercentage)){
2490 subgroupsMaxHoursDailyRealDaysMaxHours2[sb] = smd->maxHoursDaily;
2491 subgroupsMaxHoursDailyRealDaysPercentages2[sb] = smd->weightPercentage;
2492 }
2493 else if(subgroupsMaxHoursDailyRealDaysMaxHours2[sb] <= smd->maxHoursDaily &&
2494 subgroupsMaxHoursDailyRealDaysPercentages2[sb] >= smd->weightPercentage){
2495 //nothing
2496 }
2497 else{
2498 //cannot proceed
2499 ok=false;
2500
2501 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2502 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are too many constraints"
2503 " of type max hours daily for real days relating to it, which cannot be compressed in 2 constraints of this type."
2504 " Two constraints max hours can be compressed into a single one if the max hours are lower"
2505 " in the first one and the weight percentage is higher on the first one."
2506 " It is possible to use any number of such constraints for a subgroup, but their resultant must"
2507 " be maximum 2 constraints of type max hours daily for real days.\n\n"
2508 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
2509 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
2510 " Please modify your data accordingly and try again.")
2511 .arg(gt.rules.internalSubgroupsList[sb]->name),
2512 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2513 1, 0 );
2514
2515 if(t==0)
2516 return false;
2517 }
2518 }
2519 }
2520 }
2521 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_DAILY_REAL_DAYS){
2522 ConstraintStudentsSetMaxHoursDailyRealDays* smd=(ConstraintStudentsSetMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
2523
2524 if(smd->weightPercentage<100.0)
2525 thereAreSubgroupsWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
2526
2527 for(int q=0; q<smd->iSubgroupsList.count(); q++){
2528 int sb=smd->iSubgroupsList.at(q);
2529 //for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2530 if(subgroupsMaxHoursDailyRealDaysMaxHours1[sb]==-1 ||
2531 (subgroupsMaxHoursDailyRealDaysMaxHours1[sb] >= smd->maxHoursDaily &&
2532 subgroupsMaxHoursDailyRealDaysPercentages1[sb] <= smd->weightPercentage)){
2533 subgroupsMaxHoursDailyRealDaysMaxHours1[sb] = smd->maxHoursDaily;
2534 subgroupsMaxHoursDailyRealDaysPercentages1[sb] = smd->weightPercentage;
2535 }
2536 else if(subgroupsMaxHoursDailyRealDaysMaxHours1[sb] <= smd->maxHoursDaily &&
2537 subgroupsMaxHoursDailyRealDaysPercentages1[sb] >= smd->weightPercentage){
2538 //nothing
2539 }
2540 else{
2541 if(subgroupsMaxHoursDailyRealDaysMaxHours2[sb]==-1 ||
2542 (subgroupsMaxHoursDailyRealDaysMaxHours2[sb] >= smd->maxHoursDaily &&
2543 subgroupsMaxHoursDailyRealDaysPercentages2[sb] <= smd->weightPercentage)){
2544 subgroupsMaxHoursDailyRealDaysMaxHours2[sb] = smd->maxHoursDaily;
2545 subgroupsMaxHoursDailyRealDaysPercentages2[sb] = smd->weightPercentage;
2546 }
2547 else if(subgroupsMaxHoursDailyRealDaysMaxHours2[sb] <= smd->maxHoursDaily &&
2548 subgroupsMaxHoursDailyRealDaysPercentages2[sb] >= smd->weightPercentage){
2549 //nothing
2550 }
2551 else{
2552 //cannot proceed
2553 ok=false;
2554
2555 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2556 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are too many constraints"
2557 " of type max hours daily for real days relating to it, which cannot be compressed in 2 constraints of this type."
2558 " Two constraints max hours can be compressed into a single one if the max hours are lower"
2559 " in the first one and the weight percentage is higher on the first one."
2560 " It is possible to use any number of such constraints for a subgroup, but their resultant must"
2561 " be maximum 2 constraints of type max hours daily for real days.\n\n"
2562 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
2563 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
2564 " Please modify your data accordingly and try again.")
2565 .arg(gt.rules.internalSubgroupsList[sb]->name),
2566 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2567 1, 0 );
2568
2569 if(t==0)
2570 return false;
2571 }
2572 }
2573 }
2574 }
2575 }
2576
2577 if(gt.rules.mode==MORNINGS_AFTERNOONS)
2578 assert(gt.rules.nDaysPerWeek%2==0); //this is taken care of previously - the generation cannot begin otherwise
2579
2580 Matrix1D<int> nAllowedSlotsPerDay;
2581 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek/2);
2582 Matrix1D<int> dayAvailable;
2583 dayAvailable.resize(gt.rules.nDaysPerWeek/2);
2584 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2585 if(subgroupsMaxHoursDailyRealDaysPercentages1[sb]==100){
2586 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
2587 nAllowedSlotsPerDay[d]=0;
2588 for(int h=0; h<gt.rules.nHoursPerDay; h++){
2589 if(!breakDayHour[2*d][h] && !subgroupNotAvailableDayHour[sb][2*d][h])
2590 nAllowedSlotsPerDay[d]++;
2591 if(!breakDayHour[2*d+1][h] && !subgroupNotAvailableDayHour[sb][2*d+1][h])
2592 nAllowedSlotsPerDay[d]++;
2593 }
2594 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],subgroupsMaxHoursDailyRealDaysMaxHours1[sb]);
2595 }
2596
2597 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2598 dayAvailable[d]=1;
2599 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0){
2600 //n days per week has 100% weight
2601 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2602 dayAvailable[d]=0;
2603 assert(subgroupsMaxRealDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek/2);
2604 for(int k=0; k<subgroupsMaxRealDaysPerWeekMaxDays[sb]; k++){
2605 int maxPos=-1, maxVal=-1;
2606 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2607 if(dayAvailable[d]==0)
2608 if(maxVal<nAllowedSlotsPerDay[d]){
2609 maxVal=nAllowedSlotsPerDay[d];
2610 maxPos=d;
2611 }
2612 assert(maxPos>=0);
2613 assert(dayAvailable[maxPos]==0);
2614 dayAvailable[maxPos]=1;
2615 }
2616 }
2617
2618 int total=0;
2619 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2620 if(dayAvailable[d]==1)
2621 total+=nAllowedSlotsPerDay[d];
2622 if(total<nHoursPerSubgroup[sb]){
2623 ok=false;
2624
2625 QString s;
2626 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
2627 " max %2 hours daily for real days with 100% weight which cannot be respected because of number of days per week,"
2628 " number of hours per day, students (set) max real days per week, students set not available and/or breaks."
2629 " The number of total hours for this subgroup is"
2630 " %3 and the number of available slots is, considering max hours daily for real days and all other constraints, %4.")
2631 .arg(gt.rules.internalSubgroupsList[sb]->name)
2632 .arg(subgroupsMaxHoursDailyRealDaysMaxHours1[sb])
2633 .arg(nHoursPerSubgroup[sb])
2634 .arg(total);
2635 s+="\n\n";
2636 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
2637
2638 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2639 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2640 1, 0 );
2641
2642 if(t==0)
2643 return false;
2644 }
2645 }
2646 }
2647
2648 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2649 if(subgroupsMaxHoursDailyRealDaysPercentages2[sb]==100){
2650 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
2651 nAllowedSlotsPerDay[d]=0;
2652 for(int h=0; h<gt.rules.nHoursPerDay; h++){
2653 if(!breakDayHour[2*d][h] && !subgroupNotAvailableDayHour[sb][2*d][h])
2654 nAllowedSlotsPerDay[d]++;
2655 if(!breakDayHour[2*d+1][h] && !subgroupNotAvailableDayHour[sb][2*d+1][h])
2656 nAllowedSlotsPerDay[d]++;
2657 }
2658 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],subgroupsMaxHoursDailyRealDaysMaxHours1[sb]);
2659 }
2660
2661 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2662 dayAvailable[d]=1;
2663 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0){
2664 //n days per week has 100% weight
2665 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2666 dayAvailable[d]=0;
2667 assert(subgroupsMaxRealDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek/2);
2668 for(int k=0; k<subgroupsMaxRealDaysPerWeekMaxDays[sb]; k++){
2669 int maxPos=-1, maxVal=-1;
2670 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2671 if(dayAvailable[d]==0)
2672 if(maxVal<nAllowedSlotsPerDay[d]){
2673 maxVal=nAllowedSlotsPerDay[d];
2674 maxPos=d;
2675 }
2676 assert(maxPos>=0);
2677 assert(dayAvailable[maxPos]==0);
2678 dayAvailable[maxPos]=1;
2679 }
2680 }
2681
2682 int total=0;
2683 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2684 if(dayAvailable[d]==1)
2685 total+=nAllowedSlotsPerDay[d];
2686 if(total<nHoursPerSubgroup[sb]){
2687 ok=false;
2688
2689 QString s;
2690 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
2691 " max %2 hours daily for real days with 100% weight which cannot be respected because of number of days per week,"
2692 " number of hours per day, students (set) max real days per week, students set not available and/or breaks."
2693 " The number of total hours for this subgroup is"
2694 " %3 and the number of available slots is, considering max hours daily for real days and all other constraints, %4.")
2695 .arg(gt.rules.internalSubgroupsList[sb]->name)
2696 .arg(subgroupsMaxHoursDailyRealDaysMaxHours2[sb])
2697 .arg(nHoursPerSubgroup[sb])
2698 .arg(total);
2699 s+="\n\n";
2700 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
2701
2702 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2703 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2704 1, 0 );
2705
2706 if(t==0)
2707 return false;
2708 }
2709 }
2710 }
2711
2712 return ok;
2713 }
2714
2715 //must be after allowed times, after n hours per subgroup and after max days per week for subgroups
computeSubgroupsMaxSpanPerDay(QWidget * parent)2716 bool computeSubgroupsMaxSpanPerDay(QWidget* parent)
2717 {
2718 bool ok=true;
2719
2720 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
2721 subgroupsMaxSpanPerDayMaxSpan[i]=-1;
2722 subgroupsMaxSpanPerDayPercentages[i]=-1;
2723 }
2724
2725 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
2726 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_SPAN_PER_DAY){
2727 ConstraintStudentsSetMaxSpanPerDay* ssmsd=(ConstraintStudentsSetMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
2728
2729 if(ssmsd->weightPercentage!=100){
2730 ok=false;
2731
2732 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2733 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max span per day for students %1"
2734 " with weight (percentage) below 100. Please make weight 100% and try again").arg(ssmsd->students),
2735 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2736 1, 0 );
2737
2738 if(t==0)
2739 return false;
2740 }
2741 }
2742 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_SPAN_PER_DAY){
2743 ConstraintStudentsMaxSpanPerDay* smsd=(ConstraintStudentsMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
2744
2745 if(smsd->weightPercentage!=100){
2746 ok=false;
2747
2748 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2749 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max span per day"
2750 " with weight (percentage) below 100. Please make weight 100% and try again"),
2751 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2752 1, 0 );
2753
2754 if(t==0)
2755 return false;
2756 }
2757 }
2758 }
2759
2760 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
2761 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_SPAN_PER_DAY){
2762 ConstraintStudentsSetMaxSpanPerDay* ssmsd=(ConstraintStudentsSetMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
2763
2764 for(int sbg : qAsConst(ssmsd->iSubgroupsList))
2765 if(subgroupsMaxSpanPerDayPercentages[sbg]==-1
2766 || (subgroupsMaxSpanPerDayPercentages[sbg]>=0 && subgroupsMaxSpanPerDayMaxSpan[sbg]>ssmsd->maxSpanPerDay)){
2767 subgroupsMaxSpanPerDayPercentages[sbg]=100.0;
2768 subgroupsMaxSpanPerDayMaxSpan[sbg]=ssmsd->maxSpanPerDay;
2769 }
2770 }
2771 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_SPAN_PER_DAY){
2772 ConstraintStudentsMaxSpanPerDay* smsd=(ConstraintStudentsMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
2773
2774 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
2775 if(subgroupsMaxSpanPerDayPercentages[sbg]==-1
2776 || (subgroupsMaxSpanPerDayPercentages[sbg]>=0 && subgroupsMaxSpanPerDayMaxSpan[sbg]>smsd->maxSpanPerDay)){
2777 subgroupsMaxSpanPerDayPercentages[sbg]=100.0;
2778 subgroupsMaxSpanPerDayMaxSpan[sbg]=smsd->maxSpanPerDay;
2779 }
2780 }
2781 }
2782 }
2783
2784 //This is similar to subgroups max hours daily checking. It is not a very useful test, but does not hurt.
2785
2786 Matrix1D<int> nAllowedSlotsPerDay;
2787 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
2788
2789 Matrix1D<int> dayAvailable;
2790 dayAvailable.resize(gt.rules.nDaysPerWeek);
2791
2792 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2793 if(subgroupsMaxSpanPerDayPercentages[sb]==100){
2794 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
2795 nAllowedSlotsPerDay[d]=0;
2796 for(int h=0; h<gt.rules.nHoursPerDay; h++)
2797 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sb][d][h])
2798 nAllowedSlotsPerDay[d]++;
2799 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],subgroupsMaxSpanPerDayMaxSpan[sb]);
2800 }
2801
2802 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2803 dayAvailable[d]=1;
2804 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){
2805 //n days per week has 100% weight
2806 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2807 dayAvailable[d]=0;
2808 assert(subgroupsMaxDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek);
2809 for(int k=0; k<subgroupsMaxDaysPerWeekMaxDays[sb]; k++){
2810 int maxPos=-1, maxVal=-1;
2811 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2812 if(dayAvailable[d]==0)
2813 if(maxVal<nAllowedSlotsPerDay[d]){
2814 maxVal=nAllowedSlotsPerDay[d];
2815 maxPos=d;
2816 }
2817 assert(maxPos>=0);
2818 assert(dayAvailable[maxPos]==0);
2819 dayAvailable[maxPos]=1;
2820 }
2821 }
2822
2823 int total=0;
2824 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
2825 if(dayAvailable[d]==1)
2826 total+=nAllowedSlotsPerDay[d];
2827 if(total<nHoursPerSubgroup[sb]){
2828 ok=false;
2829
2830 QString s;
2831 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
2832 " max %2 span per day with 100% weight which cannot be respected because of number of days per week,"
2833 " number of hours per day, students (set) max days per week, students set not available and/or breaks."
2834 " The number of total hours for this subgroup is"
2835 " %3 and the number of available slots is, considering max span per day and all other constraints, %4.")
2836 .arg(gt.rules.internalSubgroupsList[sb]->name)
2837 .arg(subgroupsMaxSpanPerDayMaxSpan[sb])
2838 .arg(nHoursPerSubgroup[sb])
2839 .arg(total);
2840 s+="\n\n";
2841 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
2842
2843 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2844 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2845 1, 0 );
2846
2847 if(t==0)
2848 return false;
2849 }
2850 }
2851 }
2852
2853 return ok;
2854 }
2855
2856 //must be after allowed times, after n hours per subgroup and after max days per week for subgroups
computeSubgroupsMaxSpanPerRealDay(QWidget * parent)2857 bool computeSubgroupsMaxSpanPerRealDay(QWidget* parent)
2858 {
2859 bool ok=true;
2860
2861 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
2862 subgroupsMaxSpanPerRealDayMaxSpan[i]=-1;
2863 subgroupsMaxSpanPerRealDayPercentages[i]=-1;
2864 }
2865
2866 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
2867 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_SPAN_PER_REAL_DAY){
2868 ConstraintStudentsSetMaxSpanPerRealDay* ssmsd=(ConstraintStudentsSetMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
2869
2870 if(ssmsd->weightPercentage!=100){
2871 ok=false;
2872
2873 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2874 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max span per real day for students %1"
2875 " with weight (percentage) below 100. Please make weight 100% and try again").arg(ssmsd->students),
2876 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2877 1, 0 );
2878
2879 if(t==0)
2880 return false;
2881 }
2882 }
2883 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_SPAN_PER_REAL_DAY){
2884 ConstraintStudentsMaxSpanPerRealDay* smsd=(ConstraintStudentsMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
2885
2886 if(smsd->weightPercentage!=100){
2887 ok=false;
2888
2889 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
2890 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max span per real day"
2891 " with weight (percentage) below 100. Please make weight 100% and try again"),
2892 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2893 1, 0 );
2894
2895 if(t==0)
2896 return false;
2897 }
2898 }
2899 }
2900
2901 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
2902 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_SPAN_PER_REAL_DAY){
2903 ConstraintStudentsSetMaxSpanPerRealDay* ssmsd=(ConstraintStudentsSetMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
2904
2905 for(int sbg : qAsConst(ssmsd->iSubgroupsList))
2906 if(subgroupsMaxSpanPerRealDayPercentages[sbg]==-1
2907 || (subgroupsMaxSpanPerRealDayPercentages[sbg]>=0 && subgroupsMaxSpanPerRealDayMaxSpan[sbg]>ssmsd->maxSpanPerDay)){
2908 subgroupsMaxSpanPerRealDayPercentages[sbg]=100.0;
2909 subgroupsMaxSpanPerRealDayMaxSpan[sbg]=ssmsd->maxSpanPerDay;
2910 }
2911 }
2912 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_SPAN_PER_REAL_DAY){
2913 ConstraintStudentsMaxSpanPerRealDay* smsd=(ConstraintStudentsMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
2914
2915 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
2916 if(subgroupsMaxSpanPerRealDayPercentages[sbg]==-1
2917 || (subgroupsMaxSpanPerRealDayPercentages[sbg]>=0 && subgroupsMaxSpanPerRealDayMaxSpan[sbg]>smsd->maxSpanPerDay)){
2918 subgroupsMaxSpanPerRealDayPercentages[sbg]=100.0;
2919 subgroupsMaxSpanPerRealDayMaxSpan[sbg]=smsd->maxSpanPerDay;
2920 }
2921 }
2922 }
2923 }
2924
2925 if(gt.rules.mode==MORNINGS_AFTERNOONS)
2926 assert(gt.rules.nDaysPerWeek%2==0); //this is taken care of previously - the generation cannot begin otherwise
2927
2928 //This is similar to subgroups max hours daily checking. It is not a very useful test, but does not hurt.
2929 Matrix1D<int> nAllowedSlotsPerDay;
2930 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek/2);
2931 Matrix1D<int> dayAvailable;
2932 dayAvailable.resize(gt.rules.nDaysPerWeek/2);
2933 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
2934 if(subgroupsMaxSpanPerRealDayPercentages[sb]==100){
2935 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
2936 nAllowedSlotsPerDay[d]=0;
2937 for(int h=0; h<gt.rules.nHoursPerDay; h++){
2938 if(!breakDayHour[2*d][h] && !subgroupNotAvailableDayHour[sb][2*d][h])
2939 nAllowedSlotsPerDay[d]++;
2940 if(!breakDayHour[2*d+1][h] && !subgroupNotAvailableDayHour[sb][2*d+1][h])
2941 nAllowedSlotsPerDay[d]++;
2942 }
2943 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],subgroupsMaxSpanPerRealDayMaxSpan[sb]);
2944 }
2945
2946 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2947 dayAvailable[d]=1;
2948 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0){
2949 //n days per week has 100% weight
2950 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2951 dayAvailable[d]=0;
2952 assert(subgroupsMaxRealDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek/2);
2953 for(int k=0; k<subgroupsMaxRealDaysPerWeekMaxDays[sb]; k++){
2954 int maxPos=-1, maxVal=-1;
2955 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2956 if(dayAvailable[d]==0)
2957 if(maxVal<nAllowedSlotsPerDay[d]){
2958 maxVal=nAllowedSlotsPerDay[d];
2959 maxPos=d;
2960 }
2961 assert(maxPos>=0);
2962 assert(dayAvailable[maxPos]==0);
2963 dayAvailable[maxPos]=1;
2964 }
2965 }
2966
2967 int total=0;
2968 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
2969 if(dayAvailable[d]==1)
2970 total+=nAllowedSlotsPerDay[d];
2971 if(total<nHoursPerSubgroup[sb]){
2972 ok=false;
2973
2974 QString s;
2975 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
2976 " max %2 span per real day with 100% weight which cannot be respected because of number of days per week,"
2977 " number of hours per day, students (set) max real days per week, students set not available and/or breaks."
2978 " The number of total hours for this subgroup is"
2979 " %3 and the number of available slots is, considering max span per real day and all other constraints, %4.")
2980 .arg(gt.rules.internalSubgroupsList[sb]->name)
2981 .arg(subgroupsMaxSpanPerRealDayMaxSpan[sb])
2982 .arg(nHoursPerSubgroup[sb])
2983 .arg(total);
2984 s+="\n\n";
2985 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
2986
2987 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
2988 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
2989 1, 0 );
2990
2991 if(t==0)
2992 return false;
2993 }
2994 }
2995 }
2996
2997 return ok;
2998 }
2999
computeStudentsMaxHoursContinuously(QWidget * parent)3000 bool computeStudentsMaxHoursContinuously(QWidget* parent)
3001 {
3002 bool ok=true;
3003
3004 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
3005 subgroupsMaxHoursContinuouslyMaxHours1[i]=-1;
3006 subgroupsMaxHoursContinuouslyPercentages1[i]=-1;
3007
3008 subgroupsMaxHoursContinuouslyMaxHours2[i]=-1;
3009 subgroupsMaxHoursContinuouslyPercentages2[i]=-1;
3010 }
3011
3012 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
3013 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_HOURS_CONTINUOUSLY){
3014 ConstraintStudentsMaxHoursContinuously* smd=(ConstraintStudentsMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
3015
3016 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
3017 if(subgroupsMaxHoursContinuouslyMaxHours1[sb]==-1 ||
3018 (subgroupsMaxHoursContinuouslyMaxHours1[sb] >= smd->maxHoursContinuously &&
3019 subgroupsMaxHoursContinuouslyPercentages1[sb] <= smd->weightPercentage)){
3020 subgroupsMaxHoursContinuouslyMaxHours1[sb] = smd->maxHoursContinuously;
3021 subgroupsMaxHoursContinuouslyPercentages1[sb] = smd->weightPercentage;
3022 }
3023 else if(subgroupsMaxHoursContinuouslyMaxHours1[sb] <= smd->maxHoursContinuously &&
3024 subgroupsMaxHoursContinuouslyPercentages1[sb] >= smd->weightPercentage){
3025 //nothing
3026 }
3027 else{
3028 if(subgroupsMaxHoursContinuouslyMaxHours2[sb]==-1 ||
3029 (subgroupsMaxHoursContinuouslyMaxHours2[sb] >= smd->maxHoursContinuously &&
3030 subgroupsMaxHoursContinuouslyPercentages2[sb] <= smd->weightPercentage)){
3031 subgroupsMaxHoursContinuouslyMaxHours2[sb] = smd->maxHoursContinuously;
3032 subgroupsMaxHoursContinuouslyPercentages2[sb] = smd->weightPercentage;
3033 }
3034 else if(subgroupsMaxHoursContinuouslyMaxHours2[sb] <= smd->maxHoursContinuously &&
3035 subgroupsMaxHoursContinuouslyPercentages2[sb] >= smd->weightPercentage){
3036 //nothing
3037 }
3038 else{
3039 //cannot proceed
3040 ok=false;
3041
3042 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3043 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are too many constraints"
3044 " of type max hours continuously relating to it, which cannot be compressed in 2 constraints of this type."
3045 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3046 " in the first one and the weight percentage is higher on the first one."
3047 " It is possible to use any number of such constraints for a subgroup, but their resultant must"
3048 " be maximum 2 constraints of type max hours continuously.\n\n"
3049 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3050 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3051 " Please modify your data accordingly and try again.")
3052 .arg(gt.rules.internalSubgroupsList[sb]->name),
3053 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3054 1, 0 );
3055
3056 if(t==0)
3057 return false;
3058 }
3059 }
3060 }
3061 }
3062 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_CONTINUOUSLY){
3063 ConstraintStudentsSetMaxHoursContinuously* smd=(ConstraintStudentsSetMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
3064
3065 for(int q=0; q<smd->iSubgroupsList.count(); q++){
3066 int sb=smd->iSubgroupsList.at(q);
3067 //for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
3068 if(subgroupsMaxHoursContinuouslyMaxHours1[sb]==-1 ||
3069 (subgroupsMaxHoursContinuouslyMaxHours1[sb] >= smd->maxHoursContinuously &&
3070 subgroupsMaxHoursContinuouslyPercentages1[sb] <= smd->weightPercentage)){
3071 subgroupsMaxHoursContinuouslyMaxHours1[sb] = smd->maxHoursContinuously;
3072 subgroupsMaxHoursContinuouslyPercentages1[sb] = smd->weightPercentage;
3073 }
3074 else if(subgroupsMaxHoursContinuouslyMaxHours1[sb] <= smd->maxHoursContinuously &&
3075 subgroupsMaxHoursContinuouslyPercentages1[sb] >= smd->weightPercentage){
3076 //nothing
3077 }
3078 else{
3079 if(subgroupsMaxHoursContinuouslyMaxHours2[sb]==-1 ||
3080 (subgroupsMaxHoursContinuouslyMaxHours2[sb] >= smd->maxHoursContinuously &&
3081 subgroupsMaxHoursContinuouslyPercentages2[sb] <= smd->weightPercentage)){
3082 subgroupsMaxHoursContinuouslyMaxHours2[sb] = smd->maxHoursContinuously;
3083 subgroupsMaxHoursContinuouslyPercentages2[sb] = smd->weightPercentage;
3084 }
3085 else if(subgroupsMaxHoursContinuouslyMaxHours2[sb] <= smd->maxHoursContinuously &&
3086 subgroupsMaxHoursContinuouslyPercentages2[sb] >= smd->weightPercentage){
3087 //nothing
3088 }
3089 else{
3090 //cannot proceed
3091 ok=false;
3092
3093 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3094 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are too many constraints"
3095 " of type max hours continuously relating to it, which cannot be compressed in 2 constraints of this type."
3096 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3097 " in the first one and the weight percentage is higher on the first one."
3098 " It is possible to use any number of such constraints for a subgroup, but their resultant must"
3099 " be maximum 2 constraints of type max hours continuously.\n\n"
3100 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3101 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3102 " Please modify your data accordingly and try again.")
3103 .arg(gt.rules.internalSubgroupsList[sb]->name),
3104 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3105 1, 0 );
3106
3107 if(t==0)
3108 return false;
3109 }
3110 }
3111 }
3112 }
3113 }
3114
3115 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
3116 for(int sbg : qAsConst(gt.rules.internalActivitiesList[ai].iSubgroupsList)){
3117 if(subgroupsMaxHoursContinuouslyPercentages1[sbg]>=0 && gt.rules.internalActivitiesList[ai].duration > subgroupsMaxHoursContinuouslyMaxHours1[sbg]){
3118 QString s;
3119 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
3120 " max %2 hours continuously which cannot be respected because of activity with id %3 (which has duration %4).")
3121 .arg(gt.rules.internalSubgroupsList[sbg]->name)
3122 .arg(subgroupsMaxHoursContinuouslyMaxHours1[sbg])
3123 .arg(gt.rules.internalActivitiesList[ai].id)
3124 .arg(gt.rules.internalActivitiesList[ai].duration);
3125 s+="\n\n";
3126 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
3127
3128 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
3129 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3130 1, 0 );
3131
3132 if(t==0)
3133 return false;
3134 }
3135 if(subgroupsMaxHoursContinuouslyPercentages2[sbg]>=0 && gt.rules.internalActivitiesList[ai].duration > subgroupsMaxHoursContinuouslyMaxHours2[sbg]){
3136 QString s;
3137 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint of type"
3138 " max %2 hours continuously which cannot be respected because of activity with id %3 (which has duration %4).")
3139 .arg(gt.rules.internalSubgroupsList[sbg]->name)
3140 .arg(subgroupsMaxHoursContinuouslyMaxHours2[sbg])
3141 .arg(gt.rules.internalActivitiesList[ai].id)
3142 .arg(gt.rules.internalActivitiesList[ai].duration);
3143 s+="\n\n";
3144 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
3145
3146 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
3147 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3148 1, 0 );
3149
3150 if(t==0)
3151 return false;
3152 }
3153 }
3154 }
3155
3156 return ok;
3157 }
3158
computeStudentsActivityTagMaxHoursDaily(QWidget * parent)3159 bool computeStudentsActivityTagMaxHoursDaily(QWidget* parent)
3160 {
3161 haveStudentsActivityTagMaxHoursDaily=false;
3162
3163 bool ok=true;
3164
3165 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
3166 subgroupsActivityTagMaxHoursDailyMaxHours[i].clear();
3167 subgroupsActivityTagMaxHoursDailyPercentage[i].clear();
3168 subgroupsActivityTagMaxHoursDailyActivityTag[i].clear();
3169 }
3170
3171 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
3172 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_DAILY){
3173 haveStudentsActivityTagMaxHoursDaily=true;
3174
3175 ConstraintStudentsActivityTagMaxHoursDaily* samd=(ConstraintStudentsActivityTagMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
3176
3177 for(int sb : qAsConst(samd->canonicalSubgroupsList)){
3178 int pos1=-1, pos2=-1;
3179
3180 for(int j=0; j<subgroupsActivityTagMaxHoursDailyMaxHours[sb].count(); j++){
3181 if(subgroupsActivityTagMaxHoursDailyActivityTag[sb].at(j)==samd->activityTagIndex){
3182 if(pos1==-1){
3183 pos1=j;
3184 }
3185 else{
3186 assert(pos2==-1);
3187 pos2=j;
3188 }
3189 }
3190 }
3191
3192 if(pos1==-1){
3193 subgroupsActivityTagMaxHoursDailyActivityTag[sb].append(samd->activityTagIndex);
3194 subgroupsActivityTagMaxHoursDailyMaxHours[sb].append(samd->maxHoursDaily);
3195 subgroupsActivityTagMaxHoursDailyPercentage[sb].append(samd->weightPercentage);
3196 }
3197 else{
3198 if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos1) <= samd->maxHoursDaily
3199 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos1) >= samd->weightPercentage){
3200 //do nothing
3201 }
3202 else if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos1) >= samd->maxHoursDaily
3203 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos1) <= samd->weightPercentage){
3204
3205 subgroupsActivityTagMaxHoursDailyActivityTag[sb][pos1]=samd->activityTagIndex;
3206 subgroupsActivityTagMaxHoursDailyMaxHours[sb][pos1]=samd->maxHoursDaily;
3207 subgroupsActivityTagMaxHoursDailyPercentage[sb][pos1]=samd->weightPercentage;
3208 }
3209 else{
3210 if(pos2==-1){
3211 subgroupsActivityTagMaxHoursDailyActivityTag[sb].append(samd->activityTagIndex);
3212 subgroupsActivityTagMaxHoursDailyMaxHours[sb].append(samd->maxHoursDaily);
3213 subgroupsActivityTagMaxHoursDailyPercentage[sb].append(samd->weightPercentage);
3214 }
3215 else{
3216
3217 if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos2) <= samd->maxHoursDaily
3218 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos2) >= samd->weightPercentage){
3219 //do nothing
3220 }
3221 else if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos2) >= samd->maxHoursDaily
3222 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos2) <= samd->weightPercentage){
3223
3224 subgroupsActivityTagMaxHoursDailyActivityTag[sb][pos2]=samd->activityTagIndex;
3225 subgroupsActivityTagMaxHoursDailyMaxHours[sb][pos2]=samd->maxHoursDaily;
3226 subgroupsActivityTagMaxHoursDailyPercentage[sb][pos2]=samd->weightPercentage;
3227 }
3228 else{
3229 ok=false;
3230
3231 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3232 GeneratePreTranslate::tr("Cannot optimize for subgroup %1 and activity tag %2, because there are too many constraints"
3233 " of type activity tag max hours daily relating to them, which cannot be compressed in 2 constraints of this type."
3234 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3235 " in the first one and the weight percentage is higher on the first one."
3236 " It is possible to use any number of such constraints for a subgroup and an activity tag, but their resultant must"
3237 " be maximum 2 constraints of type activity tag max hours daily.\n\n"
3238 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3239 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3240 " Please modify your data accordingly and try again.")
3241 .arg(gt.rules.internalSubgroupsList[sb]->name)
3242 .arg(samd->activityTagName),
3243 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3244 1, 0 );
3245
3246 if(t==0)
3247 return false;
3248 }
3249 }
3250 }
3251 }
3252 }
3253 }
3254 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_DAILY){
3255 haveStudentsActivityTagMaxHoursDaily=true;
3256
3257 ConstraintStudentsSetActivityTagMaxHoursDaily* samd=(ConstraintStudentsSetActivityTagMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
3258
3259 for(int sb : qAsConst(samd->canonicalSubgroupsList)){
3260 int pos1=-1, pos2=-1;
3261
3262 for(int j=0; j<subgroupsActivityTagMaxHoursDailyMaxHours[sb].count(); j++){
3263 if(subgroupsActivityTagMaxHoursDailyActivityTag[sb].at(j)==samd->activityTagIndex){
3264 if(pos1==-1){
3265 pos1=j;
3266 }
3267 else{
3268 assert(pos2==-1);
3269 pos2=j;
3270 }
3271 }
3272 }
3273
3274 if(pos1==-1){
3275 subgroupsActivityTagMaxHoursDailyActivityTag[sb].append(samd->activityTagIndex);
3276 subgroupsActivityTagMaxHoursDailyMaxHours[sb].append(samd->maxHoursDaily);
3277 subgroupsActivityTagMaxHoursDailyPercentage[sb].append(samd->weightPercentage);
3278 }
3279 else{
3280 if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos1) <= samd->maxHoursDaily
3281 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos1) >= samd->weightPercentage){
3282 //do nothing
3283 }
3284 else if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos1) >= samd->maxHoursDaily
3285 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos1) <= samd->weightPercentage){
3286
3287 subgroupsActivityTagMaxHoursDailyActivityTag[sb][pos1]=samd->activityTagIndex;
3288 subgroupsActivityTagMaxHoursDailyMaxHours[sb][pos1]=samd->maxHoursDaily;
3289 subgroupsActivityTagMaxHoursDailyPercentage[sb][pos1]=samd->weightPercentage;
3290 }
3291 else{
3292 if(pos2==-1){
3293 subgroupsActivityTagMaxHoursDailyActivityTag[sb].append(samd->activityTagIndex);
3294 subgroupsActivityTagMaxHoursDailyMaxHours[sb].append(samd->maxHoursDaily);
3295 subgroupsActivityTagMaxHoursDailyPercentage[sb].append(samd->weightPercentage);
3296 }
3297 else{
3298
3299 if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos2) <= samd->maxHoursDaily
3300 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos2) >= samd->weightPercentage){
3301 //do nothing
3302 }
3303 else if(subgroupsActivityTagMaxHoursDailyMaxHours[sb].at(pos2) >= samd->maxHoursDaily
3304 && subgroupsActivityTagMaxHoursDailyPercentage[sb].at(pos2) <= samd->weightPercentage){
3305
3306 subgroupsActivityTagMaxHoursDailyActivityTag[sb][pos2]=samd->activityTagIndex;
3307 subgroupsActivityTagMaxHoursDailyMaxHours[sb][pos2]=samd->maxHoursDaily;
3308 subgroupsActivityTagMaxHoursDailyPercentage[sb][pos2]=samd->weightPercentage;
3309 }
3310 else{
3311 ok=false;
3312
3313 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3314 GeneratePreTranslate::tr("Cannot optimize for subgroup %1 and activity tag %2, because there are too many constraints"
3315 " of type activity tag max hours daily relating to them, which cannot be compressed in 2 constraints of this type."
3316 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3317 " in the first one and the weight percentage is higher on the first one."
3318 " It is possible to use any number of such constraints for a subgroup and an activity tag, but their resultant must"
3319 " be maximum 2 constraints of type activity tag max hours daily.\n\n"
3320 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3321 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3322 " Please modify your data accordingly and try again.")
3323 .arg(gt.rules.internalSubgroupsList[sb]->name)
3324 .arg(samd->activityTagName),
3325 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3326 1, 0 );
3327
3328 if(t==0)
3329 return false;
3330 }
3331 }
3332 }
3333 }
3334 }
3335 }
3336 }
3337
3338 Matrix1D<int> navd;
3339 navd.resize(gt.rules.nDaysPerWeek);
3340
3341 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
3342 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
3343 navd[d]=0;
3344 for(int h=0; h<gt.rules.nHoursPerDay; h++){
3345 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[i][d][h])
3346 navd[d]++;
3347 }
3348 }
3349
3350 for(int j=0; j<subgroupsActivityTagMaxHoursDailyMaxHours[i].count(); j++){
3351 int mh=subgroupsActivityTagMaxHoursDailyMaxHours[i].at(j);
3352 double perc=subgroupsActivityTagMaxHoursDailyPercentage[i].at(j);
3353 int at=subgroupsActivityTagMaxHoursDailyActivityTag[i].at(j);
3354 if(perc==100.0){
3355 int totalAt=0;
3356 for(int ai : qAsConst(gt.rules.internalSubgroupsList[i]->activitiesForSubgroup))
3357 if(gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(at))
3358 totalAt+=gt.rules.internalActivitiesList[ai].duration;
3359
3360 int ava=0;
3361 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
3362 ava+=min(navd[d], mh);
3363
3364 if(ava<totalAt){
3365 ok=false;
3366
3367 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3368 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint activity tag %2 max %3 hours daily for it with weight 100%"
3369 " which cannot be satisfied, considering the number of available slots (%4) and total duration of activities with this activity tag (%5)"
3370 ". Please correct and try again.", "%2 is the activity tag for this constraint, %3 is the max number of hours daily for this constraint")
3371 .arg(gt.rules.internalSubgroupsList[i]->name).arg(gt.rules.activityTagsList.at(at)->name).arg(mh).arg(ava).arg(totalAt),
3372 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3373 1, 0 );
3374
3375 if(t==0)
3376 return false;
3377 }
3378 }
3379 }
3380 }
3381
3382 return ok;
3383 }
3384
computeStudentsActivityTagMaxHoursDailyRealDays(QWidget * parent)3385 bool computeStudentsActivityTagMaxHoursDailyRealDays(QWidget* parent)
3386 {
3387 haveStudentsActivityTagMaxHoursDailyRealDays=false;
3388
3389 bool ok=true;
3390
3391 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
3392 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[i].clear();
3393 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[i].clear();
3394 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[i].clear();
3395 }
3396
3397 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
3398 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_DAILY_REAL_DAYS){
3399 haveStudentsActivityTagMaxHoursDailyRealDays=true;
3400
3401 ConstraintStudentsActivityTagMaxHoursDailyRealDays* samd=(ConstraintStudentsActivityTagMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
3402
3403 for(int sb : qAsConst(samd->canonicalSubgroupsList)){
3404 int pos1=-1, pos2=-1;
3405
3406 for(int j=0; j<subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].count(); j++){
3407 if(subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb].at(j)==samd->activityTagIndex){
3408 if(pos1==-1){
3409 pos1=j;
3410 }
3411 else{
3412 assert(pos2==-1);
3413 pos2=j;
3414 }
3415 }
3416 }
3417
3418 if(pos1==-1){
3419 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb].append(samd->activityTagIndex);
3420 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].append(samd->maxHoursDaily);
3421 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].append(samd->weightPercentage);
3422 }
3423 else{
3424 if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos1) <= samd->maxHoursDaily
3425 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos1) >= samd->weightPercentage){
3426 //do nothing
3427 }
3428 else if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos1) >= samd->maxHoursDaily
3429 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos1) <= samd->weightPercentage){
3430
3431 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb][pos1]=samd->activityTagIndex;
3432 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb][pos1]=samd->maxHoursDaily;
3433 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb][pos1]=samd->weightPercentage;
3434 }
3435 else{
3436 if(pos2==-1){
3437 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb].append(samd->activityTagIndex);
3438 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].append(samd->maxHoursDaily);
3439 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].append(samd->weightPercentage);
3440 }
3441 else{
3442
3443 if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos2) <= samd->maxHoursDaily
3444 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos2) >= samd->weightPercentage){
3445 //do nothing
3446 }
3447 else if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos2) >= samd->maxHoursDaily
3448 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos2) <= samd->weightPercentage){
3449
3450 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb][pos2]=samd->activityTagIndex;
3451 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb][pos2]=samd->maxHoursDaily;
3452 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb][pos2]=samd->weightPercentage;
3453 }
3454 else{
3455 ok=false;
3456
3457 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3458 GeneratePreTranslate::tr("Cannot optimize for subgroup %1 and activity tag %2, because there are too many constraints"
3459 " of type activity tag max hours daily per real day relating to them, which cannot be compressed in 2 constraints of this type."
3460 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3461 " in the first one and the weight percentage is higher on the first one."
3462 " It is possible to use any number of such constraints for a subgroup and an activity tag, but their resultant must"
3463 " be maximum 2 constraints of type activity tag max hours daily per real day.\n\n"
3464 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3465 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3466 " Please modify your data accordingly and try again.")
3467 .arg(gt.rules.internalSubgroupsList[sb]->name)
3468 .arg(samd->activityTagName),
3469 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3470 1, 0 );
3471
3472 if(t==0)
3473 return false;
3474 }
3475 }
3476 }
3477 }
3478 }
3479 }
3480 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_DAILY_REAL_DAYS){
3481 haveStudentsActivityTagMaxHoursDailyRealDays=true;
3482
3483 ConstraintStudentsSetActivityTagMaxHoursDailyRealDays* samd=(ConstraintStudentsSetActivityTagMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
3484
3485 for(int sb : qAsConst(samd->canonicalSubgroupsList)){
3486 int pos1=-1, pos2=-1;
3487
3488 for(int j=0; j<subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].count(); j++){
3489 if(subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb].at(j)==samd->activityTagIndex){
3490 if(pos1==-1){
3491 pos1=j;
3492 }
3493 else{
3494 assert(pos2==-1);
3495 pos2=j;
3496 }
3497 }
3498 }
3499
3500 if(pos1==-1){
3501 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb].append(samd->activityTagIndex);
3502 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].append(samd->maxHoursDaily);
3503 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].append(samd->weightPercentage);
3504 }
3505 else{
3506 if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos1) <= samd->maxHoursDaily
3507 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos1) >= samd->weightPercentage){
3508 //do nothing
3509 }
3510 else if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos1) >= samd->maxHoursDaily
3511 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos1) <= samd->weightPercentage){
3512
3513 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb][pos1]=samd->activityTagIndex;
3514 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb][pos1]=samd->maxHoursDaily;
3515 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb][pos1]=samd->weightPercentage;
3516 }
3517 else{
3518 if(pos2==-1){
3519 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb].append(samd->activityTagIndex);
3520 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].append(samd->maxHoursDaily);
3521 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].append(samd->weightPercentage);
3522 }
3523 else{
3524
3525 if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos2) <= samd->maxHoursDaily
3526 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos2) >= samd->weightPercentage){
3527 //do nothing
3528 }
3529 else if(subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb].at(pos2) >= samd->maxHoursDaily
3530 && subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb].at(pos2) <= samd->weightPercentage){
3531
3532 subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[sb][pos2]=samd->activityTagIndex;
3533 subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[sb][pos2]=samd->maxHoursDaily;
3534 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sb][pos2]=samd->weightPercentage;
3535 }
3536 else{
3537 ok=false;
3538
3539 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3540 GeneratePreTranslate::tr("Cannot optimize for subgroup %1 and activity tag %2, because there are too many constraints"
3541 " of type activity tag max hours daily per real day relating to them, which cannot be compressed in 2 constraints of this type."
3542 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3543 " in the first one and the weight percentage is higher on the first one."
3544 " It is possible to use any number of such constraints for a subgroup and an activity tag, but their resultant must"
3545 " be maximum 2 constraints of type activity tag max hours daily per real day.\n\n"
3546 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3547 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3548 " Please modify your data accordingly and try again.")
3549 .arg(gt.rules.internalSubgroupsList[sb]->name)
3550 .arg(samd->activityTagName),
3551 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3552 1, 0 );
3553
3554 if(t==0)
3555 return false;
3556 }
3557 }
3558 }
3559 }
3560 }
3561 }
3562 }
3563
3564 Matrix1D<int> navd;
3565 navd.resize(gt.rules.nDaysPerWeek/2);
3566
3567 if(gt.rules.mode==MORNINGS_AFTERNOONS)
3568 assert(gt.rules.nDaysPerWeek%2==0);
3569
3570 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
3571 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
3572 navd[d]=0;
3573 for(int h=0; h<gt.rules.nHoursPerDay; h++){
3574 if(!breakDayHour[2*d][h] && !subgroupNotAvailableDayHour[i][2*d][h])
3575 navd[d]++;
3576 if(!breakDayHour[2*d+1][h] && !subgroupNotAvailableDayHour[i][2*d+1][h])
3577 navd[d]++;
3578 }
3579 }
3580
3581 for(int j=0; j<subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[i].count(); j++){
3582 int mh=subgroupsActivityTagMaxHoursDailyRealDaysMaxHours[i].at(j);
3583 double perc=subgroupsActivityTagMaxHoursDailyRealDaysPercentage[i].at(j);
3584 int at=subgroupsActivityTagMaxHoursDailyRealDaysActivityTag[i].at(j);
3585 if(perc==100.0){
3586 int totalAt=0;
3587 for(int ai : qAsConst(gt.rules.internalSubgroupsList[i]->activitiesForSubgroup))
3588 if(gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(at))
3589 totalAt+=gt.rules.internalActivitiesList[ai].duration;
3590
3591 int ava=0;
3592 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
3593 ava+=min(navd[d], mh);
3594
3595 if(ava<totalAt){
3596 ok=false;
3597
3598 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3599 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there is a constraint activity tag %2 max %3 hours daily per real day for it with weight 100%"
3600 " which cannot be satisfied, considering the number of available slots (%4) and total duration of activities with this activity tag (%5)"
3601 ". Please correct and try again.", "%2 is the activity tag for this constraint, %3 is the max number of hours daily for this constraint")
3602 .arg(gt.rules.internalSubgroupsList[i]->name).arg(gt.rules.activityTagsList.at(at)->name).arg(mh).arg(ava).arg(totalAt),
3603 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3604 1, 0 );
3605
3606 if(t==0)
3607 return false;
3608 }
3609 }
3610 }
3611 }
3612
3613 return ok;
3614 }
3615
computeStudentsActivityTagMaxHoursContinuously(QWidget * parent)3616 bool computeStudentsActivityTagMaxHoursContinuously(QWidget* parent)
3617 {
3618 haveStudentsActivityTagMaxHoursContinuously=false;
3619
3620 bool ok=true;
3621
3622 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
3623 subgroupsActivityTagMaxHoursContinuouslyMaxHours[i].clear();
3624 subgroupsActivityTagMaxHoursContinuouslyPercentage[i].clear();
3625 subgroupsActivityTagMaxHoursContinuouslyActivityTag[i].clear();
3626 }
3627
3628 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
3629 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
3630 haveStudentsActivityTagMaxHoursContinuously=true;
3631
3632 ConstraintStudentsActivityTagMaxHoursContinuously* samc=(ConstraintStudentsActivityTagMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
3633
3634 for(int sb : qAsConst(samc->canonicalSubgroupsList)){
3635 int pos1=-1, pos2=-1;
3636
3637 for(int j=0; j<subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].count(); j++){
3638 if(subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb].at(j)==samc->activityTagIndex){
3639 if(pos1==-1){
3640 pos1=j;
3641 }
3642 else{
3643 assert(pos2==-1);
3644 pos2=j;
3645 }
3646 }
3647 }
3648
3649 if(pos1==-1){
3650 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb].append(samc->activityTagIndex);
3651 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].append(samc->maxHoursContinuously);
3652 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].append(samc->weightPercentage);
3653 }
3654 else{
3655 if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos1) <= samc->maxHoursContinuously
3656 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos1) >= samc->weightPercentage){
3657 //do nothing
3658 }
3659 else if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos1) >= samc->maxHoursContinuously
3660 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos1) <= samc->weightPercentage){
3661
3662 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb][pos1]=samc->activityTagIndex;
3663 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb][pos1]=samc->maxHoursContinuously;
3664 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb][pos1]=samc->weightPercentage;
3665 }
3666 else{
3667 if(pos2==-1){
3668 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb].append(samc->activityTagIndex);
3669 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].append(samc->maxHoursContinuously);
3670 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].append(samc->weightPercentage);
3671 }
3672 else{
3673
3674 if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos2) <= samc->maxHoursContinuously
3675 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos2) >= samc->weightPercentage){
3676 //do nothing
3677 }
3678 else if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos2) >= samc->maxHoursContinuously
3679 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos2) <= samc->weightPercentage){
3680
3681 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb][pos2]=samc->activityTagIndex;
3682 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb][pos2]=samc->maxHoursContinuously;
3683 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb][pos2]=samc->weightPercentage;
3684 }
3685 else{
3686 ok=false;
3687
3688 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3689 GeneratePreTranslate::tr("Cannot optimize for subgroup %1 and activity tag %2, because there are too many constraints"
3690 " of type activity tag max hours continuously relating to them, which cannot be compressed in 2 constraints of this type."
3691 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3692 " in the first one and the weight percentage is higher on the first one."
3693 " It is possible to use any number of such constraints for a subgroup and an activity tag, but their resultant must"
3694 " be maximum 2 constraints of type activity tag max hours continuously.\n\n"
3695 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3696 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3697 " Please modify your data accordingly and try again.")
3698 .arg(gt.rules.internalSubgroupsList[sb]->name)
3699 .arg(samc->activityTagName),
3700 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3701 1, 0 );
3702
3703 if(t==0)
3704 return false;
3705 }
3706 }
3707 }
3708 }
3709 }
3710 }
3711 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
3712 haveStudentsActivityTagMaxHoursContinuously=true;
3713
3714 ConstraintStudentsSetActivityTagMaxHoursContinuously* samc=(ConstraintStudentsSetActivityTagMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
3715
3716 for(int sb : qAsConst(samc->canonicalSubgroupsList)){
3717 int pos1=-1, pos2=-1;
3718
3719 for(int j=0; j<subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].count(); j++){
3720 if(subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb].at(j)==samc->activityTagIndex){
3721 if(pos1==-1){
3722 pos1=j;
3723 }
3724 else{
3725 assert(pos2==-1);
3726 pos2=j;
3727 }
3728 }
3729 }
3730
3731 if(pos1==-1){
3732 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb].append(samc->activityTagIndex);
3733 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].append(samc->maxHoursContinuously);
3734 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].append(samc->weightPercentage);
3735 }
3736 else{
3737 if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos1) <= samc->maxHoursContinuously
3738 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos1) >= samc->weightPercentage){
3739 //do nothing
3740 }
3741 else if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos1) >= samc->maxHoursContinuously
3742 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos1) <= samc->weightPercentage){
3743
3744 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb][pos1]=samc->activityTagIndex;
3745 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb][pos1]=samc->maxHoursContinuously;
3746 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb][pos1]=samc->weightPercentage;
3747 }
3748 else{
3749 if(pos2==-1){
3750 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb].append(samc->activityTagIndex);
3751 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].append(samc->maxHoursContinuously);
3752 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].append(samc->weightPercentage);
3753 }
3754 else{
3755
3756 if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos2) <= samc->maxHoursContinuously
3757 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos2) >= samc->weightPercentage){
3758 //do nothing
3759 }
3760 else if(subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb].at(pos2) >= samc->maxHoursContinuously
3761 && subgroupsActivityTagMaxHoursContinuouslyPercentage[sb].at(pos2) <= samc->weightPercentage){
3762
3763 subgroupsActivityTagMaxHoursContinuouslyActivityTag[sb][pos2]=samc->activityTagIndex;
3764 subgroupsActivityTagMaxHoursContinuouslyMaxHours[sb][pos2]=samc->maxHoursContinuously;
3765 subgroupsActivityTagMaxHoursContinuouslyPercentage[sb][pos2]=samc->weightPercentage;
3766 }
3767 else{
3768 ok=false;
3769
3770 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3771 GeneratePreTranslate::tr("Cannot optimize for subgroup %1 and activity tag %2, because there are too many constraints"
3772 " of type activity tag max hours continuously relating to them, which cannot be compressed in 2 constraints of this type."
3773 " Two constraints max hours can be compressed into a single one if the max hours are lower"
3774 " in the first one and the weight percentage is higher on the first one."
3775 " It is possible to use any number of such constraints for a subgroup and an activity tag, but their resultant must"
3776 " be maximum 2 constraints of type activity tag max hours continuously.\n\n"
3777 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
3778 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
3779 " Please modify your data accordingly and try again.")
3780 .arg(gt.rules.internalSubgroupsList[sb]->name)
3781 .arg(samc->activityTagName),
3782 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3783 1, 0 );
3784
3785 if(t==0)
3786 return false;
3787 }
3788 }
3789 }
3790 }
3791 }
3792 }
3793 }
3794
3795 return ok;
3796 }
3797
checkMaxHoursForActivityDuration(QWidget * parent)3798 bool checkMaxHoursForActivityDuration(QWidget* parent)
3799 {
3800 bool ok=true;
3801
3802 for(int i=0; i<gt.rules.nInternalActivities; i++){
3803 Activity* act=>.rules.internalActivitiesList[i];
3804
3805 //teachers
3806 for(int tch : qAsConst(act->iTeachersList)){
3807 if(teachersMaxHoursDailyPercentages1[tch]==100.0){
3808 int m=teachersMaxHoursDailyMaxHours1[tch];
3809 if(act->duration > m){
3810 ok=false;
3811
3812 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3813 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3814 " a constraint teacher(s) max %3 hours daily with weight = 100% for the teacher %4. The activity's duration is"
3815 " higher than the teacher's max hours daily. Please correct and try again.")
3816 .arg(act->id)
3817 .arg(act->duration)
3818 .arg(m)
3819 .arg(gt.rules.internalTeachersList[tch]->name),
3820 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3821 1, 0 );
3822
3823 if(t==0)
3824 return false;
3825 }
3826 }
3827 if(teachersMaxHoursDailyPercentages2[tch]==100.0){
3828 int m=teachersMaxHoursDailyMaxHours2[tch];
3829 if(act->duration > m){
3830 ok=false;
3831
3832 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3833 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3834 " a constraint teacher(s) max %3 hours daily with weight = 100% for the teacher %4. The activity's duration is"
3835 " higher than the teacher's max hours daily. Please correct and try again.")
3836 .arg(act->id)
3837 .arg(act->duration)
3838 .arg(m)
3839 .arg(gt.rules.internalTeachersList[tch]->name),
3840 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3841 1, 0 );
3842
3843 if(t==0)
3844 return false;
3845 }
3846 }
3847
3848 if(teachersMaxHoursContinuouslyPercentages1[tch]==100.0){
3849 int m=teachersMaxHoursContinuouslyMaxHours1[tch];
3850 if(act->duration > m){
3851 ok=false;
3852
3853 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3854 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3855 " a constraint teacher(s) max %3 hours continuously with weight = 100% for the teacher %4. The activity's duration is"
3856 " higher than the teacher's max hours continuously. Please correct and try again.")
3857 .arg(act->id)
3858 .arg(act->duration)
3859 .arg(m)
3860 .arg(gt.rules.internalTeachersList[tch]->name),
3861 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3862 1, 0 );
3863
3864 if(t==0)
3865 return false;
3866 }
3867 }
3868 if(teachersMaxHoursContinuouslyPercentages2[tch]==100.0){
3869 int m=teachersMaxHoursContinuouslyMaxHours2[tch];
3870 if(act->duration > m){
3871 ok=false;
3872
3873 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3874 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3875 " a constraint teacher(s) max %3 hours continuously with weight = 100% for the teacher %4. The activity's duration is"
3876 " higher than the teacher's max hours continuously. Please correct and try again.")
3877 .arg(act->id)
3878 .arg(act->duration)
3879 .arg(m)
3880 .arg(gt.rules.internalTeachersList[tch]->name),
3881 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3882 1, 0 );
3883
3884 if(t==0)
3885 return false;
3886 }
3887 }
3888
3889 for(int j=0; j<teachersActivityTagMaxHoursDailyMaxHours[tch].count(); j++){
3890 if(teachersActivityTagMaxHoursDailyPercentage[tch].at(j)==100.0){
3891 int m=teachersActivityTagMaxHoursDailyMaxHours[tch].at(j);
3892 int at=teachersActivityTagMaxHoursDailyActivityTag[tch].at(j);
3893 if(act->iActivityTagsSet.contains(at) && act->duration > m){
3894 ok=false;
3895
3896 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3897 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3898 " a constraint teacher(s) activity tag max %3 hours daily with weight = 100% for the teacher %4 and activity tag %5."
3899 " The activity's duration is higher than the teacher's max hours daily with this activity tag (which the activity contains)."
3900 " Please correct and try again.")
3901 .arg(act->id)
3902 .arg(act->duration)
3903 .arg(m)
3904 .arg(gt.rules.internalTeachersList[tch]->name)
3905 .arg(gt.rules.activityTagsList[at]->name),
3906 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3907 1, 0 );
3908
3909 if(t==0)
3910 return false;
3911 }
3912 }
3913 }
3914
3915 for(int j=0; j<teachersActivityTagMaxHoursContinuouslyMaxHours[tch].count(); j++){
3916 if(teachersActivityTagMaxHoursContinuouslyPercentage[tch].at(j)==100.0){
3917 int m=teachersActivityTagMaxHoursContinuouslyMaxHours[tch].at(j);
3918 int at=teachersActivityTagMaxHoursContinuouslyActivityTag[tch].at(j);
3919 if(act->iActivityTagsSet.contains(at) && act->duration > m){
3920 ok=false;
3921
3922 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3923 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3924 " a constraint teacher(s) activity tag max %3 hours continuously with weight = 100% for the teacher %4 and activity tag %5."
3925 " The activity's duration is higher than the teacher's max hours continuously with this activity tag (which the activity contains)."
3926 " Please correct and try again.")
3927 .arg(act->id)
3928 .arg(act->duration)
3929 .arg(m)
3930 .arg(gt.rules.internalTeachersList[tch]->name)
3931 .arg(gt.rules.activityTagsList[at]->name),
3932 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3933 1, 0 );
3934
3935 if(t==0)
3936 return false;
3937 }
3938 }
3939 }
3940 }
3941
3942 //students
3943 for(int sbg : qAsConst(act->iSubgroupsList)){
3944 if(subgroupsMaxHoursDailyPercentages1[sbg]==100.0){
3945 int m=subgroupsMaxHoursDailyMaxHours1[sbg];
3946 if(act->duration > m){
3947 ok=false;
3948
3949 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3950 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3951 " a constraint students (set) max %3 hours daily with weight = 100% for the subgroup %4. The activity's duration is"
3952 " higher than the subgroup's max hours daily. Please correct and try again.")
3953 .arg(act->id)
3954 .arg(act->duration)
3955 .arg(m)
3956 .arg(gt.rules.internalSubgroupsList[sbg]->name),
3957 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3958 1, 0 );
3959
3960 if(t==0)
3961 return false;
3962 }
3963 }
3964
3965 if(subgroupsMaxHoursDailyPercentages2[sbg]==100.0){
3966 int m=subgroupsMaxHoursDailyMaxHours2[sbg];
3967 if(act->duration > m){
3968 ok=false;
3969
3970 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3971 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3972 " a constraint students (set) max %3 hours daily with weight = 100% for the subgroup %4. The activity's duration is"
3973 " higher than the subgroup's max hours daily. Please correct and try again.")
3974 .arg(act->id)
3975 .arg(act->duration)
3976 .arg(m)
3977 .arg(gt.rules.internalSubgroupsList[sbg]->name),
3978 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
3979 1, 0 );
3980
3981 if(t==0)
3982 return false;
3983 }
3984 }
3985
3986 if(subgroupsMaxHoursContinuouslyPercentages1[sbg]==100.0){
3987 int m=subgroupsMaxHoursContinuouslyMaxHours1[sbg];
3988 if(act->duration > m){
3989 ok=false;
3990
3991 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
3992 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
3993 " a constraint students (set) max %3 hours continuously with weight = 100% for the subgroup %4. The activity's duration is"
3994 " higher than the subgroup's max hours continuously. Please correct and try again.")
3995 .arg(act->id)
3996 .arg(act->duration)
3997 .arg(m)
3998 .arg(gt.rules.internalSubgroupsList[sbg]->name),
3999 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4000 1, 0 );
4001
4002 if(t==0)
4003 return false;
4004 }
4005 }
4006 if(subgroupsMaxHoursContinuouslyPercentages2[sbg]==100.0){
4007 int m=subgroupsMaxHoursContinuouslyMaxHours2[sbg];
4008 if(act->duration > m){
4009 ok=false;
4010
4011 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4012 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
4013 " a constraint students (set) max %3 hours continuously with weight = 100% for the subgroup %4. The activity's duration is"
4014 " higher than the subgroup's max hours continuously. Please correct and try again.")
4015 .arg(act->id)
4016 .arg(act->duration)
4017 .arg(m)
4018 .arg(gt.rules.internalSubgroupsList[sbg]->name),
4019 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4020 1, 0 );
4021
4022 if(t==0)
4023 return false;
4024 }
4025 }
4026
4027 for(int j=0; j<subgroupsActivityTagMaxHoursDailyMaxHours[sbg].count(); j++){
4028 if(subgroupsActivityTagMaxHoursDailyPercentage[sbg].at(j)==100.0){
4029 int m=subgroupsActivityTagMaxHoursDailyMaxHours[sbg].at(j);
4030 int at=subgroupsActivityTagMaxHoursDailyActivityTag[sbg].at(j);
4031 if(act->iActivityTagsSet.contains(at) && act->duration > m){
4032 ok=false;
4033
4034 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4035 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
4036 " a constraint students (set) activity tag max %3 hours daily with weight = 100% for the subgroup %4 and activity tag %5."
4037 " The activity's duration is higher than the subgroup's max hours daily with this activity tag (which the activity contains)."
4038 " Please correct and try again.")
4039 .arg(act->id)
4040 .arg(act->duration)
4041 .arg(m)
4042 .arg(gt.rules.internalSubgroupsList[sbg]->name)
4043 .arg(gt.rules.activityTagsList[at]->name),
4044 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4045 1, 0 );
4046
4047 if(t==0)
4048 return false;
4049 }
4050 }
4051 }
4052
4053 for(int j=0; j<subgroupsActivityTagMaxHoursContinuouslyMaxHours[sbg].count(); j++){
4054 if(subgroupsActivityTagMaxHoursContinuouslyPercentage[sbg].at(j)==100.0){
4055 int m=subgroupsActivityTagMaxHoursContinuouslyMaxHours[sbg].at(j);
4056 int at=subgroupsActivityTagMaxHoursContinuouslyActivityTag[sbg].at(j);
4057 if(act->iActivityTagsSet.contains(at) && act->duration > m){
4058 ok=false;
4059
4060 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4061 GeneratePreTranslate::tr("Cannot optimize, because you have activity id = %1 with duration = %2 and"
4062 " a constraint students (set) activity tag max %3 hours continuously with weight = 100% for the subgroup %4 and activity tag %5."
4063 " The activity's duration is higher than the subgroup's max hours continuously with this activity tag (which the activity contains)."
4064 " Please correct and try again.")
4065 .arg(act->id)
4066 .arg(act->duration)
4067 .arg(m)
4068 .arg(gt.rules.internalSubgroupsList[sbg]->name)
4069 .arg(gt.rules.activityTagsList[at]->name),
4070 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4071 1, 0 );
4072
4073 if(t==0)
4074 return false;
4075 }
4076 }
4077 }
4078 }
4079 }
4080
4081 return ok;
4082 }
4083
computeSubgroupsMinHoursDaily(QWidget * parent)4084 bool computeSubgroupsMinHoursDaily(QWidget* parent)
4085 {
4086 bool ok=true;
4087
4088 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
4089 subgroupsMinHoursDailyMinHours[i][1]=-1;
4090 subgroupsMinHoursDailyPercentages[i][1]=-1;
4091 subgroupsMinHoursDailyAllowEmptyDays[i]=true;
4092 subgroupsMinHoursPerMorningAllowEmptyMornings[i]=true;
4093 }
4094
4095 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
4096 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_HOURS_DAILY){
4097 ConstraintStudentsMinHoursDaily* smd=(ConstraintStudentsMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4098
4099 if(smd->weightPercentage!=100){
4100 ok=false;
4101
4102 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4103 GeneratePreTranslate::tr("Cannot optimize for students, because the constraint of type min hours daily relating to students"
4104 " has no 100% weight"
4105 ". Please modify your data accordingly and try again"),
4106 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4107 1, 0 );
4108
4109 if(t==0)
4110 return false;
4111 }
4112
4113 //////////
4114 if(smd->minHoursDaily>gt.rules.nHoursPerDay){
4115 ok=false;
4116
4117 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4118 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min hours daily with"
4119 " %1 min hours daily, and the number of working hours per day is only %2. Please correct and try again")
4120 .arg(smd->minHoursDaily)
4121 .arg(gt.rules.nHoursPerDay),
4122 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4123 1, 0 );
4124
4125 if(t==0)
4126 return false;
4127 }
4128 //////////
4129 }
4130 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_HOURS_DAILY){
4131 ConstraintStudentsSetMinHoursDaily* smd=(ConstraintStudentsSetMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4132
4133 if(smd->weightPercentage!=100){
4134 ok=false;
4135
4136 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4137 GeneratePreTranslate::tr("Cannot optimize for students set %1, because the constraint of type min hours daily relating to it"
4138 " has no 100% weight"
4139 ". Please modify your data accordingly and try again")
4140 .arg(smd->students),
4141 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4142 1, 0 );
4143
4144 if(t==0)
4145 return false;
4146 }
4147
4148 //////////
4149 if(smd->minHoursDaily>gt.rules.nHoursPerDay){
4150 ok=false;
4151
4152 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4153 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min hours daily for students set %1 with"
4154 " %2 min hours daily, and the number of working hours per day is only %3. Please correct and try again")
4155 .arg(smd->students)
4156 .arg(smd->minHoursDaily)
4157 .arg(gt.rules.nHoursPerDay),
4158 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4159 1, 0 );
4160
4161 if(t==0)
4162 return false;
4163 }
4164 //////////
4165 }
4166 }
4167
4168 if(!ok)
4169 return ok;
4170
4171 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
4172 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_HOURS_DAILY){
4173 ConstraintStudentsMinHoursDaily* smd=(ConstraintStudentsMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4174
4175 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
4176 if(subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY]==-1 ||
4177 (subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] <= smd->minHoursDaily &&
4178 subgroupsMinHoursDailyPercentages[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] <= smd->weightPercentage)){
4179 subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] = smd->minHoursDaily;
4180 subgroupsMinHoursDailyPercentages[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] = smd->weightPercentage;
4181 }
4182 else if(subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] >= smd->minHoursDaily &&
4183 subgroupsMinHoursDailyPercentages[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] >= smd->weightPercentage){
4184 //nothing
4185 }
4186 else{ //cannot proceed
4187 ok=false;
4188
4189 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4190 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are two constraints"
4191 " of type min hours daily relating to it, and the weight percentage is higher on the constraint"
4192 " with less minimum hours. You are allowed only to have for each subgroup"
4193 " the most important constraint with maximum weight percentage and largest minimum hours daily allowed"
4194 ". Please modify your data accordingly and try again")
4195 .arg(gt.rules.internalSubgroupsList[sb]->name),
4196 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4197 1, 0 );
4198
4199 if(t==0)
4200 return false;
4201 }
4202
4203 if(smd->allowEmptyDays==false)
4204 subgroupsMinHoursDailyAllowEmptyDays[sb]=false;
4205 }
4206 }
4207 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_HOURS_DAILY){
4208 ConstraintStudentsSetMinHoursDaily* smd=(ConstraintStudentsSetMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4209
4210 for(int q=0; q<smd->iSubgroupsList.count(); q++){
4211 int sb=smd->iSubgroupsList.at(q);
4212 if(subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY]==-1 ||
4213 (subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] <= smd->minHoursDaily &&
4214 subgroupsMinHoursDailyPercentages[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] <= smd->weightPercentage)){
4215 subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] = smd->minHoursDaily;
4216 subgroupsMinHoursDailyPercentages[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] = smd->weightPercentage;
4217 }
4218 else if(subgroupsMinHoursDailyMinHours[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] >= smd->minHoursDaily &&
4219 subgroupsMinHoursDailyPercentages[sb][MIN_HOURS_DAILY_INDEX_IN_ARRAY] >= smd->weightPercentage){
4220 //nothing
4221 }
4222 else{ //cannot proceed
4223 ok=false;
4224
4225 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4226 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because there are two constraints"
4227 " of type min hours daily relating to it, and the weight percentage is higher on the constraint"
4228 " with less minimum hours. You are allowed only to have for each subgroup"
4229 " the most important constraint with maximum weight percentage and largest minimum hours daily allowed"
4230 ". Please modify your data accordingly and try again")
4231 .arg(gt.rules.internalSubgroupsList[sb]->name),
4232 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4233 1, 0 );
4234
4235 if(t==0)
4236 return false;
4237 }
4238 if(smd->allowEmptyDays==false)
4239 subgroupsMinHoursDailyAllowEmptyDays[sb]=false;
4240 }
4241 }
4242 }
4243
4244 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
4245 subgroupsMinHoursDailyMinHours[i][0]=subgroupsMinHoursDailyMinHours[i][1];
4246 subgroupsMinHoursDailyPercentages[i][0]=subgroupsMinHoursDailyPercentages[i][1];
4247 }
4248
4249
4250 //2020-06-14
4251 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
4252 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_HOURS_PER_MORNING){
4253 ConstraintStudentsSetMinHoursPerMorning* smd=(ConstraintStudentsSetMinHoursPerMorning*)gt.rules.internalTimeConstraintsList[i];
4254
4255 //////////
4256 if(smd->weightPercentage!=100){
4257 ok=false;
4258
4259 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4260 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min hours per morning for students set %1 with"
4261 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
4262 " to use 100% weight for such constraints. Please make weight 100% and try again")
4263 .arg(smd->students),
4264 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4265 1, 0 );
4266
4267 if(t==0)
4268 return false;
4269 }
4270 //////////
4271
4272 //////////
4273 if(smd->minHoursPerMorning>gt.rules.nHoursPerDay){
4274 ok=false;
4275
4276 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4277 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min hours per morning for students set %1 with"
4278 " %2 min hours per morning, and the number of working hours per day is only %3. Please correct and try again")
4279 .arg(smd->students)
4280 .arg(smd->minHoursPerMorning)
4281 .arg(gt.rules.nHoursPerDay),
4282 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4283 1, 0 );
4284
4285 if(t==0)
4286 return false;
4287 }
4288 //////////
4289
4290 for(int sbg : qAsConst(smd->iSubgroupsList)){
4291 if(subgroupsMinHoursDailyMinHours[sbg][1]==-1){
4292 ok=false;
4293
4294 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4295 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min hours per morning for subgroup %1 but not also"
4296 " min hours daily for him. Please add a constraint students (set) min hours daily affecting this subgroup.")
4297 .arg(gt.rules.internalSubgroupsList[sbg]->name),
4298 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4299 1, 0 );
4300
4301 if(t==0)
4302 return false;
4303 }
4304
4305 if(subgroupsMinHoursDailyMinHours[sbg][0]==-1 || subgroupsMinHoursDailyMinHours[sbg][0]<smd->minHoursPerMorning){
4306 subgroupsMinHoursDailyMinHours[sbg][0]=smd->minHoursPerMorning;
4307 subgroupsMinHoursDailyPercentages[sbg][0]=100;
4308 }
4309
4310 if(subgroupsMinHoursPerMorningAllowEmptyMornings[sbg]==true && smd->allowEmptyMornings==false)
4311 subgroupsMinHoursPerMorningAllowEmptyMornings[sbg]=false;
4312 }
4313 }
4314 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_HOURS_PER_MORNING){
4315 ConstraintStudentsMinHoursPerMorning* smd=(ConstraintStudentsMinHoursPerMorning*)gt.rules.internalTimeConstraintsList[i];
4316
4317 //////////
4318 if(smd->weightPercentage!=100){
4319 ok=false;
4320
4321 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4322 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min hours per morning with"
4323 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
4324 " to use 100% weight for such constraints. Please make weight 100% and try again"),
4325 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4326 1, 0 );
4327
4328 if(t==0)
4329 return false;
4330 }
4331 //////////
4332
4333 //////////
4334 if(smd->minHoursPerMorning>gt.rules.nHoursPerDay){
4335 ok=false;
4336
4337 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4338 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min hours per morning with"
4339 " %1 min hours per morning, and the number of working hours per day is only %2. Please correct and try again")
4340 .arg(smd->minHoursPerMorning)
4341 .arg(gt.rules.nHoursPerDay),
4342 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4343 1, 0 );
4344
4345 if(t==0)
4346 return false;
4347 }
4348 //////////
4349
4350 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
4351 if(subgroupsMinHoursDailyMinHours[sbg][1]==-1){
4352 ok=false;
4353
4354 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4355 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min hours per morning for subgroup %1 but not also"
4356 " min hours daily for him. Please add a constraint students (set) min hours daily affecting this subgroup.")
4357 .arg(gt.rules.internalSubgroupsList[sbg]->name),
4358 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4359 1, 0 );
4360
4361 if(t==0)
4362 return false;
4363 }
4364
4365 if(subgroupsMinHoursDailyMinHours[sbg][0]==-1 || subgroupsMinHoursDailyMinHours[sbg][0]<smd->minHoursPerMorning){
4366 subgroupsMinHoursDailyMinHours[sbg][0]=smd->minHoursPerMorning;
4367 subgroupsMinHoursDailyPercentages[sbg][0]=100;
4368 }
4369
4370 if(subgroupsMinHoursPerMorningAllowEmptyMornings[sbg]==true && smd->allowEmptyMornings==false)
4371 subgroupsMinHoursPerMorningAllowEmptyMornings[sbg]=false;
4372 }
4373 }
4374 }
4375
4376 haveStudentsMinHoursDailyMorningsAllowEmptyDays=false;
4377
4378 if(gt.rules.mode!=MORNINGS_AFTERNOONS){
4379 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
4380 if(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0 && subgroupsMinHoursDailyAllowEmptyDays[i]==true && !haveStudentsMinHoursDailyMorningsAllowEmptyDays)
4381 haveStudentsMinHoursDailyMorningsAllowEmptyDays=true;
4382
4383 if(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0 && subgroupsMinHoursDailyAllowEmptyDays[i]==false){
4384 if(gt.rules.nDaysPerWeek*subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY] > nHoursPerSubgroup[i]){
4385 ok=false;
4386
4387 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4388 GeneratePreTranslate::tr("For subgroup %1 you have too little activities to respect the constraint(s)"
4389 " of type min hours daily (the constraint(s) do not allow empty days). Please modify your data accordingly and try again.")
4390 .arg(gt.rules.internalSubgroupsList[i]->name),
4391 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4392 1, 0 );
4393
4394 if(t==0)
4395 return false;
4396 }
4397
4398 for(int j=0; j<gt.rules.nDaysPerWeek; j++){
4399 int freeSlots=0;
4400 for(int k=0; k<gt.rules.nHoursPerDay; k++)
4401 if(!subgroupNotAvailableDayHour[i][j][k] && !breakDayHour[j][k])
4402 freeSlots++;
4403 if(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>freeSlots){
4404 ok=false;
4405
4406 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4407 GeneratePreTranslate::tr("For subgroup %1 cannot respect the constraint(s)"
4408 " of type min hours daily (the constraint(s) do not allow empty days) on day %2, because of students set not available and/or break."
4409 " Please modify your data accordingly and try again")
4410 .arg(gt.rules.internalSubgroupsList[i]->name)
4411 .arg(gt.rules.daysOfTheWeek[j]),
4412 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4413 1, 0 );
4414
4415 if(t==0)
4416 return false;
4417 }
4418 }
4419 }
4420 else if(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0 && subgroupsMinHoursDailyAllowEmptyDays[i]==true){
4421
4422 if(nHoursPerSubgroup[i]>0 && subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>nHoursPerSubgroup[i]){
4423 ok=false;
4424
4425 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4426 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min %1 hours daily for subgroup"
4427 " %2 (the constraint allows empty days). This subgroup has in total only %3 hours per week, so impossible constraint."
4428 " Please correct and try again")
4429 .arg(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY])
4430 .arg(gt.rules.internalSubgroupsList[i]->name)
4431 .arg(nHoursPerSubgroup[i])
4432 ,
4433 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4434 1, 0 );
4435
4436 if(t==0)
4437 return false;
4438 }
4439
4440 if(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY]<2){
4441 ok=false;
4442
4443 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4444 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min %1 hours daily for subgroup"
4445 " %2 and the constraint allows empty days. The number of min hours daily should be at least 2, to make a non-trivial constraint. Please correct and try again")
4446 .arg(subgroupsMinHoursDailyMinHours[i][MIN_HOURS_DAILY_INDEX_IN_ARRAY])
4447 .arg(gt.rules.internalSubgroupsList[i]->name)
4448 ,
4449 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4450 1, 0 );
4451
4452 if(t==0)
4453 return false;
4454 }
4455 }
4456 }
4457 }
4458 else{
4459 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
4460 if(subgroupsMinHoursDailyMinHours[i][1]>=0 && (subgroupsMinHoursDailyAllowEmptyDays[i]==true||subgroupsMinHoursPerMorningAllowEmptyMornings[i]==true) && !haveStudentsMinHoursDailyMorningsAllowEmptyDays)
4461 haveStudentsMinHoursDailyMorningsAllowEmptyDays=true;
4462
4463 if(subgroupsMinHoursDailyMinHours[i][1]>=0 && subgroupsMinHoursDailyAllowEmptyDays[i]==false){
4464 if(gt.rules.nDaysPerWeek/2*subgroupsMinHoursDailyMinHours[i][1] > nHoursPerSubgroup[i]){
4465 ok=false;
4466
4467 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4468 GeneratePreTranslate::tr("For subgroup %1 you have too little activities to respect the constraint(s)"
4469 " of type min hours daily (the constraint(s) do not allow empty days). Please modify your data accordingly and try again.")
4470 .arg(gt.rules.internalSubgroupsList[i]->name),
4471 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4472 1, 0 );
4473
4474 if(t==0)
4475 return false;
4476 }
4477
4478 /*for(int j=0; j<gt.rules.nDaysPerWeek; j++){
4479 int freeSlots=0;
4480 for(int k=0; k<gt.rules.nHoursPerDay; k++)
4481 if(!subgroupNotAvailableDayHour[i][j][k] && !breakDayHour[j][k])
4482 freeSlots++;
4483 if(subgroupsMinHoursDailyMinHours[i]>freeSlots){
4484 ok=false;
4485
4486 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4487 GeneratePreTranslate::tr("For subgroup %1 cannot respect the constraint(s)"
4488 " of type min hours daily (the constraint(s) do not allow empty days) on day %2, because of students set not available and/or break."
4489 " Please modify your data accordingly and try again")
4490 .arg(gt.rules.internalSubgroupsList[i]->name)
4491 .arg(gt.rules.daysOfTheWeek[j]),
4492 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4493 1, 0 );
4494
4495 if(t==0)
4496 return false;
4497 }
4498 }*/
4499 }
4500 else if(subgroupsMinHoursDailyMinHours[i][1]>=0 && subgroupsMinHoursDailyAllowEmptyDays[i]==true){
4501
4502 if(nHoursPerSubgroup[i]>0 && subgroupsMinHoursDailyMinHours[i][1]>nHoursPerSubgroup[i]){
4503 ok=false;
4504
4505 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4506 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min %1 hours daily for subgroup"
4507 " %2 (the constraint allows empty days). This subgroup has in total only %3 hours per week, so impossible constraint."
4508 " Please correct and try again")
4509 .arg(subgroupsMinHoursDailyMinHours[i][1])
4510 .arg(gt.rules.internalSubgroupsList[i]->name)
4511 .arg(nHoursPerSubgroup[i])
4512 ,
4513 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4514 1, 0 );
4515
4516 if(t==0)
4517 return false;
4518 }
4519
4520 /*if(subgroupsMinHoursDailyMinHours[i][1]<2){
4521 ok=false;
4522
4523 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4524 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min %1 hours daily for subgroup"
4525 " %2 and the constraint allows empty days. The number of min hours daily should be at least 2, to make a non-trivial constraint. Please correct and try again")
4526 .arg(subgroupsMinHoursDailyMinHours[i])
4527 .arg(gt.rules.internalSubgroupsList[i]->name)
4528 ,
4529 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4530 1, 0 );
4531
4532 if(t==0)
4533 return false;
4534 }*/
4535 }
4536 if(subgroupsMinHoursDailyMinHours[i][0]>=0 && subgroupsMinHoursPerMorningAllowEmptyMornings[i]==false){
4537 if(gt.rules.nDaysPerWeek/2*subgroupsMinHoursDailyMinHours[i][0] > nHoursPerSubgroup[i]){
4538 ok=false;
4539
4540 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4541 GeneratePreTranslate::tr("For subgroup %1 you have too little activities to respect the constraint(s)"
4542 " of type min hours per morning (the constraint(s) do not allow empty mornings). Please modify your data accordingly and try again.")
4543 .arg(gt.rules.internalSubgroupsList[i]->name),
4544 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4545 1, 0 );
4546
4547 if(t==0)
4548 return false;
4549 }
4550 }
4551 }
4552 }
4553
4554 return ok;
4555 }
4556
computeStudentsActivityTagMinHoursDaily(QWidget * parent)4557 bool computeStudentsActivityTagMinHoursDaily(QWidget* parent)
4558 {
4559 haveStudentsActivityTagMinHoursDaily=false;
4560
4561 bool ok=true;
4562
4563 satmhdList.clear();
4564 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
4565 satmhdListForSubgroup[i].clear();
4566
4567 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
4568 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MIN_HOURS_DAILY){
4569 haveStudentsActivityTagMinHoursDaily=true;
4570 ConstraintStudentsActivityTagMinHoursDaily* smd=(ConstraintStudentsActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4571
4572 if(smd->weightPercentage!=100){
4573 ok=false;
4574
4575 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4576 GeneratePreTranslate::tr("Cannot optimize for students, because the constraint of type activity tag min hours daily relating to students"
4577 " has no 100% weight"
4578 ". Please modify your data accordingly and try again"),
4579 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4580 1, 0 );
4581
4582 if(t==0)
4583 return false;
4584 }
4585 }
4586 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MIN_HOURS_DAILY){
4587 haveStudentsActivityTagMinHoursDaily=true;
4588 ConstraintStudentsSetActivityTagMinHoursDaily* smd=(ConstraintStudentsSetActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4589
4590 if(smd->weightPercentage!=100){
4591 ok=false;
4592
4593 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4594 GeneratePreTranslate::tr("Cannot optimize for students, because the constraint of type activity tag min hours daily relating to students set %1"
4595 " has no 100% weight"
4596 ". Please modify your data accordingly and try again").arg(smd->students),
4597 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4598 1, 0 );
4599
4600 if(t==0)
4601 return false;
4602 }
4603 }
4604 }
4605
4606 if(haveStudentsActivityTagMinHoursDaily){
4607 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
4608 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_ACTIVITY_TAG_MIN_HOURS_DAILY){
4609 ConstraintStudentsActivityTagMinHoursDaily* smd=(ConstraintStudentsActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4610
4611 for(int sbg : qAsConst(smd->canonicalSubgroupsList)){
4612 SubgroupActivityTagMinHoursDaily_item item;
4613 item.durationOfActivitiesWithActivityTagForSubgroup=0;
4614
4615 for(int ai : qAsConst(gt.rules.internalSubgroupsList[sbg]->activitiesForSubgroup)){
4616 Activity* act=>.rules.internalActivitiesList[ai];
4617 if(act->iActivityTagsSet.contains(smd->activityTagIndex))
4618 item.durationOfActivitiesWithActivityTagForSubgroup+=act->duration;
4619 }
4620
4621 if(item.durationOfActivitiesWithActivityTagForSubgroup>0){
4622 item.activityTag=smd->activityTagIndex;
4623 item.minHoursDaily=smd->minHoursDaily;
4624 item.allowEmptyDays=smd->allowEmptyDays;
4625
4626 satmhdList.push_back(item);
4627 //satmhdListForSubgroup[sbg].append(&satmhdList[satmhdList.count()-1]);
4628 satmhdListForSubgroup[sbg].append(&satmhdList.back());
4629
4630 if(!item.allowEmptyDays && item.durationOfActivitiesWithActivityTagForSubgroup<gt.rules.nDaysPerWeek*item.minHoursDaily){
4631 ok=false;
4632
4633 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4634 GeneratePreTranslate::tr("Cannot optimize, because the constraint of type activity tag %1 min %2 hours daily relating to subgroup %3"
4635 " requires at least %4 hours of work per week, but the activities of this subgroup with this activity tag sum to only %5 hours"
4636 " per week (the constraint does not allow empty days). Please correct and try again")
4637 .arg(smd->activityTagName).arg(smd->minHoursDaily).arg(gt.rules.internalSubgroupsList[sbg]->name)
4638 .arg(gt.rules.nDaysPerWeek*item.minHoursDaily).arg(item.durationOfActivitiesWithActivityTagForSubgroup),
4639 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4640 1, 0 );
4641
4642 if(t==0)
4643 return false;
4644 }
4645 }
4646 else{
4647 assert(0);
4648 }
4649 }
4650 }
4651 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_ACTIVITY_TAG_MIN_HOURS_DAILY){
4652 ConstraintStudentsSetActivityTagMinHoursDaily* smd=(ConstraintStudentsSetActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4653
4654 for(int sbg : qAsConst(smd->canonicalSubgroupsList)){
4655 SubgroupActivityTagMinHoursDaily_item item;
4656 item.durationOfActivitiesWithActivityTagForSubgroup=0;
4657
4658 for(int ai : qAsConst(gt.rules.internalSubgroupsList[sbg]->activitiesForSubgroup)){
4659 Activity* act=>.rules.internalActivitiesList[ai];
4660 if(act->iActivityTagsSet.contains(smd->activityTagIndex))
4661 item.durationOfActivitiesWithActivityTagForSubgroup+=act->duration;
4662 }
4663
4664 if(item.durationOfActivitiesWithActivityTagForSubgroup>0){
4665 item.activityTag=smd->activityTagIndex;
4666 item.minHoursDaily=smd->minHoursDaily;
4667 item.allowEmptyDays=smd->allowEmptyDays;
4668
4669 satmhdList.push_back(item);
4670 //satmhdListForSubgroup[sbg].append(&satmhdList[satmhdList.count()-1]);
4671 satmhdListForSubgroup[sbg].append(&satmhdList.back());
4672
4673 if(!item.allowEmptyDays && item.durationOfActivitiesWithActivityTagForSubgroup<gt.rules.nDaysPerWeek*item.minHoursDaily){
4674 ok=false;
4675
4676 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4677 GeneratePreTranslate::tr("Cannot optimize, because the constraint of type activity tag %1 min %2 hours daily relating to subgroup %3"
4678 " requires at least %4 hours of work per week, but the activities of this subgroup with this activity tag sum to only %5 hours"
4679 " per week (the constraint does not allow empty days). Please correct and try again")
4680 .arg(smd->activityTagName).arg(smd->minHoursDaily).arg(gt.rules.internalSubgroupsList[sbg]->name)
4681 .arg(gt.rules.nDaysPerWeek*item.minHoursDaily).arg(item.durationOfActivitiesWithActivityTagForSubgroup),
4682 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4683 1, 0 );
4684
4685 if(t==0)
4686 return false;
4687 }
4688 }
4689 else{
4690 assert(0);
4691 }
4692 }
4693 }
4694 }
4695 }
4696
4697 return ok;
4698 }
4699
4700 //must be after allowed times, after n hours per teacher and after max days per week for teachers
computeTeachersMaxHoursDaily(QWidget * parent)4701 bool computeTeachersMaxHoursDaily(QWidget* parent)
4702 {
4703 bool ok=true;
4704
4705 for(int i=0; i<gt.rules.nInternalTeachers; i++){
4706 teachersMaxHoursDailyMaxHours1[i]=-1;
4707 teachersMaxHoursDailyPercentages1[i]=-1;
4708
4709 teachersMaxHoursDailyMaxHours2[i]=-1;
4710 teachersMaxHoursDailyPercentages2[i]=-1;
4711 }
4712
4713 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
4714 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_HOURS_DAILY){
4715 ConstraintTeacherMaxHoursDaily* tmd=(ConstraintTeacherMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4716
4717 if(tmd->weightPercentage<100.0)
4718 thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
4719
4720 //////////
4721 /*if(tmd->weightPercentage!=100){
4722 ok=false;
4723
4724 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
4725 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max hours daily for teacher %1 with"
4726 " weight (percentage) below 100. Starting with FET version 5.3.0 it is only possible"
4727 " to use 100% weight for such constraints. Please make weight 100% and try again")
4728 .arg(tmd->teacherName),
4729 GeneratePreTranslate::tr("Skip rest of max hours problems"), GeneratePreTranslate::tr("See next incompatibility max hours"), QString(),
4730 1, 0 );
4731
4732 if(t==0)
4733 return false;
4734 }*/
4735 //////////
4736
4737 if(teachersMaxHoursDailyMaxHours1[tmd->teacher_ID]==-1 ||
4738 (teachersMaxHoursDailyMaxHours1[tmd->teacher_ID] >= tmd->maxHoursDaily &&
4739 teachersMaxHoursDailyPercentages1[tmd->teacher_ID] <= tmd->weightPercentage)){
4740 teachersMaxHoursDailyMaxHours1[tmd->teacher_ID] = tmd->maxHoursDaily;
4741 teachersMaxHoursDailyPercentages1[tmd->teacher_ID] = tmd->weightPercentage;
4742 }
4743 else if(teachersMaxHoursDailyMaxHours1[tmd->teacher_ID] <= tmd->maxHoursDaily &&
4744 teachersMaxHoursDailyPercentages1[tmd->teacher_ID] >= tmd->weightPercentage){
4745 //nothing
4746 }
4747 else{
4748 if(teachersMaxHoursDailyMaxHours2[tmd->teacher_ID]==-1 ||
4749 (teachersMaxHoursDailyMaxHours2[tmd->teacher_ID] >= tmd->maxHoursDaily &&
4750 teachersMaxHoursDailyPercentages2[tmd->teacher_ID] <= tmd->weightPercentage)){
4751 teachersMaxHoursDailyMaxHours2[tmd->teacher_ID] = tmd->maxHoursDaily;
4752 teachersMaxHoursDailyPercentages2[tmd->teacher_ID] = tmd->weightPercentage;
4753 }
4754 else if(teachersMaxHoursDailyMaxHours2[tmd->teacher_ID] <= tmd->maxHoursDaily &&
4755 teachersMaxHoursDailyPercentages2[tmd->teacher_ID] >= tmd->weightPercentage){
4756 //nothing
4757 }
4758 else{ //cannot proceed
4759 ok=false;
4760
4761 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4762 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are too many constraints"
4763 " of type max hours daily relating to him, which cannot be compressed in 2 constraints of this type."
4764 " Two constraints max hours can be compressed into a single one if the max hours are lower"
4765 " in the first one and the weight percentage is higher on the first one."
4766 " It is possible to use any number of such constraints for a teacher, but their resultant must"
4767 " be maximum 2 constraints of type max hours daily.\n\n"
4768 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
4769 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
4770 " Please modify your data accordingly and try again.")
4771 .arg(gt.rules.internalTeachersList[tmd->teacher_ID]->name),
4772 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4773 1, 0 );
4774
4775 if(t==0)
4776 return false;
4777 }
4778 }
4779 }
4780 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_HOURS_DAILY){
4781 ConstraintTeachersMaxHoursDaily* tmd=(ConstraintTeachersMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
4782
4783 if(tmd->weightPercentage<100.0)
4784 thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
4785
4786 //////////
4787 /*if(tmd->weightPercentage!=100){
4788 ok=false;
4789
4790 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
4791 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max hours daily with"
4792 " weight (percentage) below 100. Starting with FET version 5.3.0 it is only possible"
4793 " to use 100% weight for such constraints. Please make weight 100% and try again"),
4794 GeneratePreTranslate::tr("Skip rest of max hours problems"), GeneratePreTranslate::tr("See next incompatibility max hours"), QString(),
4795 1, 0 );
4796
4797 if(t==0)
4798 return false;
4799 }*/
4800 //////////
4801
4802 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
4803 if(teachersMaxHoursDailyMaxHours1[tch]==-1 ||
4804 (teachersMaxHoursDailyMaxHours1[tch] >= tmd->maxHoursDaily &&
4805 teachersMaxHoursDailyPercentages1[tch] <= tmd->weightPercentage)){
4806 teachersMaxHoursDailyMaxHours1[tch] = tmd->maxHoursDaily;
4807 teachersMaxHoursDailyPercentages1[tch] = tmd->weightPercentage;
4808 }
4809 else if(teachersMaxHoursDailyMaxHours1[tch] <= tmd->maxHoursDaily &&
4810 teachersMaxHoursDailyPercentages1[tch] >= tmd->weightPercentage){
4811 //nothing
4812 }
4813 else{
4814 if(teachersMaxHoursDailyMaxHours2[tch]==-1 ||
4815 (teachersMaxHoursDailyMaxHours2[tch] >= tmd->maxHoursDaily &&
4816 teachersMaxHoursDailyPercentages2[tch] <= tmd->weightPercentage)){
4817 teachersMaxHoursDailyMaxHours2[tch] = tmd->maxHoursDaily;
4818 teachersMaxHoursDailyPercentages2[tch] = tmd->weightPercentage;
4819 }
4820 else if(teachersMaxHoursDailyMaxHours2[tch] <= tmd->maxHoursDaily &&
4821 teachersMaxHoursDailyPercentages2[tch] >= tmd->weightPercentage){
4822 //nothing
4823 }
4824 else{ //cannot proceed
4825 ok=false;
4826
4827 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
4828 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are too many constraints"
4829 " of type max hours daily relating to him, which cannot be compressed in 2 constraints of this type."
4830 " Two constraints max hours can be compressed into a single one if the max hours are lower"
4831 " in the first one and the weight percentage is higher on the first one."
4832 " It is possible to use any number of such constraints for a teacher, but their resultant must"
4833 " be maximum 2 constraints of type max hours daily.\n\n"
4834 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
4835 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
4836 " Please modify your data accordingly and try again.")
4837 .arg(gt.rules.internalTeachersList[tch]->name),
4838 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4839 1, 0 );
4840
4841 if(t==0)
4842 return false;
4843 }
4844 }
4845 }
4846 }
4847 }
4848
4849 Matrix1D<int> nAllowedSlotsPerDay;
4850 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
4851
4852 Matrix1D<int> dayAvailable;
4853 dayAvailable.resize(gt.rules.nDaysPerWeek);
4854
4855 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
4856 if(teachersMaxHoursDailyPercentages1[tc]==100){
4857 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
4858 nAllowedSlotsPerDay[d]=0;
4859 for(int h=0; h<gt.rules.nHoursPerDay; h++)
4860 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
4861 nAllowedSlotsPerDay[d]++;
4862 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxHoursDailyMaxHours1[tc]);
4863 }
4864
4865 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4866 dayAvailable[d]=1;
4867 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){
4868 //n days per week has 100% weight
4869 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4870 dayAvailable[d]=0;
4871 assert(teachersMaxDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek);
4872 for(int k=0; k<teachersMaxDaysPerWeekMaxDays[tc]; k++){
4873 int maxPos=-1, maxVal=-1;
4874 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4875 if(dayAvailable[d]==0)
4876 if(maxVal<nAllowedSlotsPerDay[d]){
4877 maxVal=nAllowedSlotsPerDay[d];
4878 maxPos=d;
4879 }
4880 assert(maxPos>=0);
4881 assert(dayAvailable[maxPos]==0);
4882 dayAvailable[maxPos]=1;
4883 }
4884 }
4885
4886 int total=0;
4887 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4888 if(dayAvailable[d]==1)
4889 total+=nAllowedSlotsPerDay[d];
4890 if(total<nHoursPerTeacher[tc]){
4891 ok=false;
4892
4893 QString s;
4894 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
4895 " max %2 hours daily with 100% weight which cannot be respected because of number of days per week,"
4896 " number of hours per day, teacher max days per week, teacher not available and/or breaks."
4897 " The number of total hours for this teacher is"
4898 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
4899 .arg(gt.rules.internalTeachersList[tc]->name)
4900 .arg(teachersMaxHoursDailyMaxHours1[tc])
4901 .arg(nHoursPerTeacher[tc])
4902 .arg(total);
4903 s+="\n\n";
4904 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
4905
4906 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
4907 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4908 1, 0 );
4909
4910 if(t==0)
4911 return false;
4912 }
4913 }
4914 }
4915
4916 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
4917 if(teachersMaxHoursDailyPercentages2[tc]==100){
4918 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
4919 nAllowedSlotsPerDay[d]=0;
4920 for(int h=0; h<gt.rules.nHoursPerDay; h++)
4921 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
4922 nAllowedSlotsPerDay[d]++;
4923 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxHoursDailyMaxHours2[tc]);
4924 }
4925
4926 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4927 dayAvailable[d]=1;
4928 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){
4929 //n days per week has 100% weight
4930 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4931 dayAvailable[d]=0;
4932 assert(teachersMaxDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek);
4933 for(int k=0; k<teachersMaxDaysPerWeekMaxDays[tc]; k++){
4934 int maxPos=-1, maxVal=-1;
4935 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4936 if(dayAvailable[d]==0)
4937 if(maxVal<nAllowedSlotsPerDay[d]){
4938 maxVal=nAllowedSlotsPerDay[d];
4939 maxPos=d;
4940 }
4941 assert(maxPos>=0);
4942 assert(dayAvailable[maxPos]==0);
4943 dayAvailable[maxPos]=1;
4944 }
4945 }
4946
4947 int total=0;
4948 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4949 if(dayAvailable[d]==1)
4950 total+=nAllowedSlotsPerDay[d];
4951 if(total<nHoursPerTeacher[tc]){
4952 ok=false;
4953
4954 QString s;
4955 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
4956 " max %2 hours daily with 100% weight which cannot be respected because of number of days per week,"
4957 " number of hours per day, teacher max days per week, teacher not available and/or breaks."
4958 " The number of total hours for this teacher is"
4959 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
4960 .arg(gt.rules.internalTeachersList[tc]->name)
4961 .arg(teachersMaxHoursDailyMaxHours2[tc])
4962 .arg(nHoursPerTeacher[tc])
4963 .arg(total);
4964 s+="\n\n";
4965 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
4966
4967 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
4968 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
4969 1, 0 );
4970
4971 if(t==0)
4972 return false;
4973 }
4974 }
4975 }
4976
4977 if(gt.rules.mode==MORNINGS_AFTERNOONS){
4978 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
4979 if(teachersMaxHoursDailyPercentages1[tc]==100){
4980 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
4981 nAllowedSlotsPerDay[d]=0;
4982 for(int h=0; h<gt.rules.nHoursPerDay; h++)
4983 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
4984 nAllowedSlotsPerDay[d]++;
4985 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxHoursDailyMaxHours1[tc]);
4986 }
4987
4988 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4989 dayAvailable[d]=1;
4990 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){
4991 //n days per week has 100% weight
4992 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4993 dayAvailable[d]=0;
4994 assert(teachersMaxRealDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek/2);
4995 for(int k=0; k<2*teachersMaxRealDaysPerWeekMaxDays[tc]; k++){
4996 int maxPos=-1, maxVal=-1;
4997 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
4998 if(dayAvailable[d]==0)
4999 if(maxVal<nAllowedSlotsPerDay[d]){
5000 maxVal=nAllowedSlotsPerDay[d];
5001 maxPos=d;
5002 }
5003 assert(maxPos>=0);
5004 assert(dayAvailable[maxPos]==0);
5005 dayAvailable[maxPos]=1;
5006 }
5007 }
5008
5009 int total=0;
5010 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5011 if(dayAvailable[d]==1)
5012 total+=nAllowedSlotsPerDay[d];
5013 if(total<nHoursPerTeacher[tc]){
5014 ok=false;
5015
5016 QString s;
5017 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5018 " max %2 hours daily with 100% weight which cannot be respected because of number of days per week,"
5019 " number of hours per day, teacher max days per week, teacher not available and/or breaks."
5020 " The number of total hours for this teacher is"
5021 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
5022 .arg(gt.rules.internalTeachersList[tc]->name)
5023 .arg(teachersMaxHoursDailyMaxHours1[tc])
5024 .arg(nHoursPerTeacher[tc])
5025 .arg(total);
5026 s+="\n\n";
5027 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5028
5029 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5030 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5031 1, 0 );
5032
5033 if(t==0)
5034 return false;
5035 }
5036 }
5037 }
5038
5039 Matrix1D<int> nAllowedSlotsPerDay;
5040 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
5041 Matrix1D<int> dayAvailable;
5042 dayAvailable.resize(gt.rules.nDaysPerWeek);
5043
5044 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
5045 if(teachersMaxHoursDailyPercentages2[tc]==100){
5046 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
5047 nAllowedSlotsPerDay[d]=0;
5048 for(int h=0; h<gt.rules.nHoursPerDay; h++)
5049 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
5050 nAllowedSlotsPerDay[d]++;
5051 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxHoursDailyMaxHours2[tc]);
5052 }
5053
5054 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5055 dayAvailable[d]=1;
5056 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){
5057 //n days per week has 100% weight
5058 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5059 dayAvailable[d]=0;
5060 assert(teachersMaxRealDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek/2);
5061 for(int k=0; k<2*teachersMaxRealDaysPerWeekMaxDays[tc]; k++){
5062 int maxPos=-1, maxVal=-1;
5063 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5064 if(dayAvailable[d]==0)
5065 if(maxVal<nAllowedSlotsPerDay[d]){
5066 maxVal=nAllowedSlotsPerDay[d];
5067 maxPos=d;
5068 }
5069 assert(maxPos>=0);
5070 assert(dayAvailable[maxPos]==0);
5071 dayAvailable[maxPos]=1;
5072 }
5073 }
5074
5075 int total=0;
5076 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5077 if(dayAvailable[d]==1)
5078 total+=nAllowedSlotsPerDay[d];
5079 if(total<nHoursPerTeacher[tc]){
5080 ok=false;
5081
5082 QString s;
5083 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5084 " max %2 hours daily with 100% weight which cannot be respected because of number of days per week,"
5085 " number of hours per day, teacher max days per week, teacher not available and/or breaks."
5086 " The number of total hours for this teacher is"
5087 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
5088 .arg(gt.rules.internalTeachersList[tc]->name)
5089 .arg(teachersMaxHoursDailyMaxHours2[tc])
5090 .arg(nHoursPerTeacher[tc])
5091 .arg(total);
5092 s+="\n\n";
5093 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5094
5095 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5096 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5097 1, 0 );
5098
5099 if(t==0)
5100 return false;
5101 }
5102 }
5103 }
5104 }
5105
5106 return ok;
5107 }
5108
5109 //must be after allowed times, after n hours per teacher and after max days per week
computeTeachersMaxHoursDailyRealDays(QWidget * parent)5110 bool computeTeachersMaxHoursDailyRealDays(QWidget* parent)
5111 {
5112 bool ok=true;
5113
5114 for(int i=0; i<gt.rules.nInternalTeachers; i++){
5115 teachersMaxHoursDailyRealDaysMaxHours1[i]=-1;
5116 teachersMaxHoursDailyRealDaysPercentages1[i]=-1;
5117
5118 teachersMaxHoursDailyRealDaysMaxHours2[i]=-1;
5119 teachersMaxHoursDailyRealDaysPercentages2[i]=-1;
5120 }
5121
5122 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5123 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_HOURS_DAILY_REAL_DAYS){
5124 ConstraintTeacherMaxHoursDailyRealDays* tmd=(ConstraintTeacherMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
5125
5126 if(tmd->weightPercentage<100.0)
5127 thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
5128
5129 //////////
5130 /*if(tmd->weightPercentage!=100){
5131 ok=false;
5132
5133 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
5134 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max hours daily for teacher %1 with"
5135 " weight (percentage) below 100. Starting with FET version 5.3.0 it is only possible"
5136 " to use 100% weight for such constraints. Please make weight 100% and try again")
5137 .arg(tmd->teacherName),
5138 GeneratePreTranslate::tr("Skip rest of max hours problems"), GeneratePreTranslate::tr("See next incompatibility max hours"), QString(),
5139 1, 0 );
5140
5141 if(t==0)
5142 return false;
5143 }*/
5144 //////////
5145
5146 if(teachersMaxHoursDailyRealDaysMaxHours1[tmd->teacher_ID]==-1 ||
5147 (teachersMaxHoursDailyRealDaysMaxHours1[tmd->teacher_ID] >= tmd->maxHoursDaily &&
5148 teachersMaxHoursDailyRealDaysPercentages1[tmd->teacher_ID] <= tmd->weightPercentage)){
5149 teachersMaxHoursDailyRealDaysMaxHours1[tmd->teacher_ID] = tmd->maxHoursDaily;
5150 teachersMaxHoursDailyRealDaysPercentages1[tmd->teacher_ID] = tmd->weightPercentage;
5151 }
5152 else if(teachersMaxHoursDailyRealDaysMaxHours1[tmd->teacher_ID] <= tmd->maxHoursDaily &&
5153 teachersMaxHoursDailyRealDaysPercentages1[tmd->teacher_ID] >= tmd->weightPercentage){
5154 //nothing
5155 }
5156 else{
5157 if(teachersMaxHoursDailyRealDaysMaxHours2[tmd->teacher_ID]==-1 ||
5158 (teachersMaxHoursDailyRealDaysMaxHours2[tmd->teacher_ID] >= tmd->maxHoursDaily &&
5159 teachersMaxHoursDailyRealDaysPercentages2[tmd->teacher_ID] <= tmd->weightPercentage)){
5160 teachersMaxHoursDailyRealDaysMaxHours2[tmd->teacher_ID] = tmd->maxHoursDaily;
5161 teachersMaxHoursDailyRealDaysPercentages2[tmd->teacher_ID] = tmd->weightPercentage;
5162 }
5163 else if(teachersMaxHoursDailyRealDaysMaxHours2[tmd->teacher_ID] <= tmd->maxHoursDaily &&
5164 teachersMaxHoursDailyRealDaysPercentages2[tmd->teacher_ID] >= tmd->weightPercentage){
5165 //nothing
5166 }
5167 else{ //cannot proceed
5168 ok=false;
5169
5170 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5171 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are too many constraints"
5172 " of type max hours daily per real day relating to him, which cannot be compressed in 2 constraints of this type."
5173 " Two constraints max hours can be compressed into a single one if the max hours are lower"
5174 " in the first one and the weight percentage is higher on the first one."
5175 " It is possible to use any number of such constraints for a teacher, but their resultant must"
5176 " be maximum 2 constraints of type max hours daily per real day.\n\n"
5177 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
5178 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
5179 " Please modify your data accordingly and try again.")
5180 .arg(gt.rules.internalTeachersList[tmd->teacher_ID]->name),
5181 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5182 1, 0 );
5183
5184 if(t==0)
5185 return false;
5186 }
5187 }
5188 }
5189 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_HOURS_DAILY_REAL_DAYS){
5190 ConstraintTeachersMaxHoursDailyRealDays* tmd=(ConstraintTeachersMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
5191
5192 if(tmd->weightPercentage<100.0)
5193 thereAreTeachersWithMaxHoursDailyOrPerRealDayWithUnder100Weight=true;
5194
5195 //////////
5196 /*if(tmd->weightPercentage!=100){
5197 ok=false;
5198
5199 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
5200 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max hours daily with"
5201 " weight (percentage) below 100. Starting with FET version 5.3.0 it is only possible"
5202 " to use 100% weight for such constraints. Please make weight 100% and try again"),
5203 GeneratePreTranslate::tr("Skip rest of max hours problems"), GeneratePreTranslate::tr("See next incompatibility max hours"), QString(),
5204 1, 0 );
5205
5206 if(t==0)
5207 return false;
5208 }*/
5209 //////////
5210
5211 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
5212 if(teachersMaxHoursDailyRealDaysMaxHours1[tch]==-1 ||
5213 (teachersMaxHoursDailyRealDaysMaxHours1[tch] >= tmd->maxHoursDaily &&
5214 teachersMaxHoursDailyRealDaysPercentages1[tch] <= tmd->weightPercentage)){
5215 teachersMaxHoursDailyRealDaysMaxHours1[tch] = tmd->maxHoursDaily;
5216 teachersMaxHoursDailyRealDaysPercentages1[tch] = tmd->weightPercentage;
5217 }
5218 else if(teachersMaxHoursDailyRealDaysMaxHours1[tch] <= tmd->maxHoursDaily &&
5219 teachersMaxHoursDailyRealDaysPercentages1[tch] >= tmd->weightPercentage){
5220 //nothing
5221 }
5222 else{
5223 if(teachersMaxHoursDailyRealDaysMaxHours2[tch]==-1 ||
5224 (teachersMaxHoursDailyRealDaysMaxHours2[tch] >= tmd->maxHoursDaily &&
5225 teachersMaxHoursDailyRealDaysPercentages2[tch] <= tmd->weightPercentage)){
5226 teachersMaxHoursDailyRealDaysMaxHours2[tch] = tmd->maxHoursDaily;
5227 teachersMaxHoursDailyRealDaysPercentages2[tch] = tmd->weightPercentage;
5228 }
5229 else if(teachersMaxHoursDailyRealDaysMaxHours2[tch] <= tmd->maxHoursDaily &&
5230 teachersMaxHoursDailyRealDaysPercentages2[tch] >= tmd->weightPercentage){
5231 //nothing
5232 }
5233 else{ //cannot proceed
5234 ok=false;
5235
5236 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5237 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are too many constraints"
5238 " of type max hours daily per real day relating to him, which cannot be compressed in 2 constraints of this type."
5239 " Two constraints max hours can be compressed into a single one if the max hours are lower"
5240 " in the first one and the weight percentage is higher on the first one."
5241 " It is possible to use any number of such constraints for a teacher, but their resultant must"
5242 " be maximum 2 constraints of type max hours daily per real day.\n\n"
5243 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
5244 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
5245 " Please modify your data accordingly and try again.")
5246 .arg(gt.rules.internalTeachersList[tch]->name),
5247 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5248 1, 0 );
5249
5250 if(t==0)
5251 return false;
5252 }
5253 }
5254 }
5255 }
5256 }
5257
5258 if(gt.rules.mode==MORNINGS_AFTERNOONS)
5259 assert(gt.rules.nDaysPerWeek%2==0); //this is taken care of previously - the generation cannot begin otherwise
5260
5261 Matrix1D<int> nAllowedSlotsPerDay;
5262 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek/2);
5263 Matrix1D<int> dayAvailable;
5264 dayAvailable.resize(gt.rules.nDaysPerWeek/2);
5265
5266 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
5267 if(teachersMaxHoursDailyRealDaysPercentages1[tc]==100){
5268 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
5269 nAllowedSlotsPerDay[d]=0;
5270 for(int h=0; h<gt.rules.nHoursPerDay; h++){
5271 if(!breakDayHour[2*d][h] && !teacherNotAvailableDayHour[tc][2*d][h])
5272 nAllowedSlotsPerDay[d]++;
5273 if(!breakDayHour[2*d+1][h] && !teacherNotAvailableDayHour[tc][2*d+1][h])
5274 nAllowedSlotsPerDay[d]++;
5275 }
5276 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxHoursDailyRealDaysMaxHours1[tc]);
5277 }
5278
5279 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5280 dayAvailable[d]=1;
5281 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){
5282 //n days per week has 100% weight
5283 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5284 dayAvailable[d]=0;
5285 assert(teachersMaxRealDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek/2);
5286 for(int k=0; k<teachersMaxRealDaysPerWeekMaxDays[tc]; k++){
5287 int maxPos=-1, maxVal=-1;
5288 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5289 if(dayAvailable[d]==0)
5290 if(maxVal<nAllowedSlotsPerDay[d]){
5291 maxVal=nAllowedSlotsPerDay[d];
5292 maxPos=d;
5293 }
5294 assert(maxPos>=0);
5295 assert(dayAvailable[maxPos]==0);
5296 dayAvailable[maxPos]=1;
5297 }
5298 }
5299
5300 int total=0;
5301 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5302 if(dayAvailable[d]==1)
5303 total+=nAllowedSlotsPerDay[d];
5304 if(total<nHoursPerTeacher[tc]){
5305 ok=false;
5306
5307 QString s;
5308 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5309 " max %2 hours daily per real day with 100% weight which cannot be respected because of number of days per week,"
5310 " number of hours per day, teacher(s) max real days per week, teacher not available and/or breaks."
5311 " The number of total hours for this teacher is"
5312 " %3 and the number of available slots is, considering max hours daily per real day and all other constraints, %4.")
5313 .arg(gt.rules.internalTeachersList[tc]->name)
5314 .arg(teachersMaxHoursDailyRealDaysMaxHours1[tc])
5315 .arg(nHoursPerTeacher[tc])
5316 .arg(total);
5317 s+="\n\n";
5318 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5319
5320 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5321 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5322 1, 0 );
5323
5324 if(t==0)
5325 return false;
5326 }
5327 }
5328 }
5329
5330 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
5331 if(teachersMaxHoursDailyRealDaysPercentages2[tc]==100){
5332 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
5333 nAllowedSlotsPerDay[d]=0;
5334 for(int h=0; h<gt.rules.nHoursPerDay; h++){
5335 if(!breakDayHour[2*d][h] && !teacherNotAvailableDayHour[tc][2*d][h])
5336 nAllowedSlotsPerDay[d]++;
5337 if(!breakDayHour[2*d+1][h] && !teacherNotAvailableDayHour[tc][2*d+1][h])
5338 nAllowedSlotsPerDay[d]++;
5339 }
5340 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxHoursDailyRealDaysMaxHours1[tc]);
5341 }
5342
5343 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5344 dayAvailable[d]=1;
5345 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){
5346 //n days per week has 100% weight
5347 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5348 dayAvailable[d]=0;
5349 assert(teachersMaxRealDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek/2);
5350 for(int k=0; k<teachersMaxRealDaysPerWeekMaxDays[tc]; k++){
5351 int maxPos=-1, maxVal=-1;
5352 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5353 if(dayAvailable[d]==0)
5354 if(maxVal<nAllowedSlotsPerDay[d]){
5355 maxVal=nAllowedSlotsPerDay[d];
5356 maxPos=d;
5357 }
5358 assert(maxPos>=0);
5359 assert(dayAvailable[maxPos]==0);
5360 dayAvailable[maxPos]=1;
5361 }
5362 }
5363
5364 int total=0;
5365 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5366 if(dayAvailable[d]==1)
5367 total+=nAllowedSlotsPerDay[d];
5368 if(total<nHoursPerTeacher[tc]){
5369 ok=false;
5370
5371 QString s;
5372 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5373 " max %2 hours daily per real day with 100% weight which cannot be respected because of number of days per week,"
5374 " number of hours per day, teacher(s) max real days per week, teacher not available and/or breaks."
5375 " The number of total hours for this teacher is"
5376 " %3 and the number of available slots is, considering max hours daily and all other constraints, %4.")
5377 .arg(gt.rules.internalTeachersList[tc]->name)
5378 .arg(teachersMaxHoursDailyRealDaysMaxHours2[tc])
5379 .arg(nHoursPerTeacher[tc])
5380 .arg(total);
5381 s+="\n\n";
5382 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5383
5384 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5385 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5386 1, 0 );
5387
5388 if(t==0)
5389 return false;
5390 }
5391 }
5392 }
5393
5394 return ok;
5395 }
5396
5397 //must be after allowed times, after n hours per teacher and after max days per week for teachers
computeTeachersMaxSpanPerDay(QWidget * parent)5398 bool computeTeachersMaxSpanPerDay(QWidget* parent)
5399 {
5400 bool ok=true;
5401
5402 for(int i=0; i<gt.rules.nInternalTeachers; i++){
5403 teachersMaxSpanPerDayMaxSpan[i]=-1;
5404 teachersMaxSpanPerDayPercentages[i]=-1;
5405 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[i]=true;
5406 }
5407
5408 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5409 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_SPAN_PER_DAY){
5410 ConstraintTeacherMaxSpanPerDay* tmsd=(ConstraintTeacherMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
5411
5412 if(tmsd->weightPercentage!=100){
5413 ok=false;
5414
5415 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5416 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max span per day for teacher %1"
5417 " with weight (percentage) below 100. Please make weight 100% and try again").arg(tmsd->teacherName),
5418 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5419 1, 0 );
5420
5421 if(t==0)
5422 return false;
5423 }
5424 }
5425 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_SPAN_PER_DAY){
5426 ConstraintTeachersMaxSpanPerDay* tmsd=(ConstraintTeachersMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
5427
5428 if(tmsd->weightPercentage!=100){
5429 ok=false;
5430
5431 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5432 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max span per day"
5433 " with weight (percentage) below 100. Please make weight 100% and try again"),
5434 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5435 1, 0 );
5436
5437 if(t==0)
5438 return false;
5439 }
5440 }
5441 }
5442
5443 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5444 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_SPAN_PER_DAY){
5445 ConstraintTeacherMaxSpanPerDay* tmsd=(ConstraintTeacherMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
5446
5447 if(teachersMaxSpanPerDayPercentages[tmsd->teacher_ID]==-1){
5448 teachersMaxSpanPerDayPercentages[tmsd->teacher_ID]=100.0;
5449 teachersMaxSpanPerDayMaxSpan[tmsd->teacher_ID]=tmsd->maxSpanPerDay;
5450 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID]=tmsd->allowOneDayExceptionPlusOne;
5451 }
5452 else if(teachersMaxSpanPerDayMaxSpan[tmsd->teacher_ID] > tmsd->maxSpanPerDay){
5453 assert(teachersMaxSpanPerDayPercentages[tmsd->teacher_ID]==100.0);
5454 teachersMaxSpanPerDayMaxSpan[tmsd->teacher_ID]=tmsd->maxSpanPerDay;
5455 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID]=tmsd->allowOneDayExceptionPlusOne;
5456 }
5457 else if(teachersMaxSpanPerDayMaxSpan[tmsd->teacher_ID]==tmsd->maxSpanPerDay){
5458 assert(teachersMaxSpanPerDayPercentages[tmsd->teacher_ID]==100.0);
5459 assert(teachersMaxSpanPerDayMaxSpan[tmsd->teacher_ID]==tmsd->maxSpanPerDay);
5460 if(!tmsd->allowOneDayExceptionPlusOne && teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID])
5461 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID]=false;
5462 }
5463 }
5464 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_SPAN_PER_DAY){
5465 ConstraintTeachersMaxSpanPerDay* tmsd=(ConstraintTeachersMaxSpanPerDay*)gt.rules.internalTimeConstraintsList[i];
5466
5467 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
5468 if(teachersMaxSpanPerDayPercentages[tch]==-1){
5469 teachersMaxSpanPerDayPercentages[tch]=100.0;
5470 teachersMaxSpanPerDayMaxSpan[tch]=tmsd->maxSpanPerDay;
5471 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tch]=tmsd->allowOneDayExceptionPlusOne;
5472 }
5473 else if(teachersMaxSpanPerDayMaxSpan[tch] > tmsd->maxSpanPerDay){
5474 assert(teachersMaxSpanPerDayPercentages[tch]==100.0);
5475 teachersMaxSpanPerDayMaxSpan[tch]=tmsd->maxSpanPerDay;
5476 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tch]=tmsd->allowOneDayExceptionPlusOne;
5477 }
5478 else if(teachersMaxSpanPerDayMaxSpan[tch]==tmsd->maxSpanPerDay){
5479 assert(teachersMaxSpanPerDayPercentages[tch]==100.0);
5480 assert(teachersMaxSpanPerDayMaxSpan[tch]==tmsd->maxSpanPerDay);
5481 if(!tmsd->allowOneDayExceptionPlusOne && teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tch])
5482 teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tch]=false;
5483 }
5484 }
5485 }
5486 }
5487
5488 Matrix1D<int> nAllowedSlotsPerDay;
5489 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
5490
5491 Matrix1D<int> dayAvailable;
5492 dayAvailable.resize(gt.rules.nDaysPerWeek);
5493
5494 //This is similar to teachers max hours daily checking. It is not a very useful test, but does not hurt.
5495 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
5496 bool exceptionUsed=false;
5497 if(!teachersMaxSpanPerDayAllowOneDayExceptionPlusOne[tc])
5498 exceptionUsed=true;
5499
5500 if(teachersMaxSpanPerDayPercentages[tc]==100){
5501 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
5502 nAllowedSlotsPerDay[d]=0;
5503 for(int h=0; h<gt.rules.nHoursPerDay; h++)
5504 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
5505 nAllowedSlotsPerDay[d]++;
5506
5507 if(exceptionUsed==false && nAllowedSlotsPerDay[d]>=teachersMaxSpanPerDayMaxSpan[tc]+1){
5508 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxSpanPerDayMaxSpan[tc]+1);
5509 exceptionUsed=true;
5510 }
5511 else{
5512 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxSpanPerDayMaxSpan[tc]);
5513 }
5514 }
5515
5516 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5517 dayAvailable[d]=1;
5518 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){
5519 //n days per week has 100% weight
5520 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5521 dayAvailable[d]=0;
5522 assert(teachersMaxDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek);
5523 for(int k=0; k<teachersMaxDaysPerWeekMaxDays[tc]; k++){
5524 int maxPos=-1, maxVal=-1;
5525 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5526 if(dayAvailable[d]==0)
5527 if(maxVal<nAllowedSlotsPerDay[d]){
5528 maxVal=nAllowedSlotsPerDay[d];
5529 maxPos=d;
5530 }
5531 assert(maxPos>=0);
5532 assert(dayAvailable[maxPos]==0);
5533 dayAvailable[maxPos]=1;
5534 }
5535 }
5536
5537 int total=0;
5538 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
5539 if(dayAvailable[d]==1)
5540 total+=nAllowedSlotsPerDay[d];
5541 if(total<nHoursPerTeacher[tc]){
5542 ok=false;
5543
5544 QString s;
5545 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5546 " max %2 span per day with 100% weight which cannot be respected because of number of days per week,"
5547 " number of hours per day, teacher max days per week, teacher not available and/or breaks."
5548 " The number of total hours for this teacher is"
5549 " %3 and the number of available slots is, considering max span per day and all other constraints, %4.")
5550 .arg(gt.rules.internalTeachersList[tc]->name)
5551 .arg(teachersMaxSpanPerDayMaxSpan[tc])
5552 .arg(nHoursPerTeacher[tc])
5553 .arg(total);
5554 s+="\n\n";
5555 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5556
5557 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5558 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5559 1, 0 );
5560
5561 if(t==0)
5562 return false;
5563 }
5564 }
5565 }
5566
5567 return ok;
5568 }
5569
5570 //must be after allowed times, after n hours per teacher and after max days per week for teachers
computeTeachersMaxSpanPerRealDay(QWidget * parent)5571 bool computeTeachersMaxSpanPerRealDay(QWidget* parent)
5572 {
5573 bool ok=true;
5574
5575 for(int i=0; i<gt.rules.nInternalTeachers; i++){
5576 teachersMaxSpanPerRealDayMaxSpan[i]=-1;
5577 teachersMaxSpanPerRealDayPercentages[i]=-1;
5578 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[i]=true;
5579 }
5580
5581 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5582 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_SPAN_PER_REAL_DAY){
5583 ConstraintTeacherMaxSpanPerRealDay* tmsd=(ConstraintTeacherMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
5584
5585 if(tmsd->weightPercentage!=100){
5586 ok=false;
5587
5588 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5589 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max span per real day for teacher %1"
5590 " with weight (percentage) below 100. Please make weight 100% and try again").arg(tmsd->teacherName),
5591 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5592 1, 0 );
5593
5594 if(t==0)
5595 return false;
5596 }
5597 }
5598 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_SPAN_PER_REAL_DAY){
5599 ConstraintTeachersMaxSpanPerRealDay* tmsd=(ConstraintTeachersMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
5600
5601 if(tmsd->weightPercentage!=100){
5602 ok=false;
5603
5604 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5605 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max span per real day"
5606 " with weight (percentage) below 100. Please make weight 100% and try again"),
5607 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5608 1, 0 );
5609
5610 if(t==0)
5611 return false;
5612 }
5613 }
5614 }
5615
5616 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5617 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_SPAN_PER_REAL_DAY){
5618 ConstraintTeacherMaxSpanPerRealDay* tmsd=(ConstraintTeacherMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
5619
5620 if(teachersMaxSpanPerRealDayPercentages[tmsd->teacher_ID]==-1){
5621 teachersMaxSpanPerRealDayPercentages[tmsd->teacher_ID]=100.0;
5622 teachersMaxSpanPerRealDayMaxSpan[tmsd->teacher_ID]=tmsd->maxSpanPerDay;
5623 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID]=tmsd->allowOneDayExceptionPlusOne;
5624 }
5625 else if(teachersMaxSpanPerRealDayMaxSpan[tmsd->teacher_ID] > tmsd->maxSpanPerDay){
5626 assert(teachersMaxSpanPerRealDayPercentages[tmsd->teacher_ID]==100.0);
5627 teachersMaxSpanPerRealDayMaxSpan[tmsd->teacher_ID]=tmsd->maxSpanPerDay;
5628 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID]=tmsd->allowOneDayExceptionPlusOne;
5629 }
5630 else if(teachersMaxSpanPerRealDayMaxSpan[tmsd->teacher_ID]==tmsd->maxSpanPerDay){
5631 assert(teachersMaxSpanPerRealDayPercentages[tmsd->teacher_ID]==100.0);
5632 assert(teachersMaxSpanPerRealDayMaxSpan[tmsd->teacher_ID]==tmsd->maxSpanPerDay);
5633 if(!tmsd->allowOneDayExceptionPlusOne && teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID])
5634 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tmsd->teacher_ID]=false;
5635 }
5636 }
5637 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_SPAN_PER_REAL_DAY){
5638 ConstraintTeachersMaxSpanPerRealDay* tmsd=(ConstraintTeachersMaxSpanPerRealDay*)gt.rules.internalTimeConstraintsList[i];
5639
5640 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
5641 if(teachersMaxSpanPerRealDayPercentages[tch]==-1){
5642 teachersMaxSpanPerRealDayPercentages[tch]=100.0;
5643 teachersMaxSpanPerRealDayMaxSpan[tch]=tmsd->maxSpanPerDay;
5644 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tch]=tmsd->allowOneDayExceptionPlusOne;
5645 }
5646 else if(teachersMaxSpanPerRealDayMaxSpan[tch] > tmsd->maxSpanPerDay){
5647 assert(teachersMaxSpanPerRealDayPercentages[tch]==100.0);
5648 teachersMaxSpanPerRealDayMaxSpan[tch]=tmsd->maxSpanPerDay;
5649 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tch]=tmsd->allowOneDayExceptionPlusOne;
5650 }
5651 else if(teachersMaxSpanPerRealDayMaxSpan[tch]==tmsd->maxSpanPerDay){
5652 assert(teachersMaxSpanPerRealDayPercentages[tch]==100.0);
5653 assert(teachersMaxSpanPerRealDayMaxSpan[tch]==tmsd->maxSpanPerDay);
5654 if(!tmsd->allowOneDayExceptionPlusOne && teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tch])
5655 teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tch]=false;
5656 }
5657 }
5658 }
5659 }
5660
5661 if(gt.rules.mode==MORNINGS_AFTERNOONS)
5662 assert(gt.rules.nDaysPerWeek%2==0); //this is taken care of previously - the generation cannot begin otherwise
5663
5664 //This is similar to teachers max hours daily checking. It is not a very useful test, but does not hurt.
5665 Matrix1D<int> nAllowedSlotsPerDay;
5666 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek/2);
5667 Matrix1D<int> dayAvailable;
5668 dayAvailable.resize(gt.rules.nDaysPerWeek/2);
5669
5670 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
5671 bool exceptionUsed=false;
5672 if(!teachersMaxSpanPerRealDayAllowOneDayExceptionPlusOne[tc])
5673 exceptionUsed=true;
5674
5675 if(teachersMaxSpanPerRealDayPercentages[tc]==100){
5676 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
5677 nAllowedSlotsPerDay[d]=0;
5678 for(int h=0; h<gt.rules.nHoursPerDay; h++){
5679 if(!breakDayHour[2*d][h] && !teacherNotAvailableDayHour[tc][2*d][h])
5680 nAllowedSlotsPerDay[d]++;
5681 if(!breakDayHour[2*d+1][h] && !teacherNotAvailableDayHour[tc][2*d+1][h])
5682 nAllowedSlotsPerDay[d]++;
5683 }
5684
5685 if(exceptionUsed==false && nAllowedSlotsPerDay[d]>=teachersMaxSpanPerRealDayMaxSpan[tc]+1){
5686 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxSpanPerRealDayMaxSpan[tc]+1);
5687 exceptionUsed=true;
5688 }
5689 else{
5690 nAllowedSlotsPerDay[d]=min(nAllowedSlotsPerDay[d],teachersMaxSpanPerRealDayMaxSpan[tc]);
5691 }
5692 }
5693
5694 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5695 dayAvailable[d]=1;
5696 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){
5697 //n days per week has 100% weight
5698 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5699 dayAvailable[d]=0;
5700 assert(teachersMaxRealDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek/2);
5701 for(int k=0; k<teachersMaxRealDaysPerWeekMaxDays[tc]; k++){
5702 int maxPos=-1, maxVal=-1;
5703 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5704 if(dayAvailable[d]==0)
5705 if(maxVal<nAllowedSlotsPerDay[d]){
5706 maxVal=nAllowedSlotsPerDay[d];
5707 maxPos=d;
5708 }
5709 assert(maxPos>=0);
5710 assert(dayAvailable[maxPos]==0);
5711 dayAvailable[maxPos]=1;
5712 }
5713 }
5714
5715 int total=0;
5716 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
5717 if(dayAvailable[d]==1)
5718 total+=nAllowedSlotsPerDay[d];
5719 if(total<nHoursPerTeacher[tc]){
5720 ok=false;
5721
5722 QString s;
5723 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5724 " max %2 span per real day with 100% weight which cannot be respected because of number of days per week,"
5725 " number of hours per day, teacher(s) max real days per week, teacher not available and/or breaks."
5726 " The number of total hours for this teacher is"
5727 " %3 and the number of available slots is, considering max span per real day and all other constraints, %4.")
5728 .arg(gt.rules.internalTeachersList[tc]->name)
5729 .arg(teachersMaxSpanPerRealDayMaxSpan[tc])
5730 .arg(nHoursPerTeacher[tc])
5731 .arg(total);
5732 s+="\n\n";
5733 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5734
5735 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5736 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5737 1, 0 );
5738
5739 if(t==0)
5740 return false;
5741 }
5742 }
5743 }
5744
5745 return ok;
5746 }
5747
computeTeachersMaxHoursContinuously(QWidget * parent)5748 bool computeTeachersMaxHoursContinuously(QWidget* parent)
5749 {
5750 bool ok=true;
5751
5752 for(int i=0; i<gt.rules.nInternalTeachers; i++){
5753 teachersMaxHoursContinuouslyMaxHours1[i]=-1;
5754 teachersMaxHoursContinuouslyPercentages1[i]=-1;
5755
5756 teachersMaxHoursContinuouslyMaxHours2[i]=-1;
5757 teachersMaxHoursContinuouslyPercentages2[i]=-1;
5758 }
5759
5760 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5761 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_HOURS_CONTINUOUSLY){
5762 ConstraintTeacherMaxHoursContinuously* tmd=(ConstraintTeacherMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
5763
5764 if(teachersMaxHoursContinuouslyMaxHours1[tmd->teacher_ID]==-1 ||
5765 (teachersMaxHoursContinuouslyMaxHours1[tmd->teacher_ID] >= tmd->maxHoursContinuously &&
5766 teachersMaxHoursContinuouslyPercentages1[tmd->teacher_ID] <= tmd->weightPercentage)){
5767 teachersMaxHoursContinuouslyMaxHours1[tmd->teacher_ID] = tmd->maxHoursContinuously;
5768 teachersMaxHoursContinuouslyPercentages1[tmd->teacher_ID] = tmd->weightPercentage;
5769 }
5770 else if(teachersMaxHoursContinuouslyMaxHours1[tmd->teacher_ID] <= tmd->maxHoursContinuously &&
5771 teachersMaxHoursContinuouslyPercentages1[tmd->teacher_ID] >= tmd->weightPercentage){
5772 //nothing
5773 }
5774 else{
5775 if(teachersMaxHoursContinuouslyMaxHours2[tmd->teacher_ID]==-1 ||
5776 (teachersMaxHoursContinuouslyMaxHours2[tmd->teacher_ID] >= tmd->maxHoursContinuously &&
5777 teachersMaxHoursContinuouslyPercentages2[tmd->teacher_ID] <= tmd->weightPercentage)){
5778 teachersMaxHoursContinuouslyMaxHours2[tmd->teacher_ID] = tmd->maxHoursContinuously;
5779 teachersMaxHoursContinuouslyPercentages2[tmd->teacher_ID] = tmd->weightPercentage;
5780 }
5781 else if(teachersMaxHoursContinuouslyMaxHours2[tmd->teacher_ID] <= tmd->maxHoursContinuously &&
5782 teachersMaxHoursContinuouslyPercentages2[tmd->teacher_ID] >= tmd->weightPercentage){
5783 //nothing
5784 }
5785 else{ //cannot proceed
5786 ok=false;
5787
5788 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5789 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are too many constraints"
5790 " of type max hours continuously relating to him, which cannot be compressed in 2 constraints of this type."
5791 " Two constraints max hours can be compressed into a single one if the max hours are lower"
5792 " in the first one and the weight percentage is higher on the first one."
5793 " It is possible to use any number of such constraints for a teacher, but their resultant must"
5794 " be maximum 2 constraints of type max hours continuously.\n\n"
5795 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
5796 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
5797 " Please modify your data accordingly and try again.")
5798 .arg(gt.rules.internalTeachersList[tmd->teacher_ID]->name),
5799 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5800 1, 0 );
5801
5802 if(t==0)
5803 return false;
5804 }
5805 }
5806 }
5807 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_HOURS_CONTINUOUSLY){
5808 ConstraintTeachersMaxHoursContinuously* tmd=(ConstraintTeachersMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
5809
5810 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
5811 if(teachersMaxHoursContinuouslyMaxHours1[tch]==-1 ||
5812 (teachersMaxHoursContinuouslyMaxHours1[tch] >= tmd->maxHoursContinuously &&
5813 teachersMaxHoursContinuouslyPercentages1[tch] <= tmd->weightPercentage)){
5814 teachersMaxHoursContinuouslyMaxHours1[tch] = tmd->maxHoursContinuously;
5815 teachersMaxHoursContinuouslyPercentages1[tch] = tmd->weightPercentage;
5816 }
5817 else if(teachersMaxHoursContinuouslyMaxHours1[tch] <= tmd->maxHoursContinuously &&
5818 teachersMaxHoursContinuouslyPercentages1[tch] >= tmd->weightPercentage){
5819 //nothing
5820 }
5821 else{
5822 if(teachersMaxHoursContinuouslyMaxHours2[tch]==-1 ||
5823 (teachersMaxHoursContinuouslyMaxHours2[tch] >= tmd->maxHoursContinuously &&
5824 teachersMaxHoursContinuouslyPercentages2[tch] <= tmd->weightPercentage)){
5825 teachersMaxHoursContinuouslyMaxHours2[tch] = tmd->maxHoursContinuously;
5826 teachersMaxHoursContinuouslyPercentages2[tch] = tmd->weightPercentage;
5827 }
5828 else if(teachersMaxHoursContinuouslyMaxHours2[tch] <= tmd->maxHoursContinuously &&
5829 teachersMaxHoursContinuouslyPercentages2[tch] >= tmd->weightPercentage){
5830 //nothing
5831 }
5832 else{ //cannot proceed
5833 ok=false;
5834
5835 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5836 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are too many constraints"
5837 " of type max hours continuously relating to him, which cannot be compressed in 2 constraints of this type."
5838 " Two constraints max hours can be compressed into a single one if the max hours are lower"
5839 " in the first one and the weight percentage is higher on the first one."
5840 " It is possible to use any number of such constraints for a teacher, but their resultant must"
5841 " be maximum 2 constraints of type max hours continuously.\n\n"
5842 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
5843 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
5844 " Please modify your data accordingly and try again.")
5845 .arg(gt.rules.internalTeachersList[tch]->name),
5846 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5847 1, 0 );
5848
5849 if(t==0)
5850 return false;
5851 }
5852 }
5853 }
5854 }
5855 }
5856
5857 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
5858 for(int tch : qAsConst(gt.rules.internalActivitiesList[ai].iTeachersList)){
5859 if(teachersMaxHoursContinuouslyPercentages1[tch]>=0 && gt.rules.internalActivitiesList[ai].duration > teachersMaxHoursContinuouslyMaxHours1[tch]){
5860 QString s;
5861 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5862 " max %2 hours continuously which cannot be respected because of activity with id %3 (which has duration %4).")
5863 .arg(gt.rules.internalTeachersList[tch]->name)
5864 .arg(teachersMaxHoursContinuouslyMaxHours1[tch])
5865 .arg(gt.rules.internalActivitiesList[ai].id)
5866 .arg(gt.rules.internalActivitiesList[ai].duration);
5867 s+="\n\n";
5868 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5869
5870 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5871 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5872 1, 0 );
5873
5874 if(t==0)
5875 return false;
5876 }
5877 if(teachersMaxHoursContinuouslyPercentages2[tch]>=0 && gt.rules.internalActivitiesList[ai].duration > teachersMaxHoursContinuouslyMaxHours2[tch]){
5878 QString s;
5879 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint of type"
5880 " max %2 hours continuously which cannot be respected because of activity with id %3 (which has duration %4).")
5881 .arg(gt.rules.internalTeachersList[tch]->name)
5882 .arg(teachersMaxHoursContinuouslyMaxHours2[tch])
5883 .arg(gt.rules.internalActivitiesList[ai].id)
5884 .arg(gt.rules.internalActivitiesList[ai].duration);
5885 s+="\n\n";
5886 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
5887
5888 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
5889 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5890 1, 0 );
5891
5892 if(t==0)
5893 return false;
5894 }
5895 }
5896 }
5897
5898 return ok;
5899 }
5900
computeTeachersActivityTagMaxHoursDaily(QWidget * parent)5901 bool computeTeachersActivityTagMaxHoursDaily(QWidget* parent)
5902 {
5903 haveTeachersActivityTagMaxHoursDaily=false;
5904
5905 bool ok=true;
5906
5907 for(int i=0; i<gt.rules.nInternalTeachers; i++){
5908 teachersActivityTagMaxHoursDailyMaxHours[i].clear();
5909 teachersActivityTagMaxHoursDailyPercentage[i].clear();
5910 teachersActivityTagMaxHoursDailyActivityTag[i].clear();
5911 }
5912
5913 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
5914 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_DAILY){
5915 haveTeachersActivityTagMaxHoursDaily=true;
5916
5917 ConstraintTeachersActivityTagMaxHoursDaily* tamd=(ConstraintTeachersActivityTagMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
5918
5919 for(int tc : qAsConst(tamd->canonicalTeachersList)){
5920 int pos1=-1, pos2=-1;
5921
5922 for(int j=0; j<teachersActivityTagMaxHoursDailyMaxHours[tc].count(); j++){
5923 if(teachersActivityTagMaxHoursDailyActivityTag[tc].at(j)==tamd->activityTagIndex){
5924 if(pos1==-1){
5925 pos1=j;
5926 }
5927 else{
5928 assert(pos2==-1);
5929 pos2=j;
5930 }
5931 }
5932 }
5933
5934 if(pos1==-1){
5935 teachersActivityTagMaxHoursDailyActivityTag[tc].append(tamd->activityTagIndex);
5936 teachersActivityTagMaxHoursDailyMaxHours[tc].append(tamd->maxHoursDaily);
5937 teachersActivityTagMaxHoursDailyPercentage[tc].append(tamd->weightPercentage);
5938 }
5939 else{
5940 if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos1) <= tamd->maxHoursDaily
5941 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos1) >= tamd->weightPercentage){
5942 //do nothing
5943 }
5944 else if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos1) >= tamd->maxHoursDaily
5945 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos1) <= tamd->weightPercentage){
5946
5947 teachersActivityTagMaxHoursDailyActivityTag[tc][pos1]=tamd->activityTagIndex;
5948 teachersActivityTagMaxHoursDailyMaxHours[tc][pos1]=tamd->maxHoursDaily;
5949 teachersActivityTagMaxHoursDailyPercentage[tc][pos1]=tamd->weightPercentage;
5950 }
5951 else{
5952 if(pos2==-1){
5953 teachersActivityTagMaxHoursDailyActivityTag[tc].append(tamd->activityTagIndex);
5954 teachersActivityTagMaxHoursDailyMaxHours[tc].append(tamd->maxHoursDaily);
5955 teachersActivityTagMaxHoursDailyPercentage[tc].append(tamd->weightPercentage);
5956 }
5957 else{
5958
5959 if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos2) <= tamd->maxHoursDaily
5960 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos2) >= tamd->weightPercentage){
5961 //do nothing
5962 }
5963 else if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos2) >= tamd->maxHoursDaily
5964 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos2) <= tamd->weightPercentage){
5965
5966 teachersActivityTagMaxHoursDailyActivityTag[tc][pos2]=tamd->activityTagIndex;
5967 teachersActivityTagMaxHoursDailyMaxHours[tc][pos2]=tamd->maxHoursDaily;
5968 teachersActivityTagMaxHoursDailyPercentage[tc][pos2]=tamd->weightPercentage;
5969 }
5970 else{
5971 ok=false;
5972
5973 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
5974 GeneratePreTranslate::tr("Cannot optimize for teacher %1 and activity tag %2, because there are too many constraints"
5975 " of type activity tag max hours daily relating to them, which cannot be compressed in 2 constraints of this type."
5976 " Two constraints max hours can be compressed into a single one if the max hours are lower"
5977 " in the first one and the weight percentage is higher on the first one."
5978 " It is possible to use any number of such constraints for a teacher and an activity tag, but their resultant must"
5979 " be maximum 2 constraints of type activity tag max hours daily.\n\n"
5980 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
5981 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
5982 " Please modify your data accordingly and try again.")
5983 .arg(gt.rules.internalTeachersList[tc]->name)
5984 .arg(tamd->activityTagName),
5985 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
5986 1, 0 );
5987
5988 if(t==0)
5989 return false;
5990 }
5991 }
5992 }
5993 }
5994 }
5995 }
5996 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_DAILY){
5997 haveTeachersActivityTagMaxHoursDaily=true;
5998
5999 ConstraintTeacherActivityTagMaxHoursDaily* tamd=(ConstraintTeacherActivityTagMaxHoursDaily*)gt.rules.internalTimeConstraintsList[i];
6000
6001 for(int tc : qAsConst(tamd->canonicalTeachersList)){
6002 int pos1=-1, pos2=-1;
6003
6004 for(int j=0; j<teachersActivityTagMaxHoursDailyMaxHours[tc].count(); j++){
6005 if(teachersActivityTagMaxHoursDailyActivityTag[tc].at(j)==tamd->activityTagIndex){
6006 if(pos1==-1){
6007 pos1=j;
6008 }
6009 else{
6010 assert(pos2==-1);
6011 pos2=j;
6012 }
6013 }
6014 }
6015
6016 if(pos1==-1){
6017 teachersActivityTagMaxHoursDailyActivityTag[tc].append(tamd->activityTagIndex);
6018 teachersActivityTagMaxHoursDailyMaxHours[tc].append(tamd->maxHoursDaily);
6019 teachersActivityTagMaxHoursDailyPercentage[tc].append(tamd->weightPercentage);
6020 }
6021 else{
6022 if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos1) <= tamd->maxHoursDaily
6023 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos1) >= tamd->weightPercentage){
6024 //do nothing
6025 }
6026 else if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos1) >= tamd->maxHoursDaily
6027 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos1) <= tamd->weightPercentage){
6028
6029 teachersActivityTagMaxHoursDailyActivityTag[tc][pos1]=tamd->activityTagIndex;
6030 teachersActivityTagMaxHoursDailyMaxHours[tc][pos1]=tamd->maxHoursDaily;
6031 teachersActivityTagMaxHoursDailyPercentage[tc][pos1]=tamd->weightPercentage;
6032 }
6033 else{
6034 if(pos2==-1){
6035 teachersActivityTagMaxHoursDailyActivityTag[tc].append(tamd->activityTagIndex);
6036 teachersActivityTagMaxHoursDailyMaxHours[tc].append(tamd->maxHoursDaily);
6037 teachersActivityTagMaxHoursDailyPercentage[tc].append(tamd->weightPercentage);
6038 }
6039 else{
6040
6041 if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos2) <= tamd->maxHoursDaily
6042 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos2) >= tamd->weightPercentage){
6043 //do nothing
6044 }
6045 else if(teachersActivityTagMaxHoursDailyMaxHours[tc].at(pos2) >= tamd->maxHoursDaily
6046 && teachersActivityTagMaxHoursDailyPercentage[tc].at(pos2) <= tamd->weightPercentage){
6047
6048 teachersActivityTagMaxHoursDailyActivityTag[tc][pos2]=tamd->activityTagIndex;
6049 teachersActivityTagMaxHoursDailyMaxHours[tc][pos2]=tamd->maxHoursDaily;
6050 teachersActivityTagMaxHoursDailyPercentage[tc][pos2]=tamd->weightPercentage;
6051 }
6052 else{
6053 ok=false;
6054
6055 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6056 GeneratePreTranslate::tr("Cannot optimize for teacher %1 and activity tag %2, because there are too many constraints"
6057 " of type activity tag max hours daily relating to them, which cannot be compressed in 2 constraints of this type."
6058 " Two constraints max hours can be compressed into a single one if the max hours are lower"
6059 " in the first one and the weight percentage is higher on the first one."
6060 " It is possible to use any number of such constraints for a teacher and an activity tag, but their resultant must"
6061 " be maximum 2 constraints of type activity tag max hours daily.\n\n"
6062 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
6063 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
6064 " Please modify your data accordingly and try again.")
6065 .arg(gt.rules.internalTeachersList[tc]->name)
6066 .arg(tamd->activityTagName),
6067 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6068 1, 0 );
6069
6070 if(t==0)
6071 return false;
6072 }
6073 }
6074 }
6075 }
6076 }
6077 }
6078 }
6079
6080 Matrix1D<int> navd;
6081 navd.resize(gt.rules.nDaysPerWeek);
6082
6083 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6084 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
6085 navd[d]=0;
6086 for(int h=0; h<gt.rules.nHoursPerDay; h++){
6087 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[i][d][h])
6088 navd[d]++;
6089 }
6090 }
6091
6092 for(int j=0; j<teachersActivityTagMaxHoursDailyMaxHours[i].count(); j++){
6093 int mh=teachersActivityTagMaxHoursDailyMaxHours[i].at(j);
6094 double perc=teachersActivityTagMaxHoursDailyPercentage[i].at(j);
6095 int at=teachersActivityTagMaxHoursDailyActivityTag[i].at(j);
6096 if(perc==100.0){
6097 int totalAt=0;
6098 for(int ai : qAsConst(gt.rules.internalTeachersList[i]->activitiesForTeacher))
6099 if(gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(at))
6100 totalAt+=gt.rules.internalActivitiesList[ai].duration;
6101
6102 int ava=0;
6103 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
6104 ava+=min(navd[d], mh);
6105
6106 if(ava<totalAt){
6107 ok=false;
6108
6109 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6110 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint activity tag %2 max %3 hours daily for it with weight 100%"
6111 " which cannot be satisfied, considering the number of available slots (%4) and total duration of activities with this activity tag (%5)"
6112 ". Please correct and try again.", "%2 is the activity tag for this constraint, %3 is the max number of hours daily for this constraint")
6113 .arg(gt.rules.internalTeachersList[i]->name).arg(gt.rules.activityTagsList.at(at)->name).arg(mh).arg(ava).arg(totalAt),
6114 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6115 1, 0 );
6116
6117 if(t==0)
6118 return false;
6119 }
6120 }
6121 }
6122 }
6123
6124 return ok;
6125 }
6126
6127
computeTeachersActivityTagMaxHoursDailyRealDays(QWidget * parent)6128 bool computeTeachersActivityTagMaxHoursDailyRealDays(QWidget* parent)
6129 {
6130 haveTeachersActivityTagMaxHoursDailyRealDays=false;
6131
6132 bool ok=true;
6133
6134 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6135 teachersActivityTagMaxHoursDailyRealDaysMaxHours[i].clear();
6136 teachersActivityTagMaxHoursDailyRealDaysPercentage[i].clear();
6137 teachersActivityTagMaxHoursDailyRealDaysActivityTag[i].clear();
6138 }
6139
6140 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6141 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_DAILY_REAL_DAYS){
6142 haveTeachersActivityTagMaxHoursDailyRealDays=true;
6143
6144 ConstraintTeachersActivityTagMaxHoursDailyRealDays* tamd=(ConstraintTeachersActivityTagMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
6145
6146 for(int tc : qAsConst(tamd->canonicalTeachersList)){
6147 int pos1=-1, pos2=-1;
6148
6149 for(int j=0; j<teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].count(); j++){
6150 if(teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc].at(j)==tamd->activityTagIndex){
6151 if(pos1==-1){
6152 pos1=j;
6153 }
6154 else{
6155 assert(pos2==-1);
6156 pos2=j;
6157 }
6158 }
6159 }
6160
6161 if(pos1==-1){
6162 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc].append(tamd->activityTagIndex);
6163 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].append(tamd->maxHoursDaily);
6164 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].append(tamd->weightPercentage);
6165 }
6166 else{
6167 if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos1) <= tamd->maxHoursDaily
6168 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos1) >= tamd->weightPercentage){
6169 //do nothing
6170 }
6171 else if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos1) >= tamd->maxHoursDaily
6172 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos1) <= tamd->weightPercentage){
6173
6174 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc][pos1]=tamd->activityTagIndex;
6175 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc][pos1]=tamd->maxHoursDaily;
6176 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc][pos1]=tamd->weightPercentage;
6177 }
6178 else{
6179 if(pos2==-1){
6180 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc].append(tamd->activityTagIndex);
6181 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].append(tamd->maxHoursDaily);
6182 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].append(tamd->weightPercentage);
6183 }
6184 else{
6185
6186 if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos2) <= tamd->maxHoursDaily
6187 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos2) >= tamd->weightPercentage){
6188 //do nothing
6189 }
6190 else if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos2) >= tamd->maxHoursDaily
6191 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos2) <= tamd->weightPercentage){
6192
6193 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc][pos2]=tamd->activityTagIndex;
6194 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc][pos2]=tamd->maxHoursDaily;
6195 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc][pos2]=tamd->weightPercentage;
6196 }
6197 else{
6198 ok=false;
6199
6200 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6201 GeneratePreTranslate::tr("Cannot optimize for teacher %1 and activity tag %2, because there are too many constraints"
6202 " of type activity tag max hours daily per real day relating to them, which cannot be compressed in 2 constraints of this type."
6203 " Two constraints max hours can be compressed into a single one if the max hours are lower"
6204 " in the first one and the weight percentage is higher on the first one."
6205 " It is possible to use any number of such constraints for a teacher and an activity tag, but their resultant must"
6206 " be maximum 2 constraints of type activity tag max hours daily per real day.\n\n"
6207 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
6208 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
6209 " Please modify your data accordingly and try again.")
6210 .arg(gt.rules.internalTeachersList[tc]->name)
6211 .arg(tamd->activityTagName),
6212 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6213 1, 0 );
6214
6215 if(t==0)
6216 return false;
6217 }
6218 }
6219 }
6220 }
6221 }
6222 }
6223 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_DAILY_REAL_DAYS){
6224 haveTeachersActivityTagMaxHoursDailyRealDays=true;
6225
6226 ConstraintTeacherActivityTagMaxHoursDailyRealDays* tamd=(ConstraintTeacherActivityTagMaxHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
6227
6228 for(int tc : qAsConst(tamd->canonicalTeachersList)){
6229 int pos1=-1, pos2=-1;
6230
6231 for(int j=0; j<teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].count(); j++){
6232 if(teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc].at(j)==tamd->activityTagIndex){
6233 if(pos1==-1){
6234 pos1=j;
6235 }
6236 else{
6237 assert(pos2==-1);
6238 pos2=j;
6239 }
6240 }
6241 }
6242
6243 if(pos1==-1){
6244 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc].append(tamd->activityTagIndex);
6245 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].append(tamd->maxHoursDaily);
6246 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].append(tamd->weightPercentage);
6247 }
6248 else{
6249 if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos1) <= tamd->maxHoursDaily
6250 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos1) >= tamd->weightPercentage){
6251 //do nothing
6252 }
6253 else if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos1) >= tamd->maxHoursDaily
6254 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos1) <= tamd->weightPercentage){
6255
6256 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc][pos1]=tamd->activityTagIndex;
6257 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc][pos1]=tamd->maxHoursDaily;
6258 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc][pos1]=tamd->weightPercentage;
6259 }
6260 else{
6261 if(pos2==-1){
6262 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc].append(tamd->activityTagIndex);
6263 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].append(tamd->maxHoursDaily);
6264 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].append(tamd->weightPercentage);
6265 }
6266 else{
6267
6268 if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos2) <= tamd->maxHoursDaily
6269 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos2) >= tamd->weightPercentage){
6270 //do nothing
6271 }
6272 else if(teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc].at(pos2) >= tamd->maxHoursDaily
6273 && teachersActivityTagMaxHoursDailyRealDaysPercentage[tc].at(pos2) <= tamd->weightPercentage){
6274
6275 teachersActivityTagMaxHoursDailyRealDaysActivityTag[tc][pos2]=tamd->activityTagIndex;
6276 teachersActivityTagMaxHoursDailyRealDaysMaxHours[tc][pos2]=tamd->maxHoursDaily;
6277 teachersActivityTagMaxHoursDailyRealDaysPercentage[tc][pos2]=tamd->weightPercentage;
6278 }
6279 else{
6280 ok=false;
6281
6282 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6283 GeneratePreTranslate::tr("Cannot optimize for teacher %1 and activity tag %2, because there are too many constraints"
6284 " of type activity tag max hours daily per real day relating to them, which cannot be compressed in 2 constraints of this type."
6285 " Two constraints max hours can be compressed into a single one if the max hours are lower"
6286 " in the first one and the weight percentage is higher on the first one."
6287 " It is possible to use any number of such constraints for a teacher and an activity tag, but their resultant must"
6288 " be maximum 2 constraints of type activity tag max hours daily per real day.\n\n"
6289 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
6290 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
6291 " Please modify your data accordingly and try again.")
6292 .arg(gt.rules.internalTeachersList[tc]->name)
6293 .arg(tamd->activityTagName),
6294 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6295 1, 0 );
6296
6297 if(t==0)
6298 return false;
6299 }
6300 }
6301 }
6302 }
6303 }
6304 }
6305 }
6306 Matrix1D<int> navd;
6307 navd.resize(gt.rules.nDaysPerWeek/2);
6308
6309 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6310 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
6311 navd[d]=0;
6312 for(int h=0; h<gt.rules.nHoursPerDay; h++){
6313 if(!breakDayHour[2*d][h] && !teacherNotAvailableDayHour[i][2*d][h])
6314 navd[d]++;
6315 if(!breakDayHour[2*d+1][h] && !teacherNotAvailableDayHour[i][2*d+1][h])
6316 navd[d]++;
6317 }
6318 }
6319
6320 for(int j=0; j<teachersActivityTagMaxHoursDailyRealDaysMaxHours[i].count(); j++){
6321 int mh=teachersActivityTagMaxHoursDailyRealDaysMaxHours[i].at(j);
6322 double perc=teachersActivityTagMaxHoursDailyRealDaysPercentage[i].at(j);
6323 int at=teachersActivityTagMaxHoursDailyRealDaysActivityTag[i].at(j);
6324 if(perc==100.0){
6325 int totalAt=0;
6326 for(int ai : qAsConst(gt.rules.internalTeachersList[i]->activitiesForTeacher))
6327 if(gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(at))
6328 totalAt+=gt.rules.internalActivitiesList[ai].duration;
6329
6330 int ava=0;
6331 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++)
6332 ava+=min(navd[d], mh);
6333
6334 if(ava<totalAt){
6335 ok=false;
6336
6337 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6338 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there is a constraint activity tag %2 max %3 hours daily per real day for it with weight 100%"
6339 " which cannot be satisfied, considering the number of available slots (%4) and total duration of activities with this activity tag (%5)"
6340 ". Please correct and try again.", "%2 is the activity tag for this constraint, %3 is the max number of hours daily for this constraint")
6341 .arg(gt.rules.internalTeachersList[i]->name).arg(gt.rules.activityTagsList.at(at)->name).arg(mh).arg(ava).arg(totalAt),
6342 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6343 1, 0 );
6344
6345 if(t==0)
6346 return false;
6347 }
6348 }
6349 }
6350 }
6351
6352 return ok;
6353 }
6354
computeTeachersActivityTagMaxHoursContinuously(QWidget * parent)6355 bool computeTeachersActivityTagMaxHoursContinuously(QWidget* parent)
6356 {
6357 haveTeachersActivityTagMaxHoursContinuously=false;
6358
6359 bool ok=true;
6360
6361 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6362 teachersActivityTagMaxHoursContinuouslyMaxHours[i].clear();
6363 teachersActivityTagMaxHoursContinuouslyPercentage[i].clear();
6364 teachersActivityTagMaxHoursContinuouslyActivityTag[i].clear();
6365 }
6366
6367 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6368 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
6369 haveTeachersActivityTagMaxHoursContinuously=true;
6370
6371 ConstraintTeachersActivityTagMaxHoursContinuously* tamc=(ConstraintTeachersActivityTagMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
6372
6373 for(int tc : qAsConst(tamc->canonicalTeachersList)){
6374 int pos1=-1, pos2=-1;
6375
6376 for(int j=0; j<teachersActivityTagMaxHoursContinuouslyMaxHours[tc].count(); j++){
6377 if(teachersActivityTagMaxHoursContinuouslyActivityTag[tc].at(j)==tamc->activityTagIndex){
6378 if(pos1==-1){
6379 pos1=j;
6380 }
6381 else{
6382 assert(pos2==-1);
6383 pos2=j;
6384 }
6385 }
6386 }
6387
6388 if(pos1==-1){
6389 teachersActivityTagMaxHoursContinuouslyActivityTag[tc].append(tamc->activityTagIndex);
6390 teachersActivityTagMaxHoursContinuouslyMaxHours[tc].append(tamc->maxHoursContinuously);
6391 teachersActivityTagMaxHoursContinuouslyPercentage[tc].append(tamc->weightPercentage);
6392 }
6393 else{
6394 if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos1) <= tamc->maxHoursContinuously
6395 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos1) >= tamc->weightPercentage){
6396 //do nothing
6397 }
6398 else if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos1) >= tamc->maxHoursContinuously
6399 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos1) <= tamc->weightPercentage){
6400
6401 teachersActivityTagMaxHoursContinuouslyActivityTag[tc][pos1]=tamc->activityTagIndex;
6402 teachersActivityTagMaxHoursContinuouslyMaxHours[tc][pos1]=tamc->maxHoursContinuously;
6403 teachersActivityTagMaxHoursContinuouslyPercentage[tc][pos1]=tamc->weightPercentage;
6404 }
6405 else{
6406 if(pos2==-1){
6407 teachersActivityTagMaxHoursContinuouslyActivityTag[tc].append(tamc->activityTagIndex);
6408 teachersActivityTagMaxHoursContinuouslyMaxHours[tc].append(tamc->maxHoursContinuously);
6409 teachersActivityTagMaxHoursContinuouslyPercentage[tc].append(tamc->weightPercentage);
6410 }
6411 else{
6412
6413 if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos2) <= tamc->maxHoursContinuously
6414 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos2) >= tamc->weightPercentage){
6415 //do nothing
6416 }
6417 else if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos2) >= tamc->maxHoursContinuously
6418 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos2) <= tamc->weightPercentage){
6419
6420 teachersActivityTagMaxHoursContinuouslyActivityTag[tc][pos2]=tamc->activityTagIndex;
6421 teachersActivityTagMaxHoursContinuouslyMaxHours[tc][pos2]=tamc->maxHoursContinuously;
6422 teachersActivityTagMaxHoursContinuouslyPercentage[tc][pos2]=tamc->weightPercentage;
6423 }
6424 else{
6425 ok=false;
6426
6427 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6428 GeneratePreTranslate::tr("Cannot optimize for teacher %1 and activity tag %2, because there are too many constraints"
6429 " of type activity tag max hours continuously relating to them, which cannot be compressed in 2 constraints of this type."
6430 " Two constraints max hours can be compressed into a single one if the max hours are lower"
6431 " in the first one and the weight percentage is higher on the first one."
6432 " It is possible to use any number of such constraints for a teacher and an activity tag, but their resultant must"
6433 " be maximum 2 constraints of type activity tag max hours continuously.\n\n"
6434 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
6435 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
6436 " Please modify your data accordingly and try again.")
6437 .arg(gt.rules.internalTeachersList[tc]->name)
6438 .arg(tamc->activityTagName),
6439 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6440 1, 0 );
6441
6442 if(t==0)
6443 return false;
6444 }
6445 }
6446 }
6447 }
6448 }
6449 }
6450 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MAX_HOURS_CONTINUOUSLY){
6451 haveTeachersActivityTagMaxHoursContinuously=true;
6452
6453 ConstraintTeacherActivityTagMaxHoursContinuously* tamc=(ConstraintTeacherActivityTagMaxHoursContinuously*)gt.rules.internalTimeConstraintsList[i];
6454
6455 for(int tc : qAsConst(tamc->canonicalTeachersList)){
6456 int pos1=-1, pos2=-1;
6457
6458 for(int j=0; j<teachersActivityTagMaxHoursContinuouslyMaxHours[tc].count(); j++){
6459 if(teachersActivityTagMaxHoursContinuouslyActivityTag[tc].at(j)==tamc->activityTagIndex){
6460 if(pos1==-1){
6461 pos1=j;
6462 }
6463 else{
6464 assert(pos2==-1);
6465 pos2=j;
6466 }
6467 }
6468 }
6469
6470 if(pos1==-1){
6471 teachersActivityTagMaxHoursContinuouslyActivityTag[tc].append(tamc->activityTagIndex);
6472 teachersActivityTagMaxHoursContinuouslyMaxHours[tc].append(tamc->maxHoursContinuously);
6473 teachersActivityTagMaxHoursContinuouslyPercentage[tc].append(tamc->weightPercentage);
6474 }
6475 else{
6476 if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos1) <= tamc->maxHoursContinuously
6477 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos1) >= tamc->weightPercentage){
6478 //do nothing
6479 }
6480 else if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos1) >= tamc->maxHoursContinuously
6481 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos1) <= tamc->weightPercentage){
6482
6483 teachersActivityTagMaxHoursContinuouslyActivityTag[tc][pos1]=tamc->activityTagIndex;
6484 teachersActivityTagMaxHoursContinuouslyMaxHours[tc][pos1]=tamc->maxHoursContinuously;
6485 teachersActivityTagMaxHoursContinuouslyPercentage[tc][pos1]=tamc->weightPercentage;
6486 }
6487 else{
6488 if(pos2==-1){
6489 teachersActivityTagMaxHoursContinuouslyActivityTag[tc].append(tamc->activityTagIndex);
6490 teachersActivityTagMaxHoursContinuouslyMaxHours[tc].append(tamc->maxHoursContinuously);
6491 teachersActivityTagMaxHoursContinuouslyPercentage[tc].append(tamc->weightPercentage);
6492 }
6493 else{
6494
6495 if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos2) <= tamc->maxHoursContinuously
6496 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos2) >= tamc->weightPercentage){
6497 //do nothing
6498 }
6499 else if(teachersActivityTagMaxHoursContinuouslyMaxHours[tc].at(pos2) >= tamc->maxHoursContinuously
6500 && teachersActivityTagMaxHoursContinuouslyPercentage[tc].at(pos2) <= tamc->weightPercentage){
6501
6502 teachersActivityTagMaxHoursContinuouslyActivityTag[tc][pos2]=tamc->activityTagIndex;
6503 teachersActivityTagMaxHoursContinuouslyMaxHours[tc][pos2]=tamc->maxHoursContinuously;
6504 teachersActivityTagMaxHoursContinuouslyPercentage[tc][pos2]=tamc->weightPercentage;
6505 }
6506 else{
6507 ok=false;
6508
6509 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6510 GeneratePreTranslate::tr("Cannot optimize for teacher %1 and activity tag %2, because there are too many constraints"
6511 " of type activity tag max hours continuously relating to them, which cannot be compressed in 2 constraints of this type."
6512 " Two constraints max hours can be compressed into a single one if the max hours are lower"
6513 " in the first one and the weight percentage is higher on the first one."
6514 " It is possible to use any number of such constraints for a teacher and an activity tag, but their resultant must"
6515 " be maximum 2 constraints of type activity tag max hours continuously.\n\n"
6516 " Example: you are allowed to use 3 constraints: 6 hours 95%, 7 hours 100% and 8 hours 100%,"
6517 " which can be compressed into 2 constraints: 6 hours 95%, 7 hours 100%\n\n"
6518 " Please modify your data accordingly and try again.")
6519 .arg(gt.rules.internalTeachersList[tc]->name)
6520 .arg(tamc->activityTagName),
6521 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6522 1, 0 );
6523
6524 if(t==0)
6525 return false;
6526 }
6527 }
6528 }
6529 }
6530 }
6531 }
6532 }
6533
6534 return ok;
6535 }
6536
6537 //2020-06-28
6538 //must be after n hours per teacher
computeTeachersMaxHoursPerAllAfternoons(QWidget * parent)6539 bool computeTeachersMaxHoursPerAllAfternoons(QWidget* parent)
6540 {
6541 bool ok=true;
6542
6543 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6544 teachersMaxHoursPerAllAfternoonsMaxHours[i]=-1;
6545 teachersMaxHoursPerAllAfternoonsPercentages[i]=-1;
6546 }
6547
6548 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6549 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_HOURS_PER_ALL_AFTERNOONS){
6550 ConstraintTeacherMaxHoursPerAllAfternoons* tmd=(ConstraintTeacherMaxHoursPerAllAfternoons*)gt.rules.internalTimeConstraintsList[i];
6551
6552 //////////
6553 if(tmd->weightPercentage!=100){
6554 ok=false;
6555
6556 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6557 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max hours per all afternoons for teacher %1 with"
6558 " weight (percentage) below 100. Please make weight 100% and try again")
6559 .arg(tmd->teacherName),
6560 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6561 1, 0 );
6562
6563 if(t==0)
6564 return false;
6565 }
6566 //////////
6567
6568 if(teachersMaxHoursPerAllAfternoonsMaxHours[tmd->teacher_ID]==-1 || teachersMaxHoursPerAllAfternoonsMaxHours[tmd->teacher_ID]>tmd->maxHoursPerAllAfternoons){
6569 teachersMaxHoursPerAllAfternoonsMaxHours[tmd->teacher_ID]=tmd->maxHoursPerAllAfternoons;
6570 teachersMaxHoursPerAllAfternoonsPercentages[tmd->teacher_ID]=100;
6571 }
6572 }
6573 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_HOURS_PER_ALL_AFTERNOONS){
6574 ConstraintTeachersMaxHoursPerAllAfternoons* tmd=(ConstraintTeachersMaxHoursPerAllAfternoons*)gt.rules.internalTimeConstraintsList[i];
6575
6576 //////////
6577 if(tmd->weightPercentage!=100){
6578 ok=false;
6579
6580 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6581 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max hours per all afternoons with"
6582 " weight (percentage) below 100. Please make weight 100% and try again"),
6583 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6584 1, 0 );
6585
6586 if(t==0)
6587 return false;
6588 }
6589 //////////
6590
6591 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
6592 if(teachersMaxHoursPerAllAfternoonsMaxHours[tch]==-1 || teachersMaxHoursPerAllAfternoonsMaxHours[tch]>tmd->maxHoursPerAllAfternoons){
6593 teachersMaxHoursPerAllAfternoonsMaxHours[tch]=tmd->maxHoursPerAllAfternoons;
6594 teachersMaxHoursPerAllAfternoonsPercentages[tch]=100;
6595 }
6596 }
6597 }
6598 }
6599
6600 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
6601 if(teachersMaxHoursPerAllAfternoonsMaxHours[tch]>=0){
6602 int nAvailableMorningHours=0;
6603 for(int d=0; d<gt.rules.nDaysPerWeek; d+=2) //morning
6604 for(int h=0; h<gt.rules.nHoursPerDay; h++)
6605 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tch][d][h])
6606 nAvailableMorningHours++;
6607
6608 if(teachersMaxHoursPerAllAfternoonsMaxHours[tch]+nAvailableMorningHours<nHoursPerTeacher[tch]){
6609 ok=false;
6610
6611 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6612 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher(s) max hours per all afternoons for teacher %1 which is impossible"
6613 " to respect (allowed afternoon = %2, available morning = %3, total hours for teacher = %4)")
6614 .arg(gt.rules.internalTeachersList[tch]->name)
6615 .arg(teachersMaxHoursPerAllAfternoonsMaxHours[tch])
6616 .arg(nAvailableMorningHours)
6617 .arg(nHoursPerTeacher[tch]),
6618 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6619 1, 0 );
6620
6621 if(t==0)
6622 return false;
6623 }
6624 }
6625 }
6626
6627 return ok;
6628 }
6629
6630 //2020-06-28
6631 //must be after n hours per subgroup
computeStudentsMaxHoursPerAllAfternoons(QWidget * parent)6632 bool computeStudentsMaxHoursPerAllAfternoons(QWidget* parent)
6633 {
6634 bool ok=true;
6635
6636 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
6637 subgroupsMaxHoursPerAllAfternoonsMaxHours[i]=-1;
6638 subgroupsMaxHoursPerAllAfternoonsPercentages[i]=-1;
6639 }
6640
6641 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6642 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_HOURS_PER_ALL_AFTERNOONS){
6643 ConstraintStudentsSetMaxHoursPerAllAfternoons* tmd=(ConstraintStudentsSetMaxHoursPerAllAfternoons*)gt.rules.internalTimeConstraintsList[i];
6644
6645 //////////
6646 if(tmd->weightPercentage!=100){
6647 ok=false;
6648
6649 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6650 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max hours per all afternoons for students set %1 with"
6651 " weight (percentage) below 100. Please make weight 100% and try again")
6652 .arg(tmd->students),
6653 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6654 1, 0 );
6655
6656 if(t==0)
6657 return false;
6658 }
6659 //////////
6660
6661 for(int sbg : qAsConst(tmd->iSubgroupsList))
6662 if(subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]==-1 || subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]>tmd->maxHoursPerAllAfternoons){
6663 subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]=tmd->maxHoursPerAllAfternoons;
6664 subgroupsMaxHoursPerAllAfternoonsPercentages[sbg]=100;
6665 }
6666 }
6667 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_HOURS_PER_ALL_AFTERNOONS){
6668 ConstraintStudentsMaxHoursPerAllAfternoons* tmd=(ConstraintStudentsMaxHoursPerAllAfternoons*)gt.rules.internalTimeConstraintsList[i];
6669
6670 //////////
6671 if(tmd->weightPercentage!=100){
6672 ok=false;
6673
6674 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6675 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max hours per all afternoons with"
6676 " weight (percentage) below 100. Please make weight 100% and try again"),
6677 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6678 1, 0 );
6679
6680 if(t==0)
6681 return false;
6682 }
6683 //////////
6684
6685 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
6686 if(subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]==-1 || subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]>tmd->maxHoursPerAllAfternoons){
6687 subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]=tmd->maxHoursPerAllAfternoons;
6688 subgroupsMaxHoursPerAllAfternoonsPercentages[sbg]=100;
6689 }
6690 }
6691 }
6692 }
6693
6694 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
6695 if(subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]>=0){
6696 int nAvailableMorningHours=0;
6697 for(int d=0; d<gt.rules.nDaysPerWeek; d+=2) //morning
6698 for(int h=0; h<gt.rules.nHoursPerDay; h++)
6699 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sbg][d][h])
6700 nAvailableMorningHours++;
6701
6702 if(subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg]+nAvailableMorningHours<nHoursPerSubgroup[sbg]){
6703 ok=false;
6704
6705 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6706 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students (set) max hours per all afternoons for subgroup %1 which is impossible"
6707 " to respect (allowed afternoon = %2, available morning = %3, total hours for subgroup = %4)")
6708 .arg(gt.rules.internalSubgroupsList[sbg]->name)
6709 .arg(subgroupsMaxHoursPerAllAfternoonsMaxHours[sbg])
6710 .arg(nAvailableMorningHours)
6711 .arg(nHoursPerSubgroup[sbg]),
6712 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6713 1, 0 );
6714
6715 if(t==0)
6716 return false;
6717 }
6718 }
6719 }
6720
6721 return ok;
6722 }
6723
6724 //must be after n hours per teacher
computeTeachersMinHoursDaily(QWidget * parent)6725 bool computeTeachersMinHoursDaily(QWidget* parent)
6726 {
6727 bool ok=true;
6728
6729 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6730 teachersMinHoursDailyMinHours[i][1]=-1;
6731 teachersMinHoursDailyPercentages[i][1]=-1;
6732 }
6733
6734 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6735 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_HOURS_DAILY){
6736 ConstraintTeacherMinHoursDaily* tmd=(ConstraintTeacherMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
6737
6738 //////////
6739 if(tmd->weightPercentage!=100){
6740 ok=false;
6741
6742 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6743 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours daily for teacher %1 with"
6744 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
6745 " to use 100% weight for such constraints. Please make weight 100% and try again")
6746 .arg(tmd->teacherName),
6747 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6748 1, 0 );
6749
6750 if(t==0)
6751 return false;
6752 }
6753 //////////
6754
6755 //////////
6756 if(tmd->minHoursDaily>gt.rules.nHoursPerDay){
6757 ok=false;
6758
6759 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6760 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours daily for teacher %1 with"
6761 " %2 min hours daily, and the number of working hours per day is only %3. Please correct and try again")
6762 .arg(tmd->teacherName)
6763 .arg(tmd->minHoursDaily)
6764 .arg(gt.rules.nHoursPerDay),
6765 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6766 1, 0 );
6767
6768 if(t==0)
6769 return false;
6770 }
6771 //////////
6772
6773 if(teachersMinHoursDailyMinHours[tmd->teacher_ID][MIN_HOURS_DAILY_INDEX_IN_ARRAY]==-1 || teachersMinHoursDailyMinHours[tmd->teacher_ID][MIN_HOURS_DAILY_INDEX_IN_ARRAY]<tmd->minHoursDaily){
6774 teachersMinHoursDailyMinHours[tmd->teacher_ID][MIN_HOURS_DAILY_INDEX_IN_ARRAY]=tmd->minHoursDaily;
6775 teachersMinHoursDailyPercentages[tmd->teacher_ID][MIN_HOURS_DAILY_INDEX_IN_ARRAY]=100;
6776 }
6777 }
6778 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_HOURS_DAILY){
6779 ConstraintTeachersMinHoursDaily* tmd=(ConstraintTeachersMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
6780
6781 //////////
6782 if(tmd->weightPercentage!=100){
6783 ok=false;
6784
6785 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6786 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours daily with"
6787 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
6788 " to use 100% weight for such constraints. Please make weight 100% and try again"),
6789 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6790 1, 0 );
6791
6792 if(t==0)
6793 return false;
6794 }
6795 //////////
6796
6797 //////////
6798 if(tmd->minHoursDaily>gt.rules.nHoursPerDay){
6799 ok=false;
6800
6801 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6802 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours daily with"
6803 " %1 min hours daily, and the number of working hours per day is only %2. Please correct and try again")
6804 .arg(tmd->minHoursDaily)
6805 .arg(gt.rules.nHoursPerDay),
6806 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6807 1, 0 );
6808
6809 if(t==0)
6810 return false;
6811 }
6812 //////////
6813 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
6814 if(teachersMinHoursDailyMinHours[tch][MIN_HOURS_DAILY_INDEX_IN_ARRAY]==-1 || teachersMinHoursDailyMinHours[tch][MIN_HOURS_DAILY_INDEX_IN_ARRAY]<tmd->minHoursDaily){
6815 teachersMinHoursDailyMinHours[tch][MIN_HOURS_DAILY_INDEX_IN_ARRAY]=tmd->minHoursDaily;
6816 teachersMinHoursDailyPercentages[tch][MIN_HOURS_DAILY_INDEX_IN_ARRAY]=100;
6817 }
6818 }
6819 }
6820 }
6821
6822 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6823 teachersMinHoursDailyMinHours[i][0]=teachersMinHoursDailyMinHours[i][1];
6824 teachersMinHoursDailyPercentages[i][0]=teachersMinHoursDailyPercentages[i][1];
6825 }
6826
6827 if(gt.rules.mode==MORNINGS_AFTERNOONS){
6828 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6829 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_HOURS_PER_MORNING){
6830 ConstraintTeacherMinHoursPerMorning* tmd=(ConstraintTeacherMinHoursPerMorning*)gt.rules.internalTimeConstraintsList[i];
6831
6832 //////////
6833 if(tmd->weightPercentage!=100){
6834 ok=false;
6835
6836 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6837 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours per morning for teacher %1 with"
6838 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
6839 " to use 100% weight for such constraints. Please make weight 100% and try again")
6840 .arg(tmd->teacherName),
6841 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6842 1, 0 );
6843
6844 if(t==0)
6845 return false;
6846 }
6847 //////////
6848
6849 //////////
6850 if(tmd->minHoursPerMorning>gt.rules.nHoursPerDay){
6851 ok=false;
6852
6853 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6854 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours per morning for teacher %1 with"
6855 " %2 min hours per morning, and the number of working hours per day is only %3. Please correct and try again")
6856 .arg(tmd->teacherName)
6857 .arg(tmd->minHoursPerMorning)
6858 .arg(gt.rules.nHoursPerDay),
6859 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6860 1, 0 );
6861
6862 if(t==0)
6863 return false;
6864 }
6865 //////////
6866
6867 if(teachersMinHoursDailyMinHours[tmd->teacher_ID][1]==-1){
6868 ok=false;
6869
6870 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6871 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours per morning for teacher %1 but not also"
6872 " min hours daily for him. Please add a constraint teacher(s) min hours daily affecting this teacher.")
6873 .arg(tmd->teacherName),
6874 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6875 1, 0 );
6876
6877 if(t==0)
6878 return false;
6879 }
6880
6881 if(teachersMinHoursDailyMinHours[tmd->teacher_ID][0]==-1 || teachersMinHoursDailyMinHours[tmd->teacher_ID][0]<tmd->minHoursPerMorning){
6882 teachersMinHoursDailyMinHours[tmd->teacher_ID][0]=tmd->minHoursPerMorning;
6883 teachersMinHoursDailyPercentages[tmd->teacher_ID][0]=100;
6884 }
6885 }
6886 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_HOURS_PER_MORNING){
6887 ConstraintTeachersMinHoursPerMorning* tmd=(ConstraintTeachersMinHoursPerMorning*)gt.rules.internalTimeConstraintsList[i];
6888
6889 //////////
6890 if(tmd->weightPercentage!=100){
6891 ok=false;
6892
6893 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6894 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours per morning with"
6895 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
6896 " to use 100% weight for such constraints. Please make weight 100% and try again"),
6897 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6898 1, 0 );
6899
6900 if(t==0)
6901 return false;
6902 }
6903 //////////
6904
6905 //////////
6906 if(tmd->minHoursPerMorning>gt.rules.nHoursPerDay){
6907 ok=false;
6908
6909 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6910 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours per morning with"
6911 " %1 min hours per morning, and the number of working hours per day is only %2. Please correct and try again")
6912 .arg(tmd->minHoursPerMorning)
6913 .arg(gt.rules.nHoursPerDay),
6914 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6915 1, 0 );
6916
6917 if(t==0)
6918 return false;
6919 }
6920 //////////
6921 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
6922 if(teachersMinHoursDailyMinHours[tch][1]==-1){
6923 ok=false;
6924
6925 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6926 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours per morning for all the teachers but not also"
6927 " min hours daily for them. Please add one or more constraints teacher(s) min hours daily."),
6928 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6929 1, 0 );
6930
6931 if(t==0)
6932 return false;
6933 }
6934
6935 if(teachersMinHoursDailyMinHours[tch][0]==-1 || teachersMinHoursDailyMinHours[tch][0]<tmd->minHoursPerMorning){
6936 teachersMinHoursDailyMinHours[tch][0]=tmd->minHoursPerMorning;
6937 teachersMinHoursDailyPercentages[tch][0]=100;
6938 }
6939 }
6940 }
6941 }
6942 }
6943
6944 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
6945 if(teachersMinHoursDailyPercentages[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]==100){
6946 assert(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0);
6947 if(nHoursPerTeacher[tc]>0 && teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>nHoursPerTeacher[tc]){
6948 ok=false;
6949
6950 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6951 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min %1 hours daily for teacher"
6952 " %2 (the constraint allows empty days). This teacher has in total only %3 hours per week, so impossible constraint."
6953 " Please correct and try again")
6954 .arg(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY])
6955 .arg(gt.rules.internalTeachersList[tc]->name)
6956 .arg(nHoursPerTeacher[tc])
6957 ,
6958 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6959 1, 0 );
6960
6961 if(t==0)
6962 return false;
6963 }
6964
6965 if(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]<2){
6966 ok=false;
6967
6968 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
6969 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min %1 hours daily for teacher"
6970 " %2 (the constraint allows empty days). The number of min hours daily should be at least 2, to make a non-trivial constraint. Please correct and try again")
6971 .arg(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY])
6972 .arg(gt.rules.internalTeachersList[tc]->name)
6973 ,
6974 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
6975 1, 0 );
6976
6977 if(t==0)
6978 return false;
6979 }
6980 }
6981 }
6982
6983 return ok;
6984 }
6985
6986 //must be after n hours per teacher
computeTeachersMinHoursDailyRealDays(QWidget * parent)6987 bool computeTeachersMinHoursDailyRealDays(QWidget* parent)
6988 {
6989 bool ok=true;
6990
6991 for(int i=0; i<gt.rules.nInternalTeachers; i++){
6992 teachersMinHoursDailyRealDaysMinHours[i]=-1;
6993 teachersMinHoursDailyRealDaysPercentages[i]=-1;
6994 }
6995
6996 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
6997 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_HOURS_DAILY_REAL_DAYS){
6998 ConstraintTeacherMinHoursDailyRealDays* tmd=(ConstraintTeacherMinHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
6999
7000 //////////
7001 if(tmd->weightPercentage!=100){
7002 ok=false;
7003
7004 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7005 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours daily for real days for teacher %1 with"
7006 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
7007 " to use 100% weight for such constraints. Please make weight 100% and try again")
7008 .arg(tmd->teacherName),
7009 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7010 1, 0 );
7011
7012 if(t==0)
7013 return false;
7014 }
7015 //////////
7016
7017 //////////
7018 if(tmd->minHoursDaily>2*gt.rules.nHoursPerDay){
7019 ok=false;
7020
7021 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7022 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min hours daily for real days for teacher %1 with"
7023 " %2 min hours daily, and the number of working hours per real day is only %3. Please correct and try again")
7024 .arg(tmd->teacherName)
7025 .arg(tmd->minHoursDaily)
7026 .arg(2*gt.rules.nHoursPerDay),
7027 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7028 1, 0 );
7029
7030 if(t==0)
7031 return false;
7032 }
7033 //////////
7034
7035 if(teachersMinHoursDailyRealDaysMinHours[tmd->teacher_ID]==-1 || teachersMinHoursDailyRealDaysMinHours[tmd->teacher_ID]<tmd->minHoursDaily){
7036 teachersMinHoursDailyRealDaysMinHours[tmd->teacher_ID]=tmd->minHoursDaily;
7037 teachersMinHoursDailyRealDaysPercentages[tmd->teacher_ID]=100;
7038 }
7039 }
7040 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_HOURS_DAILY_REAL_DAYS){
7041 ConstraintTeachersMinHoursDailyRealDays* tmd=(ConstraintTeachersMinHoursDailyRealDays*)gt.rules.internalTimeConstraintsList[i];
7042
7043 //////////
7044 if(tmd->weightPercentage!=100){
7045 ok=false;
7046
7047 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7048 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours daily for real days with"
7049 " weight (percentage) below 100. Starting with FET version 5.4.0 it is only possible"
7050 " to use 100% weight for such constraints. Please make weight 100% and try again"),
7051 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7052 1, 0 );
7053
7054 if(t==0)
7055 return false;
7056 }
7057 //////////
7058
7059 //////////
7060 if(tmd->minHoursDaily>2*gt.rules.nHoursPerDay){
7061 ok=false;
7062
7063 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7064 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min hours daily for real days with"
7065 " %1 min hours daily, and the number of working hours per real day is only %2. Please correct and try again")
7066 .arg(tmd->minHoursDaily)
7067 .arg(2*gt.rules.nHoursPerDay),
7068 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7069 1, 0 );
7070
7071 if(t==0)
7072 return false;
7073 }
7074 //////////
7075 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
7076 if(teachersMinHoursDailyRealDaysMinHours[tch]==-1 || teachersMinHoursDailyRealDaysMinHours[tch]<tmd->minHoursDaily){
7077 teachersMinHoursDailyRealDaysMinHours[tch]=tmd->minHoursDaily;
7078 teachersMinHoursDailyRealDaysPercentages[tch]=100;
7079 }
7080 }
7081 }
7082 }
7083
7084 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
7085 if(teachersMinHoursDailyRealDaysPercentages[tc]==100){
7086 assert(teachersMinHoursDailyRealDaysMinHours[tc]>=0);
7087 if(nHoursPerTeacher[tc]>0 && teachersMinHoursDailyRealDaysMinHours[tc]>nHoursPerTeacher[tc]){
7088 ok=false;
7089
7090 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7091 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min %1 hours daily for real days for teacher"
7092 " %2 (the constraint allows empty days). This teacher has in total only %3 hours per week, so impossible constraint."
7093 " Please correct and try again")
7094 .arg(teachersMinHoursDailyRealDaysMinHours[tc])
7095 .arg(gt.rules.internalTeachersList[tc]->name)
7096 .arg(nHoursPerTeacher[tc])
7097 ,
7098 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7099 1, 0 );
7100
7101 if(t==0)
7102 return false;
7103 }
7104
7105 if(teachersMinHoursDailyRealDaysMinHours[tc]<2){
7106 ok=false;
7107
7108 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7109 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min %1 hours daily for real days for teacher"
7110 " %2 (the constraint allows empty days). The number of min hours daily for real days should be at least 2, to make a non-trivial constraint. Please correct and try again")
7111 .arg(teachersMinHoursDailyRealDaysMinHours[tc])
7112 .arg(gt.rules.internalTeachersList[tc]->name)
7113 ,
7114 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7115 1, 0 );
7116
7117 if(t==0)
7118 return false;
7119 }
7120 }
7121 }
7122
7123 return ok;
7124 }
7125
computeTeachersActivityTagMinHoursDaily(QWidget * parent)7126 bool computeTeachersActivityTagMinHoursDaily(QWidget* parent)
7127 {
7128 haveTeachersActivityTagMinHoursDaily=false;
7129
7130 bool ok=true;
7131
7132 tatmhdList.clear();
7133 for(int i=0; i<gt.rules.nInternalTeachers; i++)
7134 tatmhdListForTeacher[i].clear();
7135
7136 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
7137 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MIN_HOURS_DAILY){
7138 haveTeachersActivityTagMinHoursDaily=true;
7139 ConstraintTeachersActivityTagMinHoursDaily* tmd=(ConstraintTeachersActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
7140
7141 if(tmd->weightPercentage!=100){
7142 ok=false;
7143
7144 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7145 GeneratePreTranslate::tr("Cannot optimize for teachers, because the constraint of type activity tag min hours daily relating to teachers"
7146 " has no 100% weight"
7147 ". Please modify your data accordingly and try again"),
7148 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7149 1, 0 );
7150
7151 if(t==0)
7152 return false;
7153 }
7154 }
7155 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MIN_HOURS_DAILY){
7156 haveTeachersActivityTagMinHoursDaily=true;
7157 ConstraintTeacherActivityTagMinHoursDaily* tmd=(ConstraintTeacherActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
7158
7159 if(tmd->weightPercentage!=100){
7160 ok=false;
7161
7162 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7163 GeneratePreTranslate::tr("Cannot optimize for teachers, because the constraint of type activity tag min hours daily relating to teacher %1"
7164 " has no 100% weight"
7165 ". Please modify your data accordingly and try again").arg(tmd->teacherName),
7166 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7167 1, 0 );
7168
7169 if(t==0)
7170 return false;
7171 }
7172 }
7173 }
7174
7175 if(haveTeachersActivityTagMinHoursDaily){
7176 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
7177 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_ACTIVITY_TAG_MIN_HOURS_DAILY){
7178 ConstraintTeachersActivityTagMinHoursDaily* tmd=(ConstraintTeachersActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
7179
7180 for(int tch : qAsConst(tmd->canonicalTeachersList)){
7181 TeacherActivityTagMinHoursDaily_item item;
7182 item.durationOfActivitiesWithActivityTagForTeacher=0;
7183
7184 for(int ai : qAsConst(gt.rules.internalTeachersList[tch]->activitiesForTeacher)){
7185 Activity* act=>.rules.internalActivitiesList[ai];
7186 if(act->iActivityTagsSet.contains(tmd->activityTagIndex))
7187 item.durationOfActivitiesWithActivityTagForTeacher+=act->duration;
7188 }
7189
7190 if(item.durationOfActivitiesWithActivityTagForTeacher>0){
7191 item.activityTag=tmd->activityTagIndex;
7192 item.minHoursDaily=tmd->minHoursDaily;
7193 item.allowEmptyDays=tmd->allowEmptyDays;
7194
7195 tatmhdList.push_back(item);
7196 //tatmhdListForTeacher[tch].append(&tatmhdList[tatmhdList.count()-1]);
7197 tatmhdListForTeacher[tch].append(&tatmhdList.back());
7198
7199 if(!item.allowEmptyDays && item.durationOfActivitiesWithActivityTagForTeacher<gt.rules.nDaysPerWeek*item.minHoursDaily){
7200 ok=false;
7201
7202 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7203 GeneratePreTranslate::tr("Cannot optimize, because the constraint of type activity tag %1 min %2 hours daily relating to teacher %3"
7204 " requires at least %4 hours of work per week, but the activities of this teacher with this activity tag sum to only %5 hours"
7205 " per week (the constraint does not allow empty days). Please correct and try again")
7206 .arg(tmd->activityTagName).arg(tmd->minHoursDaily).arg(gt.rules.internalTeachersList[tch]->name)
7207 .arg(gt.rules.nDaysPerWeek*item.minHoursDaily).arg(item.durationOfActivitiesWithActivityTagForTeacher),
7208 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7209 1, 0 );
7210
7211 if(t==0)
7212 return false;
7213 }
7214 }
7215 else{
7216 assert(0);
7217 }
7218 }
7219 }
7220 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_ACTIVITY_TAG_MIN_HOURS_DAILY){
7221 ConstraintTeacherActivityTagMinHoursDaily* tmd=(ConstraintTeacherActivityTagMinHoursDaily*)gt.rules.internalTimeConstraintsList[i];
7222
7223 for(int tch : qAsConst(tmd->canonicalTeachersList)){
7224 TeacherActivityTagMinHoursDaily_item item;
7225 item.durationOfActivitiesWithActivityTagForTeacher=0;
7226
7227 for(int ai : qAsConst(gt.rules.internalTeachersList[tch]->activitiesForTeacher)){
7228 Activity* act=>.rules.internalActivitiesList[ai];
7229 if(act->iActivityTagsSet.contains(tmd->activityTagIndex))
7230 item.durationOfActivitiesWithActivityTagForTeacher+=act->duration;
7231 }
7232
7233 if(item.durationOfActivitiesWithActivityTagForTeacher>0){
7234 item.activityTag=tmd->activityTagIndex;
7235 item.minHoursDaily=tmd->minHoursDaily;
7236 item.allowEmptyDays=tmd->allowEmptyDays;
7237
7238 tatmhdList.push_back(item);
7239 //tatmhdListForTeacher[tch].append(&tatmhdList[tatmhdList.count()-1]);
7240 tatmhdListForTeacher[tch].append(&tatmhdList.back());
7241
7242 if(!item.allowEmptyDays && item.durationOfActivitiesWithActivityTagForTeacher<gt.rules.nDaysPerWeek*item.minHoursDaily){
7243 ok=false;
7244
7245 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7246 GeneratePreTranslate::tr("Cannot optimize, because the constraint of type activity tag %1 min %2 hours daily relating to teacher %3"
7247 " requires at least %4 hours of work per week, but the activities of this teacher with this activity tag sum to only %5 hours"
7248 " per week (the constraint does not allow empty days). Please correct and try again")
7249 .arg(tmd->activityTagName).arg(tmd->minHoursDaily).arg(gt.rules.internalTeachersList[tch]->name)
7250 .arg(gt.rules.nDaysPerWeek*item.minHoursDaily).arg(item.durationOfActivitiesWithActivityTagForTeacher),
7251 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7252 1, 0 );
7253
7254 if(t==0)
7255 return false;
7256 }
7257 }
7258 else{
7259 assert(0);
7260 }
7261 }
7262 }
7263 }
7264 }
7265
7266 return ok;
7267 }
7268
7269 //must be after min hours for teachers
computeTeachersMinDaysPerWeek(QWidget * parent)7270 bool computeTeachersMinDaysPerWeek(QWidget* parent)
7271 {
7272 bool ok=true;
7273
7274 for(int i=0; i<gt.rules.nInternalTeachers; i++){
7275 teachersMinDaysPerWeekMinDays[i]=-1;
7276 teachersMinDaysPerWeekPercentages[i]=-1;
7277 }
7278
7279 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
7280 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_DAYS_PER_WEEK){
7281 ConstraintTeacherMinDaysPerWeek* tmd=(ConstraintTeacherMinDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
7282
7283 //////////
7284 if(tmd->weightPercentage!=100){
7285 ok=false;
7286
7287 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7288 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min days per week for teacher %1 with"
7289 " weight (percentage) below 100. Please make weight 100% and try again")
7290 .arg(tmd->teacherName),
7291 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7292 1, 0 );
7293
7294 if(t==0)
7295 return false;
7296 }
7297 //////////
7298
7299 //////////
7300 if(tmd->minDaysPerWeek>gt.rules.nDaysPerWeek){
7301 ok=false;
7302
7303 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7304 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min days per week for teacher %1 with"
7305 " %2 min days per week, and the number of working days per week is only %3. Please correct and try again")
7306 .arg(tmd->teacherName)
7307 .arg(tmd->minDaysPerWeek)
7308 .arg(gt.rules.nDaysPerWeek),
7309 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7310 1, 0 );
7311
7312 if(t==0)
7313 return false;
7314 }
7315 //////////
7316
7317 if(teachersMinDaysPerWeekMinDays[tmd->teacher_ID]==-1 || teachersMinDaysPerWeekMinDays[tmd->teacher_ID]<tmd->minDaysPerWeek){
7318 teachersMinDaysPerWeekMinDays[tmd->teacher_ID]=tmd->minDaysPerWeek;
7319 teachersMinDaysPerWeekPercentages[tmd->teacher_ID]=100;
7320 }
7321 }
7322 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_DAYS_PER_WEEK){
7323 ConstraintTeachersMinDaysPerWeek* tmd=(ConstraintTeachersMinDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
7324
7325 //////////
7326 if(tmd->weightPercentage!=100){
7327 ok=false;
7328
7329 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7330 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min days per week with weight"
7331 " (percentage) below 100. Please make weight 100% and try again"),
7332 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7333 1, 0 );
7334
7335 if(t==0)
7336 return false;
7337 }
7338 //////////
7339
7340 //////////
7341 if(tmd->minDaysPerWeek>gt.rules.nDaysPerWeek){
7342 ok=false;
7343
7344 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7345 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min days per week with"
7346 " %1 min days per week, and the number of working days per week is only %2. Please correct and try again")
7347 .arg(tmd->minDaysPerWeek)
7348 .arg(gt.rules.nDaysPerWeek),
7349 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7350 1, 0 );
7351
7352 if(t==0)
7353 return false;
7354 }
7355 //////////
7356 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
7357 if(teachersMinDaysPerWeekMinDays[tch]==-1 || teachersMinDaysPerWeekMinDays[tch]<tmd->minDaysPerWeek){
7358 teachersMinDaysPerWeekMinDays[tch]=tmd->minDaysPerWeek;
7359 teachersMinDaysPerWeekPercentages[tch]=100;
7360 }
7361 }
7362 }
7363 }
7364
7365 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
7366 if(teachersMinDaysPerWeekMinDays[tc]>=0){
7367 int md=teachersMinDaysPerWeekMinDays[tc];
7368 if(md>gt.rules.internalTeachersList[tc]->activitiesForTeacher.count()){
7369 ok=false;
7370
7371 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7372 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min days per week %2 and he has only %3 activities - impossible."
7373 " Please correct and try again.")
7374 .arg(gt.rules.internalTeachersList[tc]->name)
7375 .arg(md)
7376 .arg(gt.rules.internalTeachersList[tc]->activitiesForTeacher.count())
7377 ,
7378 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7379 1, 0 );
7380
7381 if(t==0)
7382 return false;
7383 }
7384
7385 if(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0){
7386 int mh=teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY];
7387
7388 if(md*mh>nHoursPerTeacher[tc]){
7389 ok=false;
7390
7391 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7392 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min days per week %2 and min hours daily %3"
7393 " and he has only %4 working hours - impossible. Please correct and try again.")
7394 .arg(gt.rules.internalTeachersList[tc]->name)
7395 .arg(md)
7396 .arg(mh)
7397 .arg(nHoursPerTeacher[tc])
7398 ,
7399 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7400 1, 0 );
7401
7402 if(t==0)
7403 return false;
7404 }
7405 }
7406 }
7407 }
7408
7409 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
7410 if(teachersMinDaysPerWeekMinDays[tc]>=0){
7411 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){
7412 if(teachersMaxDaysPerWeekMaxDays[tc]<teachersMinDaysPerWeekMinDays[tc]){
7413 ok=false;
7414
7415 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7416 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min days per week %2 > max days per week %3"
7417 " - impossible (min days must be <= max days). Please correct and try again.")
7418 .arg(gt.rules.internalTeachersList[tc]->name)
7419 .arg(teachersMinDaysPerWeekMinDays[tc])
7420 .arg(teachersMaxDaysPerWeekMaxDays[tc])
7421 ,
7422 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7423 1, 0 );
7424
7425 if(t==0)
7426 return false;
7427 }
7428 }
7429
7430 int med=1; //minimum each day = 1 hour
7431 if(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0)
7432 med=teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY];
7433
7434 int navdays=0;
7435
7436 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
7437 int navhours=0;
7438 for(int h=0; h<gt.rules.nHoursPerDay; h++)
7439 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
7440 navhours++;
7441 if(navhours>=med)
7442 navdays++;
7443 }
7444
7445 if(navdays<teachersMinDaysPerWeekMinDays[tc]){
7446 ok=false;
7447
7448 QString s;
7449
7450 if(teachersMinHoursDailyMinHours[tc][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0){
7451 s=GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min days per week %2 and only %3"
7452 " available days considering breaks and not available and min hours daily for this teacher. Please correct and try again.")
7453 .arg(gt.rules.internalTeachersList[tc]->name)
7454 .arg(teachersMinDaysPerWeekMinDays[tc])
7455 .arg(navdays);
7456 }
7457 else{
7458 s=GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min days per week %2 and only %3"
7459 " available days considering breaks and not available for this teacher. Please correct and try again.")
7460 .arg(gt.rules.internalTeachersList[tc]->name)
7461 .arg(teachersMinDaysPerWeekMinDays[tc])
7462 .arg(navdays);
7463 }
7464
7465 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s ,
7466 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7467 1, 0 );
7468
7469 if(t==0)
7470 return false;
7471 }
7472 }
7473 }
7474
7475
7476 return ok;
7477 }
7478
7479 //must be after min hours for teachers
computeTeachersMinRealDaysPerWeek(QWidget * parent)7480 bool computeTeachersMinRealDaysPerWeek(QWidget* parent)
7481 {
7482 bool ok=true;
7483
7484 for(int i=0; i<gt.rules.nInternalTeachers; i++){
7485 teachersMinRealDaysPerWeekMinDays[i]=-1;
7486 teachersMinRealDaysPerWeekPercentages[i]=-1;
7487 }
7488
7489 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
7490 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_REAL_DAYS_PER_WEEK){
7491 ConstraintTeacherMinRealDaysPerWeek* tmd=(ConstraintTeacherMinRealDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
7492
7493 //////////
7494 if(tmd->weightPercentage!=100){
7495 ok=false;
7496
7497 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7498 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min real days per week for teacher %1 with"
7499 " weight (percentage) below 100. Please make weight 100% and try again")
7500 .arg(tmd->teacherName),
7501 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7502 1, 0 );
7503
7504 if(t==0)
7505 return false;
7506 }
7507 //////////
7508
7509 //////////
7510 if(tmd->minDaysPerWeek>gt.rules.nDaysPerWeek/2){
7511 ok=false;
7512
7513 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7514 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min real days per week for teacher %1 with"
7515 " %2 min days per week, and the number of working real days per week is only %3. Please correct and try again")
7516 .arg(tmd->teacherName)
7517 .arg(tmd->minDaysPerWeek)
7518 .arg(gt.rules.nDaysPerWeek/2),
7519 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7520 1, 0 );
7521
7522 if(t==0)
7523 return false;
7524 }
7525 //////////
7526
7527 if(teachersMinRealDaysPerWeekMinDays[tmd->teacher_ID]==-1 || teachersMinRealDaysPerWeekMinDays[tmd->teacher_ID]<tmd->minDaysPerWeek){
7528 teachersMinRealDaysPerWeekMinDays[tmd->teacher_ID]=tmd->minDaysPerWeek;
7529 teachersMinRealDaysPerWeekPercentages[tmd->teacher_ID]=100;
7530 }
7531 }
7532 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_REAL_DAYS_PER_WEEK){
7533 ConstraintTeachersMinRealDaysPerWeek* tmd=(ConstraintTeachersMinRealDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
7534
7535 //////////
7536 if(tmd->weightPercentage!=100){
7537 ok=false;
7538
7539 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7540 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min real days per week with weight"
7541 " (percentage) below 100. Please make weight 100% and try again"),
7542 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7543 1, 0 );
7544
7545 if(t==0)
7546 return false;
7547 }
7548 //////////
7549
7550 //////////
7551 if(tmd->minDaysPerWeek>gt.rules.nDaysPerWeek/2){
7552 ok=false;
7553
7554 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7555 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min real days per week with"
7556 " %1 min days per week, and the number of working real days per week is only %2. Please correct and try again")
7557 .arg(tmd->minDaysPerWeek)
7558 .arg(gt.rules.nDaysPerWeek/2),
7559 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7560 1, 0 );
7561
7562 if(t==0)
7563 return false;
7564 }
7565 //////////
7566 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
7567 if(teachersMinRealDaysPerWeekMinDays[tch]==-1 || teachersMinRealDaysPerWeekMinDays[tch]<tmd->minDaysPerWeek){
7568 teachersMinRealDaysPerWeekMinDays[tch]=tmd->minDaysPerWeek;
7569 teachersMinRealDaysPerWeekPercentages[tch]=100;
7570 }
7571 }
7572 }
7573 }
7574
7575 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
7576 if(teachersMinRealDaysPerWeekMinDays[tc]>=0){
7577 int md=teachersMinRealDaysPerWeekMinDays[tc];
7578 if(md>gt.rules.internalTeachersList[tc]->activitiesForTeacher.count()){
7579 ok=false;
7580
7581 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7582 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and he has only %3 activities - impossible."
7583 " Please correct and try again.")
7584 .arg(gt.rules.internalTeachersList[tc]->name)
7585 .arg(md)
7586 .arg(gt.rules.internalTeachersList[tc]->activitiesForTeacher.count())
7587 ,
7588 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7589 1, 0 );
7590
7591 if(t==0)
7592 return false;
7593 }
7594
7595 if(teachersMinHoursDailyMinHours[tc][1]>=0){
7596 int mh=teachersMinHoursDailyMinHours[tc][1];
7597
7598 if(md*mh>nHoursPerTeacher[tc]){
7599 ok=false;
7600
7601 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7602 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and min hours daily %3"
7603 " and he has only %4 working hours - impossible. Please correct and try again.")
7604 .arg(gt.rules.internalTeachersList[tc]->name)
7605 .arg(md)
7606 .arg(mh)
7607 .arg(nHoursPerTeacher[tc])
7608 ,
7609 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7610 1, 0 );
7611
7612 if(t==0)
7613 return false;
7614 }
7615 }
7616 if(teachersMinHoursDailyRealDaysMinHours[tc]>=0){
7617 int mh=teachersMinHoursDailyRealDaysMinHours[tc];
7618
7619 if(md*mh>nHoursPerTeacher[tc]){
7620 ok=false;
7621
7622 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7623 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and min hours daily per real day %3"
7624 " and he has only %4 working hours - impossible. Please correct and try again.")
7625 .arg(gt.rules.internalTeachersList[tc]->name)
7626 .arg(md)
7627 .arg(mh)
7628 .arg(nHoursPerTeacher[tc])
7629 ,
7630 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7631 1, 0 );
7632
7633 if(t==0)
7634 return false;
7635 }
7636 }
7637 }
7638 }
7639
7640 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
7641 if(teachersMinRealDaysPerWeekMinDays[tc]>=0){
7642 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){
7643 if(teachersMaxRealDaysPerWeekMaxDays[tc]<teachersMinRealDaysPerWeekMinDays[tc]){
7644 ok=false;
7645
7646 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7647 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 > max real days per week %3"
7648 " - impossible (min days must be <= max days). Please correct and try again.")
7649 .arg(gt.rules.internalTeachersList[tc]->name)
7650 .arg(teachersMinRealDaysPerWeekMinDays[tc])
7651 .arg(teachersMaxRealDaysPerWeekMaxDays[tc])
7652 ,
7653 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7654 1, 0 );
7655
7656 if(t==0)
7657 return false;
7658 }
7659 }
7660
7661 int med[2]; //minimum each day = 1 hour
7662 med[1]=1; //afternoon
7663 med[0]=1; //morning
7664 if(teachersMinHoursDailyMinHours[tc][1]>=0)
7665 med[1]=teachersMinHoursDailyMinHours[tc][1];
7666 if(teachersMinHoursDailyMinHours[tc][0]>=0)
7667 med[0]=teachersMinHoursDailyMinHours[tc][0];
7668
7669 int navdays=0;
7670
7671 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
7672 int navhours=0;
7673 for(int h=0; h<gt.rules.nHoursPerDay; h++)
7674 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
7675 navhours++;
7676 if(navhours>=med[d%2])
7677 navdays++;
7678 }
7679
7680 if(navdays<teachersMinRealDaysPerWeekMinDays[tc]){
7681 ok=false;
7682
7683 QString s;
7684
7685 if(teachersMinHoursDailyMinHours[tc][1]>=0){
7686 s=GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and only %3"
7687 " available days considering breaks and not available and min hours daily for this teacher. Please correct and try again.")
7688 .arg(gt.rules.internalTeachersList[tc]->name)
7689 .arg(teachersMinRealDaysPerWeekMinDays[tc])
7690 .arg(navdays);
7691 }
7692 else{
7693 s=GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and only %3"
7694 " available days considering breaks and not available for this teacher. Please correct and try again.")
7695 .arg(gt.rules.internalTeachersList[tc]->name)
7696 .arg(teachersMinRealDaysPerWeekMinDays[tc])
7697 .arg(navdays);
7698 }
7699
7700 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s ,
7701 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7702 1, 0 );
7703
7704 if(t==0)
7705 return false;
7706 }
7707
7708 int med_wd=1; //minimum each day = 1 hour, whole day
7709 if(teachersMinHoursDailyRealDaysMinHours[tc]>=0)
7710 med_wd=teachersMinHoursDailyRealDaysMinHours[tc];
7711
7712 navdays=0;
7713
7714 for(int d=0; d<gt.rules.nDaysPerWeek/2; d++){
7715 int navhours=0;
7716 for(int h=0; h<gt.rules.nHoursPerDay; h++){
7717 if(!breakDayHour[2*d][h] && !teacherNotAvailableDayHour[tc][2*d][h])
7718 navhours++;
7719 if(!breakDayHour[2*d+1][h] && !teacherNotAvailableDayHour[tc][2*d+1][h])
7720 navhours++;
7721 }
7722 if(navhours>=med_wd)
7723 navdays++;
7724 }
7725
7726 if(navdays<teachersMinRealDaysPerWeekMinDays[tc]){
7727 ok=false;
7728
7729 QString s;
7730
7731 if(teachersMinHoursDailyRealDaysMinHours[tc]>=0){
7732 s=GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and only %3"
7733 " available days considering breaks and not available and min hours daily for real days for this teacher. Please correct and try again.")
7734 .arg(gt.rules.internalTeachersList[tc]->name)
7735 .arg(teachersMinRealDaysPerWeekMinDays[tc])
7736 .arg(navdays);
7737 }
7738 else{
7739 s=GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min real days per week %2 and only %3"
7740 " available days considering breaks and not available for this teacher. Please correct and try again.")
7741 .arg(gt.rules.internalTeachersList[tc]->name)
7742 .arg(teachersMinRealDaysPerWeekMinDays[tc])
7743 .arg(navdays);
7744 }
7745
7746 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s ,
7747 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7748 1, 0 );
7749
7750 if(t==0)
7751 return false;
7752 }
7753 }
7754 }
7755
7756 return ok;
7757 }
7758
computeTeachersMinRestingHours(QWidget * parent)7759 bool computeTeachersMinRestingHours(QWidget* parent)
7760 {
7761 bool ok=true;
7762
7763 for(int i=0; i<gt.rules.nInternalTeachers; i++){
7764 teachersMinRestingHoursCircularMinHours[i]=-1;
7765 teachersMinRestingHoursCircularPercentages[i]=-1;
7766 teachersMinRestingHoursNotCircularMinHours[i]=-1;
7767 teachersMinRestingHoursNotCircularPercentages[i]=-1;
7768 }
7769
7770 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
7771 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_RESTING_HOURS){
7772 ConstraintTeacherMinRestingHours* tmrh=(ConstraintTeacherMinRestingHours*)gt.rules.internalTimeConstraintsList[i];
7773
7774 //////////
7775 if(tmrh->weightPercentage!=100){
7776 ok=false;
7777
7778 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7779 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min resting hours for teacher %1 with"
7780 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again")
7781 .arg(tmrh->teacherName),
7782 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7783 1, 0 );
7784
7785 if(t==0)
7786 return false;
7787 }
7788 //////////
7789 if(tmrh->minRestingHours>gt.rules.nHoursPerDay){
7790 ok=false;
7791
7792 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7793 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min resting hours for teacher %1 with"
7794 " %2 min resting hours, and the number of working hours per day is only %3. Please correct and try again")
7795 .arg(tmrh->teacherName)
7796 .arg(tmrh->minRestingHours)
7797 .arg(gt.rules.nHoursPerDay),
7798 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7799 1, 0 );
7800
7801 if(t==0)
7802 return false;
7803 }
7804 //////////
7805
7806 if(tmrh->circular==true){
7807 if(teachersMinRestingHoursCircularMinHours[tmrh->teacher_ID]==-1 ||
7808 (teachersMinRestingHoursCircularMinHours[tmrh->teacher_ID]>=0 && teachersMinRestingHoursCircularMinHours[tmrh->teacher_ID]<tmrh->minRestingHours)){
7809 teachersMinRestingHoursCircularMinHours[tmrh->teacher_ID]=tmrh->minRestingHours;
7810 teachersMinRestingHoursCircularPercentages[tmrh->teacher_ID]=100;
7811 }
7812 }
7813 else{
7814 if(teachersMinRestingHoursNotCircularMinHours[tmrh->teacher_ID]==-1 ||
7815 (teachersMinRestingHoursNotCircularMinHours[tmrh->teacher_ID]>=0 && teachersMinRestingHoursNotCircularMinHours[tmrh->teacher_ID]<tmrh->minRestingHours)){
7816 teachersMinRestingHoursNotCircularMinHours[tmrh->teacher_ID]=tmrh->minRestingHours;
7817 teachersMinRestingHoursNotCircularPercentages[tmrh->teacher_ID]=100;
7818 }
7819 }
7820 }
7821 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_RESTING_HOURS){
7822 ConstraintTeachersMinRestingHours* tmrh=(ConstraintTeachersMinRestingHours*)gt.rules.internalTimeConstraintsList[i];
7823
7824 //////////
7825 if(tmrh->weightPercentage!=100){
7826 ok=false;
7827
7828 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7829 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min resting hours with"
7830 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again"),
7831 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7832 1, 0 );
7833
7834 if(t==0)
7835 return false;
7836 }
7837 //////////
7838 if(tmrh->minRestingHours>gt.rules.nHoursPerDay){
7839 ok=false;
7840
7841 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7842 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min resting hours with"
7843 " %1 min resting hours, and the number of working hours per day is only %2. Please correct and try again")
7844 .arg(tmrh->minRestingHours)
7845 .arg(gt.rules.nHoursPerDay),
7846 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7847 1, 0 );
7848
7849 if(t==0)
7850 return false;
7851 }
7852 //////////
7853
7854 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
7855 if(tmrh->circular==true){
7856 if(teachersMinRestingHoursCircularMinHours[tch]==-1 ||
7857 (teachersMinRestingHoursCircularMinHours[tch]>=0 && teachersMinRestingHoursCircularMinHours[tch]<tmrh->minRestingHours)){
7858 teachersMinRestingHoursCircularMinHours[tch]=tmrh->minRestingHours;
7859 teachersMinRestingHoursCircularPercentages[tch]=100;
7860 }
7861 }
7862 else{
7863 if(teachersMinRestingHoursNotCircularMinHours[tch]==-1 ||
7864 (teachersMinRestingHoursNotCircularMinHours[tch]>=0 && teachersMinRestingHoursNotCircularMinHours[tch]<tmrh->minRestingHours)){
7865 teachersMinRestingHoursNotCircularMinHours[tch]=tmrh->minRestingHours;
7866 teachersMinRestingHoursNotCircularPercentages[tch]=100;
7867 }
7868 }
7869 }
7870 }
7871 }
7872
7873 //small possible speedup
7874 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
7875 if(teachersMinRestingHoursCircularMinHours[tch]>=0 && teachersMinRestingHoursNotCircularMinHours[tch]>=0 &&
7876 teachersMinRestingHoursCircularMinHours[tch]>=teachersMinRestingHoursNotCircularMinHours[tch]){
7877 teachersMinRestingHoursNotCircularMinHours[tch]=-1;
7878 teachersMinRestingHoursNotCircularPercentages[tch]=-1;
7879 }
7880 }
7881
7882 return ok;
7883 }
7884
computeSubgroupsMinRestingHours(QWidget * parent)7885 bool computeSubgroupsMinRestingHours(QWidget* parent)
7886 {
7887 bool ok=true;
7888
7889 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
7890 subgroupsMinRestingHoursCircularMinHours[i]=-1;
7891 subgroupsMinRestingHoursCircularPercentages[i]=-1;
7892 subgroupsMinRestingHoursNotCircularMinHours[i]=-1;
7893 subgroupsMinRestingHoursNotCircularPercentages[i]=-1;
7894 }
7895
7896 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
7897 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_RESTING_HOURS){
7898 ConstraintStudentsSetMinRestingHours* smrh=(ConstraintStudentsSetMinRestingHours*)gt.rules.internalTimeConstraintsList[i];
7899
7900 //////////
7901 if(smrh->weightPercentage!=100){
7902 ok=false;
7903
7904 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7905 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min resting hours for students set %1 with"
7906 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again")
7907 .arg(smrh->students),
7908 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7909 1, 0 );
7910
7911 if(t==0)
7912 return false;
7913 }
7914 //////////
7915 if(smrh->minRestingHours>gt.rules.nHoursPerDay){
7916 ok=false;
7917
7918 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7919 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min resting hours for students set %1 with"
7920 " %2 min resting hours, and the number of working hours per day is only %3. Please correct and try again")
7921 .arg(smrh->students)
7922 .arg(smrh->minRestingHours)
7923 .arg(gt.rules.nHoursPerDay),
7924 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7925 1, 0 );
7926
7927 if(t==0)
7928 return false;
7929 }
7930 //////////
7931
7932 for(int sbg : qAsConst(smrh->iSubgroupsList)){
7933 if(smrh->circular==true){
7934 if(subgroupsMinRestingHoursCircularMinHours[sbg]==-1 ||
7935 (subgroupsMinRestingHoursCircularMinHours[sbg]>=0 && subgroupsMinRestingHoursCircularMinHours[sbg]<smrh->minRestingHours)){
7936 subgroupsMinRestingHoursCircularMinHours[sbg]=smrh->minRestingHours;
7937 subgroupsMinRestingHoursCircularPercentages[sbg]=100;
7938 }
7939 }
7940 else{
7941 if(subgroupsMinRestingHoursNotCircularMinHours[sbg]==-1 ||
7942 (subgroupsMinRestingHoursNotCircularMinHours[sbg]>=0 && subgroupsMinRestingHoursNotCircularMinHours[sbg]<smrh->minRestingHours)){
7943 subgroupsMinRestingHoursNotCircularMinHours[sbg]=smrh->minRestingHours;
7944 subgroupsMinRestingHoursNotCircularPercentages[sbg]=100;
7945 }
7946 }
7947 }
7948 }
7949 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_RESTING_HOURS){
7950 ConstraintStudentsMinRestingHours* smrh=(ConstraintStudentsMinRestingHours*)gt.rules.internalTimeConstraintsList[i];
7951
7952 //////////
7953 if(smrh->weightPercentage!=100){
7954 ok=false;
7955
7956 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7957 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min resting hours with"
7958 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again"),
7959 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7960 1, 0 );
7961
7962 if(t==0)
7963 return false;
7964 }
7965 //////////
7966 if(smrh->minRestingHours>gt.rules.nHoursPerDay){
7967 ok=false;
7968
7969 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
7970 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min resting hours with"
7971 " %1 min resting hours, and the number of working hours per day is only %2. Please correct and try again")
7972 .arg(smrh->minRestingHours)
7973 .arg(gt.rules.nHoursPerDay),
7974 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
7975 1, 0 );
7976
7977 if(t==0)
7978 return false;
7979 }
7980 //////////
7981
7982 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
7983 if(smrh->circular==true){
7984 if(subgroupsMinRestingHoursCircularMinHours[sbg]==-1 ||
7985 (subgroupsMinRestingHoursCircularMinHours[sbg]>=0 && subgroupsMinRestingHoursCircularMinHours[sbg]<smrh->minRestingHours)){
7986 subgroupsMinRestingHoursCircularMinHours[sbg]=smrh->minRestingHours;
7987 subgroupsMinRestingHoursCircularPercentages[sbg]=100;
7988 }
7989 }
7990 else{
7991 if(subgroupsMinRestingHoursNotCircularMinHours[sbg]==-1 ||
7992 (subgroupsMinRestingHoursNotCircularMinHours[sbg]>=0 && subgroupsMinRestingHoursNotCircularMinHours[sbg]<smrh->minRestingHours)){
7993 subgroupsMinRestingHoursNotCircularMinHours[sbg]=smrh->minRestingHours;
7994 subgroupsMinRestingHoursNotCircularPercentages[sbg]=100;
7995 }
7996 }
7997 }
7998 }
7999 }
8000
8001 //small possible speedup
8002 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
8003 if(subgroupsMinRestingHoursCircularMinHours[sbg]>=0 && subgroupsMinRestingHoursNotCircularMinHours[sbg]>=0 &&
8004 subgroupsMinRestingHoursCircularMinHours[sbg]>=subgroupsMinRestingHoursNotCircularMinHours[sbg]){
8005 subgroupsMinRestingHoursNotCircularMinHours[sbg]=-1;
8006 subgroupsMinRestingHoursNotCircularPercentages[sbg]=-1;
8007 }
8008 }
8009
8010 return ok;
8011 }
8012
8013 //must be after min hours for teachers (I think not), teachers max gaps per day and teachers max gaps per week
computeTeachersMinMorningsAfternoonsPerWeek(QWidget * parent)8014 bool computeTeachersMinMorningsAfternoonsPerWeek(QWidget* parent)
8015 {
8016 bool ok=true;
8017
8018 for(int i=0; i<gt.rules.nInternalTeachers; i++){
8019 teachersMinMorningsPerWeekMinMornings[i]=-1;
8020 teachersMinMorningsPerWeekPercentages[i]=-1;
8021
8022 teachersMinAfternoonsPerWeekMinAfternoons[i]=-1;
8023 teachersMinAfternoonsPerWeekPercentages[i]=-1;
8024 }
8025
8026 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8027 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_MORNINGS_PER_WEEK){
8028 ConstraintTeacherMinMorningsPerWeek* tmd=(ConstraintTeacherMinMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8029
8030 //////////
8031 if(tmd->weightPercentage!=100){
8032 ok=false;
8033
8034 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8035 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min mornings per week for teacher %1 with"
8036 " weight (percentage) below 100. Please make weight 100% and try again")
8037 .arg(tmd->teacherName),
8038 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8039 1, 0 );
8040
8041 if(t==0)
8042 return false;
8043 }
8044 //////////
8045
8046 //////////
8047 if(tmd->minMorningsPerWeek>gt.rules.nDaysPerWeek/2){
8048 ok=false;
8049
8050 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8051 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min mornings per week for teacher %1 with"
8052 " %2 min mornings per week, and the number of working mornings per week is only %3. Please correct and try again")
8053 .arg(tmd->teacherName)
8054 .arg(tmd->minMorningsPerWeek)
8055 .arg(gt.rules.nDaysPerWeek/2),
8056 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8057 1, 0 );
8058
8059 if(t==0)
8060 return false;
8061 }
8062 //////////
8063
8064 if(teachersMinMorningsPerWeekMinMornings[tmd->teacher_ID]==-1 || teachersMinMorningsPerWeekMinMornings[tmd->teacher_ID]<tmd->minMorningsPerWeek){
8065 teachersMinMorningsPerWeekMinMornings[tmd->teacher_ID]=tmd->minMorningsPerWeek;
8066 teachersMinMorningsPerWeekPercentages[tmd->teacher_ID]=100;
8067 }
8068 }
8069 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_MORNINGS_PER_WEEK){
8070 ConstraintTeachersMinMorningsPerWeek* tmd=(ConstraintTeachersMinMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8071
8072 //////////
8073 if(tmd->weightPercentage!=100){
8074 ok=false;
8075
8076 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8077 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min mornings per week with"
8078 " weight (percentage) below 100. Please make weight 100% and try again"),
8079 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8080 1, 0 );
8081
8082 if(t==0)
8083 return false;
8084 }
8085 //////////
8086
8087 //////////
8088 if(tmd->minMorningsPerWeek>gt.rules.nDaysPerWeek/2){
8089 ok=false;
8090
8091 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8092 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min mornings per week with"
8093 " %1 min mornings per week, and the number of working mornings per week is only %2. Please correct and try again")
8094 .arg(tmd->minMorningsPerWeek)
8095 .arg(gt.rules.nDaysPerWeek/2),
8096 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8097 1, 0 );
8098
8099 if(t==0)
8100 return false;
8101 }
8102 //////////
8103
8104 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
8105 if(teachersMinMorningsPerWeekMinMornings[tch]==-1 || teachersMinMorningsPerWeekMinMornings[tch]<tmd->minMorningsPerWeek){
8106 teachersMinMorningsPerWeekMinMornings[tch]=tmd->minMorningsPerWeek;
8107 teachersMinMorningsPerWeekPercentages[tch]=100;
8108 }
8109 }
8110 }
8111 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_AFTERNOONS_PER_WEEK){
8112 ConstraintTeacherMinAfternoonsPerWeek* tmd=(ConstraintTeacherMinAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8113
8114 //////////
8115 if(tmd->weightPercentage!=100){
8116 ok=false;
8117
8118 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8119 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min afternoons per week for teacher %1 with"
8120 " weight (percentage) below 100. Please make weight 100% and try again")
8121 .arg(tmd->teacherName),
8122 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8123 1, 0 );
8124
8125 if(t==0)
8126 return false;
8127 }
8128 //////////
8129
8130 //////////
8131 if(tmd->minAfternoonsPerWeek>gt.rules.nDaysPerWeek/2){
8132 ok=false;
8133
8134 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8135 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min afternoons per week for teacher %1 with"
8136 " %2 min afternoons per week, and the number of working afternoons per week is only %3. Please correct and try again")
8137 .arg(tmd->teacherName)
8138 .arg(tmd->minAfternoonsPerWeek)
8139 .arg(gt.rules.nDaysPerWeek/2),
8140 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8141 1, 0 );
8142
8143 if(t==0)
8144 return false;
8145 }
8146 //////////
8147
8148 if(teachersMinAfternoonsPerWeekMinAfternoons[tmd->teacher_ID]==-1 || teachersMinAfternoonsPerWeekMinAfternoons[tmd->teacher_ID]<tmd->minAfternoonsPerWeek){
8149 teachersMinAfternoonsPerWeekMinAfternoons[tmd->teacher_ID]=tmd->minAfternoonsPerWeek;
8150 teachersMinAfternoonsPerWeekPercentages[tmd->teacher_ID]=100;
8151 }
8152 }
8153 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_AFTERNOONS_PER_WEEK){
8154 ConstraintTeachersMinAfternoonsPerWeek* tmd=(ConstraintTeachersMinAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8155
8156 //////////
8157 if(tmd->weightPercentage!=100){
8158 ok=false;
8159
8160 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8161 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min afternoons per week with"
8162 " weight (percentage) below 100. Please make weight 100% and try again"),
8163 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8164 1, 0 );
8165
8166 if(t==0)
8167 return false;
8168 }
8169 //////////
8170
8171 //////////
8172 if(tmd->minAfternoonsPerWeek>gt.rules.nDaysPerWeek/2){
8173 ok=false;
8174
8175 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8176 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min afternoons per week with"
8177 " %1 min afternoons per week, and the number of working afternoons per week is only %2. Please correct and try again")
8178 .arg(tmd->minAfternoonsPerWeek)
8179 .arg(gt.rules.nDaysPerWeek/2),
8180 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8181 1, 0 );
8182
8183 if(t==0)
8184 return false;
8185 }
8186 //////////
8187
8188 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
8189 if(teachersMinAfternoonsPerWeekMinAfternoons[tch]==-1 || teachersMinAfternoonsPerWeekMinAfternoons[tch]<tmd->minAfternoonsPerWeek){
8190 teachersMinAfternoonsPerWeekMinAfternoons[tch]=tmd->minAfternoonsPerWeek;
8191 teachersMinAfternoonsPerWeekPercentages[tch]=100;
8192 }
8193 }
8194 }
8195 }
8196
8197 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
8198 if(teachersMinMorningsPerWeekMinMornings[tc]>=0){
8199 if(teachersMaxMorningsPerWeekMaxMornings[tc]>=0){
8200 if(teachersMaxMorningsPerWeekMaxMornings[tc]<teachersMinMorningsPerWeekMinMornings[tc]){
8201 ok=false;
8202
8203 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8204 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min mornings per week %2 > max mornings per week %3"
8205 " - impossible (min mornings must be <= max mornings). Please correct and try again.")
8206 .arg(gt.rules.internalTeachersList[tc]->name)
8207 .arg(teachersMinMorningsPerWeekMinMornings[tc])
8208 .arg(teachersMaxMorningsPerWeekMaxMornings[tc])
8209 ,
8210 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8211 1, 0 );
8212
8213 if(t==0)
8214 return false;
8215 }
8216 }
8217 }
8218 }
8219
8220 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
8221 if(teachersMinAfternoonsPerWeekMinAfternoons[tc]>=0){
8222 if(teachersMaxAfternoonsPerWeekMaxAfternoons[tc]>=0){
8223 if(teachersMaxAfternoonsPerWeekMaxAfternoons[tc]<teachersMinAfternoonsPerWeekMinAfternoons[tc]){
8224 ok=false;
8225
8226 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8227 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min afternoons per week %2 > max afternoons per week %3"
8228 " - impossible (min afternoons must be <= max afternoons). Please correct and try again.")
8229 .arg(gt.rules.internalTeachersList[tc]->name)
8230 .arg(teachersMinAfternoonsPerWeekMinAfternoons[tc])
8231 .arg(teachersMaxAfternoonsPerWeekMaxAfternoons[tc])
8232 ,
8233 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8234 1, 0 );
8235
8236 if(t==0)
8237 return false;
8238 }
8239 }
8240 }
8241 }
8242
8243 /*for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
8244 if(teachersMinMorningsPerWeekMinMornings[tch]>=0 || teachersMinAfternoonsPerWeekMinAfternoons[tch]>=0){
8245 if(teachersMaxGapsPerDayMaxGaps[tch]!=0 && teachersMaxGapsPerWeekMaxGaps[tch]!=0){
8246 ok=false;
8247
8248 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8249 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min mornings or min afternoons per week constraints,"
8250 " but not also max 0 gaps per day or per week. Please add max 0 gaps per day or per week for this teacher (or for all teachers) and generate again.")
8251 .arg(gt.rules.internalTeachersList[tch]->name),
8252 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8253 1, 0 );
8254
8255 if(t==0)
8256 return false;
8257 }
8258 }
8259 }*/
8260
8261 return ok;
8262 }
8263
8264
8265 //must be after min hours for students (I think not), students max gaps per day and students max gaps per week (I think not)
computeStudentsMinMorningsAfternoonsPerWeek(QWidget * parent)8266 bool computeStudentsMinMorningsAfternoonsPerWeek(QWidget* parent)
8267 {
8268 bool ok=true;
8269
8270 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
8271 subgroupsMinMorningsPerWeekMinMornings[i]=-1;
8272 subgroupsMinMorningsPerWeekPercentages[i]=-1;
8273
8274 subgroupsMinAfternoonsPerWeekMinAfternoons[i]=-1;
8275 subgroupsMinAfternoonsPerWeekPercentages[i]=-1;
8276 }
8277
8278 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8279 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_MORNINGS_PER_WEEK){
8280 ConstraintStudentsSetMinMorningsPerWeek* tmd=(ConstraintStudentsSetMinMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8281
8282 //////////
8283 if(tmd->weightPercentage!=100){
8284 ok=false;
8285
8286 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8287 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min mornings per week for students set %1 with"
8288 " weight (percentage) below 100. Please make weight 100% and try again")
8289 .arg(tmd->students),
8290 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8291 1, 0 );
8292
8293 if(t==0)
8294 return false;
8295 }
8296 //////////
8297
8298 //////////
8299 if(tmd->minMorningsPerWeek>gt.rules.nDaysPerWeek/2){
8300 ok=false;
8301
8302 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8303 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min mornings per week for students set %1 with"
8304 " %2 min mornings per week, and the number of working mornings per week is only %3. Please correct and try again")
8305 .arg(tmd->students)
8306 .arg(tmd->minMorningsPerWeek)
8307 .arg(gt.rules.nDaysPerWeek/2),
8308 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8309 1, 0 );
8310
8311 if(t==0)
8312 return false;
8313 }
8314 //////////
8315
8316 for(int sbg : tmd->iSubgroupsList)
8317 if(subgroupsMinMorningsPerWeekMinMornings[sbg]==-1 || subgroupsMinMorningsPerWeekMinMornings[sbg]<tmd->minMorningsPerWeek){
8318 subgroupsMinMorningsPerWeekMinMornings[sbg]=tmd->minMorningsPerWeek;
8319 subgroupsMinMorningsPerWeekPercentages[sbg]=100;
8320 }
8321 }
8322 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_MORNINGS_PER_WEEK){
8323 ConstraintStudentsMinMorningsPerWeek* tmd=(ConstraintStudentsMinMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8324
8325 //////////
8326 if(tmd->weightPercentage!=100){
8327 ok=false;
8328
8329 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8330 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min mornings per week with"
8331 " weight (percentage) below 100. Please make weight 100% and try again"),
8332 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8333 1, 0 );
8334
8335 if(t==0)
8336 return false;
8337 }
8338 //////////
8339
8340 //////////
8341 if(tmd->minMorningsPerWeek>gt.rules.nDaysPerWeek/2){
8342 ok=false;
8343
8344 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8345 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min mornings per week with"
8346 " %1 min mornings per week, and the number of working mornings per week is only %2. Please correct and try again")
8347 .arg(tmd->minMorningsPerWeek)
8348 .arg(gt.rules.nDaysPerWeek/2),
8349 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8350 1, 0 );
8351
8352 if(t==0)
8353 return false;
8354 }
8355 //////////
8356
8357 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
8358 if(subgroupsMinMorningsPerWeekMinMornings[sbg]==-1 || subgroupsMinMorningsPerWeekMinMornings[sbg]<tmd->minMorningsPerWeek){
8359 subgroupsMinMorningsPerWeekMinMornings[sbg]=tmd->minMorningsPerWeek;
8360 subgroupsMinMorningsPerWeekPercentages[sbg]=100;
8361 }
8362 }
8363 }
8364 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_AFTERNOONS_PER_WEEK){
8365 ConstraintStudentsSetMinAfternoonsPerWeek* tmd=(ConstraintStudentsSetMinAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8366
8367 //////////
8368 if(tmd->weightPercentage!=100){
8369 ok=false;
8370
8371 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8372 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min afternoons per week for students set %1 with"
8373 " weight (percentage) below 100. Please make weight 100% and try again")
8374 .arg(tmd->students),
8375 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8376 1, 0 );
8377
8378 if(t==0)
8379 return false;
8380 }
8381 //////////
8382
8383 //////////
8384 if(tmd->minAfternoonsPerWeek>gt.rules.nDaysPerWeek/2){
8385 ok=false;
8386
8387 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8388 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min afternoons per week for students set %1 with"
8389 " %2 min afternoons per week, and the number of working afternoons per week is only %3. Please correct and try again")
8390 .arg(tmd->students)
8391 .arg(tmd->minAfternoonsPerWeek)
8392 .arg(gt.rules.nDaysPerWeek/2),
8393 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8394 1, 0 );
8395
8396 if(t==0)
8397 return false;
8398 }
8399 //////////
8400
8401 for(int sbg : tmd->iSubgroupsList)
8402 if(subgroupsMinAfternoonsPerWeekMinAfternoons[sbg]==-1 || subgroupsMinAfternoonsPerWeekMinAfternoons[sbg]<tmd->minAfternoonsPerWeek){
8403 subgroupsMinAfternoonsPerWeekMinAfternoons[sbg]=tmd->minAfternoonsPerWeek;
8404 subgroupsMinAfternoonsPerWeekPercentages[sbg]=100;
8405 }
8406 }
8407 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_AFTERNOONS_PER_WEEK){
8408 ConstraintStudentsMinAfternoonsPerWeek* tmd=(ConstraintStudentsMinAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
8409
8410 //////////
8411 if(tmd->weightPercentage!=100){
8412 ok=false;
8413
8414 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8415 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min afternoons per week with"
8416 " weight (percentage) below 100. Please make weight 100% and try again"),
8417 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8418 1, 0 );
8419
8420 if(t==0)
8421 return false;
8422 }
8423 //////////
8424
8425 //////////
8426 if(tmd->minAfternoonsPerWeek>gt.rules.nDaysPerWeek/2){
8427 ok=false;
8428
8429 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8430 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min afternoons per week with"
8431 " %1 min afternoons per week, and the number of working afternoons per week is only %2. Please correct and try again")
8432 .arg(tmd->minAfternoonsPerWeek)
8433 .arg(gt.rules.nDaysPerWeek/2),
8434 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8435 1, 0 );
8436
8437 if(t==0)
8438 return false;
8439 }
8440 //////////
8441
8442 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
8443 if(subgroupsMinAfternoonsPerWeekMinAfternoons[sbg]==-1 || subgroupsMinAfternoonsPerWeekMinAfternoons[sbg]<tmd->minAfternoonsPerWeek){
8444 subgroupsMinAfternoonsPerWeekMinAfternoons[sbg]=tmd->minAfternoonsPerWeek;
8445 subgroupsMinAfternoonsPerWeekPercentages[sbg]=100;
8446 }
8447 }
8448 }
8449 }
8450
8451 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
8452 if(subgroupsMinMorningsPerWeekMinMornings[sb]>=0){
8453 if(subgroupsMaxMorningsPerWeekMaxMornings[sb]>=0){
8454 if(subgroupsMaxMorningsPerWeekMaxMornings[sb]<subgroupsMinMorningsPerWeekMinMornings[sb]){
8455 ok=false;
8456
8457 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8458 GeneratePreTranslate::tr("Cannot optimize because for subgroup %1 you have min mornings per week %2 > max mornings per week %3"
8459 " - impossible (min mornings must be <= max mornings). Please correct and try again.")
8460 .arg(gt.rules.internalSubgroupsList[sb]->name)
8461 .arg(subgroupsMinMorningsPerWeekMinMornings[sb])
8462 .arg(subgroupsMaxMorningsPerWeekMaxMornings[sb])
8463 ,
8464 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8465 1, 0 );
8466
8467 if(t==0)
8468 return false;
8469 }
8470 }
8471 }
8472 }
8473
8474 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
8475 if(subgroupsMinAfternoonsPerWeekMinAfternoons[sb]>=0){
8476 if(subgroupsMaxAfternoonsPerWeekMaxAfternoons[sb]>=0){
8477 if(subgroupsMaxAfternoonsPerWeekMaxAfternoons[sb]<subgroupsMinAfternoonsPerWeekMinAfternoons[sb]){
8478 ok=false;
8479
8480 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8481 GeneratePreTranslate::tr("Cannot optimize because for subgroup %1 you have min afternoons per week %2 > max afternoons per week %3"
8482 " - impossible (min afternoons must be <= max afternoons). Please correct and try again.")
8483 .arg(gt.rules.internalSubgroupsList[sb]->name)
8484 .arg(subgroupsMinAfternoonsPerWeekMinAfternoons[sb])
8485 .arg(subgroupsMaxAfternoonsPerWeekMaxAfternoons[sb])
8486 ,
8487 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8488 1, 0 );
8489
8490 if(t==0)
8491 return false;
8492 }
8493 }
8494 }
8495 }
8496
8497 /*for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
8498 if(teachersMinMorningsPerWeekMinMornings[tch]>=0 || teachersMinAfternoonsPerWeekMinAfternoons[tch]>=0){
8499 if(teachersMaxGapsPerDayMaxGaps[tch]!=0 && teachersMaxGapsPerWeekMaxGaps[tch]!=0){
8500 ok=false;
8501
8502 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8503 GeneratePreTranslate::tr("Cannot optimize because for teacher %1 you have min mornings or min afternoons per week constraints,"
8504 " but not also max 0 gaps per day or per week. Please add max 0 gaps per day or per week for this teacher (or for all teachers) and generate again.")
8505 .arg(gt.rules.internalTeachersList[tch]->name),
8506 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8507 1, 0 );
8508
8509 if(t==0)
8510 return false;
8511 }
8512 }
8513 }*/
8514
8515 return ok;
8516 }
8517
8518
computeTeachersMaxTwoConsecutiveMornings(QWidget * parent)8519 bool computeTeachersMaxTwoConsecutiveMornings(QWidget* parent)
8520 {
8521 bool ok=true;
8522
8523 for(int i=0; i<gt.rules.nInternalTeachers; i++)
8524 teachersMaxTwoConsecutiveMorningsPercentage[i]=-1;
8525
8526 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8527 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_TWO_CONSECUTIVE_MORNINGS){
8528 ConstraintTeacherMaxTwoConsecutiveMornings* tmd=(ConstraintTeacherMaxTwoConsecutiveMornings*)gt.rules.internalTimeConstraintsList[i];
8529
8530 //////////
8531 if(tmd->weightPercentage!=100){
8532 ok=false;
8533
8534 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8535 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max two consecutive mornings for teacher %1 with"
8536 " weight (percentage) below 100. Please make weight 100% and try again")
8537 .arg(tmd->teacherName),
8538 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8539 1, 0 );
8540
8541 if(t==0)
8542 return false;
8543 }
8544 //////////
8545
8546 if(teachersMaxTwoConsecutiveMorningsPercentage[tmd->teacher_ID]==-1)
8547 teachersMaxTwoConsecutiveMorningsPercentage[tmd->teacher_ID]=100;
8548 }
8549 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_TWO_CONSECUTIVE_MORNINGS){
8550 ConstraintTeachersMaxTwoConsecutiveMornings* tmd=(ConstraintTeachersMaxTwoConsecutiveMornings*)gt.rules.internalTimeConstraintsList[i];
8551
8552 //////////
8553 if(tmd->weightPercentage!=100){
8554 ok=false;
8555
8556 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8557 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max two consecutive mornings with"
8558 " weight (percentage) below 100. Please make weight 100% and try again"),
8559 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8560 1, 0 );
8561
8562 if(t==0)
8563 return false;
8564 }
8565 //////////
8566
8567 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++)
8568 if(teachersMaxTwoConsecutiveMorningsPercentage[tc]==-1)
8569 teachersMaxTwoConsecutiveMorningsPercentage[tc]=100;
8570 }
8571 }
8572
8573 return ok;
8574 }
8575
computeTeachersMaxTwoConsecutiveAfternoons(QWidget * parent)8576 bool computeTeachersMaxTwoConsecutiveAfternoons(QWidget* parent)
8577 {
8578 bool ok=true;
8579
8580 for(int i=0; i<gt.rules.nInternalTeachers; i++)
8581 teachersMaxTwoConsecutiveAfternoonsPercentage[i]=-1;
8582
8583 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8584 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_TWO_CONSECUTIVE_AFTERNOONS){
8585 ConstraintTeacherMaxTwoConsecutiveAfternoons* tmd=(ConstraintTeacherMaxTwoConsecutiveAfternoons*)gt.rules.internalTimeConstraintsList[i];
8586
8587 //////////
8588 if(tmd->weightPercentage!=100){
8589 ok=false;
8590
8591 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8592 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max two consecutive afternoons for teacher %1 with"
8593 " weight (percentage) below 100. Please make weight 100% and try again")
8594 .arg(tmd->teacherName),
8595 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8596 1, 0 );
8597
8598 if(t==0)
8599 return false;
8600 }
8601 //////////
8602
8603 if(teachersMaxTwoConsecutiveAfternoonsPercentage[tmd->teacher_ID]==-1)
8604 teachersMaxTwoConsecutiveAfternoonsPercentage[tmd->teacher_ID]=100;
8605 }
8606 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_TWO_CONSECUTIVE_AFTERNOONS){
8607 ConstraintTeachersMaxTwoConsecutiveAfternoons* tmd=(ConstraintTeachersMaxTwoConsecutiveAfternoons*)gt.rules.internalTimeConstraintsList[i];
8608
8609 //////////
8610 if(tmd->weightPercentage!=100){
8611 ok=false;
8612
8613 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8614 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max two consecutive afternoons with"
8615 " weight (percentage) below 100. Please make weight 100% and try again"),
8616 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8617 1, 0 );
8618
8619 if(t==0)
8620 return false;
8621 }
8622 //////////
8623
8624 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++)
8625 if(teachersMaxTwoConsecutiveAfternoonsPercentage[tc]==-1)
8626 teachersMaxTwoConsecutiveAfternoonsPercentage[tc]=100;
8627 }
8628 }
8629
8630 return ok;
8631 }
8632
computeTeachersMinRestingHoursBetweenMorningAndAfternoon(QWidget * parent)8633 bool computeTeachersMinRestingHoursBetweenMorningAndAfternoon(QWidget* parent)
8634 {
8635 bool ok=true;
8636
8637 for(int i=0; i<gt.rules.nInternalTeachers; i++){
8638 teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[i]=-1;
8639 teachersMinRestingHoursBetweenMorningAndAfternoonPercentages[i]=-1;
8640 }
8641
8642 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8643 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_RESTING_HOURS_BETWEEN_MORNING_AND_AFTERNOON){
8644 ConstraintTeacherMinRestingHoursBetweenMorningAndAfternoon* tmrh=(ConstraintTeacherMinRestingHoursBetweenMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
8645
8646 //////////
8647 if(tmrh->weightPercentage!=100){
8648 ok=false;
8649
8650 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8651 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min resting hours between morning and afternoon for teacher %1 with"
8652 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again")
8653 .arg(tmrh->teacherName),
8654 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8655 1, 0 );
8656
8657 if(t==0)
8658 return false;
8659 }
8660 //////////
8661 if(tmrh->minRestingHours>2*gt.rules.nHoursPerDay){
8662 ok=false;
8663
8664 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8665 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher min resting hours between morning and afternoon for teacher %1 with"
8666 " %2 min resting hours, and the number of working hours per day is only %3. Min resting hours should be at most two times the number of hours per day."
8667 " Please correct and try again")
8668 .arg(tmrh->teacherName)
8669 .arg(tmrh->minRestingHours)
8670 .arg(gt.rules.nHoursPerDay),
8671 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8672 1, 0 );
8673
8674 if(t==0)
8675 return false;
8676 }
8677 //////////
8678
8679 if(teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tmrh->teacher_ID]==-1 ||
8680 (teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tmrh->teacher_ID]>=0 && teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tmrh->teacher_ID]<tmrh->minRestingHours)){
8681 teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tmrh->teacher_ID]=tmrh->minRestingHours;
8682 teachersMinRestingHoursBetweenMorningAndAfternoonPercentages[tmrh->teacher_ID]=100;
8683 }
8684 }
8685 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_RESTING_HOURS_BETWEEN_MORNING_AND_AFTERNOON){
8686 ConstraintTeachersMinRestingHoursBetweenMorningAndAfternoon* tmrh=(ConstraintTeachersMinRestingHoursBetweenMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
8687
8688 //////////
8689 if(tmrh->weightPercentage!=100){
8690 ok=false;
8691
8692 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8693 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min resting hours between morning and afternoon with"
8694 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again"),
8695 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8696 1, 0 );
8697
8698 if(t==0)
8699 return false;
8700 }
8701 //////////
8702 if(tmrh->minRestingHours>2*gt.rules.nHoursPerDay){
8703 ok=false;
8704
8705 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8706 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers min resting hours between morning and afternoon with"
8707 " %1 min resting hours, and the number of working hours per day is only %2. Min resting hours should be at most two times the number of hours per day."
8708 " Please correct and try again")
8709 .arg(tmrh->minRestingHours)
8710 .arg(gt.rules.nHoursPerDay),
8711 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8712 1, 0 );
8713
8714 if(t==0)
8715 return false;
8716 }
8717 //////////
8718
8719 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
8720 if(teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tch]==-1 ||
8721 (teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tch]>=0 && teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tch]<tmrh->minRestingHours)){
8722 teachersMinRestingHoursBetweenMorningAndAfternoonMinHours[tch]=tmrh->minRestingHours;
8723 teachersMinRestingHoursBetweenMorningAndAfternoonPercentages[tch]=100;
8724 }
8725 }
8726 }
8727 }
8728
8729 return ok;
8730 }
8731
computeSubgroupsMinRestingHoursBetweenMorningAndAfternoon(QWidget * parent)8732 bool computeSubgroupsMinRestingHoursBetweenMorningAndAfternoon(QWidget* parent)
8733 {
8734 bool ok=true;
8735
8736 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
8737 subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[i]=-1;
8738 subgroupsMinRestingHoursBetweenMorningAndAfternoonPercentages[i]=-1;
8739 }
8740
8741 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8742 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_RESTING_HOURS_BETWEEN_MORNING_AND_AFTERNOON){
8743 ConstraintStudentsSetMinRestingHoursBetweenMorningAndAfternoon* smrh=(ConstraintStudentsSetMinRestingHoursBetweenMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
8744
8745 //////////
8746 if(smrh->weightPercentage!=100){
8747 ok=false;
8748
8749 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8750 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min resting hours between morning and afternoon for students set %1 with"
8751 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again")
8752 .arg(smrh->students),
8753 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8754 1, 0 );
8755
8756 if(t==0)
8757 return false;
8758 }
8759 //////////
8760 if(smrh->minRestingHours>2*gt.rules.nHoursPerDay){
8761 ok=false;
8762
8763 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8764 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set min resting hours between morning and afternoon for students set %1 with"
8765 " %2 min resting hours, and the number of working hours per day is only %3. Min resting hours should be at most two times the number of hours per day."
8766 " Please correct and try again")
8767 .arg(smrh->students)
8768 .arg(smrh->minRestingHours)
8769 .arg(gt.rules.nHoursPerDay),
8770 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8771 1, 0 );
8772
8773 if(t==0)
8774 return false;
8775 }
8776 //////////
8777
8778 for(int sbg : qAsConst(smrh->iSubgroupsList)){
8779 if(subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]==-1 ||
8780 (subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]>=0 && subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]<smrh->minRestingHours)){
8781 subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]=smrh->minRestingHours;
8782 subgroupsMinRestingHoursBetweenMorningAndAfternoonPercentages[sbg]=100;
8783 }
8784 }
8785 }
8786 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_RESTING_HOURS_BETWEEN_MORNING_AND_AFTERNOON){
8787 ConstraintStudentsMinRestingHoursBetweenMorningAndAfternoon* smrh=(ConstraintStudentsMinRestingHoursBetweenMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
8788
8789 //////////
8790 if(smrh->weightPercentage!=100){
8791 ok=false;
8792
8793 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8794 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min resting hours with"
8795 " weight (percentage) below 100. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again"),
8796 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8797 1, 0 );
8798
8799 if(t==0)
8800 return false;
8801 }
8802 //////////
8803 if(smrh->minRestingHours>2*gt.rules.nHoursPerDay){
8804 ok=false;
8805
8806 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8807 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students min resting hours between morning and afternoon with"
8808 " %1 min resting hours, and the number of working hours per day is only %2. Min resting hours should be at most two times the number of hours per day."
8809 " Please correct and try again")
8810 .arg(smrh->minRestingHours)
8811 .arg(gt.rules.nHoursPerDay),
8812 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8813 1, 0 );
8814
8815 if(t==0)
8816 return false;
8817 }
8818 //////////
8819
8820 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
8821 if(subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]==-1 ||
8822 (subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]>=0 && subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]<smrh->minRestingHours)){
8823 subgroupsMinRestingHoursBetweenMorningAndAfternoonMinHours[sbg]=smrh->minRestingHours;
8824 subgroupsMinRestingHoursBetweenMorningAndAfternoonPercentages[sbg]=100;
8825 }
8826 }
8827 }
8828 }
8829
8830 return ok;
8831 }
8832
computeActivitiesNotOverlapping()8833 void computeActivitiesNotOverlapping()
8834 {
8835 for(int i=0; i<gt.rules.nInternalActivities; i++){
8836 activitiesNotOverlappingActivities[i].clear();
8837 activitiesNotOverlappingPercentages[i].clear();
8838 }
8839
8840 QHash<QPair<int, int>, int> pos;
8841
8842 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
8843 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_NOT_OVERLAPPING){
8844 ConstraintActivitiesNotOverlapping* no=(ConstraintActivitiesNotOverlapping*)gt.rules.internalTimeConstraintsList[i];
8845
8846 for(int j=0; j<no->_n_activities; j++){
8847 int ai1=no->_activities[j];
8848 for(int k=0; k<no->_n_activities; k++){
8849 int ai2=no->_activities[k];
8850 if(ai1!=ai2){
8851 int t=pos.value(QPair<int, int>(ai1, ai2), -1);
8852 //int t=activitiesNotOverlappingActivities[ai1].indexOf(ai2);
8853 if(t>=0){
8854 assert(t<activitiesNotOverlappingPercentages[ai1].count());
8855 assert(activitiesNotOverlappingActivities[ai1].at(t)==ai2);
8856 if(activitiesNotOverlappingPercentages[ai1].at(t) < no->weightPercentage){
8857 activitiesNotOverlappingPercentages[ai1][t]=no->weightPercentage;
8858 }
8859 }
8860 else{
8861 pos.insert(QPair<int, int>(ai1, ai2), activitiesNotOverlappingPercentages[ai1].count());
8862 activitiesNotOverlappingPercentages[ai1].append(no->weightPercentage);
8863 activitiesNotOverlappingActivities[ai1].append(ai2);
8864 }
8865 }
8866 }
8867 }
8868 }
8869 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITY_TAGS_NOT_OVERLAPPING){
8870 ConstraintActivityTagsNotOverlapping* catno=(ConstraintActivityTagsNotOverlapping*)gt.rules.internalTimeConstraintsList[i];
8871
8872 for(int i=0; i<catno->activitiesIndicesLists.count(); i++){
8873 const QList<int>& l1=catno->activitiesIndicesLists.at(i);
8874 for(int j=0; j<catno->activitiesIndicesLists.count(); j++){
8875 if(i!=j){
8876 const QList<int>& l2=catno->activitiesIndicesLists.at(j);
8877
8878 for(int a : qAsConst(l1))
8879 for(int b : qAsConst(l2)){
8880 assert(a!=b);
8881
8882 int p=pos.value(QPair<int, int>(a, b), -1);
8883 if(p>=0){
8884 assert(p<activitiesNotOverlappingPercentages[a].count());
8885 assert(activitiesNotOverlappingActivities[a].at(p)==b);
8886 if(activitiesNotOverlappingPercentages[a].at(p) < catno->weightPercentage){
8887 activitiesNotOverlappingPercentages[a][p]=catno->weightPercentage;
8888 }
8889 }
8890 else{
8891 pos.insert(QPair<int, int>(a, b), activitiesNotOverlappingPercentages[a].count());
8892 activitiesNotOverlappingPercentages[a].append(catno->weightPercentage);
8893 activitiesNotOverlappingActivities[a].append(b);
8894 }
8895 }
8896 }
8897 }
8898 }
8899 }
8900 }
8901 }
8902
computeActivitiesSameStartingTime(QWidget * parent,QHash<int,int> & reprSameStartingTime,QHash<int,QSet<int>> & reprSameActivitiesSet)8903 bool computeActivitiesSameStartingTime(QWidget* parent, QHash<int, int> & reprSameStartingTime, QHash<int, QSet<int>> & reprSameActivitiesSet)
8904 {
8905 bool reportunder100=true;
8906 bool report100=true;
8907
8908 bool oktocontinue=true;
8909
8910 for(int i=0; i<gt.rules.nInternalActivities; i++){
8911 activitiesSameStartingTimeActivities[i].clear();
8912 activitiesSameStartingTimePercentages[i].clear();
8913 }
8914
8915 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
8916 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_TIME){
8917 ConstraintActivitiesSameStartingTime* sst=(ConstraintActivitiesSameStartingTime*)gt.rules.internalTimeConstraintsList[i];
8918
8919 for(int j=0; j<sst->_n_activities; j++){
8920 int ai1=sst->_activities[j];
8921 for(int k=j+1; k<sst->_n_activities; k++){
8922 int ai2=sst->_activities[k];
8923
8924 if(sst->weightPercentage==100.0 && activitiesConflictingPercentage[ai1].value(ai2, -1)==100)
8925 oktocontinue=false;
8926
8927 if(sst->weightPercentage<100.0 && reportunder100 && activitiesConflictingPercentage[ai1].value(ai2, -1)==100){
8928 QString s;
8929
8930 s+=sst->getDetailedDescription(gt.rules);
8931 s+="\n";
8932 s+=GeneratePreTranslate::tr("The constraint is impossible to respect, because there are the activities with id-s %1 and %2 which "
8933 "conflict one with another, because they have common students sets or teachers or must be not overlapping. FET will allow you to continue, "
8934 "because the weight of this constraint is below 100.0%, "
8935 "but anyway most probably you have made a mistake in this constraint, "
8936 "so it is recommended to modify it.")
8937 .arg(gt.rules.internalActivitiesList[ai1].id)
8938 .arg(gt.rules.internalActivitiesList[ai2].id);
8939
8940 int t=GeneratePreReconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8941 s, GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8942 1, 0 );
8943
8944 if(t==0)
8945 reportunder100=false;
8946 }
8947 else if(sst->weightPercentage==100.0 && report100 && activitiesConflictingPercentage[ai1].value(ai2, -1)==100){
8948 QString s;
8949
8950 s+=sst->getDetailedDescription(gt.rules);
8951 s+="\n";
8952 s+=GeneratePreTranslate::tr("The constraint is impossible to respect, because there are the activities with id-s %1 and %2 which "
8953 "conflict one with another, because they have common students sets or teachers or must be not overlapping. The weight of this constraint is 100.0%, "
8954 "so your timetable is impossible. Please correct this constraint.")
8955 .arg(gt.rules.internalActivitiesList[ai1].id)
8956 .arg(gt.rules.internalActivitiesList[ai2].id);
8957
8958 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
8959 s, GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
8960 1, 0 );
8961
8962 if(t==0)
8963 report100=false;
8964 }
8965 }
8966 }
8967
8968 for(int j=0; j<sst->_n_activities; j++){
8969 int ai1=sst->_activities[j];
8970 for(int k=0; k<sst->_n_activities; k++){
8971 int ai2=sst->_activities[k];
8972 if(ai1!=ai2){
8973 int t=activitiesSameStartingTimeActivities[ai1].indexOf(ai2);
8974 double perc=-1;
8975 if(t!=-1){
8976 perc=activitiesSameStartingTimePercentages[ai1].at(t);
8977 assert(perc>=0 && perc<=100);
8978 }
8979
8980 if(t==-1 /*|| perc<sst->weightPercentage*/){
8981 activitiesSameStartingTimeActivities[ai1].append(ai2);
8982 activitiesSameStartingTimePercentages[ai1].append(sst->weightPercentage);
8983 assert(activitiesSameStartingTimeActivities[ai1].count()==activitiesSameStartingTimePercentages[ai1].count());
8984 }
8985 else if(t>=0 && perc<sst->weightPercentage){
8986 activitiesSameStartingTimePercentages[ai1][t]=sst->weightPercentage;
8987 }
8988 }
8989 }
8990 }
8991 }
8992
8993
8994 //added June 2009, FET-5.10.0
8995 bool reportIndirect=true;
8996
8997 QMultiHash<int, int> adjMatrix;
8998
8999 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9000 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_TIME
9001 &>.rules.internalTimeConstraintsList[i]->weightPercentage==100.0){
9002 ConstraintActivitiesSameStartingTime* sst=(ConstraintActivitiesSameStartingTime*)gt.rules.internalTimeConstraintsList[i];
9003
9004 for(int i=1; i<sst->_n_activities; i++){
9005 adjMatrix.insert(sst->_activities[0], sst->_activities[i]);
9006 adjMatrix.insert(sst->_activities[i], sst->_activities[0]);
9007 }
9008 }
9009 }
9010
9011 QHash<int, int> repr;
9012 //repr.clear();
9013
9014 QQueue<int> queue;
9015
9016 for(int i=0; i<gt.rules.nInternalActivities; i++){
9017 int start=i;
9018
9019 if(repr.value(start, -1)==-1){ //not visited
9020 repr.insert(start, start);
9021 queue.enqueue(start);
9022 while(!queue.isEmpty()){
9023 int crtHead=queue.dequeue();
9024 assert(repr.value(crtHead, -1)==start);
9025 QList<int> neighList=adjMatrix.values(crtHead);
9026 for(int neigh : qAsConst(neighList)){
9027 if(repr.value(neigh, -1)==-1){
9028 queue.enqueue(neigh);
9029 repr.insert(neigh, start);
9030 }
9031 else{
9032 assert(repr.value(neigh, -1)==start);
9033 }
9034 }
9035 }
9036 }
9037 }
9038
9039 //faster than below
9040 for(int i=0; i<gt.rules.nInternalActivities; i++){
9041 QHash<int, int>& hashConfl=activitiesConflictingPercentage[i];
9042
9043 QHash<int, int>::const_iterator it=hashConfl.constBegin();
9044 while(it!=hashConfl.constEnd()){
9045 //cout<<it.key()<<": "<<it.value()<<endl;
9046 int j=it.key();
9047 if(i!=j){
9048 if(it.value()==100){
9049 if(repr.value(i)==repr.value(j)){
9050 oktocontinue=false;
9051
9052 if(reportIndirect){
9053 QString s=GeneratePreTranslate::tr("You have a set of impossible constraints activities same starting time, considering all the indirect links between"
9054 " activities same starting time constraints");
9055 s+="\n\n";
9056 s+=GeneratePreTranslate::tr("The activities with ids %1 and %2 must be simultaneous (request determined indirectly), but they have common teachers and/or students sets or must be not overlapping")
9057 .arg(gt.rules.internalActivitiesList[i].id).arg(gt.rules.internalActivitiesList[j].id);
9058
9059 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9060 s, GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9061 1, 0 );
9062
9063 if(t==0)
9064 reportIndirect=false;
9065 }
9066 }
9067 }
9068 }
9069 it++;
9070 }
9071 }
9072
9073 /*
9074 for(int i=0; i<gt.rules.nInternalActivities; i++)
9075 for(int j=i+1; j<gt.rules.nInternalActivities; j++)
9076 if(repr.value(i) == repr.value(j)){
9077 if(activitiesConflictingPercentage[i].value(j, -1)==100){
9078 oktocontinue=false;
9079
9080 if(reportIndirect){
9081 QString s=GeneratePreTranslate::tr("You have a set of impossible constraints activities same starting time, considering all the indirect links between"
9082 " activities same starting time constraints");
9083 s+="\n\n";
9084 s+=GeneratePreTranslate::tr("The activities with ids %1 and %2 must be simultaneous (request determined indirectly), but they have common teachers and/or students sets or must be not overlapping")
9085 .arg(gt.rules.internalActivitiesList[i].id).arg(gt.rules.internalActivitiesList[j].id);
9086
9087 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9088 s, GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9089 1, 0 );
9090
9091 if(t==0)
9092 reportIndirect=false;
9093 }
9094 }
9095 }*/
9096 ///////////end added 5.10.0, June 2009
9097
9098 QHash<int, QSet<int>> hashSet;
9099
9100 for(int i=0; i<gt.rules.nInternalActivities; i++){
9101 assert(repr.contains(i));
9102 int r=repr.value(i);
9103 hashSet[r].insert(i); //faster
9104 /*QSet<int> s;
9105 if(hashSet.contains(r))
9106 s=hashSet.value(r);
9107 s.insert(i);
9108 hashSet.insert(r, s);*/
9109 }
9110
9111 reprSameStartingTime=repr;
9112 reprSameActivitiesSet=hashSet;
9113
9114 return oktocontinue;
9115 }
9116
computeActivitiesSameStartingHour()9117 void computeActivitiesSameStartingHour()
9118 {
9119 for(int i=0; i<gt.rules.nInternalActivities; i++){
9120 activitiesSameStartingHourActivities[i].clear();
9121 activitiesSameStartingHourPercentages[i].clear();
9122 }
9123
9124 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
9125 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_HOUR){
9126 ConstraintActivitiesSameStartingHour* sst=(ConstraintActivitiesSameStartingHour*)gt.rules.internalTimeConstraintsList[i];
9127
9128 for(int j=0; j<sst->_n_activities; j++){
9129 int ai1=sst->_activities[j];
9130 for(int k=0; k<sst->_n_activities; k++){
9131 int ai2=sst->_activities[k];
9132 if(ai1!=ai2){
9133 int t=activitiesSameStartingHourActivities[ai1].indexOf(ai2);
9134 double perc=-1;
9135 if(t!=-1){
9136 perc=activitiesSameStartingHourPercentages[ai1].at(t);
9137 assert(perc>=0 && perc<=100);
9138 }
9139
9140 if(t==-1 /*|| perc<sst->weightPercentage*/){
9141 activitiesSameStartingHourActivities[ai1].append(ai2);
9142 activitiesSameStartingHourPercentages[ai1].append(sst->weightPercentage);
9143 assert(activitiesSameStartingHourActivities[ai1].count()==activitiesSameStartingHourPercentages[ai1].count());
9144 }
9145 else if(t>=0 && perc<sst->weightPercentage){
9146 activitiesSameStartingHourPercentages[ai1][t]=sst->weightPercentage;
9147 }
9148 }
9149 }
9150 }
9151 }
9152 }
9153
computeActivitiesSameStartingDay()9154 void computeActivitiesSameStartingDay()
9155 {
9156 for(int i=0; i<gt.rules.nInternalActivities; i++){
9157 activitiesSameStartingDayActivities[i].clear();
9158 activitiesSameStartingDayPercentages[i].clear();
9159 }
9160
9161 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
9162 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_DAY){
9163 ConstraintActivitiesSameStartingDay* sst=(ConstraintActivitiesSameStartingDay*)gt.rules.internalTimeConstraintsList[i];
9164
9165 for(int j=0; j<sst->_n_activities; j++){
9166 int ai1=sst->_activities[j];
9167 for(int k=0; k<sst->_n_activities; k++){
9168 int ai2=sst->_activities[k];
9169 if(ai1!=ai2){
9170 int t=activitiesSameStartingDayActivities[ai1].indexOf(ai2);
9171 double perc=-1;
9172 if(t!=-1){
9173 perc=activitiesSameStartingDayPercentages[ai1].at(t);
9174 assert(perc>=0 && perc<=100);
9175 }
9176
9177 if(t==-1 /*|| perc<sst->weightPercentage*/){
9178 activitiesSameStartingDayActivities[ai1].append(ai2);
9179 activitiesSameStartingDayPercentages[ai1].append(sst->weightPercentage);
9180 assert(activitiesSameStartingDayActivities[ai1].count()==activitiesSameStartingDayPercentages[ai1].count());
9181 }
9182 else if(t>=0 && perc<sst->weightPercentage){
9183 activitiesSameStartingDayPercentages[ai1][t]=sst->weightPercentage;
9184 }
9185 }
9186 }
9187 }
9188 }
9189 }
9190
9191 ////////////teachers' max gaps
9192 //important also for other purposes
computeNHoursPerTeacher(QWidget * parent)9193 bool computeNHoursPerTeacher(QWidget* parent)
9194 {
9195 for(int i=0; i<gt.rules.nInternalTeachers; i++)
9196 nHoursPerTeacher[i]=0;
9197 for(int i=0; i<gt.rules.nInternalActivities; i++){
9198 Activity* act=>.rules.internalActivitiesList[i];
9199 for(int j=0; j<act->iTeachersList.count(); j++){
9200 int tc=act->iTeachersList.at(j);
9201 nHoursPerTeacher[tc]+=act->duration;
9202 }
9203 }
9204
9205 bool ok=true;
9206
9207 for(int i=0; i<gt.rules.nInternalTeachers; i++)
9208 if(nHoursPerTeacher[i]>gt.rules.nHoursPerWeek){
9209 ok=false;
9210
9211 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9212 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because the number of hours for teacher is %2"
9213 " and you have only %3 days x %4 hours in a week.")
9214 .arg(gt.rules.internalTeachersList[i]->name)
9215 .arg(nHoursPerTeacher[i])
9216 .arg(gt.rules.nDaysPerWeek)
9217 .arg(gt.rules.nHoursPerDay),
9218 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9219 1, 0 );
9220
9221 if(t==0)
9222 return ok;
9223 }
9224
9225 for(int i=0; i<gt.rules.nInternalTeachers; i++){
9226 int freeSlots=0;
9227 for(int j=0; j<gt.rules.nDaysPerWeek; j++)
9228 for(int k=0; k<gt.rules.nHoursPerDay; k++)
9229 if(!teacherNotAvailableDayHour[i][j][k] && !breakDayHour[j][k])
9230 freeSlots++;
9231 if(nHoursPerTeacher[i]>freeSlots){
9232 ok=false;
9233
9234 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9235 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because the number of hours for teacher is %2"
9236 " and you have only %3 free slots from constraints teacher not available and/or break.")
9237 .arg(gt.rules.internalTeachersList[i]->name)
9238 .arg(nHoursPerTeacher[i])
9239 .arg(freeSlots),
9240 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9241 1, 0 );
9242
9243 if(t==0)
9244 return ok;
9245 }
9246 }
9247
9248 //n days per week has 100% weight
9249 for(int i=0; i<gt.rules.nInternalTeachers; i++)
9250 if(teachersMaxDaysPerWeekMaxDays[i]>=0){
9251 int nd=teachersMaxDaysPerWeekMaxDays[i];
9252 if(nHoursPerTeacher[i] > nd*gt.rules.nHoursPerDay){
9253 ok=false;
9254
9255 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9256 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because the number of hours for teacher is %2"
9257 " and you have only %3 allowed days from constraint teacher max days per week x %4 hours in a day."
9258 " Probably there is an error in your data")
9259 .arg(gt.rules.internalTeachersList[i]->name)
9260 .arg(nHoursPerTeacher[i])
9261 .arg(nd)
9262 .arg(gt.rules.nHoursPerDay),
9263 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9264 1, 0 );
9265
9266 if(t==0)
9267 return ok;
9268 }
9269 }
9270
9271 //n days per week has 100% weight
9272 if(gt.rules.mode==MORNINGS_AFTERNOONS){
9273 for(int i=0; i<gt.rules.nInternalTeachers; i++)
9274 if(teachersMaxRealDaysPerWeekMaxDays[i]>=0){
9275 int nd=teachersMaxRealDaysPerWeekMaxDays[i];
9276 if(nHoursPerTeacher[i] > 2*nd*gt.rules.nHoursPerDay){
9277 ok=false;
9278
9279 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9280 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because the number of hours for teacher is %2"
9281 " and you have only %3 allowed real days from constraint teacher max real days per week x %4 hours in a real day."
9282 " Probably there is an error in your data")
9283 .arg(gt.rules.internalTeachersList[i]->name)
9284 .arg(nHoursPerTeacher[i])
9285 .arg(nd)
9286 .arg(2*gt.rules.nHoursPerDay),
9287 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9288 1, 0 );
9289
9290 if(t==0)
9291 return ok;
9292 }
9293 }
9294 }
9295
9296 //n days per week has 100% weight
9297 //check n days per week together with not available and breaks
9298
9299 Matrix1D<int> nAllowedSlotsPerDay;
9300 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
9301
9302 Matrix1D<int> dayAvailable;
9303 dayAvailable.resize(gt.rules.nDaysPerWeek);
9304
9305 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
9306 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
9307 nAllowedSlotsPerDay[d]=0;
9308 for(int h=0; h<gt.rules.nHoursPerDay; h++)
9309 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h])
9310 nAllowedSlotsPerDay[d]++;
9311 }
9312
9313 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9314 dayAvailable[d]=1;
9315 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){
9316 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9317 dayAvailable[d]=0;
9318
9319 assert(teachersMaxDaysPerWeekMaxDays[tc]<=gt.rules.nDaysPerWeek);
9320 for(int k=0; k<teachersMaxDaysPerWeekMaxDays[tc]; k++){
9321 int maxPos=-1, maxVal=-1;
9322 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9323 if(dayAvailable[d]==0)
9324 if(maxVal<nAllowedSlotsPerDay[d]){
9325 maxVal=nAllowedSlotsPerDay[d];
9326 maxPos=d;
9327 }
9328 assert(maxPos>=0);
9329 assert(dayAvailable[maxPos]==0);
9330 dayAvailable[maxPos]=1;
9331 }
9332 }
9333
9334 int total=0;
9335 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
9336 if(dayAvailable[d]==1)
9337 total+=nAllowedSlotsPerDay[d];
9338 if(total<nHoursPerTeacher[tc]){
9339 ok=false;
9340
9341 QString s;
9342 s=GeneratePreTranslate::tr("Cannot optimize for teacher %1, because of too constrained"
9343 " teacher max days per week, teacher not available and/or breaks."
9344 " The number of total hours for this teacher is"
9345 " %2 and the number of available slots is, considering max days per week and all other constraints, %3.")
9346 .arg(gt.rules.internalTeachersList[tc]->name)
9347 .arg(nHoursPerTeacher[tc])
9348 .arg(total);
9349 s+="\n\n";
9350 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
9351
9352 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
9353 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9354 1, 0 );
9355
9356 if(t==0)
9357 return false;
9358 }
9359 }
9360
9361 return ok;
9362 }
9363
computeTeachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentages(QWidget * parent)9364 bool computeTeachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentages(QWidget* parent)
9365 {
9366 haveTeachersAfternoonsEarly=false;
9367
9368 for(int i=0; i<gt.rules.nInternalTeachers; i++){
9369 teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]=-1;
9370 teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=-1;
9371 }
9372
9373 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9374 //teachers early
9375 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_AFTERNOONS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9376 haveTeachersAfternoonsEarly=true;
9377 ConstraintTeachersAfternoonsEarlyMaxBeginningsAtSecondHour* se=(ConstraintTeachersAfternoonsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9378 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9379 if(teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9380 teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9381 if(teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9382 teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9383 }
9384 }
9385
9386 //teacher early
9387 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_AFTERNOONS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9388 haveTeachersAfternoonsEarly=true;
9389 ConstraintTeacherAfternoonsEarlyMaxBeginningsAtSecondHour* se=(ConstraintTeacherAfternoonsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9390 int j=se->teacherIndex;
9391 if(teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9392 teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9393 if(teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9394 teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9395 }
9396 }
9397
9398 bool ok=true;
9399 for(int i=0; i<gt.rules.nInternalTeachers; i++){
9400 assert((teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 &&
9401 teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]==-1) ||
9402 (teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 &&
9403 teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0));
9404
9405 bool okteacher=true;
9406
9407 if(teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 && teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]!=100){
9408 okteacher=false;
9409 ok=false;
9410
9411 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9412 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because you have an afternoons early max beginnings at second hour constraint"
9413 " with weight percentage less than 100%. Currently, the algorithm can only"
9414 " optimize with not existing constraint early m.b.a.s.h. or existing with 100% weight for it"
9415 ". Please modify your data correspondingly and try again")
9416 .arg(gt.rules.internalTeachersList[i]->name),
9417 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9418 1, 0 );
9419
9420 if(t==0)
9421 break;
9422 }
9423
9424 if(teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9425 && teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>gt.rules.nDaysPerWeek/2){
9426 okteacher=false;
9427 ok=false;
9428
9429 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9430 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because afternoons early max beginnings at second hour constraint"
9431 " has max beginnings at second hour %2, and the number of afternoons per week is %3, which is less. It must be that the number of"
9432 " afternoons per week must be greater or equal with the max beginnings at second hour\n"
9433 "Please modify your data correspondingly and try again")
9434 .arg(gt.rules.internalTeachersList[i]->name)
9435 .arg(teachersAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9436 .arg(gt.rules.nDaysPerWeek/2),
9437 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9438 1, 0 );
9439
9440 if(t==0)
9441 break;
9442 }
9443
9444 if(!okteacher)
9445 ok=false;
9446 }
9447
9448 return ok;
9449 }
9450
computeTeachersMorningsEarlyMaxBeginningsAtSecondHourPercentages(QWidget * parent)9451 bool computeTeachersMorningsEarlyMaxBeginningsAtSecondHourPercentages(QWidget* parent)
9452 {
9453 haveTeachersMorningsEarly=false;
9454
9455 for(int i=0; i<gt.rules.nInternalTeachers; i++){
9456 teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]=-1;
9457 teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=-1;
9458 }
9459
9460 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9461 //teachers early
9462 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MORNINGS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9463 haveTeachersMorningsEarly=true;
9464 ConstraintTeachersMorningsEarlyMaxBeginningsAtSecondHour* se=(ConstraintTeachersMorningsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9465 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9466 if(teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9467 teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9468 if(teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9469 teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9470 }
9471 }
9472
9473 //teacher early
9474 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MORNINGS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9475 haveTeachersMorningsEarly=true;
9476 ConstraintTeacherMorningsEarlyMaxBeginningsAtSecondHour* se=(ConstraintTeacherMorningsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9477 int j=se->teacherIndex;
9478 if(teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9479 teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9480 if(teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9481 teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9482 }
9483 }
9484
9485 bool ok=true;
9486 for(int i=0; i<gt.rules.nInternalTeachers; i++){
9487 assert((teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 &&
9488 teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]==-1) ||
9489 (teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 &&
9490 teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0));
9491
9492 bool okteacher=true;
9493
9494 if(teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 && teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]!=100){
9495 okteacher=false;
9496 ok=false;
9497
9498 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9499 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because you have an mornings early max beginnings at second hour constraint"
9500 " with weight percentage less than 100%. Currently, the algorithm can only"
9501 " optimize with not existing constraint early m.b.a.s.h. or existing with 100% weight for it"
9502 ". Please modify your data correspondingly and try again")
9503 .arg(gt.rules.internalTeachersList[i]->name),
9504 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9505 1, 0 );
9506
9507 if(t==0)
9508 break;
9509 }
9510
9511 if(teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9512 && teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>gt.rules.nDaysPerWeek/2){
9513 okteacher=false;
9514 ok=false;
9515
9516 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9517 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because mornings early max beginnings at second hour constraint"
9518 " has max beginnings at second hour %2, and the number of mornings per week is %3, which is less. It must be that the number of"
9519 " mornings per week must be greater or equal with the max beginnings at second hour\n"
9520 "Please modify your data correspondingly and try again")
9521 .arg(gt.rules.internalTeachersList[i]->name)
9522 .arg(teachersMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9523 .arg(gt.rules.nDaysPerWeek/2),
9524 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9525 1, 0 );
9526
9527 if(t==0)
9528 break;
9529 }
9530
9531 if(!okteacher)
9532 ok=false;
9533 }
9534
9535 return ok;
9536 }
9537
computeSubgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentages(QWidget * parent)9538 bool computeSubgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentages(QWidget* parent)
9539 {
9540 haveStudentsAfternoonsEarly=false;
9541
9542 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
9543 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]=-1;
9544 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=-1;
9545 }
9546
9547 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9548 //subgroups early
9549 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_AFTERNOONS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9550 haveStudentsAfternoonsEarly=true;
9551 ConstraintStudentsAfternoonsEarlyMaxBeginningsAtSecondHour* se=(ConstraintStudentsAfternoonsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9552 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
9553 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9554 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9555 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9556 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9557 }
9558 }
9559
9560 //subgroup early
9561 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_AFTERNOONS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9562 haveStudentsAfternoonsEarly=true;
9563 ConstraintStudentsSetAfternoonsEarlyMaxBeginningsAtSecondHour* se=(ConstraintStudentsSetAfternoonsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9564 for(int j : se->iSubgroupsList){
9565 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9566 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9567 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9568 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9569 }
9570 }
9571 }
9572
9573 bool ok=true;
9574 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
9575 assert((subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 &&
9576 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]==-1) ||
9577 (subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 &&
9578 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0));
9579
9580 bool oksubgroup=true;
9581
9582 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 && subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[i]!=100){
9583 oksubgroup=false;
9584 ok=false;
9585
9586 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9587 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because you have an afternoons early max beginnings at second hour constraint"
9588 " with weight percentage less than 100%. Currently, the algorithm can only"
9589 " optimize with not existing constraint early m.b.a.s.h. or existing with 100% weight for it"
9590 ". Please modify your data correspondingly and try again")
9591 .arg(gt.rules.internalSubgroupsList[i]->name),
9592 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9593 1, 0 );
9594
9595 if(t==0)
9596 break;
9597 }
9598
9599 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9600 && subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>gt.rules.nDaysPerWeek/2){
9601 oksubgroup=false;
9602 ok=false;
9603
9604 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9605 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because afternoons early max beginnings at second hour constraint"
9606 " has max beginnings at second hour %2, and the number of afternoons per week is %3, which is less. It must be that the number of"
9607 " afternoons per week must be greater or equal with the max beginnings at second hour\n"
9608 "Please modify your data correspondingly and try again")
9609 .arg(gt.rules.internalSubgroupsList[i]->name)
9610 .arg(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9611 .arg(gt.rules.nDaysPerWeek/2),
9612 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9613 1, 0 );
9614
9615 if(t==0)
9616 break;
9617 }
9618
9619 if(!oksubgroup)
9620 ok=false;
9621 }
9622
9623 if(ok){
9624 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
9625 if(subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9626 && subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9627 && subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9628 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i];
9629 }
9630 }
9631
9632 return ok;
9633 }
9634
computeSubgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentages(QWidget * parent)9635 bool computeSubgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentages(QWidget* parent)
9636 {
9637 haveStudentsMorningsEarly=false;
9638
9639 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
9640 subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]=-1;
9641 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=-1;
9642 }
9643
9644 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9645 //subgroups early
9646 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MORNINGS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9647 haveStudentsMorningsEarly=true;
9648 ConstraintStudentsMorningsEarlyMaxBeginningsAtSecondHour* se=(ConstraintStudentsMorningsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9649 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
9650 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9651 subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9652 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9653 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9654 }
9655 }
9656
9657 //subgroup early
9658 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MORNINGS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
9659 haveStudentsMorningsEarly=true;
9660 ConstraintStudentsSetMorningsEarlyMaxBeginningsAtSecondHour* se=(ConstraintStudentsSetMorningsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
9661 for(int j : se->iSubgroupsList){
9662 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
9663 subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
9664 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
9665 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
9666 }
9667 }
9668 }
9669
9670 bool ok=true;
9671 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
9672 assert((subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 &&
9673 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]==-1) ||
9674 (subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 &&
9675 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0));
9676
9677 bool oksubgroup=true;
9678
9679 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 && subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]!=100){
9680 oksubgroup=false;
9681 ok=false;
9682
9683 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9684 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because you have an mornings early max beginnings at second hour constraint"
9685 " with weight percentage less than 100%. Currently, the algorithm can only"
9686 " optimize with not existing constraint early m.b.a.s.h. or existing with 100% weight for it"
9687 ". Please modify your data correspondingly and try again")
9688 .arg(gt.rules.internalSubgroupsList[i]->name),
9689 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9690 1, 0 );
9691
9692 if(t==0)
9693 break;
9694 }
9695
9696 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9697 && subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>gt.rules.nDaysPerWeek/2){
9698 oksubgroup=false;
9699 ok=false;
9700
9701 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9702 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because mornings early max beginnings at second hour constraint"
9703 " has max beginnings at second hour %2, and the number of mornings per week is %3, which is less. It must be that the number of"
9704 " mornings per week must be greater or equal with the max beginnings at second hour\n"
9705 "Please modify your data correspondingly and try again")
9706 .arg(gt.rules.internalSubgroupsList[i]->name)
9707 .arg(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9708 .arg(gt.rules.nDaysPerWeek/2),
9709 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9710 1, 0 );
9711
9712 if(t==0)
9713 break;
9714 }
9715
9716 if(!oksubgroup)
9717 ok=false;
9718 }
9719
9720 if(ok){
9721 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
9722 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9723 && subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9724 && subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9725 subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i];
9726
9727 if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9728 && subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9729 && subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9730 && subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]+subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]<subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i])
9731 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]+subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i];
9732 else if(subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9733 && subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
9734 && subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]==-1){
9735 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=subgroupsMorningsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]+subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i];
9736 subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[i]=100;
9737 }
9738 }
9739 }
9740
9741 return ok;
9742 }
9743
computeTeachersMaxGapsPerWeekPercentage(QWidget * parent)9744 bool computeTeachersMaxGapsPerWeekPercentage(QWidget* parent)
9745 {
9746 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9747 teachersMaxGapsPerWeekMaxGaps[j]=-1;
9748 teachersMaxGapsPerWeekPercentage[j]=-1;
9749 }
9750
9751 bool ok=true;
9752
9753 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9754 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_WEEK){
9755 ConstraintTeachersMaxGapsPerWeek* tg=(ConstraintTeachersMaxGapsPerWeek*)gt.rules.internalTimeConstraintsList[i];
9756
9757 if(tg->weightPercentage!=100){
9758 ok=false;
9759
9760 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9761 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max gaps per week with"
9762 " weight (percentage) below 100. Please make weight 100% and try again"),
9763 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9764 1, 0 );
9765
9766 if(t==0)
9767 return false;
9768 }
9769 }
9770 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_WEEK){
9771 ConstraintTeacherMaxGapsPerWeek* tg=(ConstraintTeacherMaxGapsPerWeek*)gt.rules.internalTimeConstraintsList[i];
9772
9773 if(tg->weightPercentage!=100){
9774 ok=false;
9775
9776 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9777 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max gaps per week with"
9778 " weight (percentage) below 100 for teacher %1. Please make weight 100% and try again")
9779 .arg(tg->teacherName),
9780 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9781 1, 0 );
9782
9783 if(t==0)
9784 return false;
9785 }
9786 }
9787 }
9788
9789 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9790 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_WEEK){
9791 ConstraintTeachersMaxGapsPerWeek* tg=(ConstraintTeachersMaxGapsPerWeek*)gt.rules.internalTimeConstraintsList[i];
9792
9793 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9794 if(teachersMaxGapsPerWeekMaxGaps[j]==-1
9795 ||(teachersMaxGapsPerWeekMaxGaps[j]>=0 && teachersMaxGapsPerWeekMaxGaps[j]>=tg->maxGaps && teachersMaxGapsPerWeekPercentage[j]<=tg->weightPercentage)){
9796 teachersMaxGapsPerWeekMaxGaps[j]=tg->maxGaps;
9797 teachersMaxGapsPerWeekPercentage[j]=tg->weightPercentage;
9798 }
9799 else if(teachersMaxGapsPerWeekMaxGaps[j]>=0 && teachersMaxGapsPerWeekMaxGaps[j]<=tg->maxGaps && teachersMaxGapsPerWeekPercentage[j]>=tg->weightPercentage){
9800 //do nothing
9801 }
9802 else{
9803 ok=false;
9804
9805 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9806 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are two constraints"
9807 " of type max gaps per week relating to him, and the weight percentage is higher on the constraint"
9808 " with more gaps allowed. You are allowed only to have for each teacher"
9809 " the most important constraint with maximum weight percentage and minimum gaps allowed"
9810 ". Please modify your data accordingly and try again")
9811 .arg(gt.rules.internalTeachersList[j]->name),
9812 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9813 1, 0 );
9814
9815 if(t==0)
9816 return false;
9817 }
9818 }
9819 }
9820 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_WEEK){
9821 ConstraintTeacherMaxGapsPerWeek* tg=(ConstraintTeacherMaxGapsPerWeek*)gt.rules.internalTimeConstraintsList[i];
9822
9823 int j=tg->teacherIndex;
9824 if(teachersMaxGapsPerWeekMaxGaps[j]==-1
9825 ||(teachersMaxGapsPerWeekMaxGaps[j]>=0 && teachersMaxGapsPerWeekMaxGaps[j]>=tg->maxGaps && teachersMaxGapsPerWeekPercentage[j]<=tg->weightPercentage)){
9826 teachersMaxGapsPerWeekMaxGaps[j]=tg->maxGaps;
9827 teachersMaxGapsPerWeekPercentage[j]=tg->weightPercentage;
9828 }
9829 else if(teachersMaxGapsPerWeekMaxGaps[j]>=0 && teachersMaxGapsPerWeekMaxGaps[j]<=tg->maxGaps && teachersMaxGapsPerWeekPercentage[j]>=tg->weightPercentage){
9830 //do nothing
9831 }
9832 else{
9833 ok=false;
9834
9835 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9836 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are two constraints"
9837 " of type max gaps per week relating to him, and the weight percentage is higher on the constraint"
9838 " with more gaps allowed. You are allowed only to have for each teacher"
9839 " the most important constraint with maximum weight percentage and minimum gaps allowed"
9840 ". Please modify your data accordingly and try again")
9841 .arg(gt.rules.internalTeachersList[j]->name),
9842 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9843 1, 0 );
9844
9845 if(t==0)
9846 return false;
9847 }
9848 }
9849 }
9850
9851 return ok;
9852 }
9853
computeTeachersMaxGapsPerDayPercentage(QWidget * parent)9854 bool computeTeachersMaxGapsPerDayPercentage(QWidget* parent)
9855 {
9856 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9857 teachersMaxGapsPerDayMaxGaps[j]=-1;
9858 teachersMaxGapsPerDayPercentage[j]=-1;
9859 }
9860
9861 bool ok=true;
9862
9863 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9864 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_DAY){
9865 ConstraintTeachersMaxGapsPerDay* tg=(ConstraintTeachersMaxGapsPerDay*)gt.rules.internalTimeConstraintsList[i];
9866
9867 if(tg->weightPercentage!=100){
9868 ok=false;
9869
9870 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9871 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max gaps per day with"
9872 " weight (percentage) below 100. Please make weight 100% and try again"),
9873 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9874 1, 0 );
9875
9876 if(t==0)
9877 return false;
9878 }
9879 }
9880 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_DAY){
9881 ConstraintTeacherMaxGapsPerDay* tg=(ConstraintTeacherMaxGapsPerDay*)gt.rules.internalTimeConstraintsList[i];
9882
9883 if(tg->weightPercentage!=100){
9884 ok=false;
9885
9886 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9887 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max gaps per day with"
9888 " weight (percentage) below 100 for teacher %1. Please make weight 100% and try again")
9889 .arg(tg->teacherName),
9890 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9891 1, 0 );
9892
9893 if(t==0)
9894 return false;
9895 }
9896 }
9897 }
9898
9899 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9900 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_DAY){
9901 ConstraintTeachersMaxGapsPerDay* tg=(ConstraintTeachersMaxGapsPerDay*)gt.rules.internalTimeConstraintsList[i];
9902
9903 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9904 if(teachersMaxGapsPerDayMaxGaps[j]==-1
9905 ||(teachersMaxGapsPerDayMaxGaps[j]>=0 && teachersMaxGapsPerDayMaxGaps[j]>=tg->maxGaps && teachersMaxGapsPerDayPercentage[j]<=tg->weightPercentage)){
9906 teachersMaxGapsPerDayMaxGaps[j]=tg->maxGaps;
9907 teachersMaxGapsPerDayPercentage[j]=tg->weightPercentage;
9908 }
9909 else if(teachersMaxGapsPerDayMaxGaps[j]>=0 && teachersMaxGapsPerDayMaxGaps[j]<=tg->maxGaps && teachersMaxGapsPerDayPercentage[j]>=tg->weightPercentage){
9910 //do nothing
9911 }
9912 else{
9913 ok=false;
9914
9915 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9916 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are two constraints"
9917 " of type max gaps per day relating to him, and the weight percentage is higher on the constraint"
9918 " with more gaps allowed. You are allowed only to have for each teacher"
9919 " the most important constraint with maximum weight percentage and minimum gaps allowed"
9920 ". Please modify your data accordingly and try again")
9921 .arg(gt.rules.internalTeachersList[j]->name),
9922 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9923 1, 0 );
9924
9925 if(t==0)
9926 return false;
9927 }
9928 }
9929 }
9930 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_DAY){
9931 ConstraintTeacherMaxGapsPerDay* tg=(ConstraintTeacherMaxGapsPerDay*)gt.rules.internalTimeConstraintsList[i];
9932
9933 int j=tg->teacherIndex;
9934 if(teachersMaxGapsPerDayMaxGaps[j]==-1
9935 ||(teachersMaxGapsPerDayMaxGaps[j]>=0 && teachersMaxGapsPerDayMaxGaps[j]>=tg->maxGaps && teachersMaxGapsPerDayPercentage[j]<=tg->weightPercentage)){
9936 teachersMaxGapsPerDayMaxGaps[j]=tg->maxGaps;
9937 teachersMaxGapsPerDayPercentage[j]=tg->weightPercentage;
9938 }
9939 else if(teachersMaxGapsPerDayMaxGaps[j]>=0 && teachersMaxGapsPerDayMaxGaps[j]<=tg->maxGaps && teachersMaxGapsPerDayPercentage[j]>=tg->weightPercentage){
9940 //do nothing
9941 }
9942 else{
9943 ok=false;
9944
9945 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9946 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are two constraints"
9947 " of type max gaps per day relating to him, and the weight percentage is higher on the constraint"
9948 " with more gaps allowed. You are allowed only to have for each teacher"
9949 " the most important constraint with maximum weight percentage and minimum gaps allowed"
9950 ". Please modify your data accordingly and try again")
9951 .arg(gt.rules.internalTeachersList[j]->name),
9952 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9953 1, 0 );
9954
9955 if(t==0)
9956 return false;
9957 }
9958 }
9959 }
9960
9961 return ok;
9962 }
9963
computeTeachersMaxGapsPerMorningAndAfternoonPercentage(QWidget * parent)9964 bool computeTeachersMaxGapsPerMorningAndAfternoonPercentage(QWidget* parent)
9965 {
9966 for(int j=0; j<gt.rules.nInternalTeachers; j++){
9967 teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]=-1;
9968 teachersMaxGapsPerMorningAndAfternoonPercentage[j]=-1;
9969 }
9970
9971 bool ok=true;
9972
9973 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
9974 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_MORNING_AND_AFTERNOON){
9975 ConstraintTeachersMaxGapsPerMorningAndAfternoon* tg=(ConstraintTeachersMaxGapsPerMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
9976
9977 if(tg->weightPercentage!=100){
9978 ok=false;
9979
9980 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9981 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max gaps per morning and afternoon with"
9982 " weight (percentage) below 100. Please make weight 100% and try again"),
9983 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
9984 1, 0 );
9985
9986 if(t==0)
9987 return false;
9988 }
9989 }
9990 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_MORNING_AND_AFTERNOON){
9991 ConstraintTeacherMaxGapsPerMorningAndAfternoon* tg=(ConstraintTeacherMaxGapsPerMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
9992
9993 if(tg->weightPercentage!=100){
9994 ok=false;
9995
9996 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
9997 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max gaps per morning and afternoon with"
9998 " weight (percentage) below 100 for teacher %1. Please make weight 100% and try again")
9999 .arg(tg->teacherName),
10000 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10001 1, 0 );
10002
10003 if(t==0)
10004 return false;
10005 }
10006 }
10007 }
10008
10009 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10010 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_MORNING_AND_AFTERNOON){
10011 ConstraintTeachersMaxGapsPerMorningAndAfternoon* tg=(ConstraintTeachersMaxGapsPerMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
10012
10013 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10014 if(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]==-1
10015 ||(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=0 && teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=tg->maxGaps && teachersMaxGapsPerMorningAndAfternoonPercentage[j]<=tg->weightPercentage)){
10016 teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]=tg->maxGaps;
10017 teachersMaxGapsPerMorningAndAfternoonPercentage[j]=tg->weightPercentage;
10018 }
10019 else if(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=0 && teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]<=tg->maxGaps && teachersMaxGapsPerMorningAndAfternoonPercentage[j]>=tg->weightPercentage){
10020 //do nothing
10021 }
10022 else{
10023 ok=false;
10024
10025 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10026 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are two constraints"
10027 " of type max gaps per morning and afternoon relating to him, and the weight percentage is higher on the constraint"
10028 " with more gaps allowed. You are allowed only to have for each teacher"
10029 " the most important constraint with maximum weight percentage and minimum gaps allowed"
10030 ". Please modify your data accordingly and try again")
10031 .arg(gt.rules.internalTeachersList[j]->name),
10032 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10033 1, 0 );
10034
10035 if(t==0)
10036 return false;
10037 }
10038 }
10039 }
10040 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_MORNING_AND_AFTERNOON){
10041 ConstraintTeacherMaxGapsPerMorningAndAfternoon* tg=(ConstraintTeacherMaxGapsPerMorningAndAfternoon*)gt.rules.internalTimeConstraintsList[i];
10042
10043 int j=tg->teacherIndex;
10044 if(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]==-1
10045 ||(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=0 && teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=tg->maxGaps && teachersMaxGapsPerMorningAndAfternoonPercentage[j]<=tg->weightPercentage)){
10046 teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]=tg->maxGaps;
10047 teachersMaxGapsPerMorningAndAfternoonPercentage[j]=tg->weightPercentage;
10048 }
10049 else if(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=0 && teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]<=tg->maxGaps && teachersMaxGapsPerMorningAndAfternoonPercentage[j]>=tg->weightPercentage){
10050 //do nothing
10051 }
10052 else{
10053 ok=false;
10054
10055 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10056 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because there are two constraints"
10057 " of type max gaps per morning and afternoon relating to him, and the weight percentage is higher on the constraint"
10058 " with more gaps allowed. You are allowed only to have for each teacher"
10059 " the most important constraint with maximum weight percentage and minimum gaps allowed"
10060 ". Please modify your data accordingly and try again")
10061 .arg(gt.rules.internalTeachersList[j]->name),
10062 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10063 1, 0 );
10064
10065 if(t==0)
10066 return false;
10067 }
10068 }
10069 }
10070
10071 if(ok){
10072 for(int j=0; j<gt.rules.nInternalTeachers; j++)
10073 if(teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]>=0){
10074 if(teachersMaxGapsPerDayMaxGaps[j]==-1 || (teachersMaxGapsPerDayMaxGaps[j]>=0
10075 && teachersMaxGapsPerDayMaxGaps[j]>teachersMaxGapsPerMorningAndAfternoonMaxGaps[j])){
10076 teachersMaxGapsPerDayPercentage[j]=100;
10077 teachersMaxGapsPerDayMaxGaps[j]=teachersMaxGapsPerMorningAndAfternoonMaxGaps[j];
10078 }
10079
10080 if(teachersMaxGapsPerWeekMaxGaps[j]==-1 || (teachersMaxGapsPerWeekMaxGaps[j]>=0
10081 && teachersMaxGapsPerWeekMaxGaps[j]>teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]*gt.rules.nDaysPerWeek/2)){
10082 teachersMaxGapsPerWeekPercentage[j]=100;
10083 teachersMaxGapsPerWeekMaxGaps[j]=teachersMaxGapsPerMorningAndAfternoonMaxGaps[j]*gt.rules.nDaysPerWeek/2;
10084 }
10085 }
10086 }
10087
10088 return ok;
10089 }
10090
computeTeachersMaxGapsPerRealDayPercentage(QWidget * parent)10091 bool computeTeachersMaxGapsPerRealDayPercentage(QWidget* parent)
10092 {
10093 bool ok=true;
10094
10095 haveTeachersMaxGapsPerRealDay=false;
10096
10097 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10098 teachersMaxGapsPerRealDayMaxGaps[j]=-1;
10099 teachersMaxGapsPerRealDayAllowException[j]=true;
10100 teachersMaxGapsPerRealDayPercentage[j]=-1;
10101
10102 teachersMaxGapsPerWeekForRealDaysMaxGaps[j]=-1;
10103 teachersMaxGapsPerWeekForRealDaysPercentage[j]=-1;
10104 }
10105
10106 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10107 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_REAL_DAY){
10108 haveTeachersMaxGapsPerRealDay=true;
10109 ConstraintTeachersMaxGapsPerRealDay* tg=(ConstraintTeachersMaxGapsPerRealDay*)gt.rules.internalTimeConstraintsList[i];
10110
10111 if(tg->weightPercentage!=100){
10112 ok=false;
10113
10114 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10115 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max gaps per real day with"
10116 " weight (percentage) below 100. Please make weight 100% and try again"),
10117 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10118 1, 0 );
10119
10120 if(t==0)
10121 return false;
10122 }
10123 }
10124
10125 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_REAL_DAY){
10126 haveTeachersMaxGapsPerRealDay=true;
10127 ConstraintTeacherMaxGapsPerRealDay* tg=(ConstraintTeacherMaxGapsPerRealDay*)gt.rules.internalTimeConstraintsList[i];
10128
10129 if(tg->weightPercentage!=100){
10130 ok=false;
10131
10132 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10133 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max gaps per real day with"
10134 " weight (percentage) below 100 for teacher %1. Please make weight 100% and try again")
10135 .arg(tg->teacherName),
10136 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10137 1, 0 );
10138
10139 if(t==0)
10140 return false;
10141 }
10142 }
10143
10144 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_WEEK_FOR_REAL_DAYS){
10145 haveTeachersMaxGapsPerRealDay=true;
10146 ConstraintTeachersMaxGapsPerWeekForRealDays* tg=(ConstraintTeachersMaxGapsPerWeekForRealDays*)gt.rules.internalTimeConstraintsList[i];
10147
10148 if(tg->weightPercentage!=100){
10149 ok=false;
10150
10151 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10152 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max gaps per week for real days with"
10153 " weight (percentage) below 100. Please make weight 100% and try again"),
10154 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10155 1, 0 );
10156
10157 if(t==0)
10158 return false;
10159 }
10160 }
10161
10162 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_WEEK_FOR_REAL_DAYS){
10163 haveTeachersMaxGapsPerRealDay=true;
10164 ConstraintTeacherMaxGapsPerWeekForRealDays* tg=(ConstraintTeacherMaxGapsPerWeekForRealDays*)gt.rules.internalTimeConstraintsList[i];
10165
10166 if(tg->weightPercentage!=100){
10167 ok=false;
10168
10169 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10170 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max gaps per week for real days with"
10171 " weight (percentage) below 100 for teacher %1. Please make weight 100% and try again")
10172 .arg(tg->teacherName),
10173 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10174 1, 0 );
10175
10176 if(t==0)
10177 return false;
10178 }
10179 }
10180 }
10181
10182 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10183 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_REAL_DAY){
10184 ConstraintTeachersMaxGapsPerRealDay* tg=(ConstraintTeachersMaxGapsPerRealDay*)gt.rules.internalTimeConstraintsList[i];
10185
10186 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
10187 if(teachersMaxGapsPerRealDayPercentage[tch]==-1){
10188 teachersMaxGapsPerRealDayPercentage[tch]=100.0;
10189 teachersMaxGapsPerRealDayMaxGaps[tch]=tg->maxGaps;
10190 teachersMaxGapsPerRealDayAllowException[tch]=tg->allowOneDayExceptionPlusOne;
10191 }
10192 else if(teachersMaxGapsPerRealDayMaxGaps[tch]>tg->maxGaps){
10193 assert(teachersMaxGapsPerRealDayPercentage[tch]==100.0);
10194 teachersMaxGapsPerRealDayMaxGaps[tch]=tg->maxGaps;
10195 teachersMaxGapsPerRealDayAllowException[tch]=tg->allowOneDayExceptionPlusOne;
10196 }
10197 else if(teachersMaxGapsPerRealDayMaxGaps[tch]==tg->maxGaps){
10198 assert(teachersMaxGapsPerRealDayPercentage[tch]==100.0);
10199 assert(teachersMaxGapsPerRealDayMaxGaps[tch]==tg->maxGaps);
10200 if(!tg->allowOneDayExceptionPlusOne && teachersMaxGapsPerRealDayAllowException[tch])
10201 teachersMaxGapsPerRealDayAllowException[tch]=false;
10202 }
10203 }
10204 }
10205 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_REAL_DAY){
10206 ConstraintTeacherMaxGapsPerRealDay* tg=(ConstraintTeacherMaxGapsPerRealDay*)gt.rules.internalTimeConstraintsList[i];
10207
10208 int tch=tg->teacherIndex;
10209
10210 if(teachersMaxGapsPerRealDayPercentage[tch]==-1){
10211 teachersMaxGapsPerRealDayPercentage[tch]=100.0;
10212 teachersMaxGapsPerRealDayMaxGaps[tch]=tg->maxGaps;
10213 teachersMaxGapsPerRealDayAllowException[tch]=tg->allowOneDayExceptionPlusOne;
10214 }
10215 else if(teachersMaxGapsPerRealDayMaxGaps[tch]>tg->maxGaps){
10216 assert(teachersMaxGapsPerRealDayPercentage[tch]==100.0);
10217 teachersMaxGapsPerRealDayMaxGaps[tch]=tg->maxGaps;
10218 teachersMaxGapsPerRealDayAllowException[tch]=tg->allowOneDayExceptionPlusOne;
10219 }
10220 else if(teachersMaxGapsPerRealDayMaxGaps[tch]==tg->maxGaps){
10221 assert(teachersMaxGapsPerRealDayPercentage[tch]==100.0);
10222 assert(teachersMaxGapsPerRealDayMaxGaps[tch]==tg->maxGaps);
10223 if(!tg->allowOneDayExceptionPlusOne && teachersMaxGapsPerRealDayAllowException[tch])
10224 teachersMaxGapsPerRealDayAllowException[tch]=false;
10225 }
10226 }
10227
10228 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_GAPS_PER_WEEK_FOR_REAL_DAYS){
10229 ConstraintTeachersMaxGapsPerWeekForRealDays* tg=(ConstraintTeachersMaxGapsPerWeekForRealDays*)gt.rules.internalTimeConstraintsList[i];
10230
10231 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
10232 if(teachersMaxGapsPerWeekForRealDaysPercentage[tch]==-1){
10233 teachersMaxGapsPerWeekForRealDaysPercentage[tch]=100.0;
10234 teachersMaxGapsPerWeekForRealDaysMaxGaps[tch]=tg->maxGaps;
10235 }
10236 else if(teachersMaxGapsPerWeekForRealDaysMaxGaps[tch]>tg->maxGaps){
10237 assert(teachersMaxGapsPerWeekForRealDaysPercentage[tch]==100.0);
10238 teachersMaxGapsPerWeekForRealDaysMaxGaps[tch]=tg->maxGaps;
10239 }
10240 }
10241 }
10242
10243 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_GAPS_PER_WEEK_FOR_REAL_DAYS){
10244 ConstraintTeacherMaxGapsPerWeekForRealDays* tg=(ConstraintTeacherMaxGapsPerWeekForRealDays*)gt.rules.internalTimeConstraintsList[i];
10245
10246 int tch=tg->teacherIndex;
10247
10248 if(teachersMaxGapsPerWeekForRealDaysPercentage[tch]==-1){
10249 teachersMaxGapsPerWeekForRealDaysPercentage[tch]=100.0;
10250 teachersMaxGapsPerWeekForRealDaysMaxGaps[tch]=tg->maxGaps;
10251 }
10252 else if(teachersMaxGapsPerWeekForRealDaysMaxGaps[tch]>tg->maxGaps){
10253 assert(teachersMaxGapsPerWeekForRealDaysPercentage[tch]==100.0);
10254 teachersMaxGapsPerWeekForRealDaysMaxGaps[tch]=tg->maxGaps;
10255 }
10256 }
10257 }
10258
10259 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10260 if(teachersMaxGapsPerRealDayMaxGaps[j]==0 || teachersMaxGapsPerWeekForRealDaysMaxGaps[j]==0){
10261 teachersMaxGapsPerRealDayMaxGaps[j]=0;
10262 teachersMaxGapsPerRealDayPercentage[j]=100.0;
10263
10264 teachersMaxGapsPerWeekForRealDaysMaxGaps[j]=0;
10265 teachersMaxGapsPerWeekForRealDaysPercentage[j]=100.0;
10266 }
10267 else if(teachersMaxGapsPerRealDayMaxGaps[j]>=0 && (teachersMaxGapsPerWeekForRealDaysMaxGaps[j]<0 ||
10268 (teachersMaxGapsPerWeekForRealDaysMaxGaps[j]>=0 &&
10269 teachersMaxGapsPerWeekForRealDaysMaxGaps[j] > teachersMaxGapsPerRealDayMaxGaps[j]*(gt.rules.nDaysPerWeek/2)))){
10270 teachersMaxGapsPerWeekForRealDaysMaxGaps[j] = teachersMaxGapsPerRealDayMaxGaps[j]*(gt.rules.nDaysPerWeek/2);
10271 teachersMaxGapsPerWeekForRealDaysPercentage[j]=100.0;
10272 }
10273 }
10274
10275 return ok;
10276 }
10277
10278 /////////////////
10279
computeTeachersConstrainedToZeroGapsPerAfternoon(QWidget * parent)10280 bool computeTeachersConstrainedToZeroGapsPerAfternoon(QWidget* parent)
10281 {
10282 for(int j=0; j<gt.rules.nInternalTeachers; j++)
10283 teacherConstrainedToZeroGapsPerAfternoon[j]=false;
10284
10285 bool ok=true;
10286
10287 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10288 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_ZERO_GAPS_PER_AFTERNOON){
10289 ConstraintTeachersMaxZeroGapsPerAfternoon* tg=(ConstraintTeachersMaxZeroGapsPerAfternoon*)gt.rules.internalTimeConstraintsList[i];
10290
10291 if(tg->weightPercentage!=100){
10292 ok=false;
10293
10294 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10295 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max zero gaps per afternoon with"
10296 " weight (percentage) below 100. Please make weight 100% and try again"),
10297 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10298 1, 0 );
10299
10300 if(t==0)
10301 return false;
10302 }
10303 }
10304
10305 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_ZERO_GAPS_PER_AFTERNOON){
10306 ConstraintTeacherMaxZeroGapsPerAfternoon* tg=(ConstraintTeacherMaxZeroGapsPerAfternoon*)gt.rules.internalTimeConstraintsList[i];
10307
10308 if(tg->weightPercentage!=100){
10309 ok=false;
10310
10311 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10312 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max zero gaps per afternoon with"
10313 " weight (percentage) below 100 for teacher %1. Please make weight 100% and try again")
10314 .arg(tg->teacherName),
10315 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10316 1, 0 );
10317
10318 if(t==0)
10319 return false;
10320 }
10321 }
10322 }
10323
10324 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10325 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_ZERO_GAPS_PER_AFTERNOON){
10326 ConstraintTeachersMaxZeroGapsPerAfternoon* tg=(ConstraintTeachersMaxZeroGapsPerAfternoon*)gt.rules.internalTimeConstraintsList[i];
10327 assert(tg->weightPercentage==100);
10328
10329 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++)
10330 teacherConstrainedToZeroGapsPerAfternoon[tch]=true;
10331 }
10332 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_ZERO_GAPS_PER_AFTERNOON){
10333 ConstraintTeacherMaxZeroGapsPerAfternoon* tg=(ConstraintTeacherMaxZeroGapsPerAfternoon*)gt.rules.internalTimeConstraintsList[i];
10334 assert(tg->weightPercentage==100);
10335
10336 teacherConstrainedToZeroGapsPerAfternoon[tg->teacherIndex]=true;
10337 }
10338 }
10339
10340 //cout<<"teacherConstrainedToZeroGapsPerAfternoon[0]="<<teacherConstrainedToZeroGapsPerAfternoon[0]<<endl;
10341
10342 return ok;
10343 }
10344 /////////////////
10345
10346 ///////students' max gaps and early (part 1)
10347 //important also for other purposes
computeNHoursPerSubgroup(QWidget * parent)10348 bool computeNHoursPerSubgroup(QWidget* parent)
10349 {
10350 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
10351 nHoursPerSubgroup[i]=0;
10352 for(int i=0; i<gt.rules.nInternalActivities; i++){
10353 Activity* act=>.rules.internalActivitiesList[i];
10354 for(int j=0; j<act->iSubgroupsList.count(); j++){
10355 int sb=act->iSubgroupsList.at(j);
10356 nHoursPerSubgroup[sb]+=act->duration;
10357 }
10358 }
10359
10360 bool ok=true;
10361 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
10362 if(nHoursPerSubgroup[i]>gt.rules.nHoursPerWeek){
10363 ok=false;
10364
10365 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10366 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because the number of hours for subgroup is %2"
10367 " and you have only %3 days x %4 hours in a week.")
10368 .arg(gt.rules.internalSubgroupsList[i]->name)
10369 .arg(nHoursPerSubgroup[i])
10370 .arg(gt.rules.nDaysPerWeek)
10371 .arg(gt.rules.nHoursPerDay),
10372 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10373 1, 0 );
10374
10375 if(t==0)
10376 return ok;
10377 }
10378
10379 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
10380 int freeSlots=0;
10381 for(int j=0; j<gt.rules.nDaysPerWeek; j++)
10382 for(int k=0; k<gt.rules.nHoursPerDay; k++)
10383 if(!subgroupNotAvailableDayHour[i][j][k] && !breakDayHour[j][k])
10384 freeSlots++;
10385 if(nHoursPerSubgroup[i]>freeSlots){
10386 ok=false;
10387
10388 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10389 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because the number of hours for subgroup is %2"
10390 " and you have only %3 free slots from constraints students set not available and/or break.")
10391 .arg(gt.rules.internalSubgroupsList[i]->name)
10392 .arg(nHoursPerSubgroup[i])
10393 .arg(freeSlots),
10394 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10395 1, 0 );
10396
10397 if(t==0)
10398 return ok;
10399 }
10400 }
10401
10402 //n days per week has 100% weight
10403 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
10404 if(subgroupsMaxDaysPerWeekMaxDays[i]>=0){
10405 int nd=subgroupsMaxDaysPerWeekMaxDays[i];
10406 if(nHoursPerSubgroup[i] > nd*gt.rules.nHoursPerDay){
10407 ok=false;
10408
10409 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10410 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because the number of hours for subgroup is %2"
10411 " and you have only %3 allowed days from constraint students (set) max days per week x %4 hours in a day."
10412 " Probably there is an error in your data")
10413 .arg(gt.rules.internalSubgroupsList[i]->name)
10414 .arg(nHoursPerSubgroup[i])
10415 .arg(nd)
10416 .arg(gt.rules.nHoursPerDay),
10417 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10418 1, 0 );
10419
10420 if(t==0)
10421 return ok;
10422 }
10423 }
10424
10425 //n days per week has 100% weight
10426 if(gt.rules.mode==MORNINGS_AFTERNOONS){
10427 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
10428 if(subgroupsMaxRealDaysPerWeekMaxDays[i]>=0){
10429 int nd=subgroupsMaxRealDaysPerWeekMaxDays[i];
10430 if(nHoursPerSubgroup[i] > 2*nd*gt.rules.nHoursPerDay){
10431 ok=false;
10432
10433 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10434 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because the number of hours for subgroup is %2"
10435 " and you have only %3 allowed real days from constraint students (set) max real days per week x %4 hours in a real day."
10436 " Probably there is an error in your data")
10437 .arg(gt.rules.internalSubgroupsList[i]->name)
10438 .arg(nHoursPerSubgroup[i])
10439 .arg(nd)
10440 .arg(2*gt.rules.nHoursPerDay),
10441 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10442 1, 0 );
10443
10444 if(t==0)
10445 return ok;
10446 }
10447 }
10448 }
10449 //n days per week has 100% weight
10450 //check n days per week together with not available and breaks
10451
10452 Matrix1D<int> nAllowedSlotsPerDay;
10453 nAllowedSlotsPerDay.resize(gt.rules.nDaysPerWeek);
10454
10455 Matrix1D<int> dayAvailable;
10456 dayAvailable.resize(gt.rules.nDaysPerWeek);
10457
10458 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
10459 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
10460 nAllowedSlotsPerDay[d]=0;
10461 for(int h=0; h<gt.rules.nHoursPerDay; h++)
10462 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sb][d][h])
10463 nAllowedSlotsPerDay[d]++;
10464 }
10465
10466 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
10467 dayAvailable[d]=1;
10468 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){
10469 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
10470 dayAvailable[d]=0;
10471
10472 assert(subgroupsMaxDaysPerWeekMaxDays[sb]<=gt.rules.nDaysPerWeek);
10473 for(int k=0; k<subgroupsMaxDaysPerWeekMaxDays[sb]; k++){
10474 int maxPos=-1, maxVal=-1;
10475 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
10476 if(dayAvailable[d]==0)
10477 if(maxVal<nAllowedSlotsPerDay[d]){
10478 maxVal=nAllowedSlotsPerDay[d];
10479 maxPos=d;
10480 }
10481 assert(maxPos>=0);
10482 assert(dayAvailable[maxPos]==0);
10483 dayAvailable[maxPos]=1;
10484 }
10485 }
10486
10487 int total=0;
10488 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
10489 if(dayAvailable[d]==1)
10490 total+=nAllowedSlotsPerDay[d];
10491 if(total<nHoursPerSubgroup[sb]){
10492 ok=false;
10493
10494 QString s;
10495 s=GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because of too constrained"
10496 " students (set) max days per week, students set not available and/or breaks."
10497 " The number of total hours for this subgroup is"
10498 " %2 and the number of available slots is, considering max days per week and all other constraints, %3.")
10499 .arg(gt.rules.internalSubgroupsList[sb]->name)
10500 .arg(nHoursPerSubgroup[sb])
10501 .arg(total);
10502 s+="\n\n";
10503 s+=GeneratePreTranslate::tr("Please modify your data accordingly and try again");
10504
10505 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
10506 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10507 1, 0 );
10508
10509 if(t==0)
10510 return false;
10511 }
10512 }
10513
10514 return ok;
10515 }
10516
computeMaxDaysPerWeekForTeachers(QWidget * parent)10517 bool computeMaxDaysPerWeekForTeachers(QWidget* parent)
10518 {
10519 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10520 teachersMaxDaysPerWeekMaxDays[j]=-1;
10521 teachersMaxDaysPerWeekWeightPercentages[j]=-1;
10522 }
10523
10524 bool ok=true;
10525 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10526 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_DAYS_PER_WEEK){
10527 ConstraintTeacherMaxDaysPerWeek* tn=(ConstraintTeacherMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
10528
10529 if(tn->weightPercentage!=100){
10530 ok=false;
10531
10532 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10533 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max days per week with"
10534 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.2.17 it is only possible"
10535 " to use 100% weight for such constraints. Please make weight 100% and try again")
10536 .arg(tn->teacherName),
10537 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10538 1, 0 );
10539
10540 if(t==0)
10541 return false;
10542 }
10543
10544 if(teachersMaxDaysPerWeekMaxDays[tn->teacher_ID]==-1 ||
10545 (teachersMaxDaysPerWeekMaxDays[tn->teacher_ID]>=0 && teachersMaxDaysPerWeekMaxDays[tn->teacher_ID] > tn->maxDaysPerWeek)){
10546 teachersMaxDaysPerWeekMaxDays[tn->teacher_ID]=tn->maxDaysPerWeek;
10547 teachersMaxDaysPerWeekWeightPercentages[tn->teacher_ID]=tn->weightPercentage;
10548 }
10549 /*else{
10550 ok=false;
10551
10552 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
10553 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
10554 ". Please modify your data correspondingly (leave maximum one constraint of type"
10555 " constraint teacher max days per week for each teacher) and try again")
10556 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
10557 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10558 1, 0 );
10559
10560 if(t==0)
10561 break;
10562 }*/
10563 }
10564 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_DAYS_PER_WEEK){
10565 ConstraintTeachersMaxDaysPerWeek* tn=(ConstraintTeachersMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
10566
10567 if(tn->weightPercentage!=100){
10568 ok=false;
10569
10570 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10571 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max days per week with"
10572 " weight (percentage) below 100. Please make weight 100% and try again"),
10573 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10574 1, 0 );
10575
10576 if(t==0)
10577 return false;
10578 }
10579
10580 for(int t=0; t<gt.rules.nInternalTeachers; t++){
10581 if(teachersMaxDaysPerWeekMaxDays[t]==-1 ||
10582 (teachersMaxDaysPerWeekMaxDays[t]>=0 && teachersMaxDaysPerWeekMaxDays[t] > tn->maxDaysPerWeek)){
10583 teachersMaxDaysPerWeekMaxDays[t]=tn->maxDaysPerWeek;
10584 teachersMaxDaysPerWeekWeightPercentages[t]=tn->weightPercentage;
10585 }
10586 }
10587 /*else{
10588 ok=false;
10589
10590 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
10591 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
10592 ". Please modify your data correspondingly (leave maximum one constraint of type"
10593 " constraint teacher max days per week for each teacher) and try again")
10594 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
10595 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10596 1, 0 );
10597
10598 if(t==0)
10599 break;
10600 }*/
10601 }
10602 }
10603
10604 if(ok){
10605 for(int i=0; i<gt.rules.nInternalActivities; i++){
10606 teachersWithMaxDaysPerWeekForActivities[i].clear();
10607
10608 Activity* act=>.rules.internalActivitiesList[i];
10609 for(int j=0; j<act->iTeachersList.count(); j++){
10610 int tch=act->iTeachersList.at(j);
10611
10612 if(teachersMaxDaysPerWeekMaxDays[tch]>=0){
10613 assert(teachersWithMaxDaysPerWeekForActivities[i].indexOf(tch)==-1);
10614 teachersWithMaxDaysPerWeekForActivities[i].append(tch);
10615 }
10616 }
10617 }
10618 }
10619
10620 return ok;
10621 }
10622
computeMaxThreeConsecutiveDaysForTeachers(QWidget * parent)10623 bool computeMaxThreeConsecutiveDaysForTeachers(QWidget* parent)
10624 {
10625 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10626 teachersMaxThreeConsecutiveDaysAllowAMAMException[j]=true;
10627 teachersMaxThreeConsecutiveDaysPercentages[j]=-1;
10628 }
10629
10630 bool ok=true;
10631 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10632 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_THREE_CONSECUTIVE_DAYS){
10633 ConstraintTeacherMaxThreeConsecutiveDays* tn=(ConstraintTeacherMaxThreeConsecutiveDays*)gt.rules.internalTimeConstraintsList[i];
10634
10635 if(tn->weightPercentage!=100){
10636 ok=false;
10637
10638 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10639 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max three consecutive days with"
10640 " weight (percentage) below 100% for teacher %1. It is only possible to use 100% weight for such constraints."
10641 " Please make weight 100% and try again.")
10642 .arg(tn->teacherName),
10643 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10644 1, 0 );
10645
10646 if(t==0)
10647 return false;
10648 }
10649
10650 if(teachersMaxThreeConsecutiveDaysPercentages[tn->teacher_ID]==-1 ||
10651 (teachersMaxThreeConsecutiveDaysPercentages[tn->teacher_ID]>=0 &&
10652 teachersMaxThreeConsecutiveDaysAllowAMAMException[tn->teacher_ID]==true)){
10653 teachersMaxThreeConsecutiveDaysPercentages[tn->teacher_ID]=tn->weightPercentage;
10654 teachersMaxThreeConsecutiveDaysAllowAMAMException[tn->teacher_ID]=tn->allowAMAMException;
10655 }
10656 }
10657 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_THREE_CONSECUTIVE_DAYS){
10658 ConstraintTeachersMaxThreeConsecutiveDays* tn=(ConstraintTeachersMaxThreeConsecutiveDays*)gt.rules.internalTimeConstraintsList[i];
10659
10660 if(tn->weightPercentage!=100){
10661 ok=false;
10662
10663 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10664 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max three consecutive days with"
10665 " weight (percentage) below 100%. It is only possible to use 100% weight for such constraints. Please make weight 100% and try again."),
10666 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10667 1, 0 );
10668
10669 if(t==0)
10670 return false;
10671 }
10672
10673 for(int t=0; t<gt.rules.nInternalTeachers; t++){
10674 if(teachersMaxThreeConsecutiveDaysPercentages[t]==-1 ||
10675 (teachersMaxThreeConsecutiveDaysPercentages[t]>=0 &&
10676 teachersMaxThreeConsecutiveDaysAllowAMAMException[t]==true)){
10677 teachersMaxThreeConsecutiveDaysPercentages[t]=tn->weightPercentage;
10678 teachersMaxThreeConsecutiveDaysAllowAMAMException[t]=tn->allowAMAMException;
10679 }
10680 }
10681 }
10682 }
10683
10684 if(ok){
10685 for(int i=0; i<gt.rules.nInternalActivities; i++){
10686 teachersWithMaxThreeConsecutiveDaysForActivities[i].clear();
10687
10688 Activity* act=>.rules.internalActivitiesList[i];
10689 for(int j=0; j<act->iTeachersList.count(); j++){
10690 int tch=act->iTeachersList.at(j);
10691
10692 if(teachersMaxThreeConsecutiveDaysPercentages[tch]>=0){
10693 assert(teachersWithMaxThreeConsecutiveDaysForActivities[i].indexOf(tch)==-1);
10694 teachersWithMaxThreeConsecutiveDaysForActivities[i].append(tch);
10695 }
10696 }
10697 }
10698 }
10699
10700 return ok;
10701 }
10702
computeMaxDaysPerWeekForStudents(QWidget * parent)10703 bool computeMaxDaysPerWeekForStudents(QWidget* parent)
10704 {
10705 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
10706 subgroupsMaxDaysPerWeekMaxDays[j]=-1;
10707 subgroupsMaxDaysPerWeekWeightPercentages[j]=-1;
10708 }
10709
10710 bool ok=true;
10711 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10712 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_DAYS_PER_WEEK){
10713 ConstraintStudentsSetMaxDaysPerWeek* cn=(ConstraintStudentsSetMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
10714 if(cn->weightPercentage!=100){
10715 ok=false;
10716
10717 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10718 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max days per week with"
10719 " weight (percentage) below 100 for students set %1. It is only possible"
10720 " to use 100% weight for such constraints. Please make weight 100% and try again")
10721 .arg(cn->students),
10722 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10723 1, 0 );
10724
10725 if(t==0)
10726 return false;
10727 }
10728
10729 for(int sb : qAsConst(cn->iSubgroupsList)){
10730 if(subgroupsMaxDaysPerWeekMaxDays[sb]==-1 ||
10731 (subgroupsMaxDaysPerWeekMaxDays[sb]>=0 && subgroupsMaxDaysPerWeekMaxDays[sb] > cn->maxDaysPerWeek)){
10732 subgroupsMaxDaysPerWeekMaxDays[sb]=cn->maxDaysPerWeek;
10733 subgroupsMaxDaysPerWeekWeightPercentages[sb]=cn->weightPercentage;
10734 }
10735 }
10736 }
10737 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_DAYS_PER_WEEK){
10738 ConstraintStudentsMaxDaysPerWeek* cn=(ConstraintStudentsMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
10739
10740 if(cn->weightPercentage!=100){
10741 ok=false;
10742
10743 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10744 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max days per week with"
10745 " weight (percentage) below 100. Please make weight 100% and try again"),
10746 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10747 1, 0 );
10748
10749 if(t==0)
10750 return false;
10751 }
10752
10753 for(int s=0; s<gt.rules.nInternalSubgroups; s++){
10754 if(subgroupsMaxDaysPerWeekMaxDays[s]==-1 ||
10755 (subgroupsMaxDaysPerWeekMaxDays[s]>=0 && subgroupsMaxDaysPerWeekMaxDays[s] > cn->maxDaysPerWeek)){
10756 subgroupsMaxDaysPerWeekMaxDays[s]=cn->maxDaysPerWeek;
10757 subgroupsMaxDaysPerWeekWeightPercentages[s]=cn->weightPercentage;
10758 }
10759 }
10760 }
10761 }
10762
10763 if(ok){
10764 for(int i=0; i<gt.rules.nInternalActivities; i++){
10765 subgroupsWithMaxDaysPerWeekForActivities[i].clear();
10766
10767 Activity* act=>.rules.internalActivitiesList[i];
10768 for(int j=0; j<act->iSubgroupsList.count(); j++){
10769 int sb=act->iSubgroupsList.at(j);
10770
10771 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){
10772 assert(subgroupsWithMaxDaysPerWeekForActivities[i].indexOf(sb)==-1);
10773 subgroupsWithMaxDaysPerWeekForActivities[i].append(sb);
10774 }
10775 }
10776 }
10777 }
10778
10779 return ok;
10780 }
10781
computeMaxRealDaysPerWeekForTeachers(QWidget * parent)10782 bool computeMaxRealDaysPerWeekForTeachers(QWidget* parent)
10783 {
10784 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10785 teachersMaxRealDaysPerWeekMaxDays[j]=-1;
10786 teachersMaxRealDaysPerWeekWeightPercentages[j]=-1;
10787 }
10788
10789 bool ok=true;
10790 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10791 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_REAL_DAYS_PER_WEEK){
10792 ConstraintTeacherMaxRealDaysPerWeek* tn=(ConstraintTeacherMaxRealDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
10793
10794 if(tn->weightPercentage!=100){
10795 ok=false;
10796
10797 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10798 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max real days per week with"
10799 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.2.17 it is only possible"
10800 " to use 100% weight for such constraints. Please make weight 100% and try again")
10801 .arg(tn->teacherName),
10802 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10803 1, 0 );
10804
10805 if(t==0)
10806 return false;
10807 }
10808
10809 if(teachersMaxRealDaysPerWeekMaxDays[tn->teacher_ID]==-1 ||
10810 (teachersMaxRealDaysPerWeekMaxDays[tn->teacher_ID]>=0 && teachersMaxRealDaysPerWeekMaxDays[tn->teacher_ID] > tn->maxDaysPerWeek)){
10811 teachersMaxRealDaysPerWeekMaxDays[tn->teacher_ID]=tn->maxDaysPerWeek;
10812 teachersMaxRealDaysPerWeekWeightPercentages[tn->teacher_ID]=tn->weightPercentage;
10813 }
10814 /*else{
10815 ok=false;
10816
10817 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
10818 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
10819 ". Please modify your data correspondingly (leave maximum one constraint of type"
10820 " constraint teacher max days per week for each teacher) and try again")
10821 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
10822 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10823 1, 0 );
10824
10825 if(t==0)
10826 break;
10827 }*/
10828 }
10829 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_REAL_DAYS_PER_WEEK){
10830 ConstraintTeachersMaxRealDaysPerWeek* tn=(ConstraintTeachersMaxRealDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
10831
10832 if(tn->weightPercentage!=100){
10833 ok=false;
10834
10835 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10836 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max real days per week with"
10837 " weight (percentage) below 100. Please make weight 100% and try again"),
10838 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10839 1, 0 );
10840
10841 if(t==0)
10842 return false;
10843 }
10844
10845 for(int t=0; t<gt.rules.nInternalTeachers; t++){
10846 if(teachersMaxRealDaysPerWeekMaxDays[t]==-1 ||
10847 (teachersMaxRealDaysPerWeekMaxDays[t]>=0 && teachersMaxRealDaysPerWeekMaxDays[t] > tn->maxDaysPerWeek)){
10848 teachersMaxRealDaysPerWeekMaxDays[t]=tn->maxDaysPerWeek;
10849 teachersMaxRealDaysPerWeekWeightPercentages[t]=tn->weightPercentage;
10850 }
10851 }
10852 /*else{
10853 ok=false;
10854
10855 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
10856 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
10857 ". Please modify your data correspondingly (leave maximum one constraint of type"
10858 " constraint teacher max days per week for each teacher) and try again")
10859 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
10860 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10861 1, 0 );
10862
10863 if(t==0)
10864 break;
10865 }*/
10866 }
10867 }
10868
10869 if(ok){
10870 for(int i=0; i<gt.rules.nInternalActivities; i++){
10871 teachersWithMaxRealDaysPerWeekForActivities[i].clear();
10872
10873 Activity* act=>.rules.internalActivitiesList[i];
10874 for(int j=0; j<act->iTeachersList.count(); j++){
10875 int tch=act->iTeachersList.at(j);
10876
10877 if(teachersMaxRealDaysPerWeekMaxDays[tch]>=0){
10878 assert(teachersWithMaxRealDaysPerWeekForActivities[i].indexOf(tch)==-1);
10879 teachersWithMaxRealDaysPerWeekForActivities[i].append(tch);
10880 }
10881 }
10882 }
10883 }
10884
10885 return ok;
10886 }
10887
computeMaxAfternoonsPerWeekForTeachers(QWidget * parent)10888 bool computeMaxAfternoonsPerWeekForTeachers(QWidget* parent)
10889 {
10890 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10891 teachersMaxAfternoonsPerWeekMaxAfternoons[j]=-1;
10892 teachersMaxAfternoonsPerWeekWeightPercentages[j]=-1;
10893 }
10894
10895 bool ok=true;
10896 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
10897 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_AFTERNOONS_PER_WEEK){
10898 ConstraintTeacherMaxAfternoonsPerWeek* tn=(ConstraintTeacherMaxAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
10899
10900 if(tn->weightPercentage!=100){
10901 ok=false;
10902
10903 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10904 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max afternoons per week with"
10905 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.2.17 it is only possible"
10906 " to use 100% weight for such constraints. Please make weight 100% and try again")
10907 .arg(tn->teacherName),
10908 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10909 1, 0 );
10910
10911 if(t==0)
10912 return false;
10913 }
10914
10915 if(teachersMaxAfternoonsPerWeekMaxAfternoons[tn->teacher_ID]==-1 ||
10916 (teachersMaxAfternoonsPerWeekMaxAfternoons[tn->teacher_ID]>=0 && teachersMaxAfternoonsPerWeekMaxAfternoons[tn->teacher_ID] > tn->maxAfternoonsPerWeek)){
10917 teachersMaxAfternoonsPerWeekMaxAfternoons[tn->teacher_ID]=tn->maxAfternoonsPerWeek;
10918 teachersMaxAfternoonsPerWeekWeightPercentages[tn->teacher_ID]=tn->weightPercentage;
10919 }
10920 /*else{
10921 ok=false;
10922
10923 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
10924 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
10925 ". Please modify your data correspondingly (leave maximum one constraint of type"
10926 " constraint teacher max days per week for each teacher) and try again")
10927 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
10928 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10929 1, 0 );
10930
10931 if(t==0)
10932 break;
10933 }*/
10934 }
10935 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_AFTERNOONS_PER_WEEK){
10936 ConstraintTeachersMaxAfternoonsPerWeek* tn=(ConstraintTeachersMaxAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
10937
10938 if(tn->weightPercentage!=100){
10939 ok=false;
10940
10941 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
10942 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max afternoons per week with"
10943 " weight (percentage) below 100. Please make weight 100% and try again"),
10944 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10945 1, 0 );
10946
10947 if(t==0)
10948 return false;
10949 }
10950
10951 for(int t=0; t<gt.rules.nInternalTeachers; t++){
10952 if(teachersMaxAfternoonsPerWeekMaxAfternoons[t]==-1 ||
10953 (teachersMaxAfternoonsPerWeekMaxAfternoons[t]>=0 && teachersMaxAfternoonsPerWeekMaxAfternoons[t] > tn->maxAfternoonsPerWeek)){
10954 teachersMaxAfternoonsPerWeekMaxAfternoons[t]=tn->maxAfternoonsPerWeek;
10955 teachersMaxAfternoonsPerWeekWeightPercentages[t]=tn->weightPercentage;
10956 }
10957 }
10958 /*else{
10959 ok=false;
10960
10961 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
10962 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
10963 ". Please modify your data correspondingly (leave maximum one constraint of type"
10964 " constraint teacher max days per week for each teacher) and try again")
10965 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
10966 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
10967 1, 0 );
10968
10969 if(t==0)
10970 break;
10971 }*/
10972 }
10973 }
10974
10975 if(ok){
10976 for(int i=0; i<gt.rules.nInternalActivities; i++){
10977 teachersWithMaxAfternoonsPerWeekForActivities[i].clear();
10978
10979 Activity* act=>.rules.internalActivitiesList[i];
10980 for(int j=0; j<act->iTeachersList.count(); j++){
10981 int tch=act->iTeachersList.at(j);
10982
10983 if(teachersMaxAfternoonsPerWeekMaxAfternoons[tch]>=0){
10984 assert(teachersWithMaxAfternoonsPerWeekForActivities[i].indexOf(tch)==-1);
10985 teachersWithMaxAfternoonsPerWeekForActivities[i].append(tch);
10986 }
10987 }
10988 }
10989 }
10990
10991 return ok;
10992 }
10993
computeMaxMorningsPerWeekForTeachers(QWidget * parent)10994 bool computeMaxMorningsPerWeekForTeachers(QWidget* parent)
10995 {
10996 for(int j=0; j<gt.rules.nInternalTeachers; j++){
10997 teachersMaxMorningsPerWeekMaxMornings[j]=-1;
10998 teachersMaxMorningsPerWeekWeightPercentages[j]=-1;
10999 }
11000
11001 bool ok=true;
11002 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11003 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_MORNINGS_PER_WEEK){
11004 ConstraintTeacherMaxMorningsPerWeek* tn=(ConstraintTeacherMaxMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
11005
11006 if(tn->weightPercentage!=100){
11007 ok=false;
11008
11009 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11010 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher max mornings per week with"
11011 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.2.17 it is only possible"
11012 " to use 100% weight for such constraints. Please make weight 100% and try again")
11013 .arg(tn->teacherName),
11014 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11015 1, 0 );
11016
11017 if(t==0)
11018 return false;
11019 }
11020
11021 if(teachersMaxMorningsPerWeekMaxMornings[tn->teacher_ID]==-1 ||
11022 (teachersMaxMorningsPerWeekMaxMornings[tn->teacher_ID]>=0 && teachersMaxMorningsPerWeekMaxMornings[tn->teacher_ID] > tn->maxMorningsPerWeek)){
11023 teachersMaxMorningsPerWeekMaxMornings[tn->teacher_ID]=tn->maxMorningsPerWeek;
11024 teachersMaxMorningsPerWeekWeightPercentages[tn->teacher_ID]=tn->weightPercentage;
11025 }
11026 /*else{
11027 ok=false;
11028
11029 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
11030 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
11031 ". Please modify your data correspondingly (leave maximum one constraint of type"
11032 " constraint teacher max days per week for each teacher) and try again")
11033 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
11034 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11035 1, 0 );
11036
11037 if(t==0)
11038 break;
11039 }*/
11040 }
11041 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_MORNINGS_PER_WEEK){
11042 ConstraintTeachersMaxMorningsPerWeek* tn=(ConstraintTeachersMaxMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
11043
11044 if(tn->weightPercentage!=100){
11045 ok=false;
11046
11047 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11048 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers max mornings per week with"
11049 " weight (percentage) below 100. Please make weight 100% and try again"),
11050 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11051 1, 0 );
11052
11053 if(t==0)
11054 return false;
11055 }
11056
11057 for(int t=0; t<gt.rules.nInternalTeachers; t++){
11058 if(teachersMaxMorningsPerWeekMaxMornings[t]==-1 ||
11059 (teachersMaxMorningsPerWeekMaxMornings[t]>=0 && teachersMaxMorningsPerWeekMaxMornings[t] > tn->maxMorningsPerWeek)){
11060 teachersMaxMorningsPerWeekMaxMornings[t]=tn->maxMorningsPerWeek;
11061 teachersMaxMorningsPerWeekWeightPercentages[t]=tn->weightPercentage;
11062 }
11063 }
11064 /*else{
11065 ok=false;
11066
11067 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
11068 GeneratePreTranslate::tr("Cannot optimize for teacher %1, because it has at least two constraints max days per week"
11069 ". Please modify your data correspondingly (leave maximum one constraint of type"
11070 " constraint teacher max days per week for each teacher) and try again")
11071 .arg(gt.rules.internalTeachersList[tn->teacher_ID]->name),
11072 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11073 1, 0 );
11074
11075 if(t==0)
11076 break;
11077 }*/
11078 }
11079 }
11080
11081 if(ok){
11082 for(int i=0; i<gt.rules.nInternalActivities; i++){
11083 teachersWithMaxMorningsPerWeekForActivities[i].clear();
11084
11085 Activity* act=>.rules.internalActivitiesList[i];
11086 for(int j=0; j<act->iTeachersList.count(); j++){
11087 int tch=act->iTeachersList.at(j);
11088
11089 if(teachersMaxMorningsPerWeekMaxMornings[tch]>=0){
11090 assert(teachersWithMaxMorningsPerWeekForActivities[i].indexOf(tch)==-1);
11091 teachersWithMaxMorningsPerWeekForActivities[i].append(tch);
11092 }
11093 }
11094 }
11095 }
11096
11097 return ok;
11098 }
11099
computeMaxRealDaysPerWeekForStudents(QWidget * parent)11100 bool computeMaxRealDaysPerWeekForStudents(QWidget* parent)
11101 {
11102 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
11103 subgroupsMaxRealDaysPerWeekMaxDays[j]=-1;
11104 subgroupsMaxRealDaysPerWeekWeightPercentages[j]=-1;
11105 }
11106
11107 bool ok=true;
11108 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11109 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_REAL_DAYS_PER_WEEK){
11110 ConstraintStudentsSetMaxRealDaysPerWeek* cn=(ConstraintStudentsSetMaxRealDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
11111 if(cn->weightPercentage!=100){
11112 ok=false;
11113
11114 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11115 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max real days per week with"
11116 " weight (percentage) below 100 for students set %1. It is only possible"
11117 " to use 100% weight for such constraints. Please make weight 100% and try again")
11118 .arg(cn->students),
11119 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11120 1, 0 );
11121
11122 if(t==0)
11123 return false;
11124 }
11125
11126 for(int sb : qAsConst(cn->iSubgroupsList)){
11127 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]==-1 ||
11128 (subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0 && subgroupsMaxRealDaysPerWeekMaxDays[sb] > cn->maxDaysPerWeek)){
11129 subgroupsMaxRealDaysPerWeekMaxDays[sb]=cn->maxDaysPerWeek;
11130 subgroupsMaxRealDaysPerWeekWeightPercentages[sb]=cn->weightPercentage;
11131 }
11132 }
11133 }
11134 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_REAL_DAYS_PER_WEEK){
11135 ConstraintStudentsMaxRealDaysPerWeek* cn=(ConstraintStudentsMaxRealDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
11136
11137 if(cn->weightPercentage!=100){
11138 ok=false;
11139
11140 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11141 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max real days per week with"
11142 " weight (percentage) below 100. Please make weight 100% and try again"),
11143 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11144 1, 0 );
11145
11146 if(t==0)
11147 return false;
11148 }
11149
11150 for(int s=0; s<gt.rules.nInternalSubgroups; s++){
11151 if(subgroupsMaxRealDaysPerWeekMaxDays[s]==-1 ||
11152 (subgroupsMaxRealDaysPerWeekMaxDays[s]>=0 && subgroupsMaxRealDaysPerWeekMaxDays[s] > cn->maxDaysPerWeek)){
11153 subgroupsMaxRealDaysPerWeekMaxDays[s]=cn->maxDaysPerWeek;
11154 subgroupsMaxRealDaysPerWeekWeightPercentages[s]=cn->weightPercentage;
11155 }
11156 }
11157 }
11158 }
11159
11160 if(ok){
11161 for(int i=0; i<gt.rules.nInternalActivities; i++){
11162 subgroupsWithMaxRealDaysPerWeekForActivities[i].clear();
11163
11164 Activity* act=>.rules.internalActivitiesList[i];
11165 for(int j=0; j<act->iSubgroupsList.count(); j++){
11166 int sb=act->iSubgroupsList.at(j);
11167
11168 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0){
11169 assert(subgroupsWithMaxRealDaysPerWeekForActivities[i].indexOf(sb)==-1);
11170 subgroupsWithMaxRealDaysPerWeekForActivities[i].append(sb);
11171 }
11172 }
11173 }
11174 }
11175
11176 return ok;
11177 }
11178
11179 //2020-06-25
computeMaxAfternoonsPerWeekForStudents(QWidget * parent)11180 bool computeMaxAfternoonsPerWeekForStudents(QWidget* parent)
11181 {
11182 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
11183 subgroupsMaxAfternoonsPerWeekMaxAfternoons[j]=-1;
11184 subgroupsMaxAfternoonsPerWeekWeightPercentages[j]=-1;
11185 }
11186
11187 bool ok=true;
11188 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11189 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_AFTERNOONS_PER_WEEK){
11190 ConstraintStudentsSetMaxAfternoonsPerWeek* tn=(ConstraintStudentsSetMaxAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
11191
11192 if(tn->weightPercentage!=100){
11193 ok=false;
11194
11195 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11196 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max afternoons per week with"
11197 " weight (percentage) below 100 for students set %1. Please make weight 100% and try again")
11198 .arg(tn->students),
11199 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11200 1, 0 );
11201
11202 if(t==0)
11203 return false;
11204 }
11205
11206 for(int sbg : tn->iSubgroupsList)
11207 if(subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]==-1 ||
11208 (subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]>=0 && subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg] > tn->maxAfternoonsPerWeek)){
11209 subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]=tn->maxAfternoonsPerWeek;
11210 subgroupsMaxAfternoonsPerWeekWeightPercentages[sbg]=tn->weightPercentage;
11211 }
11212 }
11213 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_AFTERNOONS_PER_WEEK){
11214 ConstraintStudentsMaxAfternoonsPerWeek* tn=(ConstraintStudentsMaxAfternoonsPerWeek*)gt.rules.internalTimeConstraintsList[i];
11215
11216 if(tn->weightPercentage!=100){
11217 ok=false;
11218
11219 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11220 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max afternoons per week with"
11221 " weight (percentage) below 100. Please make weight 100% and try again"),
11222 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11223 1, 0 );
11224
11225 if(t==0)
11226 return false;
11227 }
11228
11229 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
11230 if(subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]==-1 ||
11231 (subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]>=0 && subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg] > tn->maxAfternoonsPerWeek)){
11232 subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]=tn->maxAfternoonsPerWeek;
11233 subgroupsMaxAfternoonsPerWeekWeightPercentages[sbg]=tn->weightPercentage;
11234 }
11235 }
11236 }
11237 }
11238
11239 if(ok){
11240 for(int i=0; i<gt.rules.nInternalActivities; i++){
11241 subgroupsWithMaxAfternoonsPerWeekForActivities[i].clear();
11242
11243 Activity* act=>.rules.internalActivitiesList[i];
11244 for(int j=0; j<act->iSubgroupsList.count(); j++){
11245 int sbg=act->iSubgroupsList.at(j);
11246
11247 if(subgroupsMaxAfternoonsPerWeekMaxAfternoons[sbg]>=0){
11248 assert(subgroupsWithMaxAfternoonsPerWeekForActivities[i].indexOf(sbg)==-1);
11249 subgroupsWithMaxAfternoonsPerWeekForActivities[i].append(sbg);
11250 }
11251 }
11252 }
11253 }
11254
11255 return ok;
11256 }
11257
computeMaxMorningsPerWeekForStudents(QWidget * parent)11258 bool computeMaxMorningsPerWeekForStudents(QWidget* parent)
11259 {
11260 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
11261 subgroupsMaxMorningsPerWeekMaxMornings[j]=-1;
11262 subgroupsMaxMorningsPerWeekWeightPercentages[j]=-1;
11263 }
11264
11265 bool ok=true;
11266 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11267 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_MORNINGS_PER_WEEK){
11268 ConstraintStudentsSetMaxMorningsPerWeek* tn=(ConstraintStudentsSetMaxMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
11269
11270 if(tn->weightPercentage!=100){
11271 ok=false;
11272
11273 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11274 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set max mornings per week with"
11275 " weight (percentage) below 100 for students set %1. Please make weight 100% and try again")
11276 .arg(tn->students),
11277 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11278 1, 0 );
11279
11280 if(t==0)
11281 return false;
11282 }
11283
11284 for(int sbg : tn->iSubgroupsList)
11285 if(subgroupsMaxMorningsPerWeekMaxMornings[sbg]==-1 ||
11286 (subgroupsMaxMorningsPerWeekMaxMornings[sbg]>=0 && subgroupsMaxMorningsPerWeekMaxMornings[sbg] > tn->maxMorningsPerWeek)){
11287 subgroupsMaxMorningsPerWeekMaxMornings[sbg]=tn->maxMorningsPerWeek;
11288 subgroupsMaxMorningsPerWeekWeightPercentages[sbg]=tn->weightPercentage;
11289 }
11290 }
11291 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_MORNINGS_PER_WEEK){
11292 ConstraintStudentsMaxMorningsPerWeek* tn=(ConstraintStudentsMaxMorningsPerWeek*)gt.rules.internalTimeConstraintsList[i];
11293
11294 if(tn->weightPercentage!=100){
11295 ok=false;
11296
11297 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11298 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students max mornings per week with"
11299 " weight (percentage) below 100. Please make weight 100% and try again"),
11300 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11301 1, 0 );
11302
11303 if(t==0)
11304 return false;
11305 }
11306
11307 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
11308 if(subgroupsMaxMorningsPerWeekMaxMornings[sbg]==-1 ||
11309 (subgroupsMaxMorningsPerWeekMaxMornings[sbg]>=0 && subgroupsMaxMorningsPerWeekMaxMornings[sbg] > tn->maxMorningsPerWeek)){
11310 subgroupsMaxMorningsPerWeekMaxMornings[sbg]=tn->maxMorningsPerWeek;
11311 subgroupsMaxMorningsPerWeekWeightPercentages[sbg]=tn->weightPercentage;
11312 }
11313 }
11314 }
11315 }
11316
11317 if(ok){
11318 for(int i=0; i<gt.rules.nInternalActivities; i++){
11319 subgroupsWithMaxMorningsPerWeekForActivities[i].clear();
11320
11321 Activity* act=>.rules.internalActivitiesList[i];
11322 for(int j=0; j<act->iSubgroupsList.count(); j++){
11323 int sbg=act->iSubgroupsList.at(j);
11324
11325 if(subgroupsMaxMorningsPerWeekMaxMornings[sbg]>=0){
11326 assert(subgroupsWithMaxMorningsPerWeekForActivities[i].indexOf(sbg)==-1);
11327 subgroupsWithMaxMorningsPerWeekForActivities[i].append(sbg);
11328 }
11329 }
11330 }
11331 }
11332
11333 return ok;
11334 }
11335
computeSubgroupsEarlyAndMaxGapsPercentages(QWidget * parent)11336 bool computeSubgroupsEarlyAndMaxGapsPercentages(QWidget* parent) //st max gaps & early - part 2
11337 {
11338 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11339 subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]=-1;
11340 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]=-1;
11341 subgroupsMaxGapsPerWeekPercentage[i]=-1;
11342 subgroupsMaxGapsPerWeekMaxGaps[i]=-1;
11343 }
11344
11345 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11346 //students early
11347 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
11348 ConstraintStudentsEarlyMaxBeginningsAtSecondHour* se=(ConstraintStudentsEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
11349 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
11350 if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
11351 subgroupsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
11352 if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
11353 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
11354 }
11355 }
11356
11357 //students set early
11358 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_EARLY_MAX_BEGINNINGS_AT_SECOND_HOUR){
11359 ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour* se=(ConstraintStudentsSetEarlyMaxBeginningsAtSecondHour*) gt.rules.internalTimeConstraintsList[i];
11360 for(int q=0; q<se->iSubgroupsList.count(); q++){
11361 int j=se->iSubgroupsList.at(q);
11362 if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[j] < se->weightPercentage)
11363 subgroupsEarlyMaxBeginningsAtSecondHourPercentage[j] = se->weightPercentage;
11364 if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j]==-1 || subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] > se->maxBeginningsAtSecondHour)
11365 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[j] = se->maxBeginningsAtSecondHour;
11366 }
11367 }
11368
11369 //students max gaps
11370 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_GAPS_PER_WEEK){
11371 ConstraintStudentsMaxGapsPerWeek* sg=(ConstraintStudentsMaxGapsPerWeek*) gt.rules.internalTimeConstraintsList[i];
11372 for(int j=0; j<gt.rules.nInternalSubgroups; j++){ //weight is 100% for all of them
11373 if(subgroupsMaxGapsPerWeekPercentage[j] < sg->weightPercentage)
11374 subgroupsMaxGapsPerWeekPercentage[j] = sg->weightPercentage;
11375 if(subgroupsMaxGapsPerWeekMaxGaps[j]==-1 || subgroupsMaxGapsPerWeekMaxGaps[j] > sg->maxGaps){
11376 subgroupsMaxGapsPerWeekMaxGaps[j] = sg->maxGaps;
11377 }
11378 }
11379 }
11380
11381 //students set max gaps
11382 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_WEEK){
11383 ConstraintStudentsSetMaxGapsPerWeek* sg=(ConstraintStudentsSetMaxGapsPerWeek*) gt.rules.internalTimeConstraintsList[i];
11384 for(int j=0; j<sg->iSubgroupsList.count(); j++){
11385 int s=sg->iSubgroupsList.at(j);
11386
11387 if(subgroupsMaxGapsPerWeekPercentage[s] < sg->weightPercentage)
11388 subgroupsMaxGapsPerWeekPercentage[s] = sg->weightPercentage;
11389 if(subgroupsMaxGapsPerWeekMaxGaps[s]==-1 || subgroupsMaxGapsPerWeekMaxGaps[s] > sg->maxGaps){
11390 subgroupsMaxGapsPerWeekMaxGaps[s] = sg->maxGaps;
11391 }
11392 }
11393 }
11394 }
11395
11396 bool ok=true;
11397 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11398 assert((subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 &&
11399 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]==-1) ||
11400 (subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 &&
11401 subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0));
11402
11403 assert((subgroupsMaxGapsPerWeekPercentage[i]==-1 &&
11404 subgroupsMaxGapsPerWeekMaxGaps[i]==-1) ||
11405 (subgroupsMaxGapsPerWeekPercentage[i]>=0 &&
11406 subgroupsMaxGapsPerWeekMaxGaps[i]>=0));
11407
11408 bool oksubgroup=true;
11409 /*if(subgroupsNoGapsPercentage[i]== -1 && subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 ||
11410 subgroupsNoGapsPercentage[i]>=0 && subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]==-1 ||
11411 subgroupsNoGapsPercentage[i]>=0 && subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0
11412 && subgroupsNoGapsPercentage[i]==subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i])
11413 oksubgroup=true;
11414 else
11415 oksubgroup=false;*/
11416
11417 if(subgroupsMaxGapsPerWeekPercentage[i]>=0 && subgroupsMaxGapsPerWeekPercentage[i]!=100){
11418 oksubgroup=false;
11419 ok=false;
11420
11421 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11422 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because you have a max gaps constraint"
11423 " with weight percentage less than 100%. Currently, the algorithm can only"
11424 " optimize with not existing constraint max gaps or existing with 100% weight for it"
11425 ". Please modify your data correspondingly and try again")
11426 .arg(gt.rules.internalSubgroupsList[i]->name),
11427 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11428 1, 0 );
11429
11430 if(t==0)
11431 break;
11432 }
11433 if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0 && subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]!=100){
11434 oksubgroup=false;
11435 ok=false;
11436
11437 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11438 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because you have an early max beginnings at second hour constraint"
11439 " with weight percentage less than 100%. Currently, the algorithm can only"
11440 " optimize with not existing constraint early m.b.a.s.h. or existing with 100% weight for it"
11441 ". Please modify your data correspondingly and try again")
11442 .arg(gt.rules.internalSubgroupsList[i]->name),
11443 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11444 1, 0 );
11445
11446 if(t==0)
11447 break;
11448 }
11449 /*if(subgroupsNoGapsPercentage[i]== -1 && subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0){
11450 oksubgroup=false;
11451 ok=false;
11452
11453 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
11454 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because a students early max beginnings at second hour constraint"
11455 " exists for this subgroup, and you have not 'max gaps' requirements for this subgroup. "
11456 "The algorithm can 1. optimize with 'early' and 'max gaps'"
11457 " having the same weight percentage or 2. only 'max gaps' optimization"
11458 " without 'early'. Please modify your data correspondingly and try again")
11459 .arg(gt.rules.internalSubgroupsList[i]->name),
11460 GeneratePreTranslate::tr("Skip rest of early - max gaps problems"), GeneratePreTranslate::tr("See next incompatibility max gaps - early"), QString(),
11461 1, 0 );
11462
11463 if(t==0)
11464 break;
11465 }
11466 if(subgroupsNoGapsPercentage[i]>=0 && subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]>=0
11467 && subgroupsNoGapsPercentage[i]!=subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]){
11468 oksubgroup=false;
11469 ok=false;
11470
11471 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
11472 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because early max beginnings at second hour constraint"
11473 " has weight percentage %2, and 'max gaps' constraint has weight percentage %3."
11474 ". The algorithm can:"
11475 "\n1: Optimize with 'early' and 'max gaps' having the same weight percentage or"
11476 "\n2. Only 'max gaps' optimization without 'early'."
11477 "\nPlease modify your data correspondingly and try again")
11478 .arg(gt.rules.internalSubgroupsList[i]->name)
11479 .arg(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[i]).
11480 arg(subgroupsNoGapsPercentage[i]),
11481 GeneratePreTranslate::tr("Skip rest of early - max gaps problems"), GeneratePreTranslate::tr("See next incompatibility max gaps - early"), QString(),
11482 1, 0 );
11483
11484 if(t==0)
11485 break;
11486 }*/
11487
11488 if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>=0
11489 && subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]>gt.rules.nDaysPerWeek){
11490 oksubgroup=false;
11491 ok=false;
11492
11493 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11494 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because early max beginnings at second hour constraint"
11495 " has max beginnings at second hour %2, and the number of days per week is %3, which is less. It must be that the number of"
11496 " days per week must be greater or equal with the max beginnings at second hour\n"
11497 "Please modify your data correspondingly and try again")
11498 .arg(gt.rules.internalSubgroupsList[i]->name)
11499 .arg(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[i]).
11500 arg(gt.rules.nDaysPerWeek),
11501 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11502 1, 0 );
11503
11504 if(t==0)
11505 break;
11506 }
11507
11508 if(!oksubgroup)
11509 ok=false;
11510 }
11511
11512 return ok;
11513 }
11514
computeSubgroupsMaxGapsPerDayPercentages(QWidget * parent)11515 bool computeSubgroupsMaxGapsPerDayPercentages(QWidget* parent)
11516 {
11517 haveStudentsMaxGapsPerDay=false;
11518
11519 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11520 subgroupsMaxGapsPerDayPercentage[i]=-1;
11521 subgroupsMaxGapsPerDayMaxGaps[i]=-1;
11522 }
11523
11524 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11525 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_GAPS_PER_DAY){
11526 haveStudentsMaxGapsPerDay=true;
11527 ConstraintStudentsMaxGapsPerDay* sg=(ConstraintStudentsMaxGapsPerDay*) gt.rules.internalTimeConstraintsList[i];
11528 for(int j=0; j<gt.rules.nInternalSubgroups; j++){ //weight is 100% for all of them
11529 if(subgroupsMaxGapsPerDayPercentage[j] < sg->weightPercentage)
11530 subgroupsMaxGapsPerDayPercentage[j] = sg->weightPercentage;
11531 if(subgroupsMaxGapsPerDayMaxGaps[j]==-1 || subgroupsMaxGapsPerDayMaxGaps[j] > sg->maxGaps){
11532 subgroupsMaxGapsPerDayMaxGaps[j] = sg->maxGaps;
11533 }
11534 }
11535 }
11536
11537 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_DAY){
11538 haveStudentsMaxGapsPerDay=true;
11539 ConstraintStudentsSetMaxGapsPerDay* sg=(ConstraintStudentsSetMaxGapsPerDay*) gt.rules.internalTimeConstraintsList[i];
11540 for(int j=0; j<sg->iSubgroupsList.count(); j++){
11541 int s=sg->iSubgroupsList.at(j);
11542
11543 if(subgroupsMaxGapsPerDayPercentage[s] < sg->weightPercentage)
11544 subgroupsMaxGapsPerDayPercentage[s] = sg->weightPercentage;
11545 if(subgroupsMaxGapsPerDayMaxGaps[s]==-1 || subgroupsMaxGapsPerDayMaxGaps[s] > sg->maxGaps){
11546 subgroupsMaxGapsPerDayMaxGaps[s] = sg->maxGaps;
11547 }
11548 }
11549 }
11550 }
11551
11552 bool ok=true;
11553 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11554 assert((subgroupsMaxGapsPerDayPercentage[i]==-1 &&
11555 subgroupsMaxGapsPerDayMaxGaps[i]==-1) ||
11556 (subgroupsMaxGapsPerDayPercentage[i]>=0 &&
11557 subgroupsMaxGapsPerDayMaxGaps[i]>=0));
11558
11559 bool oksubgroup=true;
11560
11561 if(subgroupsMaxGapsPerDayPercentage[i]>=0 && subgroupsMaxGapsPerDayPercentage[i]!=100){
11562 oksubgroup=false;
11563 ok=false;
11564
11565 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11566 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because you have a max gaps constraint"
11567 " with weight percentage less than 100%. Currently, the algorithm can only"
11568 " optimize with not existing constraint max gaps or existing with 100% weight for it"
11569 ". Please modify your data correspondingly and try again")
11570 .arg(gt.rules.internalSubgroupsList[i]->name),
11571 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11572 1, 0 );
11573
11574 if(t==0)
11575 break;
11576 }
11577
11578 if(!oksubgroup)
11579 ok=false;
11580 }
11581
11582 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11583 if(subgroupsMaxGapsPerDayMaxGaps[i]>=0){
11584 int mgw=gt.rules.nDaysPerWeek*subgroupsMaxGapsPerDayMaxGaps[i];
11585 assert(mgw>=0);
11586 if(subgroupsMaxGapsPerWeekMaxGaps[i]==-1 || (subgroupsMaxGapsPerWeekMaxGaps[i]>=0 && subgroupsMaxGapsPerWeekMaxGaps[i]>mgw)){
11587 subgroupsMaxGapsPerWeekMaxGaps[i]=mgw;
11588 subgroupsMaxGapsPerWeekPercentage[i]=100.0;
11589 }
11590 }
11591 }
11592
11593 return ok;
11594 }
11595
computeSubgroupsMaxGapsPerRealDayPercentages(QWidget * parent)11596 bool computeSubgroupsMaxGapsPerRealDayPercentages(QWidget* parent)
11597 {
11598 haveStudentsMaxGapsPerRealDay=false;
11599
11600 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11601 subgroupsMaxGapsPerRealDayPercentage[i]=-1;
11602 subgroupsMaxGapsPerRealDayMaxGaps[i]=-1;
11603
11604 subgroupsMaxGapsPerWeekForRealDaysPercentage[i]=-1;
11605 subgroupsMaxGapsPerWeekForRealDaysMaxGaps[i]=-1;
11606 }
11607
11608 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11609 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_GAPS_PER_REAL_DAY){
11610 haveStudentsMaxGapsPerRealDay=true;
11611 ConstraintStudentsMaxGapsPerRealDay* sg=(ConstraintStudentsMaxGapsPerRealDay*) gt.rules.internalTimeConstraintsList[i];
11612 for(int j=0; j<gt.rules.nInternalSubgroups; j++){ //weight is 100% for all of them
11613 if(subgroupsMaxGapsPerRealDayPercentage[j] < sg->weightPercentage)
11614 subgroupsMaxGapsPerRealDayPercentage[j] = sg->weightPercentage;
11615 if(subgroupsMaxGapsPerRealDayMaxGaps[j]==-1 || subgroupsMaxGapsPerRealDayMaxGaps[j] > sg->maxGaps){
11616 subgroupsMaxGapsPerRealDayMaxGaps[j] = sg->maxGaps;
11617 }
11618 }
11619 }
11620
11621 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_REAL_DAY){
11622 haveStudentsMaxGapsPerRealDay=true;
11623 ConstraintStudentsSetMaxGapsPerRealDay* sg=(ConstraintStudentsSetMaxGapsPerRealDay*) gt.rules.internalTimeConstraintsList[i];
11624 for(int j=0; j<sg->iSubgroupsList.count(); j++){
11625 int s=sg->iSubgroupsList.at(j);
11626
11627 if(subgroupsMaxGapsPerRealDayPercentage[s] < sg->weightPercentage)
11628 subgroupsMaxGapsPerRealDayPercentage[s] = sg->weightPercentage;
11629 if(subgroupsMaxGapsPerRealDayMaxGaps[s]==-1 || subgroupsMaxGapsPerRealDayMaxGaps[s] > sg->maxGaps){
11630 subgroupsMaxGapsPerRealDayMaxGaps[s] = sg->maxGaps;
11631 }
11632 }
11633 }
11634
11635 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_GAPS_PER_WEEK_FOR_REAL_DAYS){
11636 haveStudentsMaxGapsPerRealDay=true;
11637 ConstraintStudentsMaxGapsPerWeekForRealDays* sg=(ConstraintStudentsMaxGapsPerWeekForRealDays*) gt.rules.internalTimeConstraintsList[i];
11638 for(int j=0; j<gt.rules.nInternalSubgroups; j++){ //weight is 100% for all of them
11639 if(subgroupsMaxGapsPerWeekForRealDaysPercentage[j] < sg->weightPercentage)
11640 subgroupsMaxGapsPerWeekForRealDaysPercentage[j] = sg->weightPercentage;
11641 if(subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j]==-1 || subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j] > sg->maxGaps){
11642 subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j] = sg->maxGaps;
11643 }
11644 }
11645 }
11646
11647 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_GAPS_PER_WEEK_FOR_REAL_DAYS){
11648 haveStudentsMaxGapsPerRealDay=true;
11649 ConstraintStudentsSetMaxGapsPerWeekForRealDays* sg=(ConstraintStudentsSetMaxGapsPerWeekForRealDays*) gt.rules.internalTimeConstraintsList[i];
11650 for(int j=0; j<sg->iSubgroupsList.count(); j++){
11651 int s=sg->iSubgroupsList.at(j);
11652
11653 if(subgroupsMaxGapsPerWeekForRealDaysPercentage[s] < sg->weightPercentage)
11654 subgroupsMaxGapsPerWeekForRealDaysPercentage[s] = sg->weightPercentage;
11655 if(subgroupsMaxGapsPerWeekForRealDaysMaxGaps[s]==-1 || subgroupsMaxGapsPerWeekForRealDaysMaxGaps[s] > sg->maxGaps){
11656 subgroupsMaxGapsPerWeekForRealDaysMaxGaps[s] = sg->maxGaps;
11657 }
11658 }
11659 }
11660 }
11661
11662 bool ok=true;
11663 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
11664 assert((subgroupsMaxGapsPerRealDayPercentage[i]==-1 && subgroupsMaxGapsPerRealDayMaxGaps[i]==-1) ||
11665 (subgroupsMaxGapsPerRealDayPercentage[i]>=0 && subgroupsMaxGapsPerRealDayMaxGaps[i]>=0));
11666
11667 assert((subgroupsMaxGapsPerWeekForRealDaysPercentage[i]==-1 && subgroupsMaxGapsPerWeekForRealDaysMaxGaps[i]==-1) ||
11668 (subgroupsMaxGapsPerWeekForRealDaysPercentage[i]>=0 && subgroupsMaxGapsPerWeekForRealDaysMaxGaps[i]>=0));
11669
11670 bool oksubgroup=true;
11671
11672 if((subgroupsMaxGapsPerRealDayPercentage[i]>=0 && subgroupsMaxGapsPerRealDayPercentage[i]!=100) ||
11673 (subgroupsMaxGapsPerWeekForRealDaysPercentage[i]>=0 && subgroupsMaxGapsPerWeekForRealDaysPercentage[i]!=100)){
11674 oksubgroup=false;
11675 ok=false;
11676
11677 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11678 GeneratePreTranslate::tr("Cannot optimize for subgroup %1, because you have a max gaps constraint"
11679 " with weight percentage less than 100%. Currently, the algorithm can only"
11680 " optimize with not existing constraint max gaps or existing with 100% weight for it"
11681 ". Please modify your data correspondingly and try again")
11682 .arg(gt.rules.internalSubgroupsList[i]->name),
11683 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11684 1, 0 );
11685
11686 if(t==0)
11687 break;
11688 }
11689
11690 if(!oksubgroup)
11691 ok=false;
11692 }
11693
11694 for(int j=0; j<gt.rules.nInternalSubgroups; j++){
11695 if(subgroupsMaxGapsPerRealDayMaxGaps[j]==0 || subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j]==0){
11696 subgroupsMaxGapsPerRealDayMaxGaps[j]=0;
11697 subgroupsMaxGapsPerRealDayPercentage[j]=100.0;
11698
11699 subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j]=0;
11700 subgroupsMaxGapsPerWeekForRealDaysPercentage[j]=100.0;
11701 }
11702 else if(subgroupsMaxGapsPerRealDayMaxGaps[j]>=0 && (subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j]<0 ||
11703 (subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j]>=0 &&
11704 subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j] > subgroupsMaxGapsPerRealDayMaxGaps[j]*(gt.rules.nDaysPerWeek/2)))){
11705 subgroupsMaxGapsPerWeekForRealDaysMaxGaps[j] = subgroupsMaxGapsPerRealDayMaxGaps[j]*(gt.rules.nDaysPerWeek/2);
11706 subgroupsMaxGapsPerWeekForRealDaysPercentage[j]=100.0;
11707 }
11708 }
11709
11710 return ok;
11711 }
11712
computeNotAllowedTimesPercentages(QWidget * parent)11713 bool computeNotAllowedTimesPercentages(QWidget* parent)
11714 {
11715 Matrix1D<bool> allowed;
11716 allowed.resize(gt.rules.nHoursPerWeek);
11717
11718 bool ok=true;
11719
11720 assert(gt.rules.internalStructureComputed);
11721
11722 breakDayHour.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
11723 //BREAK
11724 for(int j=0; j<gt.rules.nDaysPerWeek; j++)
11725 for(int k=0; k<gt.rules.nHoursPerDay; k++)
11726 breakDayHour[j][k]=false;
11727
11728 subgroupNotAvailableDayHour.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
11729 //STUDENTS SET NOT AVAILABLE
11730 for(int i=0; i<gt.rules.nInternalSubgroups; i++)
11731 for(int j=0; j<gt.rules.nDaysPerWeek; j++)
11732 for(int k=0; k<gt.rules.nHoursPerDay; k++)
11733 subgroupNotAvailableDayHour[i][j][k]=false;
11734
11735 //used in students timetable view time horizontal dialog
11736 studentsSetNotAvailableDayHour.clear();
11737 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11738 TimeConstraint* ctr=gt.rules.internalTimeConstraintsList[i];
11739 if(ctr->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
11740 ConstraintStudentsSetNotAvailableTimes* csna=(ConstraintStudentsSetNotAvailableTimes*)ctr;
11741 assert(csna->active);
11742
11743 assert(gt.rules.studentsHash.contains(csna->students));
11744
11745 assert(!studentsSetNotAvailableDayHour.contains(csna->students));
11746 QSet<QPair<int, int>> mySet;
11747 for(int j=0; j<csna->days.count(); j++){
11748 int d=csna->days.at(j);
11749 int h=csna->hours.at(j);
11750 assert(!mySet.contains(QPair<int, int>(d,h)));
11751 mySet.insert(QPair<int, int>(d,h));
11752 }
11753 studentsSetNotAvailableDayHour.insert(csna->students, mySet);
11754 }
11755 }
11756
11757 teacherNotAvailableDayHour.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
11758 //TEACHER NOT AVAILABLE
11759 for(int i=0; i<gt.rules.nInternalTeachers; i++)
11760 for(int j=0; j<gt.rules.nDaysPerWeek; j++)
11761 for(int k=0; k<gt.rules.nHoursPerDay; k++)
11762 teacherNotAvailableDayHour[i][j][k]=false;
11763
11764 notAllowedTimesPercentages.resize(gt.rules.nInternalActivities, gt.rules.nHoursPerWeek);
11765 //improvement by Volker Dirr (late activities):
11766 for(int i=0; i<gt.rules.nInternalActivities; i++){
11767 Activity* act=>.rules.internalActivitiesList[i];
11768 for(int j=0; j<gt.rules.nHoursPerWeek; j++){
11769 int h=j/gt.rules.nDaysPerWeek;
11770 if(h+act->duration <= gt.rules.nHoursPerDay)
11771 notAllowedTimesPercentages[i][j]=-1;
11772 else
11773 notAllowedTimesPercentages[i][j]=100;
11774 }
11775 }
11776
11777 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
11778 //TEACHER not available
11779 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_NOT_AVAILABLE_TIMES){
11780 ConstraintTeacherNotAvailableTimes* tn=(ConstraintTeacherNotAvailableTimes*)gt.rules.internalTimeConstraintsList[i];
11781 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
11782 Activity* act=>.rules.internalActivitiesList[ai];
11783 for(int ti=0; ti<act->iTeachersList.count(); ti++)
11784 if(act->iTeachersList.at(ti)==tn->teacher_ID){
11785 assert(tn->days.count()==tn->hours.count());
11786 for(int kk=0; kk<tn->days.count(); kk++){
11787 int d=tn->days.at(kk);
11788 int h=tn->hours.at(kk);
11789
11790 for(int hh=max(0, h-act->duration+1); hh<=h; hh++)
11791 if(notAllowedTimesPercentages[ai][d+hh*gt.rules.nDaysPerWeek]<tn->weightPercentage)
11792 notAllowedTimesPercentages[ai][d+hh*gt.rules.nDaysPerWeek]=tn->weightPercentage;
11793 }
11794 //break; //search no more for teacher -- careful with that
11795 }
11796 }
11797
11798 if(tn->weightPercentage!=100){
11799 ok=false;
11800
11801 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
11802 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
11803 "teacher not available with weight percentage less than 100% for teacher %1. Currently, FET can only optimize with "
11804 "constraints teacher not available with 100% weight (or no constraint). Please "
11805 "modify your data accordingly and try again.").arg(tn->teacher));
11806
11807 return ok;
11808 }
11809 else{
11810 assert(tn->weightPercentage==100);
11811 assert(tn->days.count()==tn->hours.count());
11812 for(int kk=0; kk<tn->days.count(); kk++){
11813 int d=tn->days.at(kk);
11814 int h=tn->hours.at(kk);
11815
11816 teacherNotAvailableDayHour[tn->teacher_ID][d][h]=true;
11817 }
11818 }
11819 }
11820
11821 //STUDENTS SET not available
11822 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_NOT_AVAILABLE_TIMES){
11823 ConstraintStudentsSetNotAvailableTimes* sn=(ConstraintStudentsSetNotAvailableTimes*)gt.rules.internalTimeConstraintsList[i];
11824 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
11825 Activity* act=>.rules.internalActivitiesList[ai];
11826 for(int sg=0; sg<act->iSubgroupsList.count(); sg++)
11827 for(int j=0; j<sn->iSubgroupsList.count(); j++){
11828 if(act->iSubgroupsList.at(sg)==sn->iSubgroupsList.at(j)){
11829 assert(sn->days.count()==sn->hours.count());
11830 for(int kk=0; kk<sn->days.count(); kk++){
11831 int d=sn->days.at(kk);
11832 int h=sn->hours.at(kk);
11833
11834 for(int hh=max(0, h-act->duration+1); hh<=h; hh++)
11835 if(notAllowedTimesPercentages[ai][d+hh*gt.rules.nDaysPerWeek]<sn->weightPercentage)
11836 notAllowedTimesPercentages[ai][d+hh*gt.rules.nDaysPerWeek]=sn->weightPercentage;
11837 }
11838 //break; //search no more for subgroup - this can bring an improvement in precalculation
11839 //but needs attention
11840 }
11841 }
11842 }
11843
11844 if(sn->weightPercentage!=100){
11845 ok=false;
11846
11847 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
11848 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
11849 "students set not available with weight percentage less than 100% for students set %1. Currently, FET can only optimize with "
11850 "constraints students set not available with 100% weight (or no constraint). Please "
11851 "modify your data accordingly and try again.").arg(sn->students));
11852
11853 return ok;
11854 }
11855 else{
11856 assert(sn->weightPercentage==100);
11857 for(int q=0; q<sn->iSubgroupsList.count(); q++){
11858 int ss=sn->iSubgroupsList.at(q);
11859 assert(sn->days.count()==sn->hours.count());
11860 for(int kk=0; kk<sn->days.count(); kk++){
11861 int d=sn->days.at(kk);
11862 int h=sn->hours.at(kk);
11863
11864 subgroupNotAvailableDayHour[ss][d][h]=true;
11865 }
11866 }
11867 }
11868 }
11869
11870 //BREAK
11871 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_BREAK_TIMES){
11872 ConstraintBreakTimes* br=(ConstraintBreakTimes*)gt.rules.internalTimeConstraintsList[i];
11873 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
11874 Activity* act=>.rules.internalActivitiesList[ai];
11875
11876 assert(br->days.count()==br->hours.count());
11877 for(int kk=0; kk<br->days.count(); kk++){
11878 int d=br->days.at(kk);
11879 int h=br->hours.at(kk);
11880
11881 for(int hh=max(0, h-act->duration+1); hh<=h; hh++)
11882 if(notAllowedTimesPercentages[ai][d+hh*gt.rules.nDaysPerWeek]<br->weightPercentage)
11883 notAllowedTimesPercentages[ai][d+hh*gt.rules.nDaysPerWeek]=br->weightPercentage;
11884 }
11885 }
11886
11887 if(br->weightPercentage!=100){
11888 ok=false;
11889
11890 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
11891 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
11892 "break with weight percentage less than 100%. Currently, FET can only optimize with "
11893 "constraints break with 100% weight (or no constraint). Please "
11894 "modify your data accordingly and try again."));
11895
11896 return ok;
11897 }
11898 else{
11899 assert(br->weightPercentage==100);
11900
11901 assert(br->days.count()==br->hours.count());
11902 for(int kk=0; kk<br->days.count(); kk++){
11903 int d=br->days.at(kk);
11904 int h=br->hours.at(kk);
11905
11906 breakDayHour[d][h]=true;
11907 }
11908 }
11909 }
11910
11911 //ACTIVITY preferred starting time
11912 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIME){
11913 ConstraintActivityPreferredStartingTime* ap=(ConstraintActivityPreferredStartingTime*)gt.rules.internalTimeConstraintsList[i];
11914
11915 if(ap->day>=0 && ap->hour>=0){
11916 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
11917 for(int h=0; h<gt.rules.nHoursPerDay; h++)
11918 if(d!=ap->day || h!=ap->hour)
11919 if(notAllowedTimesPercentages[ap->activityIndex][d+h*gt.rules.nDaysPerWeek]<ap->weightPercentage)
11920 notAllowedTimesPercentages[ap->activityIndex][d+h*gt.rules.nDaysPerWeek]=ap->weightPercentage;
11921 }
11922 else if(ap->day>=0){
11923 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
11924 for(int h=0; h<gt.rules.nHoursPerDay; h++)
11925 if(d!=ap->day)
11926 if(notAllowedTimesPercentages[ap->activityIndex][d+h*gt.rules.nDaysPerWeek]<ap->weightPercentage)
11927 notAllowedTimesPercentages[ap->activityIndex][d+h*gt.rules.nDaysPerWeek]=ap->weightPercentage;
11928 }
11929 else if(ap->hour>=0){
11930 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
11931 for(int h=0; h<gt.rules.nHoursPerDay; h++)
11932 if(h!=ap->hour)
11933 if(notAllowedTimesPercentages[ap->activityIndex][d+h*gt.rules.nDaysPerWeek]<ap->weightPercentage)
11934 notAllowedTimesPercentages[ap->activityIndex][d+h*gt.rules.nDaysPerWeek]=ap->weightPercentage;
11935 }
11936 else{
11937 ok=false;
11938
11939 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
11940 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
11941 "activity preferred starting time with no day nor hour selected (for activity with id=%1). "
11942 "Please modify your data accordingly (remove or edit constraint) and try again.")
11943 .arg(gt.rules.internalActivitiesList[ap->activityIndex].id),
11944 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
11945 1, 0 );
11946
11947 if(t==0)
11948 break;
11949 //assert(0);
11950 }
11951 }
11952
11953 //ACTIVITY preferred starting times
11954 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITY_PREFERRED_STARTING_TIMES){
11955 ConstraintActivityPreferredStartingTimes* ap=(ConstraintActivityPreferredStartingTimes*)gt.rules.internalTimeConstraintsList[i];
11956
11957 int ai=ap->activityIndex;
11958
11959 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
11960 allowed[k]=false;
11961
11962 for(int m=0; m<ap->nPreferredStartingTimes_L; m++){
11963 int d=ap->days_L[m];
11964 int h=ap->hours_L[m];
11965
11966 if(d>=0 && h>=0){
11967 assert(d>=0 && h>=0);
11968 allowed[d+h*gt.rules.nDaysPerWeek]=true;
11969 }
11970 else if(d>=0){
11971 for(int hh=0; hh<gt.rules.nHoursPerDay; hh++)
11972 allowed[d+hh*gt.rules.nDaysPerWeek]=true;
11973 }
11974 else if(h>=0){
11975 for(int dd=0; dd<gt.rules.nDaysPerWeek; dd++)
11976 allowed[dd+h*gt.rules.nDaysPerWeek]=true;
11977 }
11978 }
11979
11980 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
11981 if(!allowed[k])
11982 if(notAllowedTimesPercentages[ai][k] < ap->weightPercentage)
11983 notAllowedTimesPercentages[ai][k] = ap->weightPercentage;
11984 }
11985
11986 //ACTIVITIES preferred starting times
11987 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_PREFERRED_STARTING_TIMES){
11988 ConstraintActivitiesPreferredStartingTimes* ap=(ConstraintActivitiesPreferredStartingTimes*)gt.rules.internalTimeConstraintsList[i];
11989
11990 for(int j=0; j<ap->nActivities; j++){
11991 int ai=ap->activitiesIndices[j];
11992
11993 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
11994 allowed[k]=false;
11995
11996 for(int m=0; m<ap->nPreferredStartingTimes_L; m++){
11997 int d=ap->days_L[m];
11998 int h=ap->hours_L[m];
11999 assert(d>=0 && h>=0);
12000 allowed[d+h*gt.rules.nDaysPerWeek]=true;
12001 }
12002
12003 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
12004 if(!allowed[k])
12005 if(notAllowedTimesPercentages[ai][k] < ap->weightPercentage)
12006 notAllowedTimesPercentages[ai][k] = ap->weightPercentage;
12007 }
12008 }
12009
12010 //subactivities preferred starting times
12011 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_STARTING_TIMES){
12012 ConstraintSubactivitiesPreferredStartingTimes* ap=(ConstraintSubactivitiesPreferredStartingTimes*)gt.rules.internalTimeConstraintsList[i];
12013
12014 for(int j=0; j<ap->nActivities; j++){
12015 int ai=ap->activitiesIndices[j];
12016
12017 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
12018 allowed[k]=false;
12019
12020 for(int m=0; m<ap->nPreferredStartingTimes_L; m++){
12021 int d=ap->days_L[m];
12022 int h=ap->hours_L[m];
12023 assert(d>=0 && h>=0);
12024 allowed[d+h*gt.rules.nDaysPerWeek]=true;
12025 }
12026
12027 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
12028 if(!allowed[k])
12029 if(notAllowedTimesPercentages[ai][k] < ap->weightPercentage)
12030 notAllowedTimesPercentages[ai][k] = ap->weightPercentage;
12031 }
12032 }
12033
12034 //ACTIVITY preferred time slots
12035 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITY_PREFERRED_TIME_SLOTS){
12036 ConstraintActivityPreferredTimeSlots* ap=(ConstraintActivityPreferredTimeSlots*)gt.rules.internalTimeConstraintsList[i];
12037
12038 int ai=ap->p_activityIndex;
12039
12040 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
12041 allowed[k]=false;
12042
12043 for(int m=0; m<ap->p_nPreferredTimeSlots_L; m++){
12044 int d=ap->p_days_L[m];
12045 int h=ap->p_hours_L[m];
12046
12047 if(d>=0 && h>=0){
12048 assert(d>=0 && h>=0);
12049 allowed[d+h*gt.rules.nDaysPerWeek]=true;
12050 }
12051 else if(d>=0){
12052 for(int hh=0; hh<gt.rules.nHoursPerDay; hh++)
12053 allowed[d+hh*gt.rules.nDaysPerWeek]=true;
12054 }
12055 else if(h>=0){
12056 for(int dd=0; dd<gt.rules.nDaysPerWeek; dd++)
12057 allowed[dd+h*gt.rules.nDaysPerWeek]=true;
12058 }
12059 }
12060
12061 for(int k=0; k<gt.rules.nHoursPerWeek; k++){
12062 int d=k%gt.rules.nDaysPerWeek;
12063 int h=k/gt.rules.nDaysPerWeek;
12064
12065 bool ok=true;
12066
12067 for(int dur=0; dur<gt.rules.internalActivitiesList[ai].duration && h+dur<gt.rules.nHoursPerDay; dur++){
12068 assert(d+(h+dur)*gt.rules.nDaysPerWeek<gt.rules.nDaysPerWeek*gt.rules.nHoursPerDay);
12069 if(!allowed[d+(h+dur)*gt.rules.nDaysPerWeek]){
12070 ok=false;
12071 break;
12072 }
12073 }
12074
12075 if(!ok)
12076 if(notAllowedTimesPercentages[ai][k] < ap->weightPercentage)
12077 notAllowedTimesPercentages[ai][k] = ap->weightPercentage;
12078 }
12079 }
12080
12081 //ACTIVITIES preferred time slots
12082 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_PREFERRED_TIME_SLOTS){
12083 ConstraintActivitiesPreferredTimeSlots* ap=(ConstraintActivitiesPreferredTimeSlots*)gt.rules.internalTimeConstraintsList[i];
12084
12085 for(int j=0; j<ap->p_nActivities; j++){
12086 int ai=ap->p_activitiesIndices[j];
12087
12088 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
12089 allowed[k]=false;
12090
12091 for(int m=0; m<ap->p_nPreferredTimeSlots_L; m++){
12092 int d=ap->p_days_L[m];
12093 int h=ap->p_hours_L[m];
12094 assert(d>=0 && h>=0);
12095 allowed[d+h*gt.rules.nDaysPerWeek]=true;
12096 }
12097
12098 for(int k=0; k<gt.rules.nHoursPerWeek; k++){
12099 int d=k%gt.rules.nDaysPerWeek;
12100 int h=k/gt.rules.nDaysPerWeek;
12101
12102 bool ok=true;
12103
12104 for(int dur=0; dur<gt.rules.internalActivitiesList[ai].duration && h+dur<gt.rules.nHoursPerDay; dur++){
12105 assert(d+(h+dur)*gt.rules.nDaysPerWeek<gt.rules.nDaysPerWeek*gt.rules.nHoursPerDay);
12106 if(!allowed[d+(h+dur)*gt.rules.nDaysPerWeek]){
12107 ok=false;
12108 break;
12109 }
12110 }
12111
12112 if(!ok)
12113 if(notAllowedTimesPercentages[ai][k] < ap->weightPercentage)
12114 notAllowedTimesPercentages[ai][k] = ap->weightPercentage;
12115 }
12116 }
12117 }
12118
12119 //subactivities preferred time slots
12120 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_SUBACTIVITIES_PREFERRED_TIME_SLOTS){
12121 ConstraintSubactivitiesPreferredTimeSlots* ap=(ConstraintSubactivitiesPreferredTimeSlots*)gt.rules.internalTimeConstraintsList[i];
12122
12123 for(int j=0; j<ap->p_nActivities; j++){
12124 int ai=ap->p_activitiesIndices[j];
12125
12126 for(int k=0; k<gt.rules.nHoursPerWeek; k++)
12127 allowed[k]=false;
12128
12129 for(int m=0; m<ap->p_nPreferredTimeSlots_L; m++){
12130 int d=ap->p_days_L[m];
12131 int h=ap->p_hours_L[m];
12132 assert(d>=0 && h>=0);
12133 allowed[d+h*gt.rules.nDaysPerWeek]=true;
12134 }
12135
12136 for(int k=0; k<gt.rules.nHoursPerWeek; k++){
12137 int d=k%gt.rules.nDaysPerWeek;
12138 int h=k/gt.rules.nDaysPerWeek;
12139
12140 bool ok=true;
12141
12142 for(int dur=0; dur<gt.rules.internalActivitiesList[ai].duration && h+dur<gt.rules.nHoursPerDay; dur++){
12143 assert(d+(h+dur)*gt.rules.nDaysPerWeek<gt.rules.nDaysPerWeek*gt.rules.nHoursPerDay);
12144 if(!allowed[d+(h+dur)*gt.rules.nDaysPerWeek]){
12145 ok=false;
12146 break;
12147 }
12148 }
12149
12150 if(!ok)
12151 if(notAllowedTimesPercentages[ai][k] < ap->weightPercentage)
12152 notAllowedTimesPercentages[ai][k] = ap->weightPercentage;
12153 }
12154 }
12155 }
12156 }
12157
12158 return ok;
12159 }
12160
computeMinDays(QWidget * parent)12161 bool computeMinDays(QWidget* parent)
12162 {
12163 QSet<ConstraintMinDaysBetweenActivities*> mdset;
12164
12165 bool ok=true;
12166
12167 for(int j=0; j<gt.rules.nInternalActivities; j++){
12168 minDaysListOfActivities[j].clear();
12169 minDaysListOfMinDays[j].clear();
12170 minDaysListOfConsecutiveIfSameDay[j].clear();
12171 minDaysListOfWeightPercentages[j].clear();
12172
12173 //for(int k=0; k<gt.rules.nInternalActivities; k++)
12174 // minDays[j][k]=0;
12175 }
12176
12177 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12178 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES
12179 /*&>.rules.internalTimeConstraintsList[i]->compulsory==true*/){
12180 ConstraintMinDaysBetweenActivities* md=
12181 (ConstraintMinDaysBetweenActivities*)gt.rules.internalTimeConstraintsList[i];
12182
12183 for(int j=0; j<md->_n_activities; j++){
12184 int ai1=md->_activities[j];
12185 for(int k=0; k<md->_n_activities; k++)
12186 if(j!=k){
12187 int ai2=md->_activities[k];
12188 if(ai1==ai2){
12189 ok=false;
12190
12191 if(!mdset.contains(md)){
12192 mdset.insert(md);
12193
12194 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12195 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint min days with duplicate activities. The constraint "
12196 "is: %1. Please correct that.").arg(md->getDetailedDescription(gt.rules)),
12197 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12198 1, 0 );
12199
12200 if(t==0)
12201 return ok;
12202 }
12203 }
12204 int m=md->minDays;
12205 /*if(m>minDays[ai1][ai2])
12206 minDays[ai1][ai2]=minDays[ai2][ai1]=m;*/
12207
12208 minDaysListOfActivities[ai1].append(ai2);
12209 minDaysListOfMinDays[ai1].append(m);
12210 assert(md->weightPercentage >=0 && md->weightPercentage<=100);
12211 minDaysListOfWeightPercentages[ai1].append(md->weightPercentage);
12212 minDaysListOfConsecutiveIfSameDay[ai1].append(md->consecutiveIfSameDay);
12213 }
12214 }
12215 }
12216
12217 /*for(int j=0; j<gt.rules.nInternalActivities; j++)
12218 for(int k=0; k<gt.rules.nInternalActivities; k++)
12219 if(minDays[j][k]>0){
12220 assert(j!=k);
12221 minDaysListOfActivities[j].append(k);
12222 minDaysListOfMinDays[j].append(minDays[j][k]);
12223 }*/
12224
12225 return ok;
12226 }
12227
computeMaxDays(QWidget * parent)12228 bool computeMaxDays(QWidget* parent)
12229 {
12230 QSet<ConstraintMaxDaysBetweenActivities*> mdset;
12231
12232 bool ok=true;
12233
12234 for(int j=0; j<gt.rules.nInternalActivities; j++){
12235 maxDaysListOfActivities[j].clear();
12236 maxDaysListOfMaxDays[j].clear();
12237 maxDaysListOfWeightPercentages[j].clear();
12238 }
12239
12240 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12241 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MAX_DAYS_BETWEEN_ACTIVITIES
12242 /*&>.rules.internalTimeConstraintsList[i]->compulsory==true*/){
12243 ConstraintMaxDaysBetweenActivities* md=
12244 (ConstraintMaxDaysBetweenActivities*)gt.rules.internalTimeConstraintsList[i];
12245
12246 for(int j=0; j<md->_n_activities; j++){
12247 int ai1=md->_activities[j];
12248 for(int k=0; k<md->_n_activities; k++)
12249 if(j!=k){
12250 int ai2=md->_activities[k];
12251 if(ai1==ai2){
12252 ok=false;
12253
12254 if(!mdset.contains(md)){
12255 mdset.insert(md);
12256
12257 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12258 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint max days between activities with duplicate activities. The constraint "
12259 "is: %1. Please correct that.").arg(md->getDetailedDescription(gt.rules)),
12260 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12261 1, 0 );
12262
12263 if(t==0)
12264 return ok;
12265 }
12266 }
12267 int m=md->maxDays;
12268 /*if(m>minDays[ai1][ai2])
12269 minDays[ai1][ai2]=minDays[ai2][ai1]=m;*/
12270
12271 maxDaysListOfActivities[ai1].append(ai2);
12272 maxDaysListOfMaxDays[ai1].append(m);
12273 assert(md->weightPercentage >=0 && md->weightPercentage<=100);
12274 maxDaysListOfWeightPercentages[ai1].append(md->weightPercentage);
12275 //maxDaysListOfConsecutiveIfSameDay[ai1].append(md->consecutiveIfSameDay);
12276 }
12277 }
12278 }
12279
12280 /*for(int j=0; j<gt.rules.nInternalActivities; j++)
12281 for(int k=0; k<gt.rules.nInternalActivities; k++)
12282 if(minDays[j][k]>0){
12283 assert(j!=k);
12284 minDaysListOfActivities[j].append(k);
12285 minDaysListOfMinDays[j].append(minDays[j][k]);
12286 }*/
12287
12288 return ok;
12289 }
12290
computeMinGapsBetweenActivities(QWidget * parent)12291 bool computeMinGapsBetweenActivities(QWidget* parent)
12292 {
12293 QSet<ConstraintMinGapsBetweenActivities*> mgset;
12294
12295 bool ok=true;
12296
12297 for(int j=0; j<gt.rules.nInternalActivities; j++){
12298 minGapsBetweenActivitiesListOfActivities[j].clear();
12299 minGapsBetweenActivitiesListOfMinGaps[j].clear();
12300 minGapsBetweenActivitiesListOfWeightPercentages[j].clear();
12301
12302 //for(int k=0; k<gt.rules.nInternalActivities; k++)
12303 // minDays[j][k]=0;
12304 }
12305
12306 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12307 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MIN_GAPS_BETWEEN_ACTIVITIES
12308 /*&>.rules.internalTimeConstraintsList[i]->compulsory==true*/){
12309 ConstraintMinGapsBetweenActivities* mg=
12310 (ConstraintMinGapsBetweenActivities*)gt.rules.internalTimeConstraintsList[i];
12311
12312 assert(mg->_n_activities==mg->_activities.count());
12313
12314 for(int j=0; j<mg->_n_activities; j++){
12315 int ai1=mg->_activities[j];
12316 for(int k=0; k<mg->_n_activities; k++)
12317 if(j!=k){
12318 int ai2=mg->_activities[k];
12319 if(ai1==ai2){
12320 ok=false;
12321
12322 if(!mgset.contains(mg)){
12323 mgset.insert(mg);
12324
12325 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12326 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint min gaps between activities with duplicate activities. The constraint "
12327 "is: %1. Please correct that.").arg(mg->getDetailedDescription(gt.rules)),
12328 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12329 1, 0 );
12330
12331 if(t==0)
12332 return ok;
12333 }
12334 }
12335 int m=mg->minGaps;
12336
12337 minGapsBetweenActivitiesListOfActivities[ai1].append(ai2);
12338 minGapsBetweenActivitiesListOfMinGaps[ai1].append(m);
12339 assert(mg->weightPercentage >=0 && mg->weightPercentage<=100);
12340 minGapsBetweenActivitiesListOfWeightPercentages[ai1].append(mg->weightPercentage);
12341 }
12342 }
12343 }
12344
12345 return ok;
12346 }
12347
computeMaxGapsBetweenActivities(QWidget * parent)12348 bool computeMaxGapsBetweenActivities(QWidget* parent)
12349 {
12350 QSet<ConstraintMaxGapsBetweenActivities*> mgset;
12351
12352 bool ok=true;
12353
12354 for(int j=0; j<gt.rules.nInternalActivities; j++){
12355 maxGapsBetweenActivitiesListOfActivities[j].clear();
12356 maxGapsBetweenActivitiesListOfMaxGaps[j].clear();
12357 maxGapsBetweenActivitiesListOfWeightPercentages[j].clear();
12358
12359 //for(int k=0; k<gt.rules.nInternalActivities; k++)
12360 // minDays[j][k]=0;
12361 }
12362
12363 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12364 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MAX_GAPS_BETWEEN_ACTIVITIES
12365 /*&>.rules.internalTimeConstraintsList[i]->compulsory==true*/){
12366 ConstraintMaxGapsBetweenActivities* mg=
12367 (ConstraintMaxGapsBetweenActivities*)gt.rules.internalTimeConstraintsList[i];
12368
12369 assert(mg->_n_activities==mg->_activities.count());
12370
12371 for(int j=0; j<mg->_n_activities; j++){
12372 int ai1=mg->_activities[j];
12373 for(int k=0; k<mg->_n_activities; k++)
12374 if(j!=k){
12375 int ai2=mg->_activities[k];
12376 if(ai1==ai2){
12377 ok=false;
12378
12379 if(!mgset.contains(mg)){
12380 mgset.insert(mg);
12381
12382 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12383 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint max gaps between activities with duplicate activities. The constraint "
12384 "is: %1. Please correct that.").arg(mg->getDetailedDescription(gt.rules)),
12385 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12386 1, 0 );
12387
12388 if(t==0)
12389 return ok;
12390 }
12391 }
12392 int m=mg->maxGaps;
12393
12394 maxGapsBetweenActivitiesListOfActivities[ai1].append(ai2);
12395 maxGapsBetweenActivitiesListOfMaxGaps[ai1].append(m);
12396 assert(mg->weightPercentage >=0 && mg->weightPercentage<=100);
12397 maxGapsBetweenActivitiesListOfWeightPercentages[ai1].append(mg->weightPercentage);
12398 }
12399 }
12400 }
12401
12402 return ok;
12403 }
12404
computeActivitiesConflictingPercentage(QWidget * parent)12405 bool computeActivitiesConflictingPercentage(QWidget* parent)
12406 {
12407 //get maximum weight percent of a basic time constraint
12408 double m=-1;
12409
12410 bool ok=false;
12411 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12412 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_BASIC_COMPULSORY_TIME){
12413 ok=true;
12414 if(gt.rules.internalTimeConstraintsList[i]->weightPercentage>m)
12415 m=gt.rules.internalTimeConstraintsList[i]->weightPercentage;
12416 }
12417
12418 if(m<100)
12419 ok=false;
12420
12421 if(!ok || m<100){
12422 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
12423 GeneratePreTranslate::tr("Cannot generate, because you do not have a constraint of type basic compulsory time or its weight is lower than 100.0%.")
12424 +" "+
12425 GeneratePreTranslate::tr("Please add a constraint of this type with weight 100%.")
12426 +" "+
12427 GeneratePreTranslate::tr("You can add this constraint from the menu Data -> Time constraints -> Miscellaneous -> Basic compulsory time constraints.")
12428 +"\n\n"+
12429 GeneratePreTranslate::tr("Explanation:")
12430 +" "+
12431 GeneratePreTranslate::tr("Each time you create a new file, it contains an automatically added constraint of this type.")
12432 +" "+
12433 GeneratePreTranslate::tr("For complete flexibility, you are allowed to remove it (even if this is a wrong idea).")
12434 +" "+
12435 GeneratePreTranslate::tr("Maybe you removed it by mistake from your file.")
12436 +" "+
12437 GeneratePreTranslate::tr("By adding it again, everything should be all right.")
12438 );
12439 return false;
12440 }
12441
12442 assert(m>=0 && m<=100);
12443 assert(m==100);
12444
12445 //compute conflicting
12446 activitiesConflictingPercentage.resize(gt.rules.nInternalActivities);
12447 for(int i=0; i<gt.rules.nInternalActivities; i++)
12448 activitiesConflictingPercentage[i].clear();
12449
12450 for(int i=0; i<gt.rules.nInternalActivities; i++)
12451 activitiesConflictingPercentage[i].insert(i, 100);
12452
12453 QProgressDialog progress(parent);
12454 progress.setWindowTitle(GeneratePreTranslate::tr("Precomputing", "Title of a progress dialog"));
12455 progress.setLabelText(GeneratePreTranslate::tr("Precomputing ... please wait"));
12456 progress.setRange(0, qMax(gt.rules.nInternalTeachers+gt.rules.nInternalSubgroups, 1));
12457 progress.setModal(true);
12458
12459 int ttt=0;
12460
12461 for(int t=0; t<gt.rules.nInternalTeachers; t++){
12462 progress.setValue(ttt);
12463 //pqapplication->processEvents();
12464 if(progress.wasCanceled()){
12465 GeneratePreIrreconcilableMessage::information(parent, GeneratePreTranslate::tr("FET information"), GeneratePreTranslate::tr("Canceled"));
12466 return false;
12467 }
12468
12469 ttt++;
12470
12471 for(int i : qAsConst(gt.rules.internalTeachersList[t]->activitiesForTeacher))
12472 for(int j : qAsConst(gt.rules.internalTeachersList[t]->activitiesForTeacher))
12473 activitiesConflictingPercentage[i].insert(j, 100);
12474 }
12475
12476 for(int s=0; s<gt.rules.nInternalSubgroups; s++){
12477 progress.setValue(ttt);
12478 //pqapplication->processEvents();
12479 if(progress.wasCanceled()){
12480 GeneratePreIrreconcilableMessage::information(parent, GeneratePreTranslate::tr("FET information"), GeneratePreTranslate::tr("Canceled"));
12481 return false;
12482 }
12483
12484 ttt++;
12485
12486 for(int i : qAsConst(gt.rules.internalSubgroupsList[s]->activitiesForSubgroup))
12487 for(int j : qAsConst(gt.rules.internalSubgroupsList[s]->activitiesForSubgroup))
12488 activitiesConflictingPercentage[i].insert(j, 100);
12489 }
12490
12491 progress.setValue(qMax(gt.rules.nInternalTeachers+gt.rules.nInternalSubgroups, 1));
12492
12493 //new Volker (start)
12494 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
12495 TimeConstraint* tc=gt.rules.internalTimeConstraintsList[i];
12496 if(tc->type==CONSTRAINT_ACTIVITIES_NOT_OVERLAPPING){
12497 if(tc->weightPercentage==100.0){
12498 ConstraintActivitiesNotOverlapping* cno=(ConstraintActivitiesNotOverlapping*) tc;
12499
12500 for(int a=0; a<cno->_n_activities; a++){
12501 for(int b=0; b<cno->_n_activities; b++){
12502 if(cno->_activities[a]!=cno->_activities[b]){
12503 activitiesConflictingPercentage[cno->_activities[a]].insert(cno->_activities[b], 100);
12504 }
12505 }
12506 }
12507 }
12508 else{
12509 ConstraintActivitiesNotOverlapping* cno=(ConstraintActivitiesNotOverlapping*) tc;
12510
12511 int ww=int(cno->weightPercentage);
12512 if(ww>100)
12513 ww=100;
12514
12515 for(int a=0; a<cno->_n_activities; a++){
12516 for(int b=0; b<cno->_n_activities; b++){
12517 if(cno->_activities[a]!=cno->_activities[b]){
12518 if(activitiesConflictingPercentage[cno->_activities[a]].value(cno->_activities[b], -1) < ww)
12519 activitiesConflictingPercentage[cno->_activities[a]].insert(cno->_activities[b], ww);
12520 }
12521 }
12522 }
12523 }
12524 }
12525 else if(tc->type==CONSTRAINT_ACTIVITY_TAGS_NOT_OVERLAPPING){
12526 ConstraintActivityTagsNotOverlapping* catno=(ConstraintActivityTagsNotOverlapping*) tc;
12527 assert(catno->weightPercentage>=0.0 && catno->weightPercentage<=100.0);
12528
12529 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
12530 Activity* act=>.rules.internalActivitiesList[ai];
12531
12532 int cnt=0;
12533
12534 for(int at : qAsConst(catno->activityTagsIndices)){
12535 if(act->iActivityTagsSet.contains(at))
12536 cnt++;
12537 }
12538
12539 if(cnt>=2){
12540 ok=false;
12541
12542 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12543 GeneratePreTranslate::tr("%1 cannot be respected because"
12544 " the activity with id=%2 refers to %3 activity tags from this constraint. Each activity"
12545 " should refer to at most one activity tag from each separated constraint of this type.")
12546 .arg(catno->getDetailedDescription(gt.rules)).arg(act->id).arg(cnt),
12547 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12548 1, 0 );
12549
12550 if(t==0)
12551 return ok;
12552 }
12553 }
12554
12555 if(!ok)
12556 return false;
12557
12558 for(int i=0; i<catno->activitiesIndicesLists.count(); i++){
12559 const QList<int>& l1=catno->activitiesIndicesLists.at(i);
12560 for(int j=0; j<catno->activitiesIndicesLists.count(); j++){
12561 if(i!=j){
12562 const QList<int>& l2=catno->activitiesIndicesLists.at(j);
12563
12564 for(int a : qAsConst(l1))
12565 for(int b : qAsConst(l2)){
12566 if(a!=b){
12567 if(activitiesConflictingPercentage[a].value(b, -1) < catno->weightPercentage){
12568 activitiesConflictingPercentage[a].insert(b, catno->weightPercentage);
12569 }
12570 }
12571 else{
12572 assert(0);
12573 }
12574 }
12575 }
12576 }
12577 }
12578 }
12579 }
12580 //new Volker (end)
12581
12582 return true;
12583 }
12584
computeConstrTwoActivitiesConsecutive()12585 void computeConstrTwoActivitiesConsecutive()
12586 {
12587 for(int i=0; i<gt.rules.nInternalActivities; i++){
12588 constrTwoActivitiesConsecutivePercentages[i].clear();
12589 constrTwoActivitiesConsecutiveActivities[i].clear();
12590
12591 inverseConstrTwoActivitiesConsecutivePercentages[i].clear();
12592 inverseConstrTwoActivitiesConsecutiveActivities[i].clear();
12593 }
12594
12595 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12596 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TWO_ACTIVITIES_CONSECUTIVE){
12597 ConstraintTwoActivitiesConsecutive* c2=(ConstraintTwoActivitiesConsecutive*)gt.rules.internalTimeConstraintsList[i];
12598
12599 int fai=c2->firstActivityIndex;
12600 int sai=c2->secondActivityIndex;
12601
12602 //direct
12603 int j=constrTwoActivitiesConsecutiveActivities[fai].indexOf(sai);
12604 if(j==-1){
12605 constrTwoActivitiesConsecutiveActivities[fai].append(sai);
12606 constrTwoActivitiesConsecutivePercentages[fai].append(c2->weightPercentage);
12607 }
12608 else if(j>=0 && constrTwoActivitiesConsecutivePercentages[fai].at(j)<c2->weightPercentage){
12609 constrTwoActivitiesConsecutivePercentages[fai][j]=c2->weightPercentage;
12610 }
12611
12612 //inverse
12613 j=inverseConstrTwoActivitiesConsecutiveActivities[sai].indexOf(fai);
12614 if(j==-1){
12615 inverseConstrTwoActivitiesConsecutiveActivities[sai].append(fai);
12616 inverseConstrTwoActivitiesConsecutivePercentages[sai].append(c2->weightPercentage);
12617 }
12618 else if(j>=0 && inverseConstrTwoActivitiesConsecutivePercentages[sai].at(j)<c2->weightPercentage){
12619 inverseConstrTwoActivitiesConsecutivePercentages[sai][j]=c2->weightPercentage;
12620 }
12621 }
12622 }
12623
computeConstrTwoActivitiesGrouped()12624 void computeConstrTwoActivitiesGrouped()
12625 {
12626 for(int i=0; i<gt.rules.nInternalActivities; i++){
12627 constrTwoActivitiesGroupedPercentages[i].clear();
12628 constrTwoActivitiesGroupedActivities[i].clear();
12629 }
12630
12631 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12632 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TWO_ACTIVITIES_GROUPED){
12633 ConstraintTwoActivitiesGrouped* c2=(ConstraintTwoActivitiesGrouped*)gt.rules.internalTimeConstraintsList[i];
12634
12635 int fai=c2->firstActivityIndex;
12636 int sai=c2->secondActivityIndex;
12637
12638 //direct
12639 int j=constrTwoActivitiesGroupedActivities[fai].indexOf(sai);
12640 if(j==-1){
12641 constrTwoActivitiesGroupedActivities[fai].append(sai);
12642 constrTwoActivitiesGroupedPercentages[fai].append(c2->weightPercentage);
12643 }
12644 else if(j>=0 && constrTwoActivitiesGroupedPercentages[fai].at(j)<c2->weightPercentage){
12645 constrTwoActivitiesGroupedPercentages[fai][j]=c2->weightPercentage;
12646 }
12647
12648 //inverse
12649 j=constrTwoActivitiesGroupedActivities[sai].indexOf(fai);
12650 if(j==-1){
12651 constrTwoActivitiesGroupedActivities[sai].append(fai);
12652 constrTwoActivitiesGroupedPercentages[sai].append(c2->weightPercentage);
12653 }
12654 else if(j>=0 && constrTwoActivitiesGroupedPercentages[sai].at(j)<c2->weightPercentage){
12655 constrTwoActivitiesGroupedPercentages[sai][j]=c2->weightPercentage;
12656 }
12657 }
12658 }
12659
computeConstrThreeActivitiesGrouped()12660 void computeConstrThreeActivitiesGrouped()
12661 {
12662 for(int i=0; i<gt.rules.nInternalActivities; i++){
12663 constrThreeActivitiesGroupedPercentages[i].clear();
12664 constrThreeActivitiesGroupedActivities[i].clear();
12665 }
12666
12667 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12668 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_THREE_ACTIVITIES_GROUPED){
12669 ConstraintThreeActivitiesGrouped* c3=(ConstraintThreeActivitiesGrouped*)gt.rules.internalTimeConstraintsList[i];
12670
12671 int fai=c3->firstActivityIndex;
12672 int sai=c3->secondActivityIndex;
12673 int tai=c3->thirdActivityIndex;
12674
12675 QPair<int, int> p23(sai, tai);
12676 int j=constrThreeActivitiesGroupedActivities[fai].indexOf(p23);
12677 if(j==-1){
12678 constrThreeActivitiesGroupedActivities[fai].append(p23);
12679 constrThreeActivitiesGroupedPercentages[fai].append(c3->weightPercentage);
12680 }
12681 else if(j>=0 && constrThreeActivitiesGroupedPercentages[fai].at(j)<c3->weightPercentage){
12682 constrThreeActivitiesGroupedPercentages[fai][j]=c3->weightPercentage;
12683 }
12684
12685 QPair<int, int> p13(fai, tai);
12686 j=constrThreeActivitiesGroupedActivities[sai].indexOf(p13);
12687 if(j==-1){
12688 constrThreeActivitiesGroupedActivities[sai].append(p13);
12689 constrThreeActivitiesGroupedPercentages[sai].append(c3->weightPercentage);
12690 }
12691 else if(j>=0 && constrThreeActivitiesGroupedPercentages[sai].at(j)<c3->weightPercentage){
12692 constrThreeActivitiesGroupedPercentages[sai][j]=c3->weightPercentage;
12693 }
12694
12695 QPair<int, int> p12(fai, sai);
12696 j=constrThreeActivitiesGroupedActivities[tai].indexOf(p12);
12697 if(j==-1){
12698 constrThreeActivitiesGroupedActivities[tai].append(p12);
12699 constrThreeActivitiesGroupedPercentages[tai].append(c3->weightPercentage);
12700 }
12701 else if(j>=0 && constrThreeActivitiesGroupedPercentages[tai].at(j)<c3->weightPercentage){
12702 constrThreeActivitiesGroupedPercentages[tai][j]=c3->weightPercentage;
12703 }
12704 }
12705 }
12706
computeConstrTwoActivitiesOrdered()12707 void computeConstrTwoActivitiesOrdered()
12708 {
12709 for(int i=0; i<gt.rules.nInternalActivities; i++){
12710 constrTwoActivitiesOrderedPercentages[i].clear();
12711 constrTwoActivitiesOrderedActivities[i].clear();
12712
12713 inverseConstrTwoActivitiesOrderedPercentages[i].clear();
12714 inverseConstrTwoActivitiesOrderedActivities[i].clear();
12715 }
12716
12717 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
12718 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TWO_ACTIVITIES_ORDERED){
12719 ConstraintTwoActivitiesOrdered* c2=(ConstraintTwoActivitiesOrdered*)gt.rules.internalTimeConstraintsList[i];
12720
12721 int fai=c2->firstActivityIndex;
12722 int sai=c2->secondActivityIndex;
12723
12724 //direct
12725 int j=constrTwoActivitiesOrderedActivities[fai].indexOf(sai);
12726 if(j==-1){
12727 constrTwoActivitiesOrderedActivities[fai].append(sai);
12728 constrTwoActivitiesOrderedPercentages[fai].append(c2->weightPercentage);
12729 }
12730 else if(j>=0 && constrTwoActivitiesOrderedPercentages[fai].at(j)<c2->weightPercentage){
12731 constrTwoActivitiesOrderedPercentages[fai][j]=c2->weightPercentage;
12732 }
12733
12734 //inverse
12735 j=inverseConstrTwoActivitiesOrderedActivities[sai].indexOf(fai);
12736 if(j==-1){
12737 inverseConstrTwoActivitiesOrderedActivities[sai].append(fai);
12738 inverseConstrTwoActivitiesOrderedPercentages[sai].append(c2->weightPercentage);
12739 }
12740 else if(j>=0 && inverseConstrTwoActivitiesOrderedPercentages[sai].at(j)<c2->weightPercentage){
12741 inverseConstrTwoActivitiesOrderedPercentages[sai][j]=c2->weightPercentage;
12742 }
12743 }
12744 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TWO_SETS_OF_ACTIVITIES_ORDERED){
12745 ConstraintTwoSetsOfActivitiesOrdered* c2=(ConstraintTwoSetsOfActivitiesOrdered*)gt.rules.internalTimeConstraintsList[i];
12746
12747 for(int fai : qAsConst(c2->firstActivitiesIndicesList)){
12748 for(int sai : qAsConst(c2->secondActivitiesIndicesList)){
12749 //direct
12750 int j=constrTwoActivitiesOrderedActivities[fai].indexOf(sai);
12751 if(j==-1){
12752 constrTwoActivitiesOrderedActivities[fai].append(sai);
12753 constrTwoActivitiesOrderedPercentages[fai].append(c2->weightPercentage);
12754 }
12755 else if(j>=0 && constrTwoActivitiesOrderedPercentages[fai].at(j)<c2->weightPercentage){
12756 constrTwoActivitiesOrderedPercentages[fai][j]=c2->weightPercentage;
12757 }
12758
12759 //inverse
12760 j=inverseConstrTwoActivitiesOrderedActivities[sai].indexOf(fai);
12761 if(j==-1){
12762 inverseConstrTwoActivitiesOrderedActivities[sai].append(fai);
12763 inverseConstrTwoActivitiesOrderedPercentages[sai].append(c2->weightPercentage);
12764 }
12765 else if(j>=0 && inverseConstrTwoActivitiesOrderedPercentages[sai].at(j)<c2->weightPercentage){
12766 inverseConstrTwoActivitiesOrderedPercentages[sai][j]=c2->weightPercentage;
12767 }
12768 }
12769 }
12770 }
12771 }
12772 }
12773
computeConstrTwoActivitiesOrderedIfSameDay()12774 void computeConstrTwoActivitiesOrderedIfSameDay()
12775 {
12776 for(int i=0; i<gt.rules.nInternalActivities; i++){
12777 constrTwoActivitiesOrderedIfSameDayPercentages[i].clear();
12778 constrTwoActivitiesOrderedIfSameDayActivities[i].clear();
12779
12780 inverseConstrTwoActivitiesOrderedIfSameDayPercentages[i].clear();
12781 inverseConstrTwoActivitiesOrderedIfSameDayActivities[i].clear();
12782 }
12783
12784 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++)
12785 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TWO_ACTIVITIES_ORDERED_IF_SAME_DAY){
12786 ConstraintTwoActivitiesOrderedIfSameDay* c2=(ConstraintTwoActivitiesOrderedIfSameDay*)gt.rules.internalTimeConstraintsList[i];
12787
12788 int fai=c2->firstActivityIndex;
12789 int sai=c2->secondActivityIndex;
12790
12791 //direct
12792 int j=constrTwoActivitiesOrderedIfSameDayActivities[fai].indexOf(sai);
12793 if(j==-1){
12794 constrTwoActivitiesOrderedIfSameDayActivities[fai].append(sai);
12795 constrTwoActivitiesOrderedIfSameDayPercentages[fai].append(c2->weightPercentage);
12796 }
12797 else if(j>=0 && constrTwoActivitiesOrderedIfSameDayPercentages[fai].at(j)<c2->weightPercentage){
12798 constrTwoActivitiesOrderedIfSameDayPercentages[fai][j]=c2->weightPercentage;
12799 }
12800
12801 //inverse
12802 j=inverseConstrTwoActivitiesOrderedIfSameDayActivities[sai].indexOf(fai);
12803 if(j==-1){
12804 inverseConstrTwoActivitiesOrderedIfSameDayActivities[sai].append(fai);
12805 inverseConstrTwoActivitiesOrderedIfSameDayPercentages[sai].append(c2->weightPercentage);
12806 }
12807 else if(j>=0 && inverseConstrTwoActivitiesOrderedIfSameDayPercentages[sai].at(j)<c2->weightPercentage){
12808 inverseConstrTwoActivitiesOrderedIfSameDayPercentages[sai][j]=c2->weightPercentage;
12809 }
12810 }
12811 }
12812
computeActivityEndsStudentsDayPercentages(QWidget * parent)12813 bool computeActivityEndsStudentsDayPercentages(QWidget* parent)
12814 {
12815 bool ok=true;
12816
12817 for(int ai=0; ai<gt.rules.nInternalActivities; ai++)
12818 activityEndsStudentsDayPercentages[ai]=-1;
12819
12820 haveActivityEndsStudentsDay=false;
12821
12822 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
12823 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITY_ENDS_STUDENTS_DAY){
12824 haveActivityEndsStudentsDay=true;
12825
12826 ConstraintActivityEndsStudentsDay* cae=(ConstraintActivityEndsStudentsDay*)gt.rules.internalTimeConstraintsList[i];
12827
12828 if(cae->weightPercentage!=100){
12829 ok=false;
12830
12831 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12832 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
12833 "activity activity ends students day for activity with id=%1 with weight percentage under 100%. "
12834 "Constraint activity ends students day can only have weight percentage 100%. "
12835 "Please modify your data accordingly (remove or edit constraint) and try again.")
12836 .arg(gt.rules.internalActivitiesList[cae->activityIndex].id),
12837 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12838 1, 0 );
12839
12840 if(t==0)
12841 break;
12842 }
12843
12844 int ai=cae->activityIndex;
12845 if(activityEndsStudentsDayPercentages[ai] < cae->weightPercentage)
12846 activityEndsStudentsDayPercentages[ai] = cae->weightPercentage;
12847 }
12848 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_END_STUDENTS_DAY){
12849 haveActivityEndsStudentsDay=true;
12850
12851 ConstraintActivitiesEndStudentsDay* cae=(ConstraintActivitiesEndStudentsDay*)gt.rules.internalTimeConstraintsList[i];
12852
12853 if(cae->weightPercentage!=100){
12854 ok=false;
12855
12856 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12857 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
12858 "activities end students day with weight percentage under 100%. "
12859 "Constraint activities end students day can only have weight percentage 100%. "
12860 "Please modify your data accordingly (remove or edit constraint) and try again."),
12861 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12862 1, 0 );
12863
12864 if(t==0)
12865 break;
12866 }
12867
12868 for(int i=0; i<cae->nActivities; i++){
12869 int ai=cae->activitiesIndices[i];
12870 if(activityEndsStudentsDayPercentages[ai] < cae->weightPercentage)
12871 activityEndsStudentsDayPercentages[ai] = cae->weightPercentage;
12872 }
12873 }
12874 }
12875
12876 return ok;
12877 }
12878
computeActivityEndsTeachersDayPercentages(QWidget * parent)12879 bool computeActivityEndsTeachersDayPercentages(QWidget* parent)
12880 {
12881 bool ok=true;
12882
12883 for(int ai=0; ai<gt.rules.nInternalActivities; ai++)
12884 activityEndsTeachersDayPercentages[ai]=-1;
12885
12886 haveActivityEndsTeachersDay=false;
12887
12888 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
12889 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITY_ENDS_TEACHERS_DAY){
12890 haveActivityEndsTeachersDay=true;
12891
12892 ConstraintActivityEndsTeachersDay* cae=(ConstraintActivityEndsTeachersDay*)gt.rules.internalTimeConstraintsList[i];
12893
12894 if(cae->weightPercentage!=100){
12895 ok=false;
12896
12897 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12898 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
12899 "activity activity ends teachers day for activity with id==%1 with weight percentage under 100%. "
12900 "Constraint activity ends teachers day can only have weight percentage 100%. "
12901 "Please modify your data accordingly (remove or edit constraint) and try again.")
12902 .arg(gt.rules.internalActivitiesList[cae->activityIndex].id),
12903 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12904 1, 0 );
12905
12906 if(t==0)
12907 break;
12908 }
12909
12910 int ai=cae->activityIndex;
12911 if(activityEndsTeachersDayPercentages[ai] < cae->weightPercentage)
12912 activityEndsTeachersDayPercentages[ai] = cae->weightPercentage;
12913 }
12914 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_END_TEACHERS_DAY){
12915 haveActivityEndsTeachersDay=true;
12916
12917 ConstraintActivitiesEndTeachersDay* cae=(ConstraintActivitiesEndTeachersDay*)gt.rules.internalTimeConstraintsList[i];
12918
12919 if(cae->weightPercentage!=100){
12920 ok=false;
12921
12922 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
12923 GeneratePreTranslate::tr("Cannot optimize, because you have constraints of type "
12924 "activities end teachers day with weight percentage under 100%. "
12925 "Constraint activities end teachers day can only have weight percentage 100%. "
12926 "Please modify your data accordingly (remove or edit constraint) and try again."),
12927 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
12928 1, 0 );
12929
12930 if(t==0)
12931 break;
12932 }
12933
12934 for(int i=0; i<cae->nActivities; i++){
12935 int ai=cae->activitiesIndices[i];
12936 if(activityEndsTeachersDayPercentages[ai] < cae->weightPercentage)
12937 activityEndsTeachersDayPercentages[ai] = cae->weightPercentage;
12938 }
12939 }
12940 }
12941
12942 return ok;
12943 }
12944
checkMinDays100Percent(QWidget * parent)12945 bool checkMinDays100Percent(QWidget* parent)
12946 {
12947 bool ok=true;
12948
12949 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
12950 daysTeacherIsAvailable[tc]=0;
12951
12952 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
12953 bool dayAvailable=false;
12954 for(int h=0; h<gt.rules.nHoursPerDay; h++)
12955 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h]){
12956 dayAvailable=true;
12957 break;
12958 }
12959
12960 if(dayAvailable)
12961 daysTeacherIsAvailable[tc]++;
12962 }
12963
12964 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){ //it has compulsory 100% weight
12965 assert(teachersMaxDaysPerWeekWeightPercentages[tc]==100);
12966 daysTeacherIsAvailable[tc]=min(daysTeacherIsAvailable[tc], teachersMaxDaysPerWeekMaxDays[tc]);
12967 }
12968
12969 if(gt.rules.mode==MORNINGS_AFTERNOONS){
12970 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){ //it has compulsory 100% weight
12971 assert(teachersMaxRealDaysPerWeekWeightPercentages[tc]==100);
12972 daysTeacherIsAvailable[tc]=min(daysTeacherIsAvailable[tc], teachersMaxRealDaysPerWeekMaxDays[tc]);
12973 }
12974 }
12975 }
12976
12977 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
12978 daysSubgroupIsAvailable[sb]=0;
12979
12980 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
12981 bool dayAvailable=false;
12982 for(int h=0; h<gt.rules.nHoursPerDay; h++)
12983 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sb][d][h]){
12984 dayAvailable=true;
12985 break;
12986 }
12987
12988 if(dayAvailable)
12989 daysSubgroupIsAvailable[sb]++;
12990 }
12991
12992 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){ //it has compulsory 100% weight
12993 assert(subgroupsMaxDaysPerWeekWeightPercentages[sb]==100);
12994 daysSubgroupIsAvailable[sb]=min(daysSubgroupIsAvailable[sb], subgroupsMaxDaysPerWeekMaxDays[sb]);
12995 }
12996
12997 if(gt.rules.mode==MORNINGS_AFTERNOONS){
12998 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0){ //it has compulsory 100% weight
12999 assert(subgroupsMaxRealDaysPerWeekWeightPercentages[sb]==100);
13000 daysSubgroupIsAvailable[sb]=min(daysSubgroupIsAvailable[sb], subgroupsMaxRealDaysPerWeekMaxDays[sb]);
13001 }
13002 }
13003 }
13004
13005 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13006 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES
13007 &>.rules.internalTimeConstraintsList[i]->weightPercentage==100.0){
13008 ConstraintMinDaysBetweenActivities* md=(ConstraintMinDaysBetweenActivities*)gt.rules.internalTimeConstraintsList[i];
13009
13010 if(md->minDays>=1){
13011 int na=md->_n_activities;
13012 int nd=md->minDays;
13013 if((na-1)*nd+1 > gt.rules.nDaysPerWeek){
13014 ok=false;
13015
13016 QString s=GeneratePreTranslate::tr("%1 cannot be respected because it contains %2 activities,"
13017 " has weight 100% and has min number of days between activities=%3. The minimum required number of days per week for"
13018 " that would be (nactivities-1)*mindays+1=%4, and you have only %5 days per week - impossible. Please correct this constraint.", "%1 is the detailed description of a constraint"
13019 )
13020 .arg(md->getDetailedDescription(gt.rules))
13021 .arg(na)
13022 .arg(nd)
13023 .arg((na-1)*nd+1)
13024 .arg(gt.rules.nDaysPerWeek)
13025 ;
13026
13027 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
13028 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13029 1, 0 );
13030
13031 if(t==0)
13032 return ok;
13033 }
13034 }
13035
13036 if(md->minDays>=1){
13037 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++)
13038 requestedDaysForTeachers[tc]=0;
13039 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++)
13040 requestedDaysForSubgroups[sb]=0;
13041
13042 for(int j=0; j<md->_n_activities; j++){
13043 int ai=md->_activities[j];
13044 for(int k=0; k<gt.rules.internalActivitiesList[ai].iTeachersList.count(); k++){
13045 int tc=gt.rules.internalActivitiesList[ai].iTeachersList.at(k);
13046 requestedDaysForTeachers[tc]++;
13047 }
13048 for(int k=0; k<gt.rules.internalActivitiesList[ai].iSubgroupsList.count(); k++){
13049 int sb=gt.rules.internalActivitiesList[ai].iSubgroupsList.at(k);
13050 requestedDaysForSubgroups[sb]++;
13051 }
13052 }
13053 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++)
13054 if(requestedDaysForTeachers[tc]>daysTeacherIsAvailable[tc]){
13055 ok=false;
13056
13057 QString s=GeneratePreTranslate::tr("%1 cannot be respected because teacher %2 has at most"
13058 " %3 available days from teacher not available, breaks and teacher max days per week."
13059 " Please lower the weight of this constraint to a value below 100% (it depends"
13060 " on your situation, if 0% is too little, make it 90%, 95% or even 99.75%."
13061 " Even a large weight should not slow down much the program."
13062 " A situation where you may need to make it larger than 0% is for instance if you have 5 activities with 4"
13063 " possible days. You want to spread them 1, 1, 1 and 2, not 2, 2 and 1)", "%1 is the detailed description of a constraint"
13064 )
13065 .arg(md->getDetailedDescription(gt.rules))
13066 .arg(gt.rules.internalTeachersList[tc]->name)
13067 .arg(daysTeacherIsAvailable[tc]);
13068
13069 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
13070 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13071 1, 0 );
13072
13073 if(t==0)
13074 return ok;
13075 }
13076 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++)
13077 if(requestedDaysForSubgroups[sb]>daysSubgroupIsAvailable[sb]){
13078 ok=false;
13079
13080 QString s=GeneratePreTranslate::tr("%1 cannot be respected because subgroup %2 has at most"
13081 " %3 available days from students set not available and breaks."
13082 " Please lower the weight of this constraint to a value below 100% (it depends"
13083 " on your situation, if 0% is too little, make it 90%, 95% or even 99.75%."
13084 " Even a large weight should not slow down much the program."
13085 " A situation where you may need to make it larger than 0% is for instance if you have 5 activities with 4"
13086 " possible days. You want to spread them 1, 1, 1 and 2, not 2, 2 and 1)", "%1 is the detailed description of a constraint"
13087 )
13088 .arg(md->getDetailedDescription(gt.rules))
13089 .arg(gt.rules.internalSubgroupsList[sb]->name)
13090 .arg(daysSubgroupIsAvailable[sb]);
13091
13092 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
13093 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13094 1, 0 );
13095
13096 if(t==0)
13097 return ok;
13098 }
13099 }
13100 }
13101 }
13102
13103 return ok;
13104 }
13105
checkMinDaysConsecutiveIfSameDay(QWidget * parent)13106 bool checkMinDaysConsecutiveIfSameDay(QWidget* parent)
13107 {
13108 bool ok=true;
13109
13110 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
13111 daysTeacherIsAvailable[tc]=0;
13112
13113 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
13114 bool dayAvailable=false;
13115 for(int h=0; h<gt.rules.nHoursPerDay; h++)
13116 if(!breakDayHour[d][h] && !teacherNotAvailableDayHour[tc][d][h]){
13117 dayAvailable=true;
13118 break;
13119 }
13120
13121 if(dayAvailable)
13122 daysTeacherIsAvailable[tc]++;
13123 }
13124
13125 if(teachersMaxDaysPerWeekMaxDays[tc]>=0){ //it has compulsory 100% weight
13126 assert(teachersMaxDaysPerWeekWeightPercentages[tc]==100);
13127 daysTeacherIsAvailable[tc]=min(daysTeacherIsAvailable[tc], teachersMaxDaysPerWeekMaxDays[tc]);
13128 }
13129
13130 if(gt.rules.mode==MORNINGS_AFTERNOONS){
13131 if(teachersMaxRealDaysPerWeekMaxDays[tc]>=0){ //it has compulsory 100% weight
13132 assert(teachersMaxRealDaysPerWeekWeightPercentages[tc]==100);
13133 daysTeacherIsAvailable[tc]=min(daysTeacherIsAvailable[tc], teachersMaxRealDaysPerWeekMaxDays[tc]);
13134 }
13135 }
13136 }
13137
13138 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
13139 daysSubgroupIsAvailable[sb]=0;
13140
13141 for(int d=0; d<gt.rules.nDaysPerWeek; d++){
13142 bool dayAvailable=false;
13143 for(int h=0; h<gt.rules.nHoursPerDay; h++)
13144 if(!breakDayHour[d][h] && !subgroupNotAvailableDayHour[sb][d][h]){
13145 dayAvailable=true;
13146 break;
13147 }
13148
13149 if(dayAvailable)
13150 daysSubgroupIsAvailable[sb]++;
13151 }
13152
13153 if(subgroupsMaxDaysPerWeekMaxDays[sb]>=0){ //it has compulsory 100% weight
13154 assert(subgroupsMaxDaysPerWeekWeightPercentages[sb]==100);
13155 daysSubgroupIsAvailable[sb]=min(daysSubgroupIsAvailable[sb], subgroupsMaxDaysPerWeekMaxDays[sb]);
13156 }
13157
13158 if(gt.rules.mode==MORNINGS_AFTERNOONS){
13159 if(subgroupsMaxRealDaysPerWeekMaxDays[sb]>=0){ //it has compulsory 100% weight
13160 assert(subgroupsMaxRealDaysPerWeekWeightPercentages[sb]==100);
13161 daysSubgroupIsAvailable[sb]=min(daysSubgroupIsAvailable[sb], subgroupsMaxRealDaysPerWeekMaxDays[sb]);
13162 }
13163 }
13164 }
13165
13166 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13167 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MIN_DAYS_BETWEEN_ACTIVITIES){
13168 ConstraintMinDaysBetweenActivities* md=(ConstraintMinDaysBetweenActivities*)gt.rules.internalTimeConstraintsList[i];
13169 if(md->consecutiveIfSameDay){
13170 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++)
13171 nReqForTeacher[tc]=0;
13172 for(int j=0; j<md->_n_activities; j++){
13173 int ai=md->_activities[j];
13174 for(int k=0; k<gt.rules.internalActivitiesList[ai].iTeachersList.count(); k++){
13175 int tc=gt.rules.internalActivitiesList[ai].iTeachersList.at(k);
13176 nReqForTeacher[tc]++;
13177 }
13178 }
13179
13180 for(int tc=0; tc<gt.rules.nInternalTeachers; tc++){
13181 if(2*daysTeacherIsAvailable[tc] < nReqForTeacher[tc]){
13182 ok=false;
13183
13184 QString s=GeneratePreTranslate::tr("%1 cannot be respected because teacher %2 has at most"
13185 " %3 available days. You specified for this constraint consecutive if same day=true."
13186 " Currently FET cannot put more than 2 activities in the same day"
13187 " if consecutive if same day is true. You have 2*available days<number of activities in this constraint."
13188 " This is a very unlikely situation, that is why I didn't care too much about it."
13189 " If you encounter it, please please modify your file (uncheck consecutive if same day"
13190 " or add other activities with larger duration).", "%1 is the detailed description of a constraint"
13191 )
13192 .arg(md->getDetailedDescription(gt.rules))
13193 .arg(gt.rules.internalTeachersList[tc]->name)
13194 .arg(daysTeacherIsAvailable[tc]);
13195
13196 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
13197 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13198 1, 0 );
13199
13200 if(t==0)
13201 return ok;
13202 }
13203 }
13204
13205 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++)
13206 nReqForSubgroup[sb]=0;
13207 for(int j=0; j<md->_n_activities; j++){
13208 int ai=md->_activities[j];
13209 for(int k=0; k<gt.rules.internalActivitiesList[ai].iSubgroupsList.count(); k++){
13210 int sb=gt.rules.internalActivitiesList[ai].iSubgroupsList.at(k);
13211 nReqForSubgroup[sb]++;
13212 }
13213 }
13214
13215 for(int sb=0; sb<gt.rules.nInternalSubgroups; sb++){
13216 if(2*daysSubgroupIsAvailable[sb] < nReqForSubgroup[sb]){
13217 ok=false;
13218
13219 QString s=GeneratePreTranslate::tr("%1 cannot be respected because subgroup %2 has at most"
13220 " %3 available days. You specified for this constraint consecutive if same day=true."
13221 " Currently FET cannot put more than 2 activities in the same day"
13222 " if consecutive if same day is true. You have 2*available days<number of activities in this constraint."
13223 " This is a very unlikely situation, that is why I didn't care too much about it."
13224 " If you encounter it, please modify your file (uncheck consecutive if same day"
13225 " or add other activities with larger duration).", "%1 is the detailed description of a constraint"
13226 )
13227 .arg(md->getDetailedDescription(gt.rules))
13228 .arg(gt.rules.internalSubgroupsList[sb]->name)
13229 .arg(daysSubgroupIsAvailable[sb]);
13230
13231 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
13232 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13233 1, 0 );
13234
13235 if(t==0)
13236 return ok;
13237 }
13238 }
13239 }
13240 }
13241 }
13242
13243 return ok;
13244 }
13245
computeTeachersIntervalMaxDaysPerWeek(QWidget * parent)13246 bool computeTeachersIntervalMaxDaysPerWeek(QWidget* parent)
13247 {
13248 for(int i=0; i<gt.rules.nInternalTeachers; i++){
13249 teachersIntervalMaxDaysPerWeekPercentages[i].clear();
13250 teachersIntervalMaxDaysPerWeekMaxDays[i].clear();
13251 teachersIntervalMaxDaysPerWeekIntervalStart[i].clear();
13252 teachersIntervalMaxDaysPerWeekIntervalEnd[i].clear();
13253 }
13254
13255 bool ok=true;
13256 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13257 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_INTERVAL_MAX_DAYS_PER_WEEK){
13258 ConstraintTeacherIntervalMaxDaysPerWeek* tn=(ConstraintTeacherIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13259
13260 if(tn->weightPercentage!=100){
13261 ok=false;
13262
13263 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13264 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher interval max days per week with"
13265 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.6.2 it is only possible"
13266 " to use 100% weight for such constraints. Please make weight 100% and try again")
13267 .arg(tn->teacherName),
13268 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13269 1, 0 );
13270
13271 if(t==0)
13272 return false;
13273 }
13274
13275 bool exists=false;
13276 for(int j=0; j<teachersIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].count(); j++)
13277 if(teachersIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].at(j)==tn->weightPercentage &&
13278 teachersIntervalMaxDaysPerWeekMaxDays[tn->teacher_ID].at(j)==tn->maxDaysPerWeek &&
13279 teachersIntervalMaxDaysPerWeekIntervalStart[tn->teacher_ID].at(j)==tn->startHour &&
13280 teachersIntervalMaxDaysPerWeekIntervalEnd[tn->teacher_ID].at(j)==tn->endHour){
13281 exists=true;
13282 break;
13283 }
13284
13285 if(!exists){
13286 teachersIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].append(tn->weightPercentage);
13287 teachersIntervalMaxDaysPerWeekMaxDays[tn->teacher_ID].append(tn->maxDaysPerWeek);
13288 teachersIntervalMaxDaysPerWeekIntervalStart[tn->teacher_ID].append(tn->startHour);
13289 teachersIntervalMaxDaysPerWeekIntervalEnd[tn->teacher_ID].append(tn->endHour);
13290 }
13291 }
13292 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_INTERVAL_MAX_DAYS_PER_WEEK){
13293 ConstraintTeachersIntervalMaxDaysPerWeek* tn=(ConstraintTeachersIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13294
13295 if(tn->weightPercentage!=100){
13296 ok=false;
13297
13298 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13299 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers interval max days per week with"
13300 " weight (percentage) below 100. Starting with FET version 5.6.2 it is only possible"
13301 " to use 100% weight for such constraints. Please make weight 100% and try again"),
13302 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13303 1, 0 );
13304
13305 if(t==0)
13306 return false;
13307 }
13308
13309 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
13310 bool exists=false;
13311 for(int j=0; j<teachersIntervalMaxDaysPerWeekPercentages[tch].count(); j++)
13312 if(teachersIntervalMaxDaysPerWeekPercentages[tch].at(j)==tn->weightPercentage &&
13313 teachersIntervalMaxDaysPerWeekMaxDays[tch].at(j)==tn->maxDaysPerWeek &&
13314 teachersIntervalMaxDaysPerWeekIntervalStart[tch].at(j)==tn->startHour &&
13315 teachersIntervalMaxDaysPerWeekIntervalEnd[tch].at(j)==tn->endHour){
13316 exists=true;
13317 break;
13318 }
13319
13320 if(!exists){
13321 teachersIntervalMaxDaysPerWeekPercentages[tch].append(tn->weightPercentage);
13322 teachersIntervalMaxDaysPerWeekMaxDays[tch].append(tn->maxDaysPerWeek);
13323 teachersIntervalMaxDaysPerWeekIntervalStart[tch].append(tn->startHour);
13324 teachersIntervalMaxDaysPerWeekIntervalEnd[tch].append(tn->endHour);
13325 }
13326 }
13327 }
13328 }
13329
13330 return ok;
13331 }
13332
13333 //morning
computeTeachersMorningIntervalMaxDaysPerWeek(QWidget * parent)13334 bool computeTeachersMorningIntervalMaxDaysPerWeek(QWidget* parent)
13335 {
13336 for(int i=0; i<gt.rules.nInternalTeachers; i++){
13337 teachersMorningIntervalMaxDaysPerWeekPercentages[i].clear();
13338 teachersMorningIntervalMaxDaysPerWeekMaxDays[i].clear();
13339 teachersMorningIntervalMaxDaysPerWeekIntervalStart[i].clear();
13340 teachersMorningIntervalMaxDaysPerWeekIntervalEnd[i].clear();
13341 }
13342
13343 bool ok=true;
13344 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13345 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MORNING_INTERVAL_MAX_DAYS_PER_WEEK){
13346 ConstraintTeacherMorningIntervalMaxDaysPerWeek* tn=(ConstraintTeacherMorningIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13347
13348 if(tn->weightPercentage!=100){
13349 ok=false;
13350
13351 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13352 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher morning interval max days per week with"
13353 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.6.2 it is only possible"
13354 " to use 100% weight for such constraints. Please make weight 100% and try again")
13355 .arg(tn->teacherName),
13356 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13357 1, 0 );
13358
13359 if(t==0)
13360 return false;
13361 }
13362
13363 bool exists=false;
13364 for(int j=0; j<teachersMorningIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].count(); j++)
13365 if(teachersMorningIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].at(j)==tn->weightPercentage &&
13366 teachersMorningIntervalMaxDaysPerWeekMaxDays[tn->teacher_ID].at(j)==tn->maxDaysPerWeek &&
13367 teachersMorningIntervalMaxDaysPerWeekIntervalStart[tn->teacher_ID].at(j)==tn->startHour &&
13368 teachersMorningIntervalMaxDaysPerWeekIntervalEnd[tn->teacher_ID].at(j)==tn->endHour){
13369 exists=true;
13370 break;
13371 }
13372
13373 if(!exists){
13374 teachersMorningIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].append(tn->weightPercentage);
13375 teachersMorningIntervalMaxDaysPerWeekMaxDays[tn->teacher_ID].append(tn->maxDaysPerWeek);
13376 teachersMorningIntervalMaxDaysPerWeekIntervalStart[tn->teacher_ID].append(tn->startHour);
13377 teachersMorningIntervalMaxDaysPerWeekIntervalEnd[tn->teacher_ID].append(tn->endHour);
13378 }
13379 }
13380 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MORNING_INTERVAL_MAX_DAYS_PER_WEEK){
13381 ConstraintTeachersMorningIntervalMaxDaysPerWeek* tn=(ConstraintTeachersMorningIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13382
13383 if(tn->weightPercentage!=100){
13384 ok=false;
13385
13386 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13387 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers morning interval max days per week with"
13388 " weight (percentage) below 100. Starting with FET version 5.6.2 it is only possible"
13389 " to use 100% weight for such constraints. Please make weight 100% and try again"),
13390 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13391 1, 0 );
13392
13393 if(t==0)
13394 return false;
13395 }
13396
13397 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
13398 bool exists=false;
13399 for(int j=0; j<teachersMorningIntervalMaxDaysPerWeekPercentages[tch].count(); j++)
13400 if(teachersMorningIntervalMaxDaysPerWeekPercentages[tch].at(j)==tn->weightPercentage &&
13401 teachersMorningIntervalMaxDaysPerWeekMaxDays[tch].at(j)==tn->maxDaysPerWeek &&
13402 teachersMorningIntervalMaxDaysPerWeekIntervalStart[tch].at(j)==tn->startHour &&
13403 teachersMorningIntervalMaxDaysPerWeekIntervalEnd[tch].at(j)==tn->endHour){
13404 exists=true;
13405 break;
13406 }
13407
13408 if(!exists){
13409 teachersMorningIntervalMaxDaysPerWeekPercentages[tch].append(tn->weightPercentage);
13410 teachersMorningIntervalMaxDaysPerWeekMaxDays[tch].append(tn->maxDaysPerWeek);
13411 teachersMorningIntervalMaxDaysPerWeekIntervalStart[tch].append(tn->startHour);
13412 teachersMorningIntervalMaxDaysPerWeekIntervalEnd[tch].append(tn->endHour);
13413 }
13414 }
13415 }
13416 }
13417
13418 return ok;
13419 }
13420
13421 //afternoon
computeTeachersAfternoonIntervalMaxDaysPerWeek(QWidget * parent)13422 bool computeTeachersAfternoonIntervalMaxDaysPerWeek(QWidget* parent)
13423 {
13424 for(int i=0; i<gt.rules.nInternalTeachers; i++){
13425 teachersAfternoonIntervalMaxDaysPerWeekPercentages[i].clear();
13426 teachersAfternoonIntervalMaxDaysPerWeekMaxDays[i].clear();
13427 teachersAfternoonIntervalMaxDaysPerWeekIntervalStart[i].clear();
13428 teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd[i].clear();
13429 }
13430
13431 bool ok=true;
13432 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13433 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_AFTERNOON_INTERVAL_MAX_DAYS_PER_WEEK){
13434 ConstraintTeacherAfternoonIntervalMaxDaysPerWeek* tn=(ConstraintTeacherAfternoonIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13435
13436 if(tn->weightPercentage!=100){
13437 ok=false;
13438
13439 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13440 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teacher afternoon interval max days per week with"
13441 " weight (percentage) below 100 for teacher %1. Starting with FET version 5.6.2 it is only possible"
13442 " to use 100% weight for such constraints. Please make weight 100% and try again")
13443 .arg(tn->teacherName),
13444 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13445 1, 0 );
13446
13447 if(t==0)
13448 return false;
13449 }
13450
13451 bool exists=false;
13452 for(int j=0; j<teachersAfternoonIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].count(); j++)
13453 if(teachersAfternoonIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].at(j)==tn->weightPercentage &&
13454 teachersAfternoonIntervalMaxDaysPerWeekMaxDays[tn->teacher_ID].at(j)==tn->maxDaysPerWeek &&
13455 teachersAfternoonIntervalMaxDaysPerWeekIntervalStart[tn->teacher_ID].at(j)==tn->startHour &&
13456 teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd[tn->teacher_ID].at(j)==tn->endHour){
13457 exists=true;
13458 break;
13459 }
13460
13461 if(!exists){
13462 teachersAfternoonIntervalMaxDaysPerWeekPercentages[tn->teacher_ID].append(tn->weightPercentage);
13463 teachersAfternoonIntervalMaxDaysPerWeekMaxDays[tn->teacher_ID].append(tn->maxDaysPerWeek);
13464 teachersAfternoonIntervalMaxDaysPerWeekIntervalStart[tn->teacher_ID].append(tn->startHour);
13465 teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd[tn->teacher_ID].append(tn->endHour);
13466 }
13467 }
13468 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_AFTERNOON_INTERVAL_MAX_DAYS_PER_WEEK){
13469 ConstraintTeachersAfternoonIntervalMaxDaysPerWeek* tn=(ConstraintTeachersAfternoonIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13470
13471 if(tn->weightPercentage!=100){
13472 ok=false;
13473
13474 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13475 GeneratePreTranslate::tr("Cannot optimize, because you have constraint teachers afternoon interval max days per week with"
13476 " weight (percentage) below 100. Starting with FET version 5.6.2 it is only possible"
13477 " to use 100% weight for such constraints. Please make weight 100% and try again"),
13478 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13479 1, 0 );
13480
13481 if(t==0)
13482 return false;
13483 }
13484
13485 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
13486 bool exists=false;
13487 for(int j=0; j<teachersAfternoonIntervalMaxDaysPerWeekPercentages[tch].count(); j++)
13488 if(teachersAfternoonIntervalMaxDaysPerWeekPercentages[tch].at(j)==tn->weightPercentage &&
13489 teachersAfternoonIntervalMaxDaysPerWeekMaxDays[tch].at(j)==tn->maxDaysPerWeek &&
13490 teachersAfternoonIntervalMaxDaysPerWeekIntervalStart[tch].at(j)==tn->startHour &&
13491 teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd[tch].at(j)==tn->endHour){
13492 exists=true;
13493 break;
13494 }
13495
13496 if(!exists){
13497 teachersAfternoonIntervalMaxDaysPerWeekPercentages[tch].append(tn->weightPercentage);
13498 teachersAfternoonIntervalMaxDaysPerWeekMaxDays[tch].append(tn->maxDaysPerWeek);
13499 teachersAfternoonIntervalMaxDaysPerWeekIntervalStart[tch].append(tn->startHour);
13500 teachersAfternoonIntervalMaxDaysPerWeekIntervalEnd[tch].append(tn->endHour);
13501 }
13502 }
13503 }
13504 }
13505
13506 return ok;
13507 }
13508
computeSubgroupsIntervalMaxDaysPerWeek(QWidget * parent)13509 bool computeSubgroupsIntervalMaxDaysPerWeek(QWidget* parent)
13510 {
13511 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
13512 subgroupsIntervalMaxDaysPerWeekPercentages[i].clear();
13513 subgroupsIntervalMaxDaysPerWeekMaxDays[i].clear();
13514 subgroupsIntervalMaxDaysPerWeekIntervalStart[i].clear();
13515 subgroupsIntervalMaxDaysPerWeekIntervalEnd[i].clear();
13516 }
13517
13518 bool ok=true;
13519
13520 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13521 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_INTERVAL_MAX_DAYS_PER_WEEK){
13522 ConstraintStudentsSetIntervalMaxDaysPerWeek* cn=(ConstraintStudentsSetIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13523
13524 if(cn->weightPercentage!=100){
13525 ok=false;
13526
13527 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13528 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set interval max days per week with"
13529 " weight (percentage) below 100 for students set %1. Starting with FET version 5.6.2 it is only possible"
13530 " to use 100% weight for such constraints. Please make weight 100% and try again")
13531 .arg(cn->students),
13532 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13533 1, 0 );
13534
13535 if(t==0)
13536 return false;
13537 }
13538
13539 for(int sbg : qAsConst(cn->iSubgroupsList)){
13540 bool exists=false;
13541 for(int j=0; j<subgroupsIntervalMaxDaysPerWeekPercentages[sbg].count(); j++)
13542 if(subgroupsIntervalMaxDaysPerWeekPercentages[sbg].at(j)==cn->weightPercentage &&
13543 subgroupsIntervalMaxDaysPerWeekMaxDays[sbg].at(j)==cn->maxDaysPerWeek &&
13544 subgroupsIntervalMaxDaysPerWeekIntervalStart[sbg].at(j)==cn->startHour &&
13545 subgroupsIntervalMaxDaysPerWeekIntervalEnd[sbg].at(j)==cn->endHour){
13546 exists=true;
13547 break;
13548 }
13549
13550 if(!exists){
13551 subgroupsIntervalMaxDaysPerWeekPercentages[sbg].append(cn->weightPercentage);
13552 subgroupsIntervalMaxDaysPerWeekMaxDays[sbg].append(cn->maxDaysPerWeek);
13553 subgroupsIntervalMaxDaysPerWeekIntervalStart[sbg].append(cn->startHour);
13554 subgroupsIntervalMaxDaysPerWeekIntervalEnd[sbg].append(cn->endHour);
13555 }
13556 }
13557 }
13558 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_INTERVAL_MAX_DAYS_PER_WEEK){
13559 ConstraintStudentsIntervalMaxDaysPerWeek* cn=(ConstraintStudentsIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13560
13561 if(cn->weightPercentage!=100){
13562 ok=false;
13563
13564 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13565 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students interval max days per week with"
13566 " weight (percentage) below 100. Starting with FET version 5.6.2 it is only possible"
13567 " to use 100% weight for such constraints. Please make weight 100% and try again")
13568 //.arg(cn->students),
13569 ,
13570 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13571 1, 0 );
13572
13573 if(t==0)
13574 return false;
13575 }
13576
13577 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
13578 bool exists=false;
13579 for(int j=0; j<subgroupsIntervalMaxDaysPerWeekPercentages[sbg].count(); j++)
13580 if(subgroupsIntervalMaxDaysPerWeekPercentages[sbg].at(j)==cn->weightPercentage &&
13581 subgroupsIntervalMaxDaysPerWeekMaxDays[sbg].at(j)==cn->maxDaysPerWeek &&
13582 subgroupsIntervalMaxDaysPerWeekIntervalStart[sbg].at(j)==cn->startHour &&
13583 subgroupsIntervalMaxDaysPerWeekIntervalEnd[sbg].at(j)==cn->endHour){
13584 exists=true;
13585 break;
13586 }
13587
13588 if(!exists){
13589 subgroupsIntervalMaxDaysPerWeekPercentages[sbg].append(cn->weightPercentage);
13590 subgroupsIntervalMaxDaysPerWeekMaxDays[sbg].append(cn->maxDaysPerWeek);
13591 subgroupsIntervalMaxDaysPerWeekIntervalStart[sbg].append(cn->startHour);
13592 subgroupsIntervalMaxDaysPerWeekIntervalEnd[sbg].append(cn->endHour);
13593 }
13594 }
13595 }
13596 }
13597
13598 return ok;
13599 }
13600
computeSubgroupsMorningIntervalMaxDaysPerWeek(QWidget * parent)13601 bool computeSubgroupsMorningIntervalMaxDaysPerWeek(QWidget* parent)
13602 {
13603 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
13604 subgroupsMorningIntervalMaxDaysPerWeekPercentages[i].clear();
13605 subgroupsMorningIntervalMaxDaysPerWeekMaxDays[i].clear();
13606 subgroupsMorningIntervalMaxDaysPerWeekIntervalStart[i].clear();
13607 subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd[i].clear();
13608 }
13609
13610 bool ok=true;
13611
13612 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13613 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MORNING_INTERVAL_MAX_DAYS_PER_WEEK){
13614 ConstraintStudentsSetMorningIntervalMaxDaysPerWeek* cn=(ConstraintStudentsSetMorningIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13615
13616 if(cn->weightPercentage!=100){
13617 ok=false;
13618
13619 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13620 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set morning interval max days per week with"
13621 " weight (percentage) below 100 for students set %1. Please make weight 100% and try again")
13622 .arg(cn->students),
13623 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13624 1, 0 );
13625
13626 if(t==0)
13627 return false;
13628 }
13629
13630 for(int sbg : qAsConst(cn->iSubgroupsList)){
13631 bool exists=false;
13632 for(int j=0; j<subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].count(); j++)
13633 if(subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].at(j)==cn->weightPercentage &&
13634 subgroupsMorningIntervalMaxDaysPerWeekMaxDays[sbg].at(j)==cn->maxDaysPerWeek &&
13635 subgroupsMorningIntervalMaxDaysPerWeekIntervalStart[sbg].at(j)==cn->startHour &&
13636 subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd[sbg].at(j)==cn->endHour){
13637 exists=true;
13638 break;
13639 }
13640
13641 if(!exists){
13642 subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].append(cn->weightPercentage);
13643 subgroupsMorningIntervalMaxDaysPerWeekMaxDays[sbg].append(cn->maxDaysPerWeek);
13644 subgroupsMorningIntervalMaxDaysPerWeekIntervalStart[sbg].append(cn->startHour);
13645 subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd[sbg].append(cn->endHour);
13646 }
13647 }
13648 }
13649 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MORNING_INTERVAL_MAX_DAYS_PER_WEEK){
13650 ConstraintStudentsMorningIntervalMaxDaysPerWeek* cn=(ConstraintStudentsMorningIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13651
13652 if(cn->weightPercentage!=100){
13653 ok=false;
13654
13655 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13656 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students morning interval max days per week with"
13657 " weight (percentage) below 100. Please make weight 100% and try again")
13658 //.arg(cn->students),
13659 ,
13660 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13661 1, 0 );
13662
13663 if(t==0)
13664 return false;
13665 }
13666
13667 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
13668 bool exists=false;
13669 for(int j=0; j<subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].count(); j++)
13670 if(subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].at(j)==cn->weightPercentage &&
13671 subgroupsMorningIntervalMaxDaysPerWeekMaxDays[sbg].at(j)==cn->maxDaysPerWeek &&
13672 subgroupsMorningIntervalMaxDaysPerWeekIntervalStart[sbg].at(j)==cn->startHour &&
13673 subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd[sbg].at(j)==cn->endHour){
13674 exists=true;
13675 break;
13676 }
13677
13678 if(!exists){
13679 subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].append(cn->weightPercentage);
13680 subgroupsMorningIntervalMaxDaysPerWeekMaxDays[sbg].append(cn->maxDaysPerWeek);
13681 subgroupsMorningIntervalMaxDaysPerWeekIntervalStart[sbg].append(cn->startHour);
13682 subgroupsMorningIntervalMaxDaysPerWeekIntervalEnd[sbg].append(cn->endHour);
13683 }
13684 }
13685 }
13686 }
13687
13688 return ok;
13689 }
13690
computeSubgroupsAfternoonIntervalMaxDaysPerWeek(QWidget * parent)13691 bool computeSubgroupsAfternoonIntervalMaxDaysPerWeek(QWidget* parent)
13692 {
13693 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
13694 subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[i].clear();
13695 subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays[i].clear();
13696 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart[i].clear();
13697 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd[i].clear();
13698 }
13699
13700 bool ok=true;
13701
13702 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13703 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_AFTERNOON_INTERVAL_MAX_DAYS_PER_WEEK){
13704 ConstraintStudentsSetAfternoonIntervalMaxDaysPerWeek* cn=(ConstraintStudentsSetAfternoonIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13705
13706 if(cn->weightPercentage!=100){
13707 ok=false;
13708
13709 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13710 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students set afternoon interval max days per week with"
13711 " weight (percentage) below 100 for students set %1. Please make weight 100% and try again")
13712 .arg(cn->students),
13713 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13714 1, 0 );
13715
13716 if(t==0)
13717 return false;
13718 }
13719
13720 for(int sbg : qAsConst(cn->iSubgroupsList)){
13721 bool exists=false;
13722 for(int j=0; j<subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].count(); j++)
13723 if(subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].at(j)==cn->weightPercentage &&
13724 subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays[sbg].at(j)==cn->maxDaysPerWeek &&
13725 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart[sbg].at(j)==cn->startHour &&
13726 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd[sbg].at(j)==cn->endHour){
13727 exists=true;
13728 break;
13729 }
13730
13731 if(!exists){
13732 subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].append(cn->weightPercentage);
13733 subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays[sbg].append(cn->maxDaysPerWeek);
13734 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart[sbg].append(cn->startHour);
13735 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd[sbg].append(cn->endHour);
13736 }
13737 }
13738 }
13739 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_AFTERNOON_INTERVAL_MAX_DAYS_PER_WEEK){
13740 ConstraintStudentsAfternoonIntervalMaxDaysPerWeek* cn=(ConstraintStudentsAfternoonIntervalMaxDaysPerWeek*)gt.rules.internalTimeConstraintsList[i];
13741
13742 if(cn->weightPercentage!=100){
13743 ok=false;
13744
13745 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13746 GeneratePreTranslate::tr("Cannot optimize, because you have constraint students afternoon interval max days per week with"
13747 " weight (percentage) below 100. Please make weight 100% and try again")
13748 //.arg(cn->students),
13749 ,
13750 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13751 1, 0 );
13752
13753 if(t==0)
13754 return false;
13755 }
13756
13757 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
13758 bool exists=false;
13759 for(int j=0; j<subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].count(); j++)
13760 if(subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].at(j)==cn->weightPercentage &&
13761 subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays[sbg].at(j)==cn->maxDaysPerWeek &&
13762 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart[sbg].at(j)==cn->startHour &&
13763 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd[sbg].at(j)==cn->endHour){
13764 exists=true;
13765 break;
13766 }
13767
13768 if(!exists){
13769 subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].append(cn->weightPercentage);
13770 subgroupsAfternoonIntervalMaxDaysPerWeekMaxDays[sbg].append(cn->maxDaysPerWeek);
13771 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalStart[sbg].append(cn->startHour);
13772 subgroupsAfternoonIntervalMaxDaysPerWeekIntervalEnd[sbg].append(cn->endHour);
13773 }
13774 }
13775 }
13776 }
13777
13778 return ok;
13779 }
13780
13781 //2011-09-25
computeActivitiesOccupyMaxTimeSlotsFromSelection(QWidget * parent)13782 bool computeActivitiesOccupyMaxTimeSlotsFromSelection(QWidget* parent)
13783 {
13784 haveActivitiesOccupyMaxConstraints=false;
13785
13786 bool ok=true;
13787
13788 aomtsList.clear();
13789 for(int i=0; i<gt.rules.nInternalActivities; i++){
13790 aomtsListForActivity[i].clear();
13791 activityHasOccupyMaxConstraints[i]=false;
13792 }
13793
13794 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13795 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_OCCUPY_MAX_TIME_SLOTS_FROM_SELECTION){
13796 if(!haveActivitiesOccupyMaxConstraints)
13797 haveActivitiesOccupyMaxConstraints=true;
13798
13799 ConstraintActivitiesOccupyMaxTimeSlotsFromSelection* cn=(ConstraintActivitiesOccupyMaxTimeSlotsFromSelection*)gt.rules.internalTimeConstraintsList[i];
13800
13801 if(cn->weightPercentage!=100.0){
13802 ok=false;
13803
13804 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13805 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities occupy max time slots from selection'"
13806 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
13807 ,
13808 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13809 1, 0 );
13810
13811 if(t==0)
13812 return false;
13813 }
13814
13815 ActivitiesOccupyMaxTimeSlotsFromSelection_item item;
13816 item.activitiesList=cn->_activitiesIndices;
13817 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
13818 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
13819 #else
13820 item.activitiesSet=item.activitiesList.toSet();
13821 #endif
13822 item.maxOccupiedTimeSlots=cn->maxOccupiedTimeSlots;
13823 for(int t=0; t < cn->selectedDays.count(); t++)
13824 item.selectedTimeSlotsList.append(cn->selectedDays.at(t)+cn->selectedHours.at(t)*gt.rules.nDaysPerWeek);
13825 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
13826 item.selectedTimeSlotsSet=QSet<int>(item.selectedTimeSlotsList.begin(), item.selectedTimeSlotsList.end());
13827 #else
13828 item.selectedTimeSlotsSet=item.selectedTimeSlotsList.toSet();
13829 #endif
13830
13831 aomtsList.push_back(item);
13832 //ActivitiesOccupyMaxTimeSlotsFromSelection_item* p_item=&aomtsList[aomtsList.count()-1];
13833 ActivitiesOccupyMaxTimeSlotsFromSelection_item* p_item=&aomtsList.back();
13834 for(int ai : qAsConst(cn->_activitiesIndices)){
13835 aomtsListForActivity[ai].append(p_item);
13836
13837 if(activityHasOccupyMaxConstraints[ai]==false)
13838 activityHasOccupyMaxConstraints[ai]=true;
13839 }
13840 }
13841 }
13842
13843 return ok;
13844 }
13845
13846 //2019-11-16
computeActivitiesOccupyMinTimeSlotsFromSelection(QWidget * parent)13847 bool computeActivitiesOccupyMinTimeSlotsFromSelection(QWidget* parent)
13848 {
13849 bool ok=true;
13850
13851 aomintsList.clear();
13852 for(int i=0; i<gt.rules.nInternalActivities; i++)
13853 aomintsListForActivity[i].clear();
13854
13855 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13856 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_OCCUPY_MIN_TIME_SLOTS_FROM_SELECTION){
13857 ConstraintActivitiesOccupyMinTimeSlotsFromSelection* cn=(ConstraintActivitiesOccupyMinTimeSlotsFromSelection*)gt.rules.internalTimeConstraintsList[i];
13858
13859 if(cn->weightPercentage!=100.0){
13860 ok=false;
13861
13862 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13863 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities occupy min time slots from selection'"
13864 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
13865 ,
13866 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13867 1, 0 );
13868
13869 if(t==0)
13870 return false;
13871 }
13872
13873 if(cn->selectedDays.count() < cn->minOccupiedTimeSlots){
13874 ok=false;
13875
13876 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13877 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint of type 'activities occupy min time slots from selection'"
13878 " with the number of selected slots being %1, but the number of requested minimum slots is %2, which is greater - impossible. The constraint is:\n"
13879 "%3\nPlease correct and try again.")
13880 .arg(cn->selectedDays.count())
13881 .arg(cn->minOccupiedTimeSlots)
13882 .arg(cn->getDetailedDescription(gt.rules))
13883 ,
13884 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13885 1, 0 );
13886
13887 if(t==0)
13888 return false;
13889 }
13890
13891 int totalDuration=0;
13892 for(int ai : qAsConst(cn->_activitiesIndices))
13893 totalDuration+=gt.rules.internalActivitiesList[ai].duration;
13894 if(totalDuration < cn->minOccupiedTimeSlots){
13895 ok=false;
13896
13897 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13898 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint of type 'activities occupy min time slots from selection'"
13899 " with the total duration of the selected activities being %1, but the number of requested minimum slots is %2, which is greater - impossible."
13900 " The constraint is:\n%3\nPlease correct and try again.")
13901 .arg(totalDuration)
13902 .arg(cn->minOccupiedTimeSlots)
13903 .arg(cn->getDetailedDescription(gt.rules))
13904 ,
13905 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13906 1, 0 );
13907
13908 if(t==0)
13909 return false;
13910 }
13911
13912 ActivitiesOccupyMinTimeSlotsFromSelection_item item;
13913 item.activitiesList=cn->_activitiesIndices;
13914 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
13915 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
13916 #else
13917 item.activitiesSet=item.activitiesList.toSet();
13918 #endif
13919 item.minOccupiedTimeSlots=cn->minOccupiedTimeSlots;
13920 for(int t=0; t < cn->selectedDays.count(); t++)
13921 item.selectedTimeSlotsList.append(cn->selectedDays.at(t)+cn->selectedHours.at(t)*gt.rules.nDaysPerWeek);
13922 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
13923 item.selectedTimeSlotsSet=QSet<int>(item.selectedTimeSlotsList.begin(), item.selectedTimeSlotsList.end());
13924 #else
13925 item.selectedTimeSlotsSet=item.selectedTimeSlotsList.toSet();
13926 #endif
13927
13928 aomintsList.push_back(item);
13929 //ActivitiesOccupyMinTimeSlotsFromSelection_item* p_item=&aomintsList[aomintsList.count()-1];
13930 ActivitiesOccupyMinTimeSlotsFromSelection_item* p_item=&aomintsList.back();
13931 for(int ai : qAsConst(cn->_activitiesIndices))
13932 aomintsListForActivity[ai].append(p_item);
13933 }
13934 }
13935
13936 return ok;
13937 }
13938
13939 //2011-09-30
computeActivitiesMaxSimultaneousInSelectedTimeSlots(QWidget * parent)13940 bool computeActivitiesMaxSimultaneousInSelectedTimeSlots(QWidget* parent)
13941 {
13942 haveActivitiesMaxSimultaneousConstraints=false;
13943
13944 bool ok=true;
13945
13946 amsistsList.clear();
13947 for(int i=0; i<gt.rules.nInternalActivities; i++){
13948 amsistsListForActivity[i].clear();
13949 activityHasMaxSimultaneousConstraints[i]=false;
13950 }
13951
13952 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
13953 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_MAX_SIMULTANEOUS_IN_SELECTED_TIME_SLOTS){
13954 if(!haveActivitiesMaxSimultaneousConstraints)
13955 haveActivitiesMaxSimultaneousConstraints=true;
13956
13957 ConstraintActivitiesMaxSimultaneousInSelectedTimeSlots* cn=(ConstraintActivitiesMaxSimultaneousInSelectedTimeSlots*)gt.rules.internalTimeConstraintsList[i];
13958
13959 if(cn->weightPercentage!=100.0){
13960 ok=false;
13961
13962 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
13963 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities max simultaneous in selected time slots'"
13964 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
13965 ,
13966 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
13967 1, 0 );
13968
13969 if(t==0)
13970 return false;
13971 }
13972
13973 ActivitiesMaxSimultaneousInSelectedTimeSlots_item item;
13974 item.activitiesList=cn->_activitiesIndices;
13975 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
13976 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
13977 #else
13978 item.activitiesSet=item.activitiesList.toSet();
13979 #endif
13980 item.maxSimultaneous=cn->maxSimultaneous;
13981 for(int t=0; t < cn->selectedDays.count(); t++)
13982 item.selectedTimeSlotsList.append(cn->selectedDays.at(t)+cn->selectedHours.at(t)*gt.rules.nDaysPerWeek);
13983 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
13984 item.selectedTimeSlotsSet=QSet<int>(item.selectedTimeSlotsList.begin(), item.selectedTimeSlotsList.end());
13985 #else
13986 item.selectedTimeSlotsSet=item.selectedTimeSlotsList.toSet();
13987 #endif
13988
13989 amsistsList.push_back(item);
13990 //ActivitiesMaxSimultaneousInSelectedTimeSlots_item* p_item=&amsistsList[amsistsList.count()-1];
13991 ActivitiesMaxSimultaneousInSelectedTimeSlots_item* p_item=&amsistsList.back();
13992 for(int ai : qAsConst(cn->_activitiesIndices)){
13993 amsistsListForActivity[ai].append(p_item);
13994
13995 if(activityHasMaxSimultaneousConstraints[ai]==false)
13996 activityHasMaxSimultaneousConstraints[ai]=true;
13997 }
13998 }
13999 }
14000
14001 return ok;
14002 }
14003
14004 //2019-11-16
computeActivitiesMinSimultaneousInSelectedTimeSlots(QWidget * parent)14005 bool computeActivitiesMinSimultaneousInSelectedTimeSlots(QWidget* parent)
14006 {
14007 bool ok=true;
14008
14009 aminsistsList.clear();
14010 for(int i=0; i<gt.rules.nInternalActivities; i++)
14011 aminsistsListForActivity[i].clear();
14012
14013 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
14014 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_MIN_SIMULTANEOUS_IN_SELECTED_TIME_SLOTS){
14015 ConstraintActivitiesMinSimultaneousInSelectedTimeSlots* cn=(ConstraintActivitiesMinSimultaneousInSelectedTimeSlots*)gt.rules.internalTimeConstraintsList[i];
14016
14017 if(cn->weightPercentage!=100.0){
14018 ok=false;
14019
14020 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14021 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities min simultaneous in selected time slots'"
14022 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14023 ,
14024 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14025 1, 0 );
14026
14027 if(t==0)
14028 return false;
14029 }
14030
14031 if(!cn->allowEmptySlots){
14032 int totalDuration=0;
14033 for(int ai : qAsConst(cn->_activitiesIndices))
14034 totalDuration+=gt.rules.internalActivitiesList[ai].duration;
14035 if(totalDuration < cn->minSimultaneous*cn->selectedDays.count()){
14036 ok=false;
14037
14038 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14039 GeneratePreTranslate::tr("Cannot optimize, because you have a constraint of type 'activities min simultaneous in selected time slots'"
14040 " with the total duration of the selected activities being %1, but the required number of occupying slots is"
14041 " %2 (minimum simultaneous) x %3 (selected slots) = %4, which is greater - impossible (the constraint does not allow empty slots)."
14042 " The constraint is:\n%5\nPlease correct and try again.")
14043 .arg(totalDuration)
14044 .arg(cn->minSimultaneous)
14045 .arg(cn->selectedDays.count())
14046 .arg(cn->minSimultaneous*cn->selectedDays.count())
14047 .arg(cn->getDetailedDescription(gt.rules))
14048 ,
14049 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14050 1, 0 );
14051
14052 if(t==0)
14053 return false;
14054 }
14055 }
14056
14057 ActivitiesMinSimultaneousInSelectedTimeSlots_item item;
14058 item.activitiesList=cn->_activitiesIndices;
14059 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14060 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
14061 #else
14062 item.activitiesSet=item.activitiesList.toSet();
14063 #endif
14064 item.minSimultaneous=cn->minSimultaneous;
14065 for(int t=0; t < cn->selectedDays.count(); t++)
14066 item.selectedTimeSlotsList.append(cn->selectedDays.at(t)+cn->selectedHours.at(t)*gt.rules.nDaysPerWeek);
14067 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14068 item.selectedTimeSlotsSet=QSet<int>(item.selectedTimeSlotsList.begin(), item.selectedTimeSlotsList.end());
14069 #else
14070 item.selectedTimeSlotsSet=item.selectedTimeSlotsList.toSet();
14071 #endif
14072 item.allowEmptySlots=cn->allowEmptySlots;
14073
14074 aminsistsList.push_back(item);
14075 //ActivitiesMinSimultaneousInSelectedTimeSlots_item* p_item=&aminsistsList[aminsistsList.count()-1];
14076 ActivitiesMinSimultaneousInSelectedTimeSlots_item* p_item=&aminsistsList.back();
14077 for(int ai : qAsConst(cn->_activitiesIndices))
14078 aminsistsListForActivity[ai].append(p_item);
14079 }
14080 }
14081
14082 return ok;
14083 }
14084
14085 //2020-05-02
computeActivitiesMaxTotalFromSetInSelectedTimeSlots(QWidget * parent)14086 bool computeActivitiesMaxTotalFromSetInSelectedTimeSlots(QWidget* parent)
14087 {
14088 bool ok=true;
14089
14090 amtfsistsList.clear();
14091 for(int i=0; i<gt.rules.nInternalActivities; i++)
14092 amtfsistsListForActivity[i].clear();
14093
14094 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
14095 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_MAX_TOTAL_ACTIVITIES_FROM_SET_IN_SELECTED_TIME_SLOTS){
14096 ConstraintMaxTotalActivitiesFromSetInSelectedTimeSlots* cn=(ConstraintMaxTotalActivitiesFromSetInSelectedTimeSlots*)gt.rules.internalTimeConstraintsList[i];
14097
14098 if(cn->weightPercentage!=100.0){
14099 ok=false;
14100
14101 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14102 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'max total activities from set in selected time slots'"
14103 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14104 ,
14105 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14106 1, 0 );
14107
14108 if(t==0)
14109 return false;
14110 }
14111
14112 ActivitiesMaxTotalFromSetInSelectedTimeSlots_item item;
14113 item.activitiesList=cn->_activitiesIndices;
14114 /*#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14115 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
14116 #else
14117 item.activitiesSet=item.activitiesList.toSet();
14118 #endif*/
14119 item.maxActivities=cn->maxActivities;
14120 for(int t=0; t < cn->selectedDays.count(); t++)
14121 // item.selectedTimeSlotsList.append(cn->selectedDays.at(t)+cn->selectedHours.at(t)*gt.rules.nDaysPerWeek);
14122 item.selectedTimeSlotsSet.insert(cn->selectedDays.at(t)+cn->selectedHours.at(t)*gt.rules.nDaysPerWeek);
14123 /*#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14124 item.selectedTimeSlotsSet=QSet<int>(item.selectedTimeSlotsList.begin(), item.selectedTimeSlotsList.end());
14125 #else
14126 item.selectedTimeSlotsSet=item.selectedTimeSlotsList.toSet();
14127 #endif*/
14128 // item.allowEmptySlots=cn->allowEmptySlots;
14129
14130 amtfsistsList.push_back(item);
14131 //ActivitiesMinSimultaneousInSelectedTimeSlots_item* p_item=&aminsistsList[aminsistsList.count()-1];
14132 ActivitiesMaxTotalFromSetInSelectedTimeSlots_item * p_item=&amtfsistsList.back();
14133 for(int ai : qAsConst(cn->_activitiesIndices))
14134 amtfsistsListForActivity[ai].append(p_item);
14135 }
14136 }
14137
14138 return ok;
14139 }
14140
14141 //for terms
14142 //2020-01-14
computeActivitiesMaxInATerm(QWidget * parent)14143 bool computeActivitiesMaxInATerm(QWidget* parent)
14144 {
14145 bool ok=true;
14146
14147 amiatList.clear();
14148 for(int i=0; i<gt.rules.nInternalActivities; i++){
14149 amiatListForActivity[i].clear();
14150 }
14151
14152 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
14153 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_MAX_IN_A_TERM){
14154
14155 ConstraintActivitiesMaxInATerm* cn=(ConstraintActivitiesMaxInATerm*)gt.rules.internalTimeConstraintsList[i];
14156
14157 if(cn->weightPercentage!=100.0){
14158 ok=false;
14159
14160 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14161 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities max in a term'"
14162 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14163 ,
14164 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14165 1, 0 );
14166
14167 if(t==0)
14168 return false;
14169 }
14170
14171 ActivitiesMaxInATerm_item item;
14172 item.activitiesList=cn->_activitiesIndices;
14173 item.maxActivitiesInATerm=cn->maxActivitiesInATerm;
14174
14175 amiatList.push_back(item);
14176 ActivitiesMaxInATerm_item* p_item=&amiatList.back();
14177 for(int ai : qAsConst(cn->_activitiesIndices)){
14178 amiatListForActivity[ai].append(p_item);
14179 }
14180 }
14181 }
14182
14183 return ok;
14184 }
14185
14186 //2020-01-14
computeActivitiesOccupyMaxTerms(QWidget * parent)14187 bool computeActivitiesOccupyMaxTerms(QWidget* parent)
14188 {
14189 bool ok=true;
14190
14191 aomtList.clear();
14192 for(int i=0; i<gt.rules.nInternalActivities; i++){
14193 aomtListForActivity[i].clear();
14194 }
14195
14196 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
14197 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_OCCUPY_MAX_TERMS){
14198
14199 ConstraintActivitiesOccupyMaxTerms* cn=(ConstraintActivitiesOccupyMaxTerms*)gt.rules.internalTimeConstraintsList[i];
14200
14201 if(cn->weightPercentage!=100.0){
14202 ok=false;
14203
14204 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14205 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities occupy max terms'"
14206 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14207 ,
14208 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14209 1, 0 );
14210
14211 if(t==0)
14212 return false;
14213 }
14214
14215 ActivitiesOccupyMaxTerms_item item;
14216 item.activitiesList=cn->_activitiesIndices;
14217 item.maxOccupiedTerms=cn->maxOccupiedTerms;
14218
14219 aomtList.push_back(item);
14220 ActivitiesOccupyMaxTerms_item* p_item=&aomtList.back();
14221 for(int ai : qAsConst(cn->_activitiesIndices)){
14222 aomtListForActivity[ai].append(p_item);
14223 }
14224 }
14225 }
14226
14227 return ok;
14228 }
14229
14230 //2019-06-08
computeStudentsMinGapsBetweenOrderedPairOfActivityTags(QWidget * parent)14231 bool computeStudentsMinGapsBetweenOrderedPairOfActivityTags(QWidget* parent)
14232 {
14233 bool ok=true;
14234
14235 smgbopoatList.clear();
14236 for(int i=0; i<gt.rules.nInternalActivities; i++)
14237 smgbopoatListForActivity[i].clear();
14238
14239 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
14240 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
14241 ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags* cn=(ConstraintStudentsSetMinGapsBetweenOrderedPairOfActivityTags*)gt.rules.internalTimeConstraintsList[i];
14242
14243 if(cn->weightPercentage!=100.0){
14244 ok=false;
14245
14246 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14247 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'students set min gaps between ordered pair of activity tags'"
14248 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14249 ,
14250 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14251 1, 0 );
14252
14253 if(t==0)
14254 return false;
14255 }
14256
14257 if(cn->canonicalSubgroupsList.isEmpty())
14258 continue;
14259
14260 StudentsMinGapsBetweenOrderedPairOfActivityTags_item item;
14261 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14262 item.canonicalSetOfSubgroups=QSet<int>(cn->canonicalSubgroupsList.begin(), cn->canonicalSubgroupsList.end());
14263 #else
14264 item.canonicalSetOfSubgroups=cn->canonicalSubgroupsList.toSet();
14265 #endif
14266 item.minGaps=cn->minGaps;
14267 item.firstActivityTag=cn->_firstActivityTagIndex;
14268 item.secondActivityTag=cn->_secondActivityTagIndex;
14269
14270 smgbopoatList.push_back(item);
14271 //StudentsMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&smgbopoatList[smgbopoatList.count()-1];
14272 StudentsMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&smgbopoatList.back();
14273
14274 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
14275 Activity* act=>.rules.internalActivitiesList[ai];
14276
14277 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14278 QSet<int> studentsSet(act->iSubgroupsList.begin(), act->iSubgroupsList.end());
14279 #else
14280 QSet<int> studentsSet=act->iSubgroupsList.toSet();
14281 #endif
14282 studentsSet.intersect(item.canonicalSetOfSubgroups);
14283 if(studentsSet.isEmpty())
14284 continue;
14285
14286 bool first, second;
14287
14288 if(act->iActivityTagsSet.contains(cn->_firstActivityTagIndex))
14289 first=true;
14290 else
14291 first=false;
14292
14293 if(act->iActivityTagsSet.contains(cn->_secondActivityTagIndex))
14294 second=true;
14295 else
14296 second=false;
14297
14298 if(first && second){
14299 ok=false;
14300
14301 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14302 GeneratePreTranslate::tr("Cannot optimize, because the activity with id %1 has both the first and the second activity tags"
14303 " of the constraint of type 'students set min %2 gaps between ordered pair of activity tags %3 and %4'. Please"
14304 " correct and try again.").arg(act->id).arg(cn->minGaps).arg(cn->firstActivityTag).arg(cn->secondActivityTag)
14305 ,
14306 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14307 1, 0 );
14308
14309 if(t==0)
14310 return false;
14311 }
14312 else if(first || second){
14313 smgbopoatListForActivity[ai].append(p_item);
14314 }
14315 else{
14316 //do nothing
14317 }
14318 }
14319 }
14320 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
14321 ConstraintStudentsMinGapsBetweenOrderedPairOfActivityTags* cn=(ConstraintStudentsMinGapsBetweenOrderedPairOfActivityTags*)gt.rules.internalTimeConstraintsList[i];
14322
14323 if(cn->weightPercentage!=100.0){
14324 ok=false;
14325
14326 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14327 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'students min gaps between ordered pair of activity tags'"
14328 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14329 ,
14330 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14331 1, 0 );
14332
14333 if(t==0)
14334 return false;
14335 }
14336
14337 if(cn->canonicalSubgroupsList.isEmpty())
14338 continue;
14339
14340 StudentsMinGapsBetweenOrderedPairOfActivityTags_item item;
14341 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14342 item.canonicalSetOfSubgroups=QSet<int>(cn->canonicalSubgroupsList.begin(), cn->canonicalSubgroupsList.end());
14343 #else
14344 item.canonicalSetOfSubgroups=cn->canonicalSubgroupsList.toSet();
14345 #endif
14346 item.minGaps=cn->minGaps;
14347 item.firstActivityTag=cn->_firstActivityTagIndex;
14348 item.secondActivityTag=cn->_secondActivityTagIndex;
14349
14350 smgbopoatList.push_back(item);
14351 //StudentsMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&smgbopoatList[smgbopoatList.count()-1];
14352 StudentsMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&smgbopoatList.back();
14353
14354 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
14355 Activity* act=>.rules.internalActivitiesList[ai];
14356
14357 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14358 QSet<int> studentsSet(act->iSubgroupsList.begin(), act->iSubgroupsList.end());
14359 #else
14360 QSet<int> studentsSet=act->iSubgroupsList.toSet();
14361 #endif
14362 studentsSet.intersect(item.canonicalSetOfSubgroups);
14363 if(studentsSet.isEmpty())
14364 continue;
14365
14366 bool first, second;
14367
14368 if(act->iActivityTagsSet.contains(cn->_firstActivityTagIndex))
14369 first=true;
14370 else
14371 first=false;
14372
14373 if(act->iActivityTagsSet.contains(cn->_secondActivityTagIndex))
14374 second=true;
14375 else
14376 second=false;
14377
14378 if(first && second){
14379 ok=false;
14380
14381 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14382 GeneratePreTranslate::tr("Cannot optimize, because the activity with id %1 has both the first and the second activity tags"
14383 " of the constraint of type 'students min %2 gaps between ordered pair of activity tags %3 and %4'. Please"
14384 " correct and try again.").arg(act->id).arg(cn->minGaps).arg(cn->firstActivityTag).arg(cn->secondActivityTag)
14385 ,
14386 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14387 1, 0 );
14388
14389 if(t==0)
14390 return false;
14391 }
14392 else if(first || second){
14393 smgbopoatListForActivity[ai].append(p_item);
14394 }
14395 else{
14396 //do nothing
14397 }
14398 }
14399 }
14400 }
14401
14402 return ok;
14403 }
14404
14405 //2019-06-08
computeTeachersMinGapsBetweenOrderedPairOfActivityTags(QWidget * parent)14406 bool computeTeachersMinGapsBetweenOrderedPairOfActivityTags(QWidget* parent)
14407 {
14408 bool ok=true;
14409
14410 tmgbopoatList.clear();
14411 for(int i=0; i<gt.rules.nInternalActivities; i++)
14412 tmgbopoatListForActivity[i].clear();
14413
14414 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
14415 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
14416 ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags* cn=(ConstraintTeacherMinGapsBetweenOrderedPairOfActivityTags*)gt.rules.internalTimeConstraintsList[i];
14417
14418 if(cn->weightPercentage!=100.0){
14419 ok=false;
14420
14421 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14422 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'teacher min gaps between ordered pair of activity tags'"
14423 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14424 ,
14425 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14426 1, 0 );
14427
14428 if(t==0)
14429 return false;
14430 }
14431
14432 if(cn->canonicalTeachersList.isEmpty())
14433 continue;
14434 assert(cn->canonicalTeachersList.count()==1);
14435
14436 TeachersMinGapsBetweenOrderedPairOfActivityTags_item item;
14437 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14438 item.canonicalSetOfTeachers=QSet<int>(cn->canonicalTeachersList.begin(), cn->canonicalTeachersList.end());
14439 #else
14440 item.canonicalSetOfTeachers=cn->canonicalTeachersList.toSet();
14441 #endif
14442 item.minGaps=cn->minGaps;
14443 item.firstActivityTag=cn->_firstActivityTagIndex;
14444 item.secondActivityTag=cn->_secondActivityTagIndex;
14445
14446 tmgbopoatList.push_back(item);
14447 //TeachersMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&tmgbopoatList[tmgbopoatList.count()-1];
14448 TeachersMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&tmgbopoatList.back();
14449
14450 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
14451 Activity* act=>.rules.internalActivitiesList[ai];
14452
14453 if(!act->iTeachersList.contains(cn->canonicalTeachersList.at(0)))
14454 continue;
14455
14456 bool first, second;
14457
14458 if(act->iActivityTagsSet.contains(cn->_firstActivityTagIndex))
14459 first=true;
14460 else
14461 first=false;
14462
14463 if(act->iActivityTagsSet.contains(cn->_secondActivityTagIndex))
14464 second=true;
14465 else
14466 second=false;
14467
14468 if(first && second){
14469 ok=false;
14470
14471 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14472 GeneratePreTranslate::tr("Cannot optimize, because the activity with id %1 has both the first and the second activity tags"
14473 " of the constraint of type 'teacher min %2 gaps between ordered pair of activity tags %3 and %4'. Please"
14474 " correct and try again.").arg(act->id).arg(cn->minGaps).arg(cn->firstActivityTag).arg(cn->secondActivityTag)
14475 ,
14476 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14477 1, 0 );
14478
14479 if(t==0)
14480 return false;
14481 }
14482 else if(first || second){
14483 tmgbopoatListForActivity[ai].append(p_item);
14484 }
14485 else{
14486 //do nothing
14487 }
14488 }
14489 }
14490 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_GAPS_BETWEEN_ORDERED_PAIR_OF_ACTIVITY_TAGS){
14491 ConstraintTeachersMinGapsBetweenOrderedPairOfActivityTags* cn=(ConstraintTeachersMinGapsBetweenOrderedPairOfActivityTags*)gt.rules.internalTimeConstraintsList[i];
14492
14493 if(cn->weightPercentage!=100.0){
14494 ok=false;
14495
14496 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14497 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'teachers min gaps between ordered pair of activity tags'"
14498 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14499 ,
14500 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14501 1, 0 );
14502
14503 if(t==0)
14504 return false;
14505 }
14506
14507 if(cn->canonicalTeachersList.isEmpty())
14508 continue;
14509
14510 TeachersMinGapsBetweenOrderedPairOfActivityTags_item item;
14511 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14512 item.canonicalSetOfTeachers=QSet<int>(cn->canonicalTeachersList.begin(), cn->canonicalTeachersList.end());
14513 #else
14514 item.canonicalSetOfTeachers=cn->canonicalTeachersList.toSet();
14515 #endif
14516 item.minGaps=cn->minGaps;
14517 item.firstActivityTag=cn->_firstActivityTagIndex;
14518 item.secondActivityTag=cn->_secondActivityTagIndex;
14519
14520 tmgbopoatList.push_back(item);
14521 //TeachersMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&tmgbopoatList[tmgbopoatList.count()-1];
14522 TeachersMinGapsBetweenOrderedPairOfActivityTags_item* p_item=&tmgbopoatList.back();
14523
14524 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
14525 Activity* act=>.rules.internalActivitiesList[ai];
14526
14527 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14528 QSet<int> teachersSet(act->iTeachersList.begin(), act->iTeachersList.end());
14529 #else
14530 QSet<int> teachersSet=act->iTeachersList.toSet();
14531 #endif
14532 teachersSet.intersect(item.canonicalSetOfTeachers);
14533 if(teachersSet.isEmpty())
14534 continue;
14535
14536 bool first, second;
14537
14538 if(act->iActivityTagsSet.contains(cn->_firstActivityTagIndex))
14539 first=true;
14540 else
14541 first=false;
14542
14543 if(act->iActivityTagsSet.contains(cn->_secondActivityTagIndex))
14544 second=true;
14545 else
14546 second=false;
14547
14548 if(first && second){
14549 ok=false;
14550
14551 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14552 GeneratePreTranslate::tr("Cannot optimize, because the activity with id %1 has both the first and the second activity tags"
14553 " of the constraint of type 'teachers min %2 gaps between ordered pair of activity tags %3 and %4'. Please"
14554 " correct and try again.").arg(act->id).arg(cn->minGaps).arg(cn->firstActivityTag).arg(cn->secondActivityTag)
14555 ,
14556 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14557 1, 0 );
14558
14559 if(t==0)
14560 return false;
14561 }
14562 else if(first || second){
14563 tmgbopoatListForActivity[ai].append(p_item);
14564 }
14565 else{
14566 //do nothing
14567 }
14568 }
14569 }
14570 }
14571
14572 return ok;
14573 }
14574
14575 //2012-04-29
computeActivitiesOccupyMaxDifferentRooms(QWidget * parent)14576 bool computeActivitiesOccupyMaxDifferentRooms(QWidget* parent)
14577 {
14578 bool ok=true;
14579
14580 aomdrList.clear();
14581 for(int i=0; i<gt.rules.nInternalActivities; i++)
14582 aomdrListForActivity[i].clear();
14583
14584 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
14585 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_OCCUPY_MAX_DIFFERENT_ROOMS){
14586 ConstraintActivitiesOccupyMaxDifferentRooms* cn=(ConstraintActivitiesOccupyMaxDifferentRooms*)gt.rules.internalSpaceConstraintsList[i];
14587
14588 if(cn->weightPercentage!=100.0){
14589 ok=false;
14590
14591 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14592 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities occupy max different rooms'"
14593 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14594 ,
14595 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14596 1, 0 );
14597
14598 if(t==0)
14599 return false;
14600 }
14601
14602 ActivitiesOccupyMaxDifferentRooms_item item;
14603 item.activitiesList=cn->_activitiesIndices;
14604 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14605 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
14606 #else
14607 item.activitiesSet=item.activitiesList.toSet();
14608 #endif
14609 item.maxDifferentRooms=cn->maxDifferentRooms;
14610
14611 aomdrList.push_back(item);
14612 //ActivitiesOccupyMaxDifferentRooms_item* p_item=&aomdrList[aomdrList.count()-1];
14613 ActivitiesOccupyMaxDifferentRooms_item* p_item=&aomdrList.back();
14614 for(int ai : qAsConst(cn->_activitiesIndices))
14615 aomdrListForActivity[ai].append(p_item);
14616 }
14617 }
14618
14619 return ok;
14620 }
14621
14622 //2013-09-14
computeActivitiesSameRoomIfConsecutive(QWidget * parent)14623 bool computeActivitiesSameRoomIfConsecutive(QWidget* parent)
14624 {
14625 bool ok=true;
14626
14627 asricList.clear();
14628 for(int i=0; i<gt.rules.nInternalActivities; i++)
14629 asricListForActivity[i].clear();
14630
14631 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
14632 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_SAME_ROOM_IF_CONSECUTIVE){
14633 ConstraintActivitiesSameRoomIfConsecutive* cn=(ConstraintActivitiesSameRoomIfConsecutive*)gt.rules.internalSpaceConstraintsList[i];
14634
14635 if(cn->weightPercentage!=100.0){
14636 ok=false;
14637
14638 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14639 GeneratePreTranslate::tr("Cannot optimize, because you have constraint(s) of type 'activities same room if consecutive'"
14640 " with weight (percentage) below 100.0%. Please make the weight 100.0% and try again")
14641 ,
14642 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14643 1, 0 );
14644
14645 if(t==0)
14646 return false;
14647 }
14648
14649 ActivitiesSameRoomIfConsecutive_item item;
14650 item.activitiesList=cn->_activitiesIndices;
14651 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
14652 item.activitiesSet=QSet<int>(item.activitiesList.begin(), item.activitiesList.end());
14653 #else
14654 item.activitiesSet=item.activitiesList.toSet();
14655 #endif
14656
14657 asricList.push_back(item);
14658 //ActivitiesSameRoomIfConsecutive_item* p_item=&asricList[asricList.count()-1];
14659 ActivitiesSameRoomIfConsecutive_item* p_item=&asricList.back();
14660 for(int ai : qAsConst(cn->_activitiesIndices))
14661 asricListForActivity[ai].append(p_item);
14662 }
14663 }
14664
14665 return ok;
14666 }
14667
computeBasicSpace(QWidget * parent)14668 bool computeBasicSpace(QWidget* parent)
14669 {
14670 double m=-1;
14671 bool ok=false;
14672 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++)
14673 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_BASIC_COMPULSORY_SPACE){
14674 ok=true;
14675 if(gt.rules.internalSpaceConstraintsList[i]->weightPercentage>m)
14676 m=gt.rules.internalSpaceConstraintsList[i]->weightPercentage;
14677 }
14678
14679 if(m<100)
14680 ok=false;
14681
14682 if(!ok || m<100){
14683 GeneratePreIrreconcilableMessage::mediumInformation(parent, GeneratePreTranslate::tr("FET warning"),
14684 GeneratePreTranslate::tr("Cannot generate, because you do not have a constraint of type basic compulsory space or its weight is lower than 100.0%.")
14685 +" "+
14686 GeneratePreTranslate::tr("Please add a constraint of this type with weight 100%.")
14687 +" "+
14688 GeneratePreTranslate::tr("You can add this constraint from the menu Data -> Space constraints -> Miscellaneous -> Basic compulsory space constraints.")
14689 +"\n\n"+
14690 GeneratePreTranslate::tr("Explanation:")
14691 +" "+
14692 GeneratePreTranslate::tr("Each time you create a new file, it contains an automatically added constraint of this type.")
14693 +" "+
14694 GeneratePreTranslate::tr("For complete flexibility, you are allowed to remove it (even if this is a wrong idea).")
14695 +" "+
14696 GeneratePreTranslate::tr("Maybe you removed it by mistake from your file.")
14697 +" "+
14698 GeneratePreTranslate::tr("By adding it again, everything should be all right.")
14699 );
14700 return false;
14701 }
14702 return ok;
14703 }
14704
computeNotAllowedRoomTimePercentages()14705 bool computeNotAllowedRoomTimePercentages()
14706 {
14707 notAllowedRoomTimePercentages.resize(gt.rules.nInternalRooms, gt.rules.nHoursPerWeek);
14708
14709 for(int i=0; i<gt.rules.nInternalRooms; i++)
14710 for(int j=0; j<gt.rules.nHoursPerWeek; j++)
14711 notAllowedRoomTimePercentages[i][j]=-1;
14712
14713 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
14714 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ROOM_NOT_AVAILABLE_TIMES){
14715 ConstraintRoomNotAvailableTimes* rn=(ConstraintRoomNotAvailableTimes*)gt.rules.internalSpaceConstraintsList[i];
14716
14717 assert(rn->days.count()==rn->hours.count());
14718 for(int kk=0; kk<rn->days.count(); kk++){
14719 int d=rn->days.at(kk);
14720 int h=rn->hours.at(kk);
14721
14722 if(notAllowedRoomTimePercentages[rn->room_ID][d+h*gt.rules.nDaysPerWeek]<rn->weightPercentage)
14723 notAllowedRoomTimePercentages[rn->room_ID][d+h*gt.rules.nDaysPerWeek]=rn->weightPercentage;
14724 }
14725 }
14726 }
14727
14728 return true;
14729 }
14730
computeNotAllowedTeacherRoomTimePercentages()14731 bool computeNotAllowedTeacherRoomTimePercentages()
14732 {
14733 haveTeacherRoomNotAllowedTimesConstraints=false;
14734 //QHash<QPair<qint64, qint64>, double > notAllowedTeacherRoomTimePercentages;
14735 //first qint64 is (teacher, room), second qint64 is (day, hour)
14736 notAllowedTeacherRoomTimePercentages.clear();
14737
14738 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
14739 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_ROOM_NOT_AVAILABLE_TIMES){
14740 haveTeacherRoomNotAllowedTimesConstraints=true;
14741 ConstraintTeacherRoomNotAvailableTimes* rn=(ConstraintTeacherRoomNotAvailableTimes*)gt.rules.internalSpaceConstraintsList[i];
14742
14743 assert(rn->days.count()==rn->hours.count());
14744 for(int kk=0; kk<rn->days.count(); kk++){
14745 int d=rn->days.at(kk);
14746 int h=rn->hours.at(kk);
14747
14748 int tch=rn->teacher_ID;
14749 int rm=rn->room_ID;
14750
14751 double perc=notAllowedTeacherRoomTimePercentages.value(QPair<qint64, qint64>(teacherRoomQInt64Combination(tch, rm), dayHourQInt64Combination(d, h)), -1);
14752 if(perc<rn->weightPercentage)
14753 notAllowedTeacherRoomTimePercentages.insert(QPair<qint64, qint64>(teacherRoomQInt64Combination(tch, rm), dayHourQInt64Combination(d, h)), rn->weightPercentage);
14754 }
14755 }
14756 }
14757
14758 return true;
14759 }
14760
computeActivitiesRoomsPreferences(QWidget * parent)14761 bool computeActivitiesRoomsPreferences(QWidget* parent)
14762 {
14763 constraintsForActivity.resize(gt.rules.nInternalActivities);
14764
14765 preferredRealRooms.resize(gt.rules.nInternalActivities);
14766
14767 tmpPreferredRealRooms.resize(gt.rules.nInternalActivities);
14768 tmpFoundNonEmpty.resize(gt.rules.nInternalActivities);
14769
14770 //to disallow duplicates
14771 QSet<QString> studentsSetHomeRoom;
14772 QSet<QString> teachersHomeRoom;
14773 /*QSet<QString> subjectsPreferredRoom;
14774 QSet<QPair<QString, QString>> subjectsActivityTagsPreferredRoom;*/
14775 //QSet<int> activitiesPreferredRoom;
14776
14777 for(int i=0; i<gt.rules.nInternalActivities; i++){
14778 constraintsForActivity[i].clear();
14779
14780 unspecifiedPreferredRoom[i]=true;
14781 activitiesPreferredRoomsList[i].clear();
14782 //activitiesPreferredRoomsPercentage[i]=-1;
14783
14784 unspecifiedHomeRoom[i]=true;
14785 activitiesHomeRoomsHomeRooms[i].clear();
14786 activitiesHomeRoomsPercentage[i]=-1;
14787
14788 preferredRealRooms[i].clear();
14789 }
14790
14791 bool ok=true;
14792
14793 visitedActivityResultantRealRooms.resize(gt.rules.nInternalActivities);
14794 for(int a=0; a<gt.rules.nInternalActivities; a++)
14795 visitedActivityResultantRealRooms[a]=false;
14796
14797 for(int a=0; a<gt.rules.nInternalActivities; a++){
14798 tmpPreferredRealRooms[a].clear();
14799 tmpFoundNonEmpty[a]=false;
14800 }
14801 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
14802 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
14803 ConstraintActivityPreferredRoom* apr=(ConstraintActivityPreferredRoom*)gt.rules.internalSpaceConstraintsList[i];
14804
14805 int a=apr->_activity;
14806
14807 if(apr->weightPercentage==100.0){
14808 if(!apr->preferredRealRooms.isEmpty()){
14809 if(tmpFoundNonEmpty[a]){
14810 tmpPreferredRealRooms[a].intersect(apr->preferredRealRooms);
14811 }
14812 else{
14813 tmpPreferredRealRooms[a]=apr->preferredRealRooms;
14814 tmpFoundNonEmpty[a]=true;
14815 }
14816 }
14817 }
14818 }
14819 }
14820
14821 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
14822 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_HOME_ROOM){
14823 ConstraintStudentsSetHomeRoom* spr=(ConstraintStudentsSetHomeRoom*)gt.rules.internalSpaceConstraintsList[i];
14824
14825 if(studentsSetHomeRoom.contains(spr->studentsName)){
14826 ok=false;
14827
14828 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14829 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
14830 "students set home room(s) for students set %1. Please leave only one of them")
14831 .arg(spr->studentsName),
14832 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14833 1, 0 );
14834
14835 if(t==0)
14836 break;
14837 }
14838 studentsSetHomeRoom.insert(spr->studentsName);
14839
14840 for(int a : qAsConst(spr->_activities)){
14841 if(unspecifiedHomeRoom[a]){
14842 unspecifiedHomeRoom[a]=false;
14843 activitiesHomeRoomsPercentage[a]=spr->weightPercentage;
14844 assert(activitiesHomeRoomsHomeRooms[a].count()==0);
14845 activitiesHomeRoomsHomeRooms[a].append(spr->_room);
14846 }
14847 else{
14848 int t=activitiesHomeRoomsHomeRooms[a].indexOf(spr->_room);
14849 activitiesHomeRoomsHomeRooms[a].clear();
14850 activitiesHomeRoomsPercentage[a]=max(activitiesHomeRoomsPercentage[a], spr->weightPercentage);
14851 if(t!=-1){
14852 activitiesHomeRoomsHomeRooms[a].append(spr->_room);
14853 }
14854 }
14855 }
14856 }
14857 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_HOME_ROOMS){
14858 ConstraintStudentsSetHomeRooms* spr=(ConstraintStudentsSetHomeRooms*)gt.rules.internalSpaceConstraintsList[i];
14859
14860 if(studentsSetHomeRoom.contains(spr->studentsName)){
14861 ok=false;
14862
14863 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14864 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
14865 "students set home room(s) for students set %1. Please leave only one of them")
14866 .arg(spr->studentsName),
14867 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14868 1, 0 );
14869
14870 if(t==0)
14871 break;
14872 }
14873 studentsSetHomeRoom.insert(spr->studentsName);
14874
14875 for(int a : qAsConst(spr->_activities)){
14876 if(unspecifiedHomeRoom[a]){
14877 unspecifiedHomeRoom[a]=false;
14878 activitiesHomeRoomsPercentage[a]=spr->weightPercentage;
14879 assert(activitiesHomeRoomsHomeRooms[a].count()==0);
14880 for(int rm : qAsConst(spr->_rooms)){
14881 activitiesHomeRoomsHomeRooms[a].append(rm);
14882 }
14883 }
14884 else{
14885 QList<int> shared;
14886 for(int rm : qAsConst(spr->_rooms)){
14887 if(activitiesHomeRoomsHomeRooms[a].indexOf(rm)!=-1)
14888 shared.append(rm);
14889 }
14890 activitiesHomeRoomsPercentage[a]=max(activitiesHomeRoomsPercentage[a], spr->weightPercentage);
14891 activitiesHomeRoomsHomeRooms[a]=shared;
14892 }
14893 }
14894 }
14895 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_HOME_ROOM){
14896 ConstraintTeacherHomeRoom* spr=(ConstraintTeacherHomeRoom*)gt.rules.internalSpaceConstraintsList[i];
14897
14898 if(teachersHomeRoom.contains(spr->teacherName)){
14899 ok=false;
14900
14901 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14902 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
14903 "teacher home room(s) for teacher %1. Please leave only one of them")
14904 .arg(spr->teacherName),
14905 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14906 1, 0 );
14907
14908 if(t==0)
14909 break;
14910 }
14911 teachersHomeRoom.insert(spr->teacherName);
14912
14913 for(int a : qAsConst(spr->_activities)){
14914 if(unspecifiedHomeRoom[a]){
14915 unspecifiedHomeRoom[a]=false;
14916 activitiesHomeRoomsPercentage[a]=spr->weightPercentage;
14917 assert(activitiesHomeRoomsHomeRooms[a].count()==0);
14918 activitiesHomeRoomsHomeRooms[a].append(spr->_room);
14919 }
14920 else{
14921 int t=activitiesHomeRoomsHomeRooms[a].indexOf(spr->_room);
14922 activitiesHomeRoomsHomeRooms[a].clear();
14923 activitiesHomeRoomsPercentage[a]=max(activitiesHomeRoomsPercentage[a], spr->weightPercentage);
14924 if(t!=-1){
14925 activitiesHomeRoomsHomeRooms[a].append(spr->_room);
14926 }
14927 }
14928 }
14929 }
14930 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_HOME_ROOMS){
14931 ConstraintTeacherHomeRooms* spr=(ConstraintTeacherHomeRooms*)gt.rules.internalSpaceConstraintsList[i];
14932
14933 if(teachersHomeRoom.contains(spr->teacherName)){
14934 ok=false;
14935
14936 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
14937 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
14938 "teacher home room(s) for teacher %1. Please leave only one of them")
14939 .arg(spr->teacherName),
14940 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
14941 1, 0 );
14942
14943 if(t==0)
14944 break;
14945 }
14946 teachersHomeRoom.insert(spr->teacherName);
14947
14948 for(int a : qAsConst(spr->_activities)){
14949 if(unspecifiedHomeRoom[a]){
14950 unspecifiedHomeRoom[a]=false;
14951 activitiesHomeRoomsPercentage[a]=spr->weightPercentage;
14952 assert(activitiesHomeRoomsHomeRooms[a].count()==0);
14953 for(int rm : qAsConst(spr->_rooms)){
14954 activitiesHomeRoomsHomeRooms[a].append(rm);
14955 }
14956 }
14957 else{
14958 QList<int> shared;
14959 for(int rm : qAsConst(spr->_rooms)){
14960 if(activitiesHomeRoomsHomeRooms[a].indexOf(rm)!=-1)
14961 shared.append(rm);
14962 }
14963 activitiesHomeRoomsPercentage[a]=max(activitiesHomeRoomsPercentage[a], spr->weightPercentage);
14964 activitiesHomeRoomsHomeRooms[a]=shared;
14965 }
14966 }
14967 }
14968 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_SUBJECT_PREFERRED_ROOM){
14969 ConstraintSubjectPreferredRoom* spr=(ConstraintSubjectPreferredRoom*)gt.rules.internalSpaceConstraintsList[i];
14970
14971 /*if(subjectsPreferredRoom.contains(spr->subjectName)){
14972 ok=false;
14973
14974 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
14975 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
14976 "subject preferred room(s) for subject %1. Please leave only one of them")
14977 .arg(spr->subjectName),
14978 GeneratePreTranslate::tr("Skip rest of such problems"), GeneratePreTranslate::tr("See next problem"), QString(),
14979 1, 0 );
14980
14981 if(t==0)
14982 break;
14983 }
14984 subjectsPreferredRoom.insert(spr->subjectName);*/
14985
14986 for(int a : qAsConst(spr->_activities)){
14987 if(spr->weightPercentage==100.0){
14988 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
14989 }
14990 else{
14991 PreferredRoomsItem it;
14992
14993 it.percentage=spr->weightPercentage;
14994 it.preferredRooms.insert(spr->_room);
14995
14996 if(unspecifiedPreferredRoom[a]){
14997 unspecifiedPreferredRoom[a]=false;
14998 //activitiesPreferredRoomsPercentage[a]=spr->weightPercentage;
14999 //assert(activitiesPreferredRoomsPreferredRooms[a].count()==0);
15000 //activitiesPreferredRoomsPreferredRooms[a].append(spr->_room);
15001 }
15002 else{
15003 //int t=activitiesPreferredRoomsPreferredRooms[a].indexOf(spr->_room);
15004 //activitiesPreferredRoomsPreferredRooms[a].clear();
15005 //activitiesPreferredRoomsPercentage[a]=max(activitiesPreferredRoomsPercentage[a], spr->weightPercentage);
15006 //if(t!=-1){
15007 // activitiesPreferredRoomsPreferredRooms[a].append(spr->_room);
15008 //}
15009 }
15010
15011 activitiesPreferredRoomsList[a].append(it);
15012 }
15013 }
15014 }
15015 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_SUBJECT_PREFERRED_ROOMS){
15016 ConstraintSubjectPreferredRooms* spr=(ConstraintSubjectPreferredRooms*)gt.rules.internalSpaceConstraintsList[i];
15017
15018 /*if(subjectsPreferredRoom.contains(spr->subjectName)){
15019 ok=false;
15020
15021 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
15022 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
15023 "subject preferred room(s) for subject %1. Please leave only one of them")
15024 .arg(spr->subjectName),
15025 GeneratePreTranslate::tr("Skip rest of such problems"), GeneratePreTranslate::tr("See next problem"), QString(),
15026 1, 0 );
15027
15028 if(t==0)
15029 break;
15030 }
15031 subjectsPreferredRoom.insert(spr->subjectName);*/
15032
15033 for(int a : qAsConst(spr->_activities)){
15034 if(spr->weightPercentage==100.0){
15035 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15036 }
15037 else{
15038 PreferredRoomsItem it;
15039
15040 it.percentage=spr->weightPercentage;
15041 for(int k : qAsConst(spr->_rooms))
15042 it.preferredRooms.insert(k);
15043
15044 if(unspecifiedPreferredRoom[a])
15045 unspecifiedPreferredRoom[a]=false;
15046
15047 activitiesPreferredRoomsList[a].append(it);
15048 }
15049 }
15050 }
15051 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOM){
15052 ConstraintSubjectActivityTagPreferredRoom* spr=(ConstraintSubjectActivityTagPreferredRoom*)gt.rules.internalSpaceConstraintsList[i];
15053
15054 /*QPair<QString, QString> pair=qMakePair(spr->subjectName, spr->activityTagName);
15055 if(subjectsActivityTagsPreferredRoom.contains(pair)){
15056 ok=false;
15057
15058 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
15059 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
15060 "subject activity tag preferred room(s) for subject %1, activity tag %2. Please leave only one of them")
15061 .arg(spr->subjectName)
15062 .arg(spr->activityTagName),
15063 GeneratePreTranslate::tr("Skip rest of such problems"), GeneratePreTranslate::tr("See next problem"), QString(),
15064 1, 0 );
15065
15066 if(t==0)
15067 break;
15068 }
15069 subjectsActivityTagsPreferredRoom.insert(pair);*/
15070
15071 //for(int j=0; j<spr->_nActivities; j++){
15072 // int a=spr->_activities[j];
15073 for(int a : qAsConst(spr->_activities)){
15074 if(spr->weightPercentage==100.0){
15075 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15076 }
15077 else{
15078 PreferredRoomsItem it;
15079
15080 it.percentage=spr->weightPercentage;
15081 it.preferredRooms.insert(spr->_room);
15082
15083 if(unspecifiedPreferredRoom[a])
15084 unspecifiedPreferredRoom[a]=false;
15085
15086 activitiesPreferredRoomsList[a].append(it);
15087 }
15088
15089 /*if(unspecifiedPreferredRoom[a]){
15090 unspecifiedPreferredRoom[a]=false;
15091 activitiesPreferredRoomsPercentage[a]=spr->weightPercentage;
15092 assert(activitiesPreferredRoomsPreferredRooms[a].count()==0);
15093 activitiesPreferredRoomsPreferredRooms[a].append(spr->_room);
15094 }
15095 else{
15096 int t=activitiesPreferredRoomsPreferredRooms[a].indexOf(spr->_room);
15097 activitiesPreferredRoomsPreferredRooms[a].clear();
15098 activitiesPreferredRoomsPercentage[a]=max(activitiesPreferredRoomsPercentage[a], spr->weightPercentage);
15099 if(t!=-1){
15100 activitiesPreferredRoomsPreferredRooms[a].append(spr->_room);
15101 }
15102 }*/
15103 }
15104 }
15105 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOMS){
15106 ConstraintSubjectActivityTagPreferredRooms* spr=(ConstraintSubjectActivityTagPreferredRooms*)gt.rules.internalSpaceConstraintsList[i];
15107
15108 /*QPair<QString, QString> pair=qMakePair(spr->subjectName, spr->activityTagName);
15109 if(subjectsActivityTagsPreferredRoom.contains(pair)){
15110 ok=false;
15111
15112 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
15113 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
15114 "subject activity tag preferred room(s) for subject %1, activity tag %2. Please leave only one of them")
15115 .arg(spr->subjectName)
15116 .arg(spr->activityTagName),
15117 GeneratePreTranslate::tr("Skip rest of such problems"), GeneratePreTranslate::tr("See next problem"), QString(),
15118 1, 0 );
15119
15120 if(t==0)
15121 break;
15122 }
15123 subjectsActivityTagsPreferredRoom.insert(pair);*/
15124
15125 for(int a : qAsConst(spr->_activities)){
15126 if(spr->weightPercentage==100.0){
15127 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15128 }
15129 else{
15130 PreferredRoomsItem it;
15131
15132 it.percentage=spr->weightPercentage;
15133 for(int k : qAsConst(spr->_rooms))
15134 it.preferredRooms.insert(k);
15135
15136 if(unspecifiedPreferredRoom[a])
15137 unspecifiedPreferredRoom[a]=false;
15138
15139 activitiesPreferredRoomsList[a].append(it);
15140 }
15141 }
15142 }
15143
15144 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOM){
15145 ConstraintActivityTagPreferredRoom* spr=(ConstraintActivityTagPreferredRoom*)gt.rules.internalSpaceConstraintsList[i];
15146
15147 for(int a : qAsConst(spr->_activities)){
15148 if(spr->weightPercentage==100.0){
15149 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15150 }
15151 else{
15152 PreferredRoomsItem it;
15153
15154 it.percentage=spr->weightPercentage;
15155 it.preferredRooms.insert(spr->_room);
15156
15157 if(unspecifiedPreferredRoom[a])
15158 unspecifiedPreferredRoom[a]=false;
15159
15160 activitiesPreferredRoomsList[a].append(it);
15161 }
15162 }
15163 }
15164 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOMS){
15165 ConstraintActivityTagPreferredRooms* spr=(ConstraintActivityTagPreferredRooms*)gt.rules.internalSpaceConstraintsList[i];
15166
15167 for(int a : qAsConst(spr->_activities)){
15168 if(spr->weightPercentage==100.0){
15169 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15170 }
15171 else{
15172 PreferredRoomsItem it;
15173
15174 it.percentage=spr->weightPercentage;
15175 for(int k : qAsConst(spr->_rooms))
15176 it.preferredRooms.insert(k);
15177
15178 if(unspecifiedPreferredRoom[a])
15179 unspecifiedPreferredRoom[a]=false;
15180
15181 activitiesPreferredRoomsList[a].append(it);
15182 }
15183 }
15184 }
15185
15186 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
15187 ConstraintActivityPreferredRoom* apr=(ConstraintActivityPreferredRoom*)gt.rules.internalSpaceConstraintsList[i];
15188
15189 /*if(activitiesPreferredRoom.contains(apr->activityId)){
15190 ok=false;
15191
15192 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
15193 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
15194 "activity preferred room(s) for activity with id %1. Please leave only one of them")
15195 .arg(apr->activityId),
15196 GeneratePreTranslate::tr("Skip rest of such problems"), GeneratePreTranslate::tr("See next problem"), QString(),
15197 1, 0 );
15198
15199 if(t==0)
15200 break;
15201 }
15202 activitiesPreferredRoom.insert(apr->activityId);*/
15203
15204 int a=apr->_activity;
15205
15206 if(!apr->preferredRealRooms.isEmpty()){
15207 if(gt.rules.internalRoomsList[apr->_room]->isVirtual==false){
15208 ok=false;
15209
15210 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15211 GeneratePreTranslate::tr("Cannot generate the timetable, because you have a constraint activity preferred room for the activity"
15212 " with id=%1 which specifies a list of real rooms, but the preferred room is not virtual. Please correct.")
15213 .arg(gt.rules.internalActivitiesList[a].id),
15214 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15215 1, 0 );
15216
15217 if(t==0)
15218 break;
15219 }
15220
15221 int t2=-1;
15222 for(int rr : qAsConst(apr->preferredRealRooms))
15223 if(gt.rules.internalRoomsList[rr]->isVirtual==true){
15224 ok=false;
15225
15226 t2=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15227 GeneratePreTranslate::tr("Cannot generate the timetable, because you have a constraint activity preferred room for the activity"
15228 " with id=%1 which specifies a list of real rooms, but the room %2 from this list is virtual. Please correct.")
15229 .arg(gt.rules.internalActivitiesList[a].id).arg(gt.rules.internalRoomsList[rr]->name),
15230 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15231 1, 0 );
15232
15233 if(t2==0)
15234 break;
15235 }
15236 if(t2==0){
15237 assert(!ok);
15238 break;
15239 }
15240 }
15241
15242 if(apr->weightPercentage==100.0){
15243 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15244
15245 if(!apr->preferredRealRooms.isEmpty()){
15246 if(apr->preferredRealRooms.count()!=gt.rules.internalRoomsList[apr->_room]->rrsl.count()){
15247 ok=false;
15248
15249 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15250 GeneratePreTranslate::tr("Cannot generate the timetable, because you have a preferred room constraint for the activity"
15251 " with id=%1 which specifies a real rooms list which does not have the same"
15252 " number of elements as the number of sets of real rooms for the preferred virtual room (%2)."
15253 " Please correct this.").arg(gt.rules.internalActivitiesList[a].id).arg(gt.rules.internalRoomsList[apr->_room]->name),
15254 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15255 1, 0 );
15256
15257 if(t==0)
15258 break;
15259 }
15260
15261 assert(tmpFoundNonEmpty[a]==true);
15262 if(tmpPreferredRealRooms[a].count()!=gt.rules.internalRoomsList[apr->_room]->rrsl.count()){
15263 if(visitedActivityResultantRealRooms[a]){
15264 assert(ok==false);
15265 }
15266 else{
15267 visitedActivityResultantRealRooms[a]=true;
15268
15269 ok=false;
15270
15271 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15272 GeneratePreTranslate::tr("Cannot generate the timetable, because you have more preferred room constraints for the activity"
15273 " with id=%1 which specify one or more lists of real rooms whose resultant real rooms list does not have the same"
15274 " number of elements as the number of sets of real rooms for the preferred virtual room (%2)."
15275 " Please correct this.").arg(gt.rules.internalActivitiesList[a].id).arg(gt.rules.internalRoomsList[apr->_room]->name),
15276 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15277 1, 0 );
15278
15279 if(t==0)
15280 break;
15281 }
15282 }
15283
15284 preferredRealRooms[a]=tmpPreferredRealRooms[a];
15285 }
15286 }
15287 else{
15288 if(!apr->preferredRealRooms.isEmpty()){
15289 ok=false;
15290
15291 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15292 GeneratePreTranslate::tr("Cannot generate the timetable, because you have a constraint activity preferred room for the activity"
15293 " with id=%1 which specifies a nonempty list of real rooms and has weight <100.0%. It is necessary that the weight is exactly 100.0% or the list"
15294 " of real rooms to be empty in this case. Please correct.").arg(gt.rules.internalActivitiesList[a].id),
15295 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15296 1, 0 );
15297
15298 if(t==0)
15299 break;
15300 }
15301
15302 PreferredRoomsItem it;
15303
15304 it.percentage=apr->weightPercentage;
15305 it.preferredRooms.insert(apr->_room);
15306
15307 if(unspecifiedPreferredRoom[a])
15308 unspecifiedPreferredRoom[a]=false;
15309
15310 activitiesPreferredRoomsList[a].append(it);
15311 }
15312 /*if(unspecifiedPreferredRoom[a]){
15313 unspecifiedPreferredRoom[a]=false;
15314 activitiesPreferredRoomsPercentage[a]=apr->weightPercentage;
15315 assert(activitiesPreferredRoomsPreferredRooms[a].count()==0);
15316 activitiesPreferredRoomsPreferredRooms[a].append(apr->_room);
15317 }
15318 else{
15319 int t=activitiesPreferredRoomsPreferredRooms[a].indexOf(apr->_room);
15320 activitiesPreferredRoomsPreferredRooms[a].clear();
15321 activitiesPreferredRoomsPercentage[a]=max(activitiesPreferredRoomsPercentage[a], apr->weightPercentage);
15322 if(t!=-1){
15323 activitiesPreferredRoomsPreferredRooms[a].append(apr->_room);
15324 }
15325 }*/
15326 }
15327 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOMS){
15328 ConstraintActivityPreferredRooms* apr=(ConstraintActivityPreferredRooms*)gt.rules.internalSpaceConstraintsList[i];
15329
15330 /*if(activitiesPreferredRoom.contains(apr->activityId)){
15331 ok=false;
15332
15333 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
15334 GeneratePreTranslate::tr("Cannot generate timetable, because you have more than one constraint of type "
15335 "activity preferred room(s) for activity with id %1. Please leave only one of them")
15336 .arg(apr->activityId),
15337 GeneratePreTranslate::tr("Skip rest of such problems"), GeneratePreTranslate::tr("See next problem"), QString(),
15338 1, 0 );
15339
15340 if(t==0)
15341 break;
15342 }
15343 activitiesPreferredRoom.insert(apr->activityId);*/
15344
15345 int a=apr->_activity;
15346
15347 if(apr->weightPercentage==100.0){
15348 constraintsForActivity[a].append(gt.rules.internalSpaceConstraintsList[i]);
15349 }
15350 else{
15351 PreferredRoomsItem it;
15352
15353 it.percentage=apr->weightPercentage;
15354 for(int k : qAsConst(apr->_rooms))
15355 it.preferredRooms.insert(k);
15356
15357 if(unspecifiedPreferredRoom[a])
15358 unspecifiedPreferredRoom[a]=false;
15359
15360 activitiesPreferredRoomsList[a].append(it);
15361 }
15362 }
15363 }
15364
15365 for(int a=0; a<gt.rules.nInternalActivities; a++){
15366 QList<SpaceConstraint*> scl=constraintsForActivity[a];
15367
15368 if(scl.count()==0){
15369 //nothing
15370 }
15371 else{
15372 if(unspecifiedPreferredRoom[a])
15373 unspecifiedPreferredRoom[a]=false;
15374
15375 PreferredRoomsItem it;
15376 it.percentage=100.0;
15377 it.preferredRooms.clear();
15378
15379 bool begin=true;
15380 for(SpaceConstraint* ctr : qAsConst(scl)){
15381 if(ctr->type==CONSTRAINT_SUBJECT_PREFERRED_ROOM){
15382 ConstraintSubjectPreferredRoom* spr=(ConstraintSubjectPreferredRoom*)ctr;
15383
15384 if(begin){
15385 it.preferredRooms.insert(spr->_room);
15386 begin=false;
15387 }
15388 else{
15389 QSet<int> set;
15390 set.insert(spr->_room);
15391 it.preferredRooms.intersect(set);
15392 }
15393 }
15394 else if(ctr->type==CONSTRAINT_SUBJECT_PREFERRED_ROOMS){
15395 ConstraintSubjectPreferredRooms* spr=(ConstraintSubjectPreferredRooms*)ctr;
15396
15397 if(begin){
15398 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15399 it.preferredRooms=QSet<int>(spr->_rooms.begin(), spr->_rooms.end());
15400 #else
15401 it.preferredRooms=spr->_rooms.toSet();
15402 #endif
15403 begin=false;
15404 }
15405 else{
15406 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15407 it.preferredRooms.intersect(QSet<int>(spr->_rooms.begin(), spr->_rooms.end()));
15408 #else
15409 it.preferredRooms.intersect(spr->_rooms.toSet());
15410 #endif
15411 }
15412 }
15413 else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOM){
15414 ConstraintSubjectActivityTagPreferredRoom* spr=(ConstraintSubjectActivityTagPreferredRoom*)ctr;
15415
15416 if(begin){
15417 it.preferredRooms.insert(spr->_room);
15418 begin=false;
15419 }
15420 else{
15421 QSet<int> set;
15422 set.insert(spr->_room);
15423 it.preferredRooms.intersect(set);
15424 }
15425 }
15426 else if(ctr->type==CONSTRAINT_SUBJECT_ACTIVITY_TAG_PREFERRED_ROOMS){
15427 ConstraintSubjectActivityTagPreferredRooms* spr=(ConstraintSubjectActivityTagPreferredRooms*)ctr;
15428
15429 if(begin){
15430 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15431 it.preferredRooms=QSet<int>(spr->_rooms.begin(), spr->_rooms.end());
15432 #else
15433 it.preferredRooms=spr->_rooms.toSet();
15434 #endif
15435 begin=false;
15436 }
15437 else{
15438 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15439 it.preferredRooms.intersect(QSet<int>(spr->_rooms.begin(), spr->_rooms.end()));
15440 #else
15441 it.preferredRooms.intersect(spr->_rooms.toSet());
15442 #endif
15443 }
15444 }
15445 else if(ctr->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOM){
15446 ConstraintActivityTagPreferredRoom* spr=(ConstraintActivityTagPreferredRoom*)ctr;
15447
15448 if(begin){
15449 it.preferredRooms.insert(spr->_room);
15450 begin=false;
15451 }
15452 else{
15453 QSet<int> set;
15454 set.insert(spr->_room);
15455 it.preferredRooms.intersect(set);
15456 }
15457 }
15458 else if(ctr->type==CONSTRAINT_ACTIVITY_TAG_PREFERRED_ROOMS){
15459 ConstraintActivityTagPreferredRooms* spr=(ConstraintActivityTagPreferredRooms*)ctr;
15460
15461 if(begin){
15462 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15463 it.preferredRooms=QSet<int>(spr->_rooms.begin(), spr->_rooms.end());
15464 #else
15465 it.preferredRooms=spr->_rooms.toSet();
15466 #endif
15467 begin=false;
15468 }
15469 else{
15470 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15471 it.preferredRooms.intersect(QSet<int>(spr->_rooms.begin(), spr->_rooms.end()));
15472 #else
15473 it.preferredRooms.intersect(spr->_rooms.toSet());
15474 #endif
15475 }
15476 }
15477 else if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOM){
15478 ConstraintActivityPreferredRoom* spr=(ConstraintActivityPreferredRoom*)ctr;
15479
15480 if(begin){
15481 it.preferredRooms.insert(spr->_room);
15482 begin=false;
15483 }
15484 else{
15485 QSet<int> set;
15486 set.insert(spr->_room);
15487 it.preferredRooms.intersect(set);
15488 }
15489 }
15490 else if(ctr->type==CONSTRAINT_ACTIVITY_PREFERRED_ROOMS){
15491 ConstraintActivityPreferredRooms* spr=(ConstraintActivityPreferredRooms*)ctr;
15492
15493 if(begin){
15494 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15495 it.preferredRooms=QSet<int>(spr->_rooms.begin(), spr->_rooms.end());
15496 #else
15497 it.preferredRooms=spr->_rooms.toSet();
15498 #endif
15499 begin=false;
15500 }
15501 else{
15502 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
15503 it.preferredRooms.intersect(QSet<int>(spr->_rooms.begin(), spr->_rooms.end()));
15504 #else
15505 it.preferredRooms.intersect(spr->_rooms.toSet());
15506 #endif
15507 }
15508 }
15509 }
15510
15511 activitiesPreferredRoomsList[a].append(it);
15512 }
15513 }
15514
15515 /*for(int i=0; i<gt.rules.nInternalActivities; i++)
15516 if(!unspecifiedPreferredRoom[i])
15517 if(activitiesPreferredRoomsPreferredRooms[i].count()==0){
15518 ok=false;
15519
15520 int t=QMessageBox::warning(parent, GeneratePreTranslate::tr("FET warning"),
15521 GeneratePreTranslate::tr("Cannot generate timetable, because for activity with id=%1 "
15522 "you have no allowed room (from constraints activity preferred room(s) and subject (activity tag) preferred room(s) )")
15523 .arg(gt.rules.internalActivitiesList[i].id),
15524 GeneratePreTranslate::tr("Skip rest of activities without rooms"), GeneratePreTranslate::tr("See next problem"), QString(),
15525 1, 0 );
15526
15527 if(t==0)
15528 break;
15529 }*/
15530
15531 for(int i=0; i<gt.rules.nInternalActivities; i++)
15532 if(!unspecifiedHomeRoom[i])
15533 if(activitiesHomeRoomsHomeRooms[i].count()==0){
15534 ok=false;
15535
15536 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15537 GeneratePreTranslate::tr("Cannot generate timetable, because for activity with id=%1 "
15538 "you have no allowed home room (from constraints students set home room(s) and teacher home room(s))")
15539 .arg(gt.rules.internalActivitiesList[i].id),
15540 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15541 1, 0 );
15542
15543 if(t==0)
15544 break;
15545 }
15546
15547 for(int i=0; i<gt.rules.nInternalActivities; i++){
15548 if(!unspecifiedPreferredRoom[i]){
15549 for(int kk=0; kk<activitiesPreferredRoomsList[i].count(); kk++){
15550 PreferredRoomsItem& it=activitiesPreferredRoomsList[i][kk];
15551
15552 bool okinitial=true;
15553 if(it.preferredRooms.count()==0){
15554 okinitial=false;
15555
15556 ok=false;
15557
15558 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15559 GeneratePreTranslate::tr("Cannot generate timetable, because for activity with id=%1 "
15560 "you have no allowed preferred room (from preferred room(s) constraints).")
15561 .arg(gt.rules.internalActivitiesList[i].id),
15562 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15563 1, 0 );
15564
15565 if(t==0)
15566 goto jumpOverPrefRoomsNStudents;
15567
15568 //assert(0);
15569 }
15570 QSet<int> tmp=it.preferredRooms;
15571 for(int r : qAsConst(tmp)){
15572 if(gt.rules.internalRoomsList[r]->capacity < gt.rules.internalActivitiesList[i].nTotalStudents){
15573 it.preferredRooms.remove(r);
15574 }
15575 }
15576 if(okinitial && it.preferredRooms.count()==0){
15577 ok=false;
15578
15579 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15580 GeneratePreTranslate::tr("Cannot generate timetable, because for activity with id=%1 "
15581 "you have no allowed preferred room (from the allowed number of students and preferred room(s) constraints)")
15582 .arg(gt.rules.internalActivitiesList[i].id),
15583 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15584 1, 0 );
15585
15586 if(t==0)
15587 goto jumpOverPrefRoomsNStudents;
15588 }
15589 }
15590 }
15591 }
15592 jumpOverPrefRoomsNStudents:
15593
15594 for(int i=0; i<gt.rules.nInternalActivities; i++){
15595 if(!unspecifiedHomeRoom[i]){
15596 bool okinitial=true;
15597 if(activitiesHomeRoomsHomeRooms[i].count()==0)
15598 okinitial=false;
15599 /* QList<int> tmp=activitiesHomeRoomsHomeRooms[i];
15600 for(int r : qAsConst(tmp)){
15601 if(gt.rules.internalRoomsList[r]->capacity < gt.rules.internalActivitiesList[i].nTotalStudents){
15602 int t=activitiesHomeRoomsHomeRooms[i].removeAll(r);
15603 assert(t==1);
15604 }
15605 }*/
15606 //Better:
15607 QList<int> tmp;
15608 for(int r : qAsConst(activitiesHomeRoomsHomeRooms[i]))
15609 if(gt.rules.internalRoomsList[r]->capacity >= gt.rules.internalActivitiesList[i].nTotalStudents)
15610 tmp.append(r);
15611 activitiesHomeRoomsHomeRooms[i]=tmp;
15612
15613 if(okinitial && activitiesHomeRoomsHomeRooms[i].count()==0){
15614 ok=false;
15615
15616 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15617 GeneratePreTranslate::tr("Cannot generate timetable, because for activity with id=%1 "
15618 "you have no allowed home room (from the allowed number of students)")
15619 .arg(gt.rules.internalActivitiesList[i].id),
15620 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15621 1, 0 );
15622
15623 if(t==0)
15624 break;
15625 }
15626 }
15627 }
15628
15629
15630 //////////new test, 9 Sept. 2009
15631 if(ok){
15632 for(int i=0; i<gt.rules.nInternalActivities; i++){
15633 if(!unspecifiedPreferredRoom[i]){
15634 bool begin=true;
15635 QSet<int> allowedRooms;
15636 for(int kk=0; kk<activitiesPreferredRoomsList[i].count(); kk++){
15637 PreferredRoomsItem& it=activitiesPreferredRoomsList[i][kk];
15638 if(it.percentage==100.0){
15639 if(begin){
15640 allowedRooms=it.preferredRooms;
15641 begin=false;
15642 }
15643 else
15644 allowedRooms.intersect(it.preferredRooms);
15645 }
15646 }
15647 if(!begin && allowedRooms.count()==0){
15648 ok=false;
15649
15650 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15651 GeneratePreTranslate::tr("Cannot generate the timetable, because for activity with id=%1 "
15652 "you have no allowed preferred room (considering rooms' capacities and constraints preferred"
15653 " room(s) with 100.0% weight percentage)")
15654 .arg(gt.rules.internalActivitiesList[i].id),
15655 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15656 1, 0 );
15657
15658 if(t==0)
15659 break;
15660 }
15661 }
15662 }
15663 }
15664 //////////
15665
15666 return ok;
15667 }
15668
computeMaxBuildingChangesPerDayForStudents(QWidget * parent)15669 bool computeMaxBuildingChangesPerDayForStudents(QWidget* parent)
15670 {
15671 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
15672 maxBuildingChangesPerDayForStudentsPercentages[i]=-1;
15673 maxBuildingChangesPerDayForStudentsMaxChanges[i]=-1;
15674 }
15675
15676 bool ok=true;
15677
15678 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
15679 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_BUILDING_CHANGES_PER_DAY){
15680 ConstraintStudentsSetMaxBuildingChangesPerDay* spr=(ConstraintStudentsSetMaxBuildingChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
15681
15682 if(spr->weightPercentage!=100){
15683 ok=false;
15684
15685 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15686 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set max building changes per day"
15687 " with weight under 100%. Please correct and try again"),
15688 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15689 1, 0 );
15690
15691 if(t==0)
15692 return false;
15693 }
15694
15695 for(int sbg : qAsConst(spr->iSubgroupsList)){
15696 maxBuildingChangesPerDayForStudentsPercentages[sbg]=100;
15697 if(maxBuildingChangesPerDayForStudentsMaxChanges[sbg]<0)
15698 maxBuildingChangesPerDayForStudentsMaxChanges[sbg]=spr->maxBuildingChangesPerDay;
15699 else
15700 maxBuildingChangesPerDayForStudentsMaxChanges[sbg]=min(maxBuildingChangesPerDayForStudentsMaxChanges[sbg], spr->maxBuildingChangesPerDay);
15701 }
15702 }
15703 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_BUILDING_CHANGES_PER_DAY){
15704 ConstraintStudentsMaxBuildingChangesPerDay* spr=(ConstraintStudentsMaxBuildingChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
15705
15706 if(spr->weightPercentage!=100){
15707 ok=false;
15708
15709 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15710 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students max building changes per day"
15711 " with weight under 100%. Please correct and try again"),
15712 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15713 1, 0 );
15714
15715 if(t==0)
15716 return false;
15717 }
15718
15719 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
15720 maxBuildingChangesPerDayForStudentsPercentages[sbg]=100;
15721 if(maxBuildingChangesPerDayForStudentsMaxChanges[sbg]<0)
15722 maxBuildingChangesPerDayForStudentsMaxChanges[sbg]=spr->maxBuildingChangesPerDay;
15723 else
15724 maxBuildingChangesPerDayForStudentsMaxChanges[sbg]=min(maxBuildingChangesPerDayForStudentsMaxChanges[sbg], spr->maxBuildingChangesPerDay);
15725 }
15726 }
15727 }
15728
15729 return ok;
15730 }
15731
computeMaxBuildingChangesPerWeekForStudents(QWidget * parent)15732 bool computeMaxBuildingChangesPerWeekForStudents(QWidget* parent)
15733 {
15734 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
15735 maxBuildingChangesPerWeekForStudentsPercentages[i]=-1;
15736 maxBuildingChangesPerWeekForStudentsMaxChanges[i]=-1;
15737 }
15738
15739 bool ok=true;
15740
15741 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
15742 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_BUILDING_CHANGES_PER_WEEK){
15743 ConstraintStudentsSetMaxBuildingChangesPerWeek* spr=(ConstraintStudentsSetMaxBuildingChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
15744
15745 if(spr->weightPercentage!=100){
15746 ok=false;
15747
15748 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15749 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set max building changes per week"
15750 " with weight under 100%. Please correct and try again"),
15751 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15752 1, 0 );
15753
15754 if(t==0)
15755 return false;
15756 }
15757
15758 for(int sbg : qAsConst(spr->iSubgroupsList)){
15759 maxBuildingChangesPerWeekForStudentsPercentages[sbg]=100;
15760 if(maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]<0)
15761 maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]=spr->maxBuildingChangesPerWeek;
15762 else
15763 maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]=min(maxBuildingChangesPerWeekForStudentsMaxChanges[sbg], spr->maxBuildingChangesPerWeek);
15764 }
15765 }
15766 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_BUILDING_CHANGES_PER_WEEK){
15767 ConstraintStudentsMaxBuildingChangesPerWeek* spr=(ConstraintStudentsMaxBuildingChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
15768
15769 if(spr->weightPercentage!=100){
15770 ok=false;
15771
15772 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15773 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students max building changes per week"
15774 " with weight under 100%. Please correct and try again"),
15775 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15776 1, 0 );
15777
15778 if(t==0)
15779 return false;
15780 }
15781
15782 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
15783 maxBuildingChangesPerWeekForStudentsPercentages[sbg]=100;
15784 if(maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]<0)
15785 maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]=spr->maxBuildingChangesPerWeek;
15786 else
15787 maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]=min(maxBuildingChangesPerWeekForStudentsMaxChanges[sbg], spr->maxBuildingChangesPerWeek);
15788 }
15789 }
15790 }
15791
15792 return ok;
15793 }
15794
computeMinGapsBetweenBuildingChangesForStudents(QWidget * parent)15795 bool computeMinGapsBetweenBuildingChangesForStudents(QWidget* parent)
15796 {
15797 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
15798 minGapsBetweenBuildingChangesForStudentsPercentages[i]=-1;
15799 minGapsBetweenBuildingChangesForStudentsMinGaps[i]=-1;
15800 }
15801
15802 bool ok=true;
15803
15804 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
15805 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
15806 ConstraintStudentsSetMinGapsBetweenBuildingChanges* spr=(ConstraintStudentsSetMinGapsBetweenBuildingChanges*)gt.rules.internalSpaceConstraintsList[i];
15807
15808 if(spr->weightPercentage!=100){
15809 ok=false;
15810
15811 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15812 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set min gaps between building changes"
15813 " with weight under 100%. Please correct and try again"),
15814 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15815 1, 0 );
15816
15817 if(t==0)
15818 return false;
15819 }
15820
15821 for(int sbg : qAsConst(spr->iSubgroupsList)){
15822 minGapsBetweenBuildingChangesForStudentsPercentages[sbg]=100;
15823 if(minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]<0)
15824 minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]=spr->minGapsBetweenBuildingChanges;
15825 else
15826 minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]=max(minGapsBetweenBuildingChangesForStudentsMinGaps[sbg], spr->minGapsBetweenBuildingChanges);
15827 }
15828 }
15829 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
15830 ConstraintStudentsMinGapsBetweenBuildingChanges* spr=(ConstraintStudentsMinGapsBetweenBuildingChanges*)gt.rules.internalSpaceConstraintsList[i];
15831
15832 if(spr->weightPercentage!=100){
15833 ok=false;
15834
15835 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15836 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students min gaps between building changes"
15837 " with weight under 100%. Please correct and try again"),
15838 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15839 1, 0 );
15840
15841 if(t==0)
15842 return false;
15843 }
15844
15845 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
15846 minGapsBetweenBuildingChangesForStudentsPercentages[sbg]=100;
15847 if(minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]<0)
15848 minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]=spr->minGapsBetweenBuildingChanges;
15849 else
15850 minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]=max(minGapsBetweenBuildingChangesForStudentsMinGaps[sbg], spr->minGapsBetweenBuildingChanges);
15851 }
15852 }
15853 }
15854
15855 return ok;
15856 }
15857
computeMaxBuildingChangesPerDayForTeachers(QWidget * parent)15858 bool computeMaxBuildingChangesPerDayForTeachers(QWidget* parent)
15859 {
15860 for(int i=0; i<gt.rules.nInternalTeachers; i++){
15861 maxBuildingChangesPerDayForTeachersPercentages[i]=-1;
15862 maxBuildingChangesPerDayForTeachersMaxChanges[i]=-1;
15863 }
15864
15865 bool ok=true;
15866
15867 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
15868 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_BUILDING_CHANGES_PER_DAY){
15869 ConstraintTeacherMaxBuildingChangesPerDay* spr=(ConstraintTeacherMaxBuildingChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
15870
15871 if(spr->weightPercentage!=100){
15872 ok=false;
15873
15874 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15875 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher max building changes per day"
15876 " with weight under 100%. Please correct and try again"),
15877 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15878 1, 0 );
15879
15880 if(t==0)
15881 return false;
15882 }
15883
15884 maxBuildingChangesPerDayForTeachersPercentages[spr->teacher_ID]=100;
15885 if(maxBuildingChangesPerDayForTeachersMaxChanges[spr->teacher_ID]<0)
15886 maxBuildingChangesPerDayForTeachersMaxChanges[spr->teacher_ID]=spr->maxBuildingChangesPerDay;
15887 else
15888 maxBuildingChangesPerDayForTeachersMaxChanges[spr->teacher_ID]=min(maxBuildingChangesPerDayForTeachersMaxChanges[spr->teacher_ID], spr->maxBuildingChangesPerDay);
15889 }
15890 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_BUILDING_CHANGES_PER_DAY){
15891 ConstraintTeachersMaxBuildingChangesPerDay* spr=(ConstraintTeachersMaxBuildingChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
15892
15893 if(spr->weightPercentage!=100){
15894 ok=false;
15895
15896 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15897 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers max building changes per day"
15898 " with weight under 100%. Please correct and try again"),
15899 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15900 1, 0 );
15901
15902 if(t==0)
15903 return false;
15904 }
15905
15906 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
15907 maxBuildingChangesPerDayForTeachersPercentages[tch]=100;
15908 if(maxBuildingChangesPerDayForTeachersMaxChanges[tch]<0)
15909 maxBuildingChangesPerDayForTeachersMaxChanges[tch]=spr->maxBuildingChangesPerDay;
15910 else
15911 maxBuildingChangesPerDayForTeachersMaxChanges[tch]=min(maxBuildingChangesPerDayForTeachersMaxChanges[tch], spr->maxBuildingChangesPerDay);
15912 }
15913 }
15914 }
15915
15916 return ok;
15917 }
15918
computeMaxBuildingChangesPerWeekForTeachers(QWidget * parent)15919 bool computeMaxBuildingChangesPerWeekForTeachers(QWidget* parent)
15920 {
15921 for(int i=0; i<gt.rules.nInternalTeachers; i++){
15922 maxBuildingChangesPerWeekForTeachersPercentages[i]=-1;
15923 maxBuildingChangesPerWeekForTeachersMaxChanges[i]=-1;
15924 }
15925
15926 bool ok=true;
15927
15928 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
15929 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_BUILDING_CHANGES_PER_WEEK){
15930 ConstraintTeacherMaxBuildingChangesPerWeek* spr=(ConstraintTeacherMaxBuildingChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
15931
15932 if(spr->weightPercentage!=100){
15933 ok=false;
15934
15935 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15936 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher max building changes per week"
15937 " with weight under 100%. Please correct and try again"),
15938 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15939 1, 0 );
15940
15941 if(t==0)
15942 return false;
15943 }
15944
15945 maxBuildingChangesPerWeekForTeachersPercentages[spr->teacher_ID]=100;
15946 if(maxBuildingChangesPerWeekForTeachersMaxChanges[spr->teacher_ID]<0)
15947 maxBuildingChangesPerWeekForTeachersMaxChanges[spr->teacher_ID]=spr->maxBuildingChangesPerWeek;
15948 else
15949 maxBuildingChangesPerWeekForTeachersMaxChanges[spr->teacher_ID]=min(maxBuildingChangesPerWeekForTeachersMaxChanges[spr->teacher_ID], spr->maxBuildingChangesPerWeek);
15950 }
15951 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_BUILDING_CHANGES_PER_WEEK){
15952 ConstraintTeachersMaxBuildingChangesPerWeek* spr=(ConstraintTeachersMaxBuildingChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
15953
15954 if(spr->weightPercentage!=100){
15955 ok=false;
15956
15957 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15958 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers max building changes per week"
15959 " with weight under 100%. Please correct and try again"),
15960 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
15961 1, 0 );
15962
15963 if(t==0)
15964 return false;
15965 }
15966
15967 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
15968 maxBuildingChangesPerWeekForTeachersPercentages[tch]=100;
15969 if(maxBuildingChangesPerWeekForTeachersMaxChanges[tch]<0)
15970 maxBuildingChangesPerWeekForTeachersMaxChanges[tch]=spr->maxBuildingChangesPerWeek;
15971 else
15972 maxBuildingChangesPerWeekForTeachersMaxChanges[tch]=min(maxBuildingChangesPerWeekForTeachersMaxChanges[tch], spr->maxBuildingChangesPerWeek);
15973 }
15974 }
15975 }
15976
15977 return ok;
15978 }
15979
computeMinGapsBetweenBuildingChangesForTeachers(QWidget * parent)15980 bool computeMinGapsBetweenBuildingChangesForTeachers(QWidget* parent)
15981 {
15982 for(int i=0; i<gt.rules.nInternalTeachers; i++){
15983 minGapsBetweenBuildingChangesForTeachersPercentages[i]=-1;
15984 minGapsBetweenBuildingChangesForTeachersMinGaps[i]=-1;
15985 }
15986
15987 bool ok=true;
15988
15989 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
15990 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
15991 ConstraintTeacherMinGapsBetweenBuildingChanges* spr=(ConstraintTeacherMinGapsBetweenBuildingChanges*)gt.rules.internalSpaceConstraintsList[i];
15992
15993 if(spr->weightPercentage!=100){
15994 ok=false;
15995
15996 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
15997 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher min gaps between building changes"
15998 " with weight under 100%. Please correct and try again"),
15999 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16000 1, 0 );
16001
16002 if(t==0)
16003 return false;
16004 }
16005
16006 minGapsBetweenBuildingChangesForTeachersPercentages[spr->teacher_ID]=100;
16007 if(minGapsBetweenBuildingChangesForTeachersMinGaps[spr->teacher_ID]<0)
16008 minGapsBetweenBuildingChangesForTeachersMinGaps[spr->teacher_ID]=spr->minGapsBetweenBuildingChanges;
16009 else
16010 minGapsBetweenBuildingChangesForTeachersMinGaps[spr->teacher_ID]=max(minGapsBetweenBuildingChangesForTeachersMinGaps[spr->teacher_ID], spr->minGapsBetweenBuildingChanges);
16011 }
16012 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_GAPS_BETWEEN_BUILDING_CHANGES){
16013 ConstraintTeachersMinGapsBetweenBuildingChanges* spr=(ConstraintTeachersMinGapsBetweenBuildingChanges*)gt.rules.internalSpaceConstraintsList[i];
16014
16015 if(spr->weightPercentage!=100){
16016 ok=false;
16017
16018 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16019 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers min gaps between building changes"
16020 " with weight under 100%. Please correct and try again"),
16021 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16022 1, 0 );
16023
16024 if(t==0)
16025 return false;
16026 }
16027
16028 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
16029 minGapsBetweenBuildingChangesForTeachersPercentages[tch]=100;
16030 if(minGapsBetweenBuildingChangesForTeachersMinGaps[tch]<0)
16031 minGapsBetweenBuildingChangesForTeachersMinGaps[tch]=spr->minGapsBetweenBuildingChanges;
16032 else
16033 minGapsBetweenBuildingChangesForTeachersMinGaps[tch]=max(minGapsBetweenBuildingChangesForTeachersMinGaps[tch], spr->minGapsBetweenBuildingChanges);
16034 }
16035 }
16036 }
16037
16038 return ok;
16039 }
16040
computeMaxRoomChangesPerDayForStudents(QWidget * parent)16041 bool computeMaxRoomChangesPerDayForStudents(QWidget* parent)
16042 {
16043 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
16044 maxRoomChangesPerDayForStudentsPercentages[i]=-1;
16045 maxRoomChangesPerDayForStudentsMaxChanges[i]=-1;
16046 }
16047
16048 bool ok=true;
16049
16050 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16051 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_DAY){
16052 ConstraintStudentsSetMaxRoomChangesPerDay* spr=(ConstraintStudentsSetMaxRoomChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
16053
16054 if(spr->weightPercentage!=100){
16055 ok=false;
16056
16057 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16058 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set max room changes per day"
16059 " with weight under 100%. Please correct and try again"),
16060 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16061 1, 0 );
16062
16063 if(t==0)
16064 return false;
16065 }
16066
16067 for(int sbg : qAsConst(spr->iSubgroupsList)){
16068 maxRoomChangesPerDayForStudentsPercentages[sbg]=100;
16069 if(maxRoomChangesPerDayForStudentsMaxChanges[sbg]<0)
16070 maxRoomChangesPerDayForStudentsMaxChanges[sbg]=spr->maxRoomChangesPerDay;
16071 else
16072 maxRoomChangesPerDayForStudentsMaxChanges[sbg]=min(maxRoomChangesPerDayForStudentsMaxChanges[sbg], spr->maxRoomChangesPerDay);
16073 }
16074 }
16075 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_ROOM_CHANGES_PER_DAY){
16076 ConstraintStudentsMaxRoomChangesPerDay* spr=(ConstraintStudentsMaxRoomChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
16077
16078 if(spr->weightPercentage!=100){
16079 ok=false;
16080
16081 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16082 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students max room changes per day"
16083 " with weight under 100%. Please correct and try again"),
16084 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16085 1, 0 );
16086
16087 if(t==0)
16088 return false;
16089 }
16090
16091 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
16092 maxRoomChangesPerDayForStudentsPercentages[sbg]=100;
16093 if(maxRoomChangesPerDayForStudentsMaxChanges[sbg]<0)
16094 maxRoomChangesPerDayForStudentsMaxChanges[sbg]=spr->maxRoomChangesPerDay;
16095 else
16096 maxRoomChangesPerDayForStudentsMaxChanges[sbg]=min(maxRoomChangesPerDayForStudentsMaxChanges[sbg], spr->maxRoomChangesPerDay);
16097 }
16098 }
16099 }
16100
16101 return ok;
16102 }
16103
computeMaxRoomChangesPerWeekForStudents(QWidget * parent)16104 bool computeMaxRoomChangesPerWeekForStudents(QWidget* parent)
16105 {
16106 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
16107 maxRoomChangesPerWeekForStudentsPercentages[i]=-1;
16108 maxRoomChangesPerWeekForStudentsMaxChanges[i]=-1;
16109 }
16110
16111 bool ok=true;
16112
16113 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16114 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_WEEK){
16115 ConstraintStudentsSetMaxRoomChangesPerWeek* spr=(ConstraintStudentsSetMaxRoomChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
16116
16117 if(spr->weightPercentage!=100){
16118 ok=false;
16119
16120 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16121 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set max room changes per week"
16122 " with weight under 100%. Please correct and try again"),
16123 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16124 1, 0 );
16125
16126 if(t==0)
16127 return false;
16128 }
16129
16130 for(int sbg : qAsConst(spr->iSubgroupsList)){
16131 maxRoomChangesPerWeekForStudentsPercentages[sbg]=100;
16132 if(maxRoomChangesPerWeekForStudentsMaxChanges[sbg]<0)
16133 maxRoomChangesPerWeekForStudentsMaxChanges[sbg]=spr->maxRoomChangesPerWeek;
16134 else
16135 maxRoomChangesPerWeekForStudentsMaxChanges[sbg]=min(maxRoomChangesPerWeekForStudentsMaxChanges[sbg], spr->maxRoomChangesPerWeek);
16136 }
16137 }
16138 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_ROOM_CHANGES_PER_WEEK){
16139 ConstraintStudentsMaxRoomChangesPerWeek* spr=(ConstraintStudentsMaxRoomChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
16140
16141 if(spr->weightPercentage!=100){
16142 ok=false;
16143
16144 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16145 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students max room changes per week"
16146 " with weight under 100%. Please correct and try again"),
16147 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16148 1, 0 );
16149
16150 if(t==0)
16151 return false;
16152 }
16153
16154 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
16155 maxRoomChangesPerWeekForStudentsPercentages[sbg]=100;
16156 if(maxRoomChangesPerWeekForStudentsMaxChanges[sbg]<0)
16157 maxRoomChangesPerWeekForStudentsMaxChanges[sbg]=spr->maxRoomChangesPerWeek;
16158 else
16159 maxRoomChangesPerWeekForStudentsMaxChanges[sbg]=min(maxRoomChangesPerWeekForStudentsMaxChanges[sbg], spr->maxRoomChangesPerWeek);
16160 }
16161 }
16162 }
16163
16164 return ok;
16165 }
16166
computeMinGapsBetweenRoomChangesForStudents(QWidget * parent)16167 bool computeMinGapsBetweenRoomChangesForStudents(QWidget* parent)
16168 {
16169 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
16170 minGapsBetweenRoomChangesForStudentsPercentages[i]=-1;
16171 minGapsBetweenRoomChangesForStudentsMinGaps[i]=-1;
16172 }
16173
16174 bool ok=true;
16175
16176 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16177 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MIN_GAPS_BETWEEN_ROOM_CHANGES){
16178 ConstraintStudentsSetMinGapsBetweenRoomChanges* spr=(ConstraintStudentsSetMinGapsBetweenRoomChanges*)gt.rules.internalSpaceConstraintsList[i];
16179
16180 if(spr->weightPercentage!=100){
16181 ok=false;
16182
16183 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16184 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set min gaps between room changes"
16185 " with weight under 100%. Please correct and try again"),
16186 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16187 1, 0 );
16188
16189 if(t==0)
16190 return false;
16191 }
16192
16193 for(int sbg : qAsConst(spr->iSubgroupsList)){
16194 minGapsBetweenRoomChangesForStudentsPercentages[sbg]=100;
16195 if(minGapsBetweenRoomChangesForStudentsMinGaps[sbg]<0)
16196 minGapsBetweenRoomChangesForStudentsMinGaps[sbg]=spr->minGapsBetweenRoomChanges;
16197 else
16198 minGapsBetweenRoomChangesForStudentsMinGaps[sbg]=max(minGapsBetweenRoomChangesForStudentsMinGaps[sbg], spr->minGapsBetweenRoomChanges);
16199 }
16200 }
16201 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MIN_GAPS_BETWEEN_ROOM_CHANGES){
16202 ConstraintStudentsMinGapsBetweenRoomChanges* spr=(ConstraintStudentsMinGapsBetweenRoomChanges*)gt.rules.internalSpaceConstraintsList[i];
16203
16204 if(spr->weightPercentage!=100){
16205 ok=false;
16206
16207 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16208 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students min gaps between room changes"
16209 " with weight under 100%. Please correct and try again"),
16210 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16211 1, 0 );
16212
16213 if(t==0)
16214 return false;
16215 }
16216
16217 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
16218 minGapsBetweenRoomChangesForStudentsPercentages[sbg]=100;
16219 if(minGapsBetweenRoomChangesForStudentsMinGaps[sbg]<0)
16220 minGapsBetweenRoomChangesForStudentsMinGaps[sbg]=spr->minGapsBetweenRoomChanges;
16221 else
16222 minGapsBetweenRoomChangesForStudentsMinGaps[sbg]=max(minGapsBetweenRoomChangesForStudentsMinGaps[sbg], spr->minGapsBetweenRoomChanges);
16223 }
16224 }
16225 }
16226
16227 return ok;
16228 }
16229
computeMaxRoomChangesPerDayForTeachers(QWidget * parent)16230 bool computeMaxRoomChangesPerDayForTeachers(QWidget* parent)
16231 {
16232 for(int i=0; i<gt.rules.nInternalTeachers; i++){
16233 maxRoomChangesPerDayForTeachersPercentages[i]=-1;
16234 maxRoomChangesPerDayForTeachersMaxChanges[i]=-1;
16235 }
16236
16237 bool ok=true;
16238
16239 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16240 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_ROOM_CHANGES_PER_DAY){
16241 ConstraintTeacherMaxRoomChangesPerDay* spr=(ConstraintTeacherMaxRoomChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
16242
16243 if(spr->weightPercentage!=100){
16244 ok=false;
16245
16246 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16247 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher max room changes per day"
16248 " with weight under 100%. Please correct and try again"),
16249 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16250 1, 0 );
16251
16252 if(t==0)
16253 return false;
16254 }
16255
16256 maxRoomChangesPerDayForTeachersPercentages[spr->teacher_ID]=100;
16257 if(maxRoomChangesPerDayForTeachersMaxChanges[spr->teacher_ID]<0)
16258 maxRoomChangesPerDayForTeachersMaxChanges[spr->teacher_ID]=spr->maxRoomChangesPerDay;
16259 else
16260 maxRoomChangesPerDayForTeachersMaxChanges[spr->teacher_ID]=min(maxRoomChangesPerDayForTeachersMaxChanges[spr->teacher_ID], spr->maxRoomChangesPerDay);
16261 }
16262 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_ROOM_CHANGES_PER_DAY){
16263 ConstraintTeachersMaxRoomChangesPerDay* spr=(ConstraintTeachersMaxRoomChangesPerDay*)gt.rules.internalSpaceConstraintsList[i];
16264
16265 if(spr->weightPercentage!=100){
16266 ok=false;
16267
16268 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16269 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers max room changes per day"
16270 " with weight under 100%. Please correct and try again"),
16271 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16272 1, 0 );
16273
16274 if(t==0)
16275 return false;
16276 }
16277
16278 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
16279 maxRoomChangesPerDayForTeachersPercentages[tch]=100;
16280 if(maxRoomChangesPerDayForTeachersMaxChanges[tch]<0)
16281 maxRoomChangesPerDayForTeachersMaxChanges[tch]=spr->maxRoomChangesPerDay;
16282 else
16283 maxRoomChangesPerDayForTeachersMaxChanges[tch]=min(maxRoomChangesPerDayForTeachersMaxChanges[tch], spr->maxRoomChangesPerDay);
16284 }
16285 }
16286 }
16287
16288 return ok;
16289 }
16290
computeMaxRoomChangesPerWeekForTeachers(QWidget * parent)16291 bool computeMaxRoomChangesPerWeekForTeachers(QWidget* parent)
16292 {
16293 for(int i=0; i<gt.rules.nInternalTeachers; i++){
16294 maxRoomChangesPerWeekForTeachersPercentages[i]=-1;
16295 maxRoomChangesPerWeekForTeachersMaxChanges[i]=-1;
16296 }
16297
16298 bool ok=true;
16299
16300 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16301 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_ROOM_CHANGES_PER_WEEK){
16302 ConstraintTeacherMaxRoomChangesPerWeek* spr=(ConstraintTeacherMaxRoomChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
16303
16304 if(spr->weightPercentage!=100){
16305 ok=false;
16306
16307 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16308 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher max room changes per week"
16309 " with weight under 100%. Please correct and try again"),
16310 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16311 1, 0 );
16312
16313 if(t==0)
16314 return false;
16315 }
16316
16317 maxRoomChangesPerWeekForTeachersPercentages[spr->teacher_ID]=100;
16318 if(maxRoomChangesPerWeekForTeachersMaxChanges[spr->teacher_ID]<0)
16319 maxRoomChangesPerWeekForTeachersMaxChanges[spr->teacher_ID]=spr->maxRoomChangesPerWeek;
16320 else
16321 maxRoomChangesPerWeekForTeachersMaxChanges[spr->teacher_ID]=min(maxRoomChangesPerWeekForTeachersMaxChanges[spr->teacher_ID], spr->maxRoomChangesPerWeek);
16322 }
16323 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_ROOM_CHANGES_PER_WEEK){
16324 ConstraintTeachersMaxRoomChangesPerWeek* spr=(ConstraintTeachersMaxRoomChangesPerWeek*)gt.rules.internalSpaceConstraintsList[i];
16325
16326 if(spr->weightPercentage!=100){
16327 ok=false;
16328
16329 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16330 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers max room changes per week"
16331 " with weight under 100%. Please correct and try again"),
16332 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16333 1, 0 );
16334
16335 if(t==0)
16336 return false;
16337 }
16338
16339 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
16340 maxRoomChangesPerWeekForTeachersPercentages[tch]=100;
16341 if(maxRoomChangesPerWeekForTeachersMaxChanges[tch]<0)
16342 maxRoomChangesPerWeekForTeachersMaxChanges[tch]=spr->maxRoomChangesPerWeek;
16343 else
16344 maxRoomChangesPerWeekForTeachersMaxChanges[tch]=min(maxRoomChangesPerWeekForTeachersMaxChanges[tch], spr->maxRoomChangesPerWeek);
16345 }
16346 }
16347 }
16348
16349 return ok;
16350 }
16351
computeMinGapsBetweenRoomChangesForTeachers(QWidget * parent)16352 bool computeMinGapsBetweenRoomChangesForTeachers(QWidget* parent)
16353 {
16354 for(int i=0; i<gt.rules.nInternalTeachers; i++){
16355 minGapsBetweenRoomChangesForTeachersPercentages[i]=-1;
16356 minGapsBetweenRoomChangesForTeachersMinGaps[i]=-1;
16357 }
16358
16359 bool ok=true;
16360
16361 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16362 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MIN_GAPS_BETWEEN_ROOM_CHANGES){
16363 ConstraintTeacherMinGapsBetweenRoomChanges* spr=(ConstraintTeacherMinGapsBetweenRoomChanges*)gt.rules.internalSpaceConstraintsList[i];
16364
16365 if(spr->weightPercentage!=100){
16366 ok=false;
16367
16368 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16369 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher min gaps between room changes"
16370 " with weight under 100%. Please correct and try again"),
16371 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16372 1, 0 );
16373
16374 if(t==0)
16375 return false;
16376 }
16377
16378 minGapsBetweenRoomChangesForTeachersPercentages[spr->teacher_ID]=100;
16379 if(minGapsBetweenRoomChangesForTeachersMinGaps[spr->teacher_ID]<0)
16380 minGapsBetweenRoomChangesForTeachersMinGaps[spr->teacher_ID]=spr->minGapsBetweenRoomChanges;
16381 else
16382 minGapsBetweenRoomChangesForTeachersMinGaps[spr->teacher_ID]=max(minGapsBetweenRoomChangesForTeachersMinGaps[spr->teacher_ID], spr->minGapsBetweenRoomChanges);
16383 }
16384 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MIN_GAPS_BETWEEN_ROOM_CHANGES){
16385 ConstraintTeachersMinGapsBetweenRoomChanges* spr=(ConstraintTeachersMinGapsBetweenRoomChanges*)gt.rules.internalSpaceConstraintsList[i];
16386
16387 if(spr->weightPercentage!=100){
16388 ok=false;
16389
16390 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16391 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers min gaps between room changes"
16392 " with weight under 100%. Please correct and try again"),
16393 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16394 1, 0 );
16395
16396 if(t==0)
16397 return false;
16398 }
16399
16400 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
16401 minGapsBetweenRoomChangesForTeachersPercentages[tch]=100;
16402 if(minGapsBetweenRoomChangesForTeachersMinGaps[tch]<0)
16403 minGapsBetweenRoomChangesForTeachersMinGaps[tch]=spr->minGapsBetweenRoomChanges;
16404 else
16405 minGapsBetweenRoomChangesForTeachersMinGaps[tch]=max(minGapsBetweenRoomChangesForTeachersMinGaps[tch], spr->minGapsBetweenRoomChanges);
16406 }
16407 }
16408 }
16409
16410 return ok;
16411 }
16412
computeMaxRoomChangesPerRealDayForTeachers(QWidget * parent)16413 bool computeMaxRoomChangesPerRealDayForTeachers(QWidget* parent)
16414 {
16415 for(int i=0; i<gt.rules.nInternalTeachers; i++){
16416 maxRoomChangesPerRealDayForTeachersPercentages[i]=-1;
16417 maxRoomChangesPerRealDayForTeachersMaxChanges[i]=-1;
16418 }
16419
16420 bool ok=true;
16421
16422 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16423 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_ROOM_CHANGES_PER_REAL_DAY){
16424 ConstraintTeacherMaxRoomChangesPerRealDay* spr=(ConstraintTeacherMaxRoomChangesPerRealDay*)gt.rules.internalSpaceConstraintsList[i];
16425
16426 if(spr->weightPercentage!=100){
16427 ok=false;
16428
16429 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16430 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teacher max room changes per day"
16431 " with weight under 100%. Please correct and try again"),
16432 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16433 1, 0 );
16434
16435 if(t==0)
16436 return false;
16437 }
16438
16439 maxRoomChangesPerRealDayForTeachersPercentages[spr->teacher_ID]=100;
16440 if(maxRoomChangesPerRealDayForTeachersMaxChanges[spr->teacher_ID]<0)
16441 maxRoomChangesPerRealDayForTeachersMaxChanges[spr->teacher_ID]=spr->maxRoomChangesPerDay;
16442 else
16443 maxRoomChangesPerRealDayForTeachersMaxChanges[spr->teacher_ID]=min(maxRoomChangesPerRealDayForTeachersMaxChanges[spr->teacher_ID], spr->maxRoomChangesPerDay);
16444 }
16445 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_ROOM_CHANGES_PER_REAL_DAY){
16446 ConstraintTeachersMaxRoomChangesPerRealDay* spr=(ConstraintTeachersMaxRoomChangesPerRealDay*)gt.rules.internalSpaceConstraintsList[i];
16447
16448 if(spr->weightPercentage!=100){
16449 ok=false;
16450
16451 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16452 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint teachers max room changes per day"
16453 " with weight under 100%. Please correct and try again"),
16454 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16455 1, 0 );
16456
16457 if(t==0)
16458 return false;
16459 }
16460
16461 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++){
16462 maxRoomChangesPerRealDayForTeachersPercentages[tch]=100;
16463 if(maxRoomChangesPerRealDayForTeachersMaxChanges[tch]<0)
16464 maxRoomChangesPerRealDayForTeachersMaxChanges[tch]=spr->maxRoomChangesPerDay;
16465 else
16466 maxRoomChangesPerRealDayForTeachersMaxChanges[tch]=min(maxRoomChangesPerRealDayForTeachersMaxChanges[tch], spr->maxRoomChangesPerDay);
16467 }
16468 }
16469 }
16470
16471 return ok;
16472 }
16473
computeMaxRoomChangesPerRealDayForStudents(QWidget * parent)16474 bool computeMaxRoomChangesPerRealDayForStudents(QWidget* parent)
16475 {
16476 for(int i=0; i<gt.rules.nInternalSubgroups; i++){
16477 maxRoomChangesPerRealDayForSubgroupsPercentages[i]=-1;
16478 maxRoomChangesPerRealDayForSubgroupsMaxChanges[i]=-1;
16479 }
16480
16481 bool ok=true;
16482
16483 for(int i=0; i<gt.rules.nInternalSpaceConstraints; i++){
16484 if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_SET_MAX_ROOM_CHANGES_PER_REAL_DAY){
16485 ConstraintStudentsSetMaxRoomChangesPerRealDay* spr=(ConstraintStudentsSetMaxRoomChangesPerRealDay*)gt.rules.internalSpaceConstraintsList[i];
16486
16487 if(spr->weightPercentage!=100){
16488 ok=false;
16489
16490 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16491 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students set max room changes per day"
16492 " with weight under 100%. Please correct and try again"),
16493 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16494 1, 0 );
16495
16496 if(t==0)
16497 return false;
16498 }
16499
16500 for(int sbg : spr->iSubgroupsList){
16501 maxRoomChangesPerRealDayForSubgroupsPercentages[sbg]=100;
16502 if(maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg]<0)
16503 maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg]=spr->maxRoomChangesPerDay;
16504 else
16505 maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg]=min(maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg], spr->maxRoomChangesPerDay);
16506 }
16507 }
16508 else if(gt.rules.internalSpaceConstraintsList[i]->type==CONSTRAINT_STUDENTS_MAX_ROOM_CHANGES_PER_REAL_DAY){
16509 ConstraintStudentsMaxRoomChangesPerRealDay* spr=(ConstraintStudentsMaxRoomChangesPerRealDay*)gt.rules.internalSpaceConstraintsList[i];
16510
16511 if(spr->weightPercentage!=100){
16512 ok=false;
16513
16514 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
16515 GeneratePreTranslate::tr("Cannot optimize, because there is a space constraint students max room changes per day"
16516 " with weight under 100%. Please correct and try again"),
16517 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16518 1, 0 );
16519
16520 if(t==0)
16521 return false;
16522 }
16523
16524 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++){
16525 maxRoomChangesPerRealDayForSubgroupsPercentages[sbg]=100;
16526 if(maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg]<0)
16527 maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg]=spr->maxRoomChangesPerDay;
16528 else
16529 maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg]=min(maxRoomChangesPerRealDayForSubgroupsMaxChanges[sbg], spr->maxRoomChangesPerDay);
16530 }
16531 }
16532 }
16533
16534 return ok;
16535 }
16536
computeMustComputeTimetableSubgroups()16537 void computeMustComputeTimetableSubgroups()
16538 {
16539 for(int sbg=0; sbg<gt.rules.nInternalSubgroups; sbg++)
16540 mustComputeTimetableSubgroup[sbg]=false;
16541
16542 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
16543 Activity* act=>.rules.internalActivitiesList[ai];
16544
16545 mustComputeTimetableSubgroups[ai].clear();
16546
16547 for(int sbg : qAsConst(act->iSubgroupsList))
16548 if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0 ||
16549 subgroupsMaxGapsPerDayPercentage[sbg]>=0 ||
16550 subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0 ||
16551 subgroupsMaxHoursDailyPercentages1[sbg]>=0 ||
16552 subgroupsMaxHoursDailyPercentages2[sbg]>=0 ||
16553 subgroupsMaxHoursContinuouslyPercentages1[sbg]>=0 ||
16554 subgroupsMaxHoursContinuouslyPercentages2[sbg]>=0 ||
16555 subgroupsMinHoursDailyPercentages[sbg][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0 || //daily for official, afternoon for mornings-afternoons
16556
16557 subgroupsMaxSpanPerDayPercentages[sbg]>=0 ||
16558 subgroupsMinRestingHoursCircularPercentages[sbg]>=0 ||
16559 subgroupsMinRestingHoursNotCircularPercentages[sbg]>=0 ||
16560
16561 subgroupsIntervalMaxDaysPerWeekPercentages[sbg].count()>0 ||
16562
16563 maxBuildingChangesPerDayForStudentsPercentages[sbg]>=0 ||
16564 maxBuildingChangesPerWeekForStudentsPercentages[sbg]>=0 ||
16565 minGapsBetweenBuildingChangesForStudentsPercentages[sbg]>=0 ||
16566
16567 maxRoomChangesPerDayForStudentsPercentages[sbg]>=0 ||
16568 maxRoomChangesPerWeekForStudentsPercentages[sbg]>=0 ||
16569 minGapsBetweenRoomChangesForStudentsPercentages[sbg]>=0 ||
16570
16571 subgroupsActivityTagMaxHoursContinuouslyPercentage[sbg].count()>0 ||
16572 subgroupsActivityTagMaxHoursDailyPercentage[sbg].count()>0 ||
16573 satmhdListForSubgroup[sbg].count()>0 ||
16574 //no need to consider constraints students (set) min gaps between ordered pair of activity tags
16575
16576 //mornings-afternoons
16577 subgroupsMaxGapsPerRealDayPercentage[sbg]>=0 ||
16578 subgroupsMaxGapsPerWeekForRealDaysPercentage[sbg]>=0 ||
16579 subgroupsMaxHoursDailyRealDaysPercentages1[sbg]>=0 ||
16580 subgroupsMaxHoursDailyRealDaysPercentages2[sbg]>=0 ||
16581 subgroupsMinHoursDailyPercentages[sbg][0]>=0 || //mornings-afternoons: morning (daily or morning constraint)
16582
16583 subgroupsMaxHoursPerAllAfternoonsPercentages[sbg]>=0 ||
16584
16585 subgroupsMinMorningsPerWeekPercentages[sbg]>=0 ||
16586 subgroupsMinAfternoonsPerWeekPercentages[sbg]>=0 ||
16587
16588 subgroupsMaxSpanPerRealDayPercentages[sbg]>=0 ||
16589 subgroupsMinRestingHoursBetweenMorningAndAfternoonPercentages[sbg]>=0 ||
16590
16591 subgroupsMorningIntervalMaxDaysPerWeekPercentages[sbg].count()>0 ||
16592 subgroupsAfternoonIntervalMaxDaysPerWeekPercentages[sbg].count()>0 ||
16593
16594 maxRoomChangesPerRealDayForSubgroupsPercentages[sbg]>=0 ||
16595
16596 subgroupsActivityTagMaxHoursDailyRealDaysPercentage[sbg].count()>0 ||
16597
16598 subgroupsAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0 ||
16599 subgroupsMorningsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0
16600 ){
16601
16602 mustComputeTimetableSubgroups[ai].append(sbg);
16603 mustComputeTimetableSubgroup[sbg]=true;
16604 }
16605 }
16606 }
16607
computeMustComputeTimetableTeachers()16608 void computeMustComputeTimetableTeachers()
16609 {
16610 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++)
16611 mustComputeTimetableTeacher[tch]=false;
16612
16613 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
16614 Activity* act=>.rules.internalActivitiesList[ai];
16615
16616 mustComputeTimetableTeachers[ai].clear();
16617
16618 for(int tch : qAsConst(act->iTeachersList))
16619 if(teachersMaxGapsPerWeekPercentage[tch]>=0 ||
16620 teachersMaxGapsPerDayPercentage[tch]>=0 ||
16621 teachersMaxHoursDailyPercentages1[tch]>=0 ||
16622 teachersMaxHoursDailyPercentages2[tch]>=0 ||
16623 teachersMaxHoursContinuouslyPercentages1[tch]>=0 ||
16624 teachersMaxHoursContinuouslyPercentages2[tch]>=0 ||
16625 teachersMinHoursDailyPercentages[tch][MIN_HOURS_DAILY_INDEX_IN_ARRAY]>=0 || //daily for official, afternoon for mornings-afternoons
16626
16627 teachersMinDaysPerWeekPercentages[tch]>=0 ||
16628
16629 teachersMaxSpanPerDayPercentages[tch]>=0 ||
16630 teachersMinRestingHoursCircularPercentages[tch]>=0 ||
16631 teachersMinRestingHoursNotCircularPercentages[tch]>=0 ||
16632
16633 teachersIntervalMaxDaysPerWeekPercentages[tch].count()>0 ||
16634
16635 maxBuildingChangesPerDayForTeachersPercentages[tch]>=0 ||
16636 maxBuildingChangesPerWeekForTeachersPercentages[tch]>=0 ||
16637 minGapsBetweenBuildingChangesForTeachersPercentages[tch]>=0 ||
16638
16639 maxRoomChangesPerDayForTeachersPercentages[tch]>=0 ||
16640 maxRoomChangesPerWeekForTeachersPercentages[tch]>=0 ||
16641 minGapsBetweenRoomChangesForTeachersPercentages[tch]>=0 ||
16642
16643 teachersActivityTagMaxHoursContinuouslyPercentage[tch].count()>0 ||
16644 teachersActivityTagMaxHoursDailyPercentage[tch].count()>0 ||
16645 tatmhdListForTeacher[tch].count()>0 ||
16646 //no need to consider constraints teacher(s) min gaps between ordered pair of activity tags
16647
16648 //mornings-afternoons
16649 teachersMaxGapsPerRealDayPercentage[tch]>=0 ||
16650 teachersMaxGapsPerWeekForRealDaysPercentage[tch]>=0 ||
16651 teachersMaxHoursDailyRealDaysPercentages1[tch]>=0 ||
16652 teachersMaxHoursDailyRealDaysPercentages2[tch]>=0 ||
16653
16654 teachersMinHoursDailyPercentages[tch][0]>=0 || //mornings-afternoons: morning (daily or morning constraint)
16655 teachersMinHoursDailyRealDaysPercentages[tch]>=0 ||
16656
16657 teachersMaxHoursPerAllAfternoonsPercentages[tch]>=0 ||
16658
16659 teachersMinRealDaysPerWeekPercentages[tch]>=0 ||
16660 teachersMinMorningsPerWeekPercentages[tch]>=0 ||
16661 teachersMinAfternoonsPerWeekPercentages[tch]>=0 ||
16662
16663 teachersMaxSpanPerRealDayPercentages[tch]>=0 ||
16664 teachersMinRestingHoursBetweenMorningAndAfternoonPercentages[tch]>=0 ||
16665
16666 teachersMorningIntervalMaxDaysPerWeekPercentages[tch].count()>0 ||
16667 teachersAfternoonIntervalMaxDaysPerWeekPercentages[tch].count()>0 ||
16668
16669 maxRoomChangesPerRealDayForTeachersPercentages[tch]>=0 ||
16670
16671 teachersActivityTagMaxHoursDailyRealDaysPercentage[tch].count()>0 ||
16672
16673 teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages[tch]>=0 ||
16674
16675 teachersAfternoonsEarlyMaxBeginningsAtSecondHourPercentage[tch]>=0 ||
16676 teachersMorningsEarlyMaxBeginningsAtSecondHourPercentage[tch]>=0 ||
16677
16678 teachersMaxGapsPerMorningAndAfternoonPercentage[tch]>=0 ||
16679
16680 teacherConstrainedToZeroGapsPerAfternoon[tch]==true
16681 ){
16682
16683 mustComputeTimetableTeachers[ai].append(tch);
16684 mustComputeTimetableTeacher[tch]=true;
16685 }
16686 }
16687 }
16688
computeN1N2N3(QWidget * parent)16689 bool computeN1N2N3(QWidget* parent)
16690 {
16691 for(int i=0; i<gt.rules.nInternalTeachers; i++){
16692 teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages[i]=-1.0;
16693 }
16694
16695 //bool haveN1N2N3=false;
16696
16697 bool ok=true;
16698 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
16699 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHER_MAX_TWO_ACTIVITY_TAGS_PER_DAY_FROM_N1N2N3){
16700 //haveN1N2N3=true;
16701
16702 ConstraintTeacherMaxTwoActivityTagsPerDayFromN1N2N3* tn=(ConstraintTeacherMaxTwoActivityTagsPerDayFromN1N2N3*)gt.rules.internalTimeConstraintsList[i];
16703
16704 teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages[tn->teacher_ID]=100.0;
16705 }
16706 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TEACHERS_MAX_TWO_ACTIVITY_TAGS_PER_DAY_FROM_N1N2N3){
16707 //haveN1N2N3=true;
16708
16709 //ConstraintTeachersMaxTwoActivityTagsPerDayFromN1N2N3* tn=(ConstraintTeachersMaxTwoActivityTagsPerDayFromN1N2N3*)gt.rules.internalTimeConstraintsList[i];
16710
16711 //teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages[tn->teacher_ID]=100.0;
16712 for(int tch=0; tch<gt.rules.nInternalTeachers; tch++)
16713 teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages[tch]=100.0;
16714 break;
16715 }
16716 }
16717
16718 for(int i=0; i<gt.rules.nInternalActivities; i++){
16719 teachersWithN1N2N3ForActivities[i].clear();
16720
16721 Activity* act=>.rules.internalActivitiesList[i];
16722 for(int j=0; j<act->iTeachersList.count(); j++){
16723 int tch=act->iTeachersList.at(j);
16724
16725 if(teachersMaxTwoActivityTagsPerDayFromN1N2N3Percentages[tch]>=0){
16726 assert(teachersWithN1N2N3ForActivities[i].indexOf(tch)==-1);
16727 teachersWithN1N2N3ForActivities[i].append(tch);
16728 }
16729 }
16730 }
16731
16732 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
16733 Activity* act=>.rules.internalActivitiesList[ai];
16734 int cnt=0;
16735 for(const QString& tag : qAsConst(act->activityTagsNames)){
16736 if(tag=="N1"){
16737 activityTagN1N2N3[ai]=0;
16738 cnt++;
16739 }
16740 else if(tag=="N2"){
16741 activityTagN1N2N3[ai]=1;
16742 cnt++;
16743 }
16744 else if(tag=="N3"){
16745 activityTagN1N2N3[ai]=2;
16746 cnt++;
16747 }
16748 }
16749 if(cnt==0){
16750 activityTagN1N2N3[ai]=3; //none
16751 }
16752 else if(teachersWithN1N2N3ForActivities[ai].count()>=1 && cnt>=2){
16753 ok=false;
16754
16755 QString s=GeneratePreTranslate::tr("Activity with id=%1 has more than one activity tag from N1, N2, and N3, and you have"
16756 " at least a constraint of type teacher(s) max two activity tags from N1, N2, and N3 per day for the teacher(s) of this activity - please correct that.")
16757 .arg(gt.rules.internalActivitiesList[ai].id);
16758 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
16759 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16760 1, 0 );
16761
16762 if(t==0)
16763 return false;
16764 }
16765 }
16766
16767 return ok;
16768 }
16769
computeFixedActivities(QWidget * parent)16770 bool computeFixedActivities(QWidget* parent)
16771 {
16772 bool ok=true;
16773
16774 fixedVirtualSpaceNonZeroButNotTimeActivities.clear();
16775
16776 for(int ai=0; ai<gt.rules.nInternalActivities; ai++){
16777 int notAllowedSlots=0;
16778 for(int tim=0; tim<gt.rules.nHoursPerWeek; tim++)
16779 if(notAllowedTimesPercentages[ai][tim]==100)
16780 notAllowedSlots++;
16781
16782 if(notAllowedSlots==gt.rules.nHoursPerWeek){
16783 ok=false;
16784
16785 QString s=GeneratePreTranslate::tr("Activity with id=%1 has no allowed slot - please correct that.").arg(gt.rules.internalActivitiesList[ai].id);
16786 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
16787 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16788 1, 0 );
16789
16790 if(t==0)
16791 return false;
16792 }
16793 else if(notAllowedSlots==gt.rules.nHoursPerWeek-1)
16794 fixedTimeActivity[ai]=true;
16795 else
16796 fixedTimeActivity[ai]=false;
16797
16798 //space
16799 //2019-09-22: after computeActivitiesRoomsPreferences
16800 QSet<int> srrs; //single real rooms set
16801 for(int r=0; r<gt.rules.nInternalRooms; r++){
16802 Room* rm=gt.rules.internalRoomsList[r];
16803
16804 if(rm->isVirtual==false)
16805 continue;
16806
16807 bool allSetsAreSingle=true;
16808 for(const QList<int>& tl : qAsConst(rm->rrsl))
16809 if(tl.count()!=1){
16810 assert(tl.count()>=2);
16811 allSetsAreSingle=false;
16812 break;
16813 }
16814
16815 if(allSetsAreSingle)
16816 srrs.insert(r);
16817 }
16818
16819 fixedSpaceActivity[ai]=false;
16820 for(const PreferredRoomsItem& it : qAsConst(activitiesPreferredRoomsList[ai]))
16821 if(it.percentage==100.0 && it.preferredRooms.count()==1){
16822 //int rm=it.preferredRooms.toList().at(0);
16823 int rm=*(it.preferredRooms.begin());
16824 assert(rm>=0 && rm<gt.rules.nInternalRooms);
16825
16826 /*
16827 if(gt.rules.internalRoomsList[rm]->isVirtual==false ||
16828 //2019-09-22: the test below is not too good for the initial order, but otherwise the partially locked timetables become impossible
16829 //(it's more like a hack).
16830 (gt.rules.internalRoomsList[rm]->isVirtual==true && preferredRealRooms[ai].count()!=0) ||
16831 (gt.rules.internalRoomsList[rm]->isVirtual==true && preferredRealRooms[ai].count()==0 && srrs.contains(rm))){
16832 fixedSpaceActivity[ai]=true;
16833 break;
16834 }*/
16835
16836 //If the preferred real rooms are not fixed (preferredRealRooms[ai].count()==0) for a virtual room, we cannot
16837 //make fixedSpaceActivity[ai]=true, because otherwise we might get an impossible timetable for fixed timetables.
16838 if(gt.rules.internalRoomsList[rm]->isVirtual==false){
16839 fixedSpaceActivity[ai]=true;
16840 break;
16841 }
16842 else if(gt.rules.internalRoomsList[rm]->isVirtual==true && preferredRealRooms[ai].count()==0 && srrs.contains(rm)){
16843 fixedSpaceActivity[ai]=true;
16844 break;
16845 }
16846 else if(gt.rules.internalRoomsList[rm]->isVirtual==true && preferredRealRooms[ai].count()!=0){
16847 fixedSpaceActivity[ai]=true;
16848
16849 if(fixedTimeActivity[ai]==false && !fixedVirtualSpaceNonZeroButNotTimeActivities.contains(ai))
16850 fixedVirtualSpaceNonZeroButNotTimeActivities.insert(ai);
16851
16852 break;
16853 }
16854 }
16855 /////////////////////////////////////////////////////
16856 }
16857
16858 return ok;
16859 }
16860
homeRoomsAreOk(QWidget * parent)16861 bool homeRoomsAreOk(QWidget* parent)
16862 {
16863 for(int r=0; r<gt.rules.nInternalRooms; r++)
16864 nHoursRequiredForRoom[r]=0;
16865
16866 for(int a=0; a<gt.rules.nInternalActivities; a++)
16867 if(unspecifiedPreferredRoom[a] && !unspecifiedHomeRoom[a]
16868 && activitiesHomeRoomsHomeRooms[a].count()==1 && activitiesHomeRoomsPercentage[a]==100.0){
16869 int r=activitiesHomeRoomsHomeRooms[a].at(0);
16870 nHoursRequiredForRoom[r]+=gt.rules.internalActivitiesList[a].duration;
16871 }
16872
16873 for(int r=0; r<gt.rules.nInternalRooms; r++){
16874 nHoursAvailableForRoom[r]=0;
16875 for(int d=0; d<gt.rules.nDaysPerWeek; d++)
16876 for(int h=0; h<gt.rules.nHoursPerDay; h++)
16877 if(!breakDayHour[d][h] && notAllowedRoomTimePercentages[r][d+h*gt.rules.nDaysPerWeek]<100.0)
16878 nHoursAvailableForRoom[r]++;
16879 }
16880
16881 bool ok=true;
16882
16883 for(int r=0; r<gt.rules.nInternalRooms; r++)
16884 if(nHoursRequiredForRoom[r]>nHoursAvailableForRoom[r]){
16885 ok=false;
16886
16887 QString s=GeneratePreTranslate::tr("Room %1 has not enough slots for home rooms constraints (requested %2, available %3) - please correct that.")
16888 .arg(gt.rules.internalRoomsList[r]->name).arg(nHoursRequiredForRoom[r]).arg(nHoursAvailableForRoom[r]);
16889 int t=GeneratePreIrreconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"), s,
16890 GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
16891 1, 0 );
16892
16893 if(t==0)
16894 return false;
16895 }
16896
16897 return ok;
16898 }
16899
sortActivities(QWidget * parent,const QHash<int,int> & reprSameStartingTime,const QHash<int,QSet<int>> & reprSameActivitiesSet,QTextStream * initialOrderStream)16900 void sortActivities(QWidget* parent, const QHash<int, int> & reprSameStartingTime, const QHash<int, QSet<int>> & reprSameActivitiesSet, QTextStream* initialOrderStream)
16901 {
16902 //I should take care of home rooms, but I don't want to change the routine below which works well
16903
16904 // const int INF = 2000000000;
16905 const int INF = 1500000000; //INF and INF2 values of variables may be increased, so they should be INF2>>INF and INF2<<MAXINT(2147.........)
16906 // const int INF2 = 2000000001;
16907 const int INF2 = 2000000000;
16908
16909 const double THRESHOLD=80.0;
16910
16911 //rooms init
16912 for(int j=0; j<gt.rules.nInternalRooms; j++){
16913 nRoomsIncompat[j]=0;
16914 if(gt.rules.internalRoomsList[j]->isVirtual==false){
16915 for(int k=0; k<gt.rules.nHoursPerWeek; k++){
16916 if(notAllowedRoomTimePercentages[j][k]>=THRESHOLD){
16917 nRoomsIncompat[j]++;
16918 }
16919 }
16920 }
16921 else{
16922 for(int k=0; k<gt.rules.nHoursPerWeek; k++){
16923 bool available=true;
16924 if(notAllowedRoomTimePercentages[j][k]>=THRESHOLD){
16925 available=false;
16926 }
16927 if(available){
16928 for(const QList<int>& tl : qAsConst(gt.rules.internalRoomsList[j]->rrsl)){
16929 bool ok=false;
16930 for(int r2 : qAsConst(tl)){
16931 if(notAllowedRoomTimePercentages[r2][k]<THRESHOLD){
16932 ok=true;
16933 break;
16934 }
16935 }
16936 if(!ok){
16937 available=false;
16938 break;
16939 }
16940 }
16941 }
16942 if(!available){
16943 nRoomsIncompat[j]++;
16944 }
16945 }
16946 }
16947 }
16948
16949 for(int j=0; j<gt.rules.nInternalRooms; j++)
16950 nHoursForRoom[j]=0.0;
16951
16952 //only consider for each activity the constraint preferred room(s) with highest percentage (and then lowest number of rooms)
16953 for(int j=0; j<gt.rules.nInternalActivities; j++){
16954 maxPercentagePrefRooms[j].percentage=-1;
16955 maxPercentagePrefRooms[j].preferredRooms.clear();
16956
16957 double maxPercentage=-1;
16958 double minNRooms=INF;
16959 for(const PreferredRoomsItem& it : qAsConst(activitiesPreferredRoomsList[j]))
16960 if(maxPercentage<it.percentage || (maxPercentage==it.percentage && minNRooms>it.preferredRooms.count())){
16961 maxPercentage=it.percentage;
16962 minNRooms=it.preferredRooms.count();
16963 maxPercentagePrefRooms[j]=it;
16964 }
16965 }
16966
16967 for(int j=0; j<gt.rules.nInternalActivities; j++){
16968 PreferredRoomsItem it=maxPercentagePrefRooms[j];
16969 if(it.percentage>=THRESHOLD){
16970 assert(!unspecifiedPreferredRoom[j]);
16971 for(int rm : qAsConst(it.preferredRooms))
16972 nHoursForRoom[rm]+=double(gt.rules.internalActivitiesList[j].duration)/double(it.preferredRooms.count());
16973 }
16974 }
16975
16976 //make those with same starting time have conflicts
16977 //for instance, if A1 simultaneous with A2 and A2 conflicts with A3. then A1 conflicts with A3
16978 //also, A1 will conflict with A2, but this conflict is not counted
16979 //idea of Volker Dirr, implementation of Liviu
16980
16981 QSet<int> allRepresentants;
16982 for(int r : qAsConst(reprSameStartingTime)) //only values, which are representants
16983 allRepresentants.insert(r);
16984
16985 for(int r : qAsConst(allRepresentants)){
16986 assert(reprSameActivitiesSet.contains(r));
16987 QSet<int> s=reprSameActivitiesSet.value(r);
16988
16989 assert(s.count()>=1);
16990 if(s.count()>=2){
16991 //Faster
16992 QHash<int, int> conflHash;
16993
16994 for(int i : qAsConst(s)){
16995 QHash<int, int>::const_iterator it=activitiesConflictingPercentage[i].constBegin();
16996 while(it!=activitiesConflictingPercentage[i].constEnd()){
16997 int j=it.key();
16998 int weight=it.value();
16999 if(conflHash.value(j, -1)<weight)
17000 conflHash.insert(j, weight);
17001 it++;
17002 }
17003 }
17004
17005 for(int i : qAsConst(s)){
17006 QHash<int, int>::const_iterator it=conflHash.constBegin();
17007 while(it!=conflHash.constEnd()){
17008 int j=it.key();
17009 int weight=it.value();
17010 if(activitiesConflictingPercentage[i].value(j, -1)<weight)
17011 activitiesConflictingPercentage[i].insert(j, weight);
17012
17013 if(activitiesConflictingPercentage[j].value(i, -1)<weight)
17014 activitiesConflictingPercentage[j].insert(i, weight);
17015
17016 it++;
17017 }
17018 }
17019 }
17020 }
17021 //end same starting time
17022
17023 for(int i=0; i<gt.rules.nInternalActivities; i++){
17024 nIncompatible[i]=0;
17025
17026 assert(reprSameStartingTime.contains(i));
17027
17028 //basic
17029 QHash<int, int>& hashConfl=activitiesConflictingPercentage[i];
17030
17031 QHash<int, int>::const_iterator iter=hashConfl.constBegin();
17032 while(iter!=hashConfl.constEnd()){
17033 int j=iter.key();
17034 assert(reprSameStartingTime.contains(j));
17035
17036 if(reprSameStartingTime.value(i)!=reprSameStartingTime.value(j)){
17037 if(i!=j && iter.value()>=THRESHOLD){
17038 nIncompatible[i]+=gt.rules.internalActivitiesList[j].duration;
17039 }
17040 }
17041 iter++;
17042 }
17043
17044 //not available, break, preferred time(s)
17045 for(int j=0; j<gt.rules.nHoursPerWeek; j++)
17046 if(notAllowedTimesPercentages[i][j]>=THRESHOLD)
17047 nIncompatible[i]++;
17048
17049 //min days between activities - no
17050
17051 if(gt.rules.mode!=MORNINGS_AFTERNOONS){
17052 //students max days per week
17053 for(int s : qAsConst(gt.rules.internalActivitiesList[i].iSubgroupsList)){
17054 if(subgroupsMaxDaysPerWeekWeightPercentages[s]>=THRESHOLD){
17055 assert(gt.rules.nDaysPerWeek-subgroupsMaxDaysPerWeekMaxDays[s] >=0 );
17056 nIncompatible[i]+=(gt.rules.nDaysPerWeek-subgroupsMaxDaysPerWeekMaxDays[s])*gt.rules.nHoursPerDay;
17057 }
17058 }
17059
17060 //teachers max days per week
17061 for(int t : qAsConst(gt.rules.internalActivitiesList[i].iTeachersList)){
17062 if(teachersMaxDaysPerWeekWeightPercentages[t]>=THRESHOLD){
17063 assert(gt.rules.nDaysPerWeek-teachersMaxDaysPerWeekMaxDays[t] >=0 );
17064 nIncompatible[i]+=(gt.rules.nDaysPerWeek-teachersMaxDaysPerWeekMaxDays[t])*gt.rules.nHoursPerDay;
17065 }
17066 }
17067 }
17068 else{
17069 assert(gt.rules.nDaysPerWeek%2==0);
17070
17071 //students max real days per week
17072 for(int s : qAsConst(gt.rules.internalActivitiesList[i].iSubgroupsList)){
17073 int nIncompat=0;
17074 if(subgroupsMaxDaysPerWeekWeightPercentages[s]>=THRESHOLD){
17075 assert(gt.rules.nDaysPerWeek-subgroupsMaxDaysPerWeekMaxDays[s] >=0 );
17076 nIncompat=(gt.rules.nDaysPerWeek-subgroupsMaxDaysPerWeekMaxDays[s])*gt.rules.nHoursPerDay;
17077 }
17078
17079 int nIncompatReal=0;
17080 if(subgroupsMaxRealDaysPerWeekWeightPercentages[s]>=THRESHOLD){
17081 assert(gt.rules.nDaysPerWeek/2-subgroupsMaxRealDaysPerWeekMaxDays[s] >=0 );
17082 nIncompatReal=(gt.rules.nDaysPerWeek/2-subgroupsMaxRealDaysPerWeekMaxDays[s])*2*gt.rules.nHoursPerDay;
17083 }
17084
17085 nIncompatible[i]+=max(nIncompat, nIncompatReal);
17086 }
17087
17088 //teachers max real days per week
17089 for(int t : qAsConst(gt.rules.internalActivitiesList[i].iTeachersList)){
17090 int nIncompat=0;
17091 if(teachersMaxDaysPerWeekWeightPercentages[t]>=THRESHOLD){
17092 assert(gt.rules.nDaysPerWeek-teachersMaxDaysPerWeekMaxDays[t] >=0 );
17093 nIncompat=(gt.rules.nDaysPerWeek-teachersMaxDaysPerWeekMaxDays[t])*gt.rules.nHoursPerDay;
17094 }
17095
17096 int nIncompatReal=0;
17097 if(teachersMaxRealDaysPerWeekWeightPercentages[t]>=THRESHOLD){
17098 assert(gt.rules.nDaysPerWeek/2-teachersMaxRealDaysPerWeekMaxDays[t] >=0 );
17099 nIncompatReal=(gt.rules.nDaysPerWeek/2-teachersMaxRealDaysPerWeekMaxDays[t])*2*gt.rules.nHoursPerDay;
17100 }
17101
17102 nIncompatible[i]+=max(nIncompat, nIncompatReal);
17103 }
17104 }
17105
17106
17107 //rooms
17108 PreferredRoomsItem it=maxPercentagePrefRooms[i];
17109 if(it.percentage>=THRESHOLD){
17110 double cnt=0.0;
17111 assert(!unspecifiedPreferredRoom[i]);
17112 for(int rm : qAsConst(it.preferredRooms))
17113 cnt+=double(nRoomsIncompat[rm])+nHoursForRoom[rm]-(double(gt.rules.internalActivitiesList[i].duration)/double(it.preferredRooms.count()));
17114 //-duration because we considered also current activity
17115
17116 if(cnt<0.0){
17117 //assert(cnt+0.01>=0.0); //maybe rouding error, but not too high
17118 if(!(cnt+0.01>=0.0)){
17119 cout<<"Probable ERROR in file "<<__FILE__<<", line "<<__LINE__<<", cnt should be >=0.0"<<endl;
17120 }
17121 cnt=0.0;
17122 }
17123
17124 assert(cnt>=0.0);
17125
17126 //2013-01-08 - So that generation is identical on all computers
17127 double t = cnt / double(it.preferredRooms.count()); //average for all the rooms
17128
17129 t*=100000.0;
17130 t=floor(t+0.5);
17131 t/=100000.0;
17132
17133 nIncompatible[i] += int(t); //average for all the rooms.
17134 }
17135
17136 nIncompatible[i]*=gt.rules.internalActivitiesList[i].duration;
17137
17138 assert(nIncompatible[i]<INF);
17139
17140 assert(nIncompatible[i]>=0);
17141
17142 if(fixedTimeActivity[i]){
17143 nIncompatible[i]=INF;
17144
17145 if(fixedSpaceActivity[i])
17146 nIncompatible[i]=INF2;
17147
17148 //this is to avoid an "impossible to generate" bug in fixed timetables - does not eliminate completely the bug, unfortunately
17149 nIncompatible[i]+=gt.rules.internalActivitiesList[i].iSubgroupsList.count()+
17150 gt.rules.internalActivitiesList[i].iTeachersList.count();
17151
17152 assert(nIncompatible[i]>=INF);
17153 }
17154 }
17155
17156 //DEPRECATED COMMENT
17157 //same starting time - not computing, the algo takes care even without correct sorting
17158 //it is difficult to sort about same starting time
17159
17160 //IT IS POSSIBLE TO SORT ABOUT SAME STARTING TIME, see below, idea of Volker Dirr. It is much faster for some data sets.
17161 //(for some data sets, it is 7 times faster)
17162
17163 //compute repr:
17164 /////////////////
17165 QMultiHash<int, int> adjMatrix;
17166
17167 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
17168 if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_TIME
17169 &>.rules.internalTimeConstraintsList[i]->weightPercentage==100.0){
17170 ConstraintActivitiesSameStartingTime* sst=(ConstraintActivitiesSameStartingTime*)gt.rules.internalTimeConstraintsList[i];
17171
17172 for(int i=1; i<sst->_n_activities; i++){
17173 adjMatrix.insert(sst->_activities[0], sst->_activities[i]);
17174 adjMatrix.insert(sst->_activities[i], sst->_activities[0]);
17175 }
17176 }
17177 else if(gt.rules.internalTimeConstraintsList[i]->type==CONSTRAINT_TWO_ACTIVITIES_CONSECUTIVE
17178 && gt.rules.internalTimeConstraintsList[i]->weightPercentage==100.0){
17179 ConstraintTwoActivitiesConsecutive* c2c=(ConstraintTwoActivitiesConsecutive*)gt.rules.internalTimeConstraintsList[i];
17180
17181 adjMatrix.insert(c2c->firstActivityIndex, c2c->secondActivityIndex);
17182 adjMatrix.insert(c2c->secondActivityIndex, c2c->firstActivityIndex);
17183 }
17184 }
17185
17186 QHash<int, int> repr;
17187 //repr.clear();
17188
17189 QQueue<int> queue;
17190
17191 for(int i=0; i<gt.rules.nInternalActivities; i++){
17192 int start=i;
17193
17194 if(repr.value(start, -1)==-1){ //not visited
17195 repr.insert(start, start);
17196 queue.enqueue(start);
17197 while(!queue.isEmpty()){
17198 int crtHead=queue.dequeue();
17199 assert(repr.value(crtHead, -1)==start);
17200 QList<int> neighList=adjMatrix.values(crtHead);
17201 for(int neigh : qAsConst(neighList)){
17202 if(repr.value(neigh, -1)==-1){
17203 queue.enqueue(neigh);
17204 repr.insert(neigh, start);
17205 }
17206 else{
17207 assert(repr.value(neigh, -1)==start);
17208 }
17209 }
17210 }
17211 }
17212 }
17213
17214 /////////////////
17215
17216 //take care of chains of constraints with 100% weight
17217 for(int i=0; i<gt.rules.nInternalActivities; i++)
17218 reprNInc[i]=-1;
17219
17220 //repr contains the representant of each activity
17221 for(int i=0; i<gt.rules.nInternalActivities; i++){
17222 //int MM=nIncompatible[i];
17223 assert(repr.contains(i));
17224 int r=repr.value(i);
17225
17226 int xx=nIncompatible[i];
17227 if(fixedTimeActivity[i] && fixedSpaceActivity[i]){
17228 assert(xx>=INF2);
17229 xx-=(INF2-INF);
17230 }
17231
17232 assert(xx<INF2);
17233 assert(xx>=0);
17234
17235 if(reprNInc[r]<xx)
17236 reprNInc[r]=xx;
17237 }
17238
17239 for(int i=0; i<gt.rules.nInternalActivities; i++){
17240 int r=repr.value(i);
17241 assert(reprNInc[r]>=0);
17242 if(nIncompatible[i]<reprNInc[r])
17243 nIncompatible[i]=reprNInc[r];
17244 }
17245
17246 //new Volker (start), modified by Liviu
17247 //takes care of 100% weight constraints (not necessary - already took care above) and also <100% and >=80% weight constraints
17248 for(int i=0; i<gt.rules.nInternalTimeConstraints; i++){
17249 TimeConstraint* tc=gt.rules.internalTimeConstraintsList[i];
17250 if(tc->type==CONSTRAINT_ACTIVITIES_SAME_STARTING_TIME && tc->weightPercentage>=THRESHOLD){
17251 ConstraintActivitiesSameStartingTime* c=(ConstraintActivitiesSameStartingTime*) tc;
17252
17253 int xx=nIncompatible[c->_activities[0]];
17254 if(fixedTimeActivity[c->_activities[0]] && fixedSpaceActivity[c->_activities[0]]){
17255 assert(xx>=INF2);
17256 xx-=(INF2-INF);
17257 }
17258 assert(xx>=0);
17259 assert(xx<INF2);
17260
17261 int MM=xx;
17262
17263 for(int a=1; a<c->_n_activities; a++){
17264 int yy=nIncompatible[c->_activities[a]];
17265 if(fixedTimeActivity[c->_activities[a]] && fixedSpaceActivity[c->_activities[a]]){
17266 assert(yy>=INF2);
17267 yy-=(INF2-INF);
17268 }
17269 assert(yy>=0);
17270 assert(yy<INF2);
17271
17272 if(MM<yy)
17273 MM=yy;
17274 }
17275
17276 for(int a=0; a<c->_n_activities; a++)
17277 if(nIncompatible[c->_activities[a]]<MM)
17278 nIncompatible[c->_activities[a]]=MM;
17279 }
17280 else if(tc->type==CONSTRAINT_TWO_ACTIVITIES_CONSECUTIVE && tc->weightPercentage>=THRESHOLD){
17281 ConstraintTwoActivitiesConsecutive* c=(ConstraintTwoActivitiesConsecutive*) tc;
17282
17283 int xx=nIncompatible[c->firstActivityIndex];
17284 if(fixedTimeActivity[c->firstActivityIndex] && fixedSpaceActivity[c->firstActivityIndex]){
17285 assert(xx>=INF2);
17286 xx-=(INF2-INF);
17287 }
17288 assert(xx>=0);
17289 assert(xx<INF2);
17290
17291 int MM=xx;
17292
17293 int yy=nIncompatible[c->secondActivityIndex];
17294 if(fixedTimeActivity[c->secondActivityIndex] && fixedSpaceActivity[c->secondActivityIndex]){
17295 assert(yy>=INF2);
17296 yy-=(INF2-INF);
17297 }
17298 assert(yy>=0);
17299 assert(yy<INF2);
17300
17301 if(MM<yy)
17302 MM=yy;
17303
17304 if(nIncompatible[c->firstActivityIndex] < MM)
17305 nIncompatible[c->firstActivityIndex] = MM;
17306
17307 if(nIncompatible[c->secondActivityIndex] < MM)
17308 nIncompatible[c->secondActivityIndex] = MM;
17309 }
17310 else if(tc->type==CONSTRAINT_TWO_ACTIVITIES_GROUPED && tc->weightPercentage>=THRESHOLD){
17311 ConstraintTwoActivitiesGrouped* c=(ConstraintTwoActivitiesGrouped*) tc;
17312
17313 int xx=nIncompatible[c->firstActivityIndex];
17314 if(fixedTimeActivity[c->firstActivityIndex] && fixedSpaceActivity[c->firstActivityIndex]){
17315 assert(xx>=INF2);
17316 xx-=(INF2-INF);
17317 }
17318 assert(xx>=0);
17319 assert(xx<INF2);
17320
17321 int MM=xx;
17322
17323 int yy=nIncompatible[c->secondActivityIndex];
17324 if(fixedTimeActivity[c->secondActivityIndex] && fixedSpaceActivity[c->secondActivityIndex]){
17325 assert(yy>=INF2);
17326 yy-=(INF2-INF);
17327 }
17328 assert(yy>=0);
17329 assert(yy<INF2);
17330
17331 if(MM<yy)
17332 MM=yy;
17333
17334 if(nIncompatible[c->firstActivityIndex] < MM)
17335 nIncompatible[c->firstActivityIndex] = MM;
17336
17337 if(nIncompatible[c->secondActivityIndex] < MM)
17338 nIncompatible[c->secondActivityIndex] = MM;
17339 }
17340 }
17341 //new Volker (end)
17342
17343 //2014-06-30 - group activities in initial order
17344 if(gt.rules.groupActivitiesInInitialOrderList.count()>0){
17345 for(int i=0; i<gt.rules.nInternalActivities; i++)
17346 fatherActivityInInitialOrder[i]=-1;
17347
17348 bool report=true;
17349 int j=0;
17350
17351 for(GroupActivitiesInInitialOrderItem* item : qAsConst(gt.rules.groupActivitiesInInitialOrderList)){
17352 j++;
17353
17354 if(!item->active)
17355 continue;
17356
17357 if(item->indices.count()<2){
17358 if(report){
17359 QString s=GeneratePreTranslate::tr("Group activities in initial order item number %1 is ignored, because it contains less than"
17360 " two active activities").arg(j);
17361
17362 int t=GeneratePreReconcilableMessage::mediumConfirmation(parent, GeneratePreTranslate::tr("FET warning"),
17363 s, GeneratePreTranslate::tr("Skip rest"), GeneratePreTranslate::tr("See next"), QString(),
17364 1, 0 );
17365
17366 if(t==0)
17367 report=false;
17368 }
17369 }
17370 else{
17371 int index0=item->indices.at(0);
17372 int xx=nIncompatible[index0];
17373 /*if(fixedTimeActivity[index0] && fixedSpaceActivity[index0]){
17374 assert(xx>=INF2);
17375 xx-=(INF2-INF);
17376 }
17377 assert(xx>=0);
17378 assert(xx<INF2);*/
17379
17380 int MM=xx;
17381 int father=0;
17382
17383 for(int i=1; i<item->indices.count(); i++){
17384 int indexi=item->indices.at(i);
17385
17386 int yy=nIncompatible[indexi];
17387 /*if(fixedTimeActivity[indexi] && fixedSpaceActivity[indexi]){
17388 assert(yy>=INF2);
17389 yy-=(INF2-INF);
17390 }
17391 assert(yy>=0);
17392 assert(yy<INF2);*/
17393
17394 if(MM<yy){
17395 MM=yy;
17396 father=i;
17397 }
17398 }
17399
17400 //if(MM>=INF)
17401 // MM=INF-1;
17402
17403 for(int i=0; i<item->indices.count(); i++)
17404 if(i!=father){
17405 assert(fatherActivityInInitialOrder[item->indices.at(i)]==-1);
17406 fatherActivityInInitialOrder[item->indices.at(i)]=item->indices.at(father);
17407 }
17408
17409 /*for(int i=0; i<item.indices.count(); i++){
17410 int ai=item.indices.at(i);
17411 if(nIncompatible[ai]<MM)
17412 nIncompatible[ai]=MM;
17413 }*/
17414 }
17415 }
17416 }
17417
17418 //this is to avoid an "impossible to generate" bug in fixed timetables - does not eliminate completely the bug, unfortunately
17419 for(int i=0; i<gt.rules.nInternalActivities; i++){
17420 if(nIncompatible[i]>=INF && nIncompatible[i]<INF2){
17421 if(fixedTimeActivity[i]){
17422 nIncompatible[i]=INF;
17423
17424 nIncompatible[i]+=gt.rules.internalActivitiesList[i].iSubgroupsList.count()+
17425 gt.rules.internalActivitiesList[i].iTeachersList.count();
17426
17427 assert(nIncompatible[i]>=INF);
17428 }
17429 else{
17430 nIncompatible[i]=INF;
17431 }
17432 }
17433 else if(nIncompatible[i]>=INF2){
17434 assert(fixedTimeActivity[i] && fixedSpaceActivity[i]);
17435
17436 int xx=nIncompatible[i]-INF2;
17437 assert(xx==gt.rules.internalActivitiesList[i].iSubgroupsList.count()+
17438 gt.rules.internalActivitiesList[i].iTeachersList.count());
17439 }
17440 }
17441
17442 QHash<int, int> allowedSlotForFixedActivity;
17443 for(int i=0; i<gt.rules.nInternalActivities; i++){
17444 if(fixedTimeActivity[i]){
17445 int cnt=0;
17446 int allowed=-1;
17447 for(int s=0; s<gt.rules.nHoursPerWeek; s++){
17448 if(notAllowedTimesPercentages[i][s]<100.0){
17449 allowed=s;
17450 cnt++;
17451 }
17452 }
17453 assert(cnt==1);
17454 allowedSlotForFixedActivity.insert(i, allowed);
17455 }
17456 }
17457 for(int i=0; i<gt.rules.nInternalActivities; i++){
17458 nMinDaysConstraintsBroken[i]=1.0;
17459
17460 if(fixedTimeActivity[i]){
17461 assert(allowedSlotForFixedActivity.contains(i));
17462 int si=allowedSlotForFixedActivity.value(i);
17463 int di=si%gt.rules.nDaysPerWeek;
17464
17465 for(int d=0; d<minDaysListOfActivities[i].count(); d++){
17466 int j=minDaysListOfActivities[i].at(d);
17467 if(!fixedTimeActivity[j])
17468 continue;
17469 int m=minDaysListOfMinDays[i].at(d);
17470 double w=minDaysListOfWeightPercentages[i].at(d)/100.0;
17471
17472 assert(allowedSlotForFixedActivity.contains(j));
17473 int sj=allowedSlotForFixedActivity.value(j);
17474 int dj=sj%gt.rules.nDaysPerWeek;
17475
17476 int dist;
17477 if(gt.rules.mode!=MORNINGS_AFTERNOONS)
17478 dist=abs(di-dj);
17479 else
17480 dist=abs(di/2-dj/2);
17481 if(dist<m){
17482 //careful, don't assert weight is <100.0, because the data may be impossible and we get assert failed
17483 nMinDaysConstraintsBroken[i]*=(1.0-w);
17484 }
17485 }
17486 }
17487
17488 nMinDaysConstraintsBroken[i]=1.0-nMinDaysConstraintsBroken[i];
17489 //the resultant weight of all broken constraints
17490 //(the probability that after one try, we are not OK)
17491 }
17492
17493 //DEPRECATED
17494 //Sort activities in increasing order of number of the other activities with which
17495 //this activity does not conflict
17496 //Selection sort, based on a permutation
17497
17498 for(int i=0; i<gt.rules.nInternalActivities; i++)
17499 copyOfInitialPermutation[i]=i;
17500
17501 /*for(int i=0; i<gt.rules.nInternalActivities; i++){
17502 for(int j=i+1; j<gt.rules.nInternalActivities; j++){
17503 if(nIncompatible[copyOfInitialPermutation[i]]<nIncompatible[copyOfInitialPermutation[j]] ||
17504 (nIncompatible[copyOfInitialPermutation[i]]==nIncompatible[copyOfInitialPermutation[j]] && nMinDaysConstraintsBroken[copyOfInitialPermutation[i]]<nMinDaysConstraintsBroken[copyOfInitialPermutation[j]])){
17505 int t=copyOfInitialPermutation[i];
17506 copyOfInitialPermutation[i]=copyOfInitialPermutation[j];
17507 copyOfInitialPermutation[j]=t;
17508 }
17509 }
17510 }*/
17511
17512 //descending by nIncompatible, then by nMinDaysConstraintsBroken
17513 //(by nMinDaysConstraintsBroken to alleviate an 'impossible to generate' bug if generating for a fixed timetable).
17514 if(gt.rules.groupActivitiesInInitialOrderList.count()==0){
17515 //qStableSort(copyOfInitialPermutation+0, copyOfInitialPermutation+gt.rules.nInternalActivities, compareFunctionGeneratePre);
17516 //std::stable_sort(copyOfInitialPermutation+0, copyOfInitialPermutation+gt.rules.nInternalActivities, compareFunctionGeneratePre);
17517 std::stable_sort(©OfInitialPermutation[0], ©OfInitialPermutation[gt.rules.nInternalActivities], compareFunctionGeneratePre);
17518
17519 for(int q=1; q<gt.rules.nInternalActivities; q++){
17520 int i=copyOfInitialPermutation[q-1];
17521 int j=copyOfInitialPermutation[q];
17522 //DEPRECATED COMMENT: don't assert nMinDaysConstraintsBroken is descending (if nIncompatible is equal), because it is a double number and we may get rounding errors
17523 //assert(nIncompatible[copyOfInitialPermutation[i-1]]>=nIncompatible[copyOfInitialPermutation[i]]);
17524 assert(nIncompatible[i]>nIncompatible[j] || (nIncompatible[i]==nIncompatible[j] && nMinDaysConstraintsBroken[i]>=nMinDaysConstraintsBroken[j]));
17525 }
17526 }
17527 else{
17528 for(int i=0; i<gt.rules.nInternalActivities; i++){
17529 int nInc_i;
17530
17531 if(fatherActivityInInitialOrder[i]==-1)
17532 nInc_i=nIncompatible[i];
17533 else
17534 nInc_i=nIncompatible[fatherActivityInInitialOrder[i]];
17535
17536 if(nInc_i>=INF2){
17537 if(fixedTimeActivity[i] && fixedSpaceActivity[i]){
17538 nInc_i=INF2;
17539
17540 nInc_i+=gt.rules.internalActivitiesList[i].iSubgroupsList.count()+
17541 gt.rules.internalActivitiesList[i].iTeachersList.count();
17542
17543 assert(nInc_i>=INF2);
17544 }
17545 else if(fixedTimeActivity[i]){
17546 nInc_i=INF;
17547
17548 nInc_i+=gt.rules.internalActivitiesList[i].iSubgroupsList.count()+
17549 gt.rules.internalActivitiesList[i].iTeachersList.count();
17550
17551 assert(nInc_i>=INF);
17552 }
17553 else{
17554 nInc_i=INF;
17555 }
17556 }
17557 else if(nInc_i>=INF && nInc_i<INF2){
17558 if(fixedTimeActivity[i]){
17559 nInc_i=INF;
17560
17561 nInc_i+=gt.rules.internalActivitiesList[i].iSubgroupsList.count()+
17562 gt.rules.internalActivitiesList[i].iTeachersList.count();
17563
17564 assert(nInc_i>=INF);
17565 }
17566 else{
17567 nInc_i=INF;
17568 }
17569 }
17570
17571 nIncompatibleFromFather[i]=nInc_i;
17572 }
17573
17574 //qStableSort(copyOfInitialPermutation+0, copyOfInitialPermutation+gt.rules.nInternalActivities, compareFunctionGeneratePreWithGroupedActivities);
17575 //std::stable_sort(copyOfInitialPermutation+0, copyOfInitialPermutation+gt.rules.nInternalActivities, compareFunctionGeneratePreWithGroupedActivities);
17576 std::stable_sort(©OfInitialPermutation[0], ©OfInitialPermutation[gt.rules.nInternalActivities], compareFunctionGeneratePreWithGroupedActivities);
17577
17578 for(int q=1; q<gt.rules.nInternalActivities; q++){
17579 int i=copyOfInitialPermutation[q-1];
17580 int j=copyOfInitialPermutation[q];
17581 assert( nIncompatibleFromFather[i]>nIncompatibleFromFather[j]
17582 || (nIncompatibleFromFather[i]==nIncompatibleFromFather[j] && nMinDaysConstraintsBroken[i]>nMinDaysConstraintsBroken[j])
17583 || (nIncompatibleFromFather[i]==nIncompatibleFromFather[j] && nMinDaysConstraintsBroken[i]==nMinDaysConstraintsBroken[j] && nIncompatible[i]>=nIncompatible[j] ) );
17584 }
17585 }
17586
17587 if(VERBOSE){
17588 cout<<"The order of activities (id-s):"<<endl;
17589 for(int i=0; i<gt.rules.nInternalActivities; i++){
17590 cout<<"No: "<<i+1;
17591
17592 Activity* act=>.rules.internalActivitiesList[copyOfInitialPermutation[i]];
17593 cout<<", Id="<<act->id;
17594
17595 bool spacerBefore=false, spacerAfter=false;
17596 if(act->isSplit()){
17597 if(act->id==act->activityGroupId){
17598 spacerBefore=false;
17599 spacerAfter=true;
17600 }
17601 else{
17602 spacerBefore=true;
17603 spacerAfter=false;
17604 }
17605 }
17606 cout<<", ";
17607 if(spacerBefore)
17608 cout<<" ";
17609 if(act->isSplit())
17610 cout<<"Duration: "<<act->duration<<"/"<<act->totalDuration;
17611 else
17612 cout<<"Duration: "<<act->duration;
17613 cout<<", ";
17614 if(spacerAfter)
17615 cout<<" ";
17616
17617 cout<<"Teachers: ";
17618 QString tj=act->teachersNames.join(" ");
17619 cout<<qPrintable(tj);
17620 cout<<", Subject: "<<qPrintable(act->subjectName);
17621 if(act->activityTagsNames.count()>0){
17622 QString atj=act->activityTagsNames.join(" ");
17623 cout<<", Activity tags: "<<qPrintable(atj);
17624 }
17625 cout<<", Students: ";
17626 QString sj=act->studentsNames.join(" ");
17627 cout<<qPrintable(sj);
17628
17629 cout<<", nIncompatible[copyOfInitialPermutation[i]]="<<nIncompatible[copyOfInitialPermutation[i]];
17630 if(nMinDaysConstraintsBroken[copyOfInitialPermutation[i]]>0.0)
17631 cout<<", nMinDaysConstraintsBroken[copyOfInitialPermutation[i]]="<<nMinDaysConstraintsBroken[copyOfInitialPermutation[i]];
17632
17633 if(gt.rules.groupActivitiesInInitialOrderList.count()>0)
17634 if(fatherActivityInInitialOrder[copyOfInitialPermutation[i]]>=0)
17635 cout<<" (grouped with id "<<gt.rules.internalActivitiesList[fatherActivityInInitialOrder[copyOfInitialPermutation[i]]].id<<")";
17636
17637 cout<<endl;
17638 }
17639 cout<<"End - the order of activities (id-s):"<<endl;
17640 }
17641
17642 QString s="";
17643 s+=GeneratePreTranslate::tr("This is the initial evaluation order of activities computed by FET."
17644 " If the generation gets stuck after a certain number of activities, please check the activity"
17645 " corresponding to this number+1. You might find errors in your input.");
17646 s+="\n\n";
17647 s+=GeneratePreTranslate::tr("The initial order of activities (id-s):");
17648 s+="\n\n";
17649 for(int i=0; i<gt.rules.nInternalActivities; i++){
17650 initialOrderOfActivitiesIndices[i]=copyOfInitialPermutation[i];
17651
17652 s+=GeneratePreTranslate::tr("No: %1", "Number").arg(i+1);
17653 s+=", ";
17654
17655 Activity* act=>.rules.internalActivitiesList[copyOfInitialPermutation[i]];
17656 s+=GeneratePreTranslate::tr("Id: %1", "Id of activity").arg(act->id);
17657 s+=", ";
17658
17659 bool spacerBefore=false, spacerAfter=false;
17660 if(act->isSplit()){
17661 if(act->id==act->activityGroupId){
17662 spacerBefore=false;
17663 spacerAfter=true;
17664 }
17665 else{
17666 spacerBefore=true;
17667 spacerAfter=false;
17668 }
17669 }
17670 if(spacerBefore)
17671 s+=" ";
17672 if(act->isSplit())
17673 s+=GeneratePreTranslate::tr("Duration: %1").arg(CustomFETString::number(act->duration)+QString("/")+CustomFETString::number(act->totalDuration));
17674 else
17675 s+=GeneratePreTranslate::tr("Duration: %1").arg(act->duration);
17676 s+=", ";
17677 if(spacerAfter)
17678 s+=" ";
17679
17680 s+=GeneratePreTranslate::tr("Teachers: %1").arg(act->teachersNames.join(", "));
17681 s+=", ";
17682 s+=GeneratePreTranslate::tr("Subject: %1").arg(act->subjectName);
17683 s+=", ";
17684 //if(act->activityTagsNames.count()>0)
17685 s+=GeneratePreTranslate::tr("Activity tags: %1").arg(act->activityTagsNames.join(", "));
17686 s+=", ";
17687 s+=GeneratePreTranslate::tr("Students: %1").arg(act->studentsNames.join(", "));
17688
17689 if(gt.rules.groupActivitiesInInitialOrderList.count()>0){
17690 s+=", ";
17691 s+=GeneratePreTranslate::tr("nIncompatible: %1").arg(nIncompatible[copyOfInitialPermutation[i]]);
17692 if(nMinDaysConstraintsBroken[copyOfInitialPermutation[i]]>0.0){
17693 s+=", ";
17694 s+=GeneratePreTranslate::tr("nMinDaysConstraintsBroken: %1").arg(nMinDaysConstraintsBroken[copyOfInitialPermutation[i]]);
17695 }
17696
17697 if(fatherActivityInInitialOrder[copyOfInitialPermutation[i]]>=0){
17698 s+=" ";
17699 s+=GeneratePreTranslate::tr("(grouped with id %1)").arg(gt.rules.internalActivitiesList[fatherActivityInInitialOrder[copyOfInitialPermutation[i]]].id);
17700 }
17701 }
17702
17703 s+="\n";
17704 }
17705 s+=GeneratePreTranslate::tr("End - the order of activities (id-s)");
17706 s+="\n";
17707 initialOrderOfActivities=s;
17708
17709 if(initialOrderStream!=nullptr){
17710 (*initialOrderStream)<<s;
17711 (*initialOrderStream).flush();
17712 }
17713 }
17714