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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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 		 &&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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 		 /*&&gt.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 		 /*&&gt.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 		 /*&&gt.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 		 /*&&gt.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=&gt.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 		 &&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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=&gt.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 		 &&gt.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(&copyOfInitialPermutation[0], &copyOfInitialPermutation[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(&copyOfInitialPermutation[0], &copyOfInitialPermutation[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=&gt.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=&gt.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