Back to index

fet  5.18.0
generate.cpp
Go to the documentation of this file.
00001 /*
00002 File generate.cpp
00003 */
00004 
00005 /*
00006 Copyright 2007 Lalescu Liviu.
00007 
00008 This file is part of FET.
00009 
00010 FET is free software; you can redistribute it and/or modify
00011 it under the terms of the GNU General Public License as published by
00012 the Free Software Foundation; either version 2 of the License, or
00013 (at your option) any later version.
00014 
00015 FET is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with FET; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 */
00024 
00025 #include <iomanip>
00026 #include <iostream>
00027 using namespace std;
00028 
00029 #include <ctime>
00030 
00031 #include <QtAlgorithms>
00032 
00033 #include <cmath>
00034 #include <algorithm>
00035 #include <cstdlib>
00036 
00037 #include "timetable_defs.h"
00038 #include "timetable.h"
00039 #include "generate.h"
00040 #include "rules.h"
00041 
00042 #include "generate_pre.h"
00043 
00044 #include "matrix.h"
00045 
00046 #include <QMutex>
00047 
00048 #include <QDateTime>
00049 
00050 #include <QList>
00051 #include <QSet>
00052 
00053 #include <QSemaphore>
00054 
00055 extern QMutex mutex; //timetablegenerateform.cpp
00056 
00057 extern QSemaphore semaphorePlacedActivity;
00058 extern QSemaphore finishedSemaphore;
00059 
00060 extern Timetable gt;
00061 
00062 static bool swappedActivities[MAX_ACTIVITIES];
00063 
00064 static bool foundGoodSwap;
00065 
00066 //not sure, it might be necessary 2*... or even more
00067 static int restoreActIndex[4*MAX_ACTIVITIES]; //the index of the act. to restore
00068 static int restoreTime[4*MAX_ACTIVITIES]; //the time when to restore
00069 static int restoreRoom[4*MAX_ACTIVITIES]; //the time when to restore
00070 static int nRestore;
00071 
00072 static int limitcallsrandomswap;
00073 
00074 const int MAX_LEVEL=31;
00075 
00076 const int LEVEL_STOP_CONFLICTS_CALCULATION=MAX_LEVEL;
00077 
00078 static int level_limit;
00079 
00080 static int ncallsrandomswap;
00081 static int maxncallsrandomswap;
00082 
00083 Solution highestStageSolution;
00084 
00085 
00086 //if level==0, choose best position with lowest number
00087 //of conflicting activities
00088 static QList<int> conflActivitiesTimeSlot;
00089 static int timeSlot;
00090 static int roomSlot;
00091 
00092 
00093 //int triedRemovals[MAX_ACTIVITIES][MAX_HOURS_PER_WEEK];
00094 static Matrix2D<int> triedRemovals;
00095 
00096 static bool impossibleActivity;
00097 
00098 static int invPermutation[MAX_ACTIVITIES];
00099 
00100 const int INF=2000000000;
00101 
00102 
00104 //const int MAX_TABU=MAX_ACTIVITIES*MAX_HOURS_PER_WEEK;
00105 static int tabu_size;
00106 static int crt_tabu_index;
00107 /*qint16 tabu_activities[MAX_TABU];
00108 qint16 tabu_times[MAX_TABU];*/
00109 static Matrix1D<qint16> tabu_activities;
00110 static Matrix1D<qint16> tabu_times;
00112 
00113 /*static qint16 teachersTimetable[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00114 static qint16 subgroupsTimetable[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00115 static qint16 roomsTimetable[MAX_ROOMS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];*/
00116 static Matrix3D<qint16> teachersTimetable;
00117 static Matrix3D<qint16> subgroupsTimetable;
00118 static Matrix3D<qint16> roomsTimetable;
00119 
00120 
00121 /*static qint16 newTeachersTimetable[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00122 static qint16 newSubgroupsTimetable[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00123 static qint16 newTeachersDayNHours[MAX_TEACHERS][MAX_DAYS_PER_WEEK];
00124 static qint16 newTeachersDayNGaps[MAX_TEACHERS][MAX_DAYS_PER_WEEK];
00125 static qint16 newSubgroupsDayNHours[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];
00126 static qint16 newSubgroupsDayNGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];
00127 static qint16 newSubgroupsDayNFirstGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];*/
00128 static Matrix3D<qint16> newTeachersTimetable;
00129 static Matrix3D<qint16> newSubgroupsTimetable;
00130 static Matrix2D<qint16> newTeachersDayNHours;
00131 static Matrix2D<qint16> newTeachersDayNGaps;
00132 static Matrix2D<qint16> newSubgroupsDayNHours;
00133 static Matrix2D<qint16> newSubgroupsDayNGaps;
00134 static Matrix2D<qint16> newSubgroupsDayNFirstGaps;
00135 
00136 
00137 /*static qint16 oldTeachersTimetable[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00138 static qint16 oldSubgroupsTimetable[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00139 static qint16 oldTeachersDayNHours[MAX_TEACHERS][MAX_DAYS_PER_WEEK];
00140 static qint16 oldTeachersDayNGaps[MAX_TEACHERS][MAX_DAYS_PER_WEEK];
00141 static qint16 oldSubgroupsDayNHours[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];
00142 static qint16 oldSubgroupsDayNGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];
00143 static qint16 oldSubgroupsDayNFirstGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];*/
00144 static Matrix3D<qint16> oldTeachersTimetable;
00145 static Matrix3D<qint16> oldSubgroupsTimetable;
00146 static Matrix2D<qint16> oldTeachersDayNHours;
00147 static Matrix2D<qint16> oldTeachersDayNGaps;
00148 static Matrix2D<qint16> oldSubgroupsDayNHours;
00149 static Matrix2D<qint16> oldSubgroupsDayNGaps;
00150 static Matrix2D<qint16> oldSubgroupsDayNFirstGaps;
00151 
00152 
00153 /*static qint16 tchTimetable[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00154 static qint16 tchDayNHours[MAX_DAYS_PER_WEEK];
00155 static qint16 tchDayNGaps[MAX_DAYS_PER_WEEK];
00156 
00157 static qint16 sbgTimetable[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
00158 static qint16 sbgDayNHours[MAX_DAYS_PER_WEEK];
00159 static qint16 sbgDayNGaps[MAX_DAYS_PER_WEEK];
00160 static qint16 sbgDayNFirstGaps[MAX_DAYS_PER_WEEK];*/
00161 static Matrix2D<qint16> tchTimetable;
00162 static Matrix1D<qint16> tchDayNHours;
00163 static Matrix1D<qint16> tchDayNGaps;
00164 
00165 static Matrix2D<qint16> sbgTimetable;
00166 static Matrix1D<qint16> sbgDayNHours;
00167 static Matrix1D<qint16> sbgDayNGaps;
00168 static Matrix1D<qint16> sbgDayNFirstGaps;
00169 
00170 
00171 //static QList<int> teacherActivitiesOfTheDay[MAX_TEACHERS][MAX_DAYS_PER_WEEK];
00172 static Matrix2D<QList<int> > teacherActivitiesOfTheDay;
00173 
00174 int maxActivitiesPlaced;
00175 
00176 QDateTime generationStartDateTime;
00177 QDateTime generationHighestStageDateTime;
00178 
00179 const int MAX_RETRIES_FOR_AN_ACTIVITY_AT_LEVEL_0=400000;
00180 
00181 //used at level 0
00182 static Matrix1D<int> l0nWrong;
00183 static Matrix1D<int> l0minWrong;
00184 static Matrix1D<int> l0minIndexAct;
00185 
00186 //2011-09-25
00187 static Matrix1D<QSet<int> > slotSetOfActivities;
00188 static Matrix1D<bool> slotCanEmpty;
00189 
00190 static Matrix1D<QSet<int> > activitiesAtTime;
00192 
00193 
00194 inline int max(qint16 a, int b){
00195        if(int(a)>=b)
00196               return int(a);
00197        else
00198               return b;
00199 }
00200 
00201 inline void Generate::addAiToNewTimetable(int ai, const Activity* act, int d, int h)
00202 {
00203        //foreach(int tch, act->iTeachersList){
00204        foreach(int tch, mustComputeTimetableTeachers[ai]){
00205               for(int dur=0; dur<act->duration; dur++){
00206                      oldTeachersTimetable(tch,d,h+dur)=newTeachersTimetable(tch,d,h+dur);
00207                      newTeachersTimetable(tch,d,h+dur)=ai;
00208               }
00209               oldTeachersDayNHours(tch,d)=newTeachersDayNHours(tch,d);
00210               oldTeachersDayNGaps(tch,d)=newTeachersDayNGaps(tch,d);
00211        }
00212 
00213        //foreach(int sbg, act->iSubgroupsList){
00214        foreach(int sbg, mustComputeTimetableSubgroups[ai]){
00215               for(int dur=0; dur<act->duration; dur++){
00216                      oldSubgroupsTimetable(sbg,d,h+dur)=newSubgroupsTimetable(sbg,d,h+dur);
00217                      newSubgroupsTimetable(sbg,d,h+dur)=ai;
00218               }
00219               oldSubgroupsDayNHours(sbg,d)=newSubgroupsDayNHours(sbg,d);
00220               oldSubgroupsDayNGaps(sbg,d)=newSubgroupsDayNGaps(sbg,d);
00221               oldSubgroupsDayNFirstGaps(sbg,d)=newSubgroupsDayNFirstGaps(sbg,d);
00222        }
00223 }
00224 
00225 inline void Generate::removeAiFromNewTimetable(int ai, const Activity* act, int d, int h)
00226 {
00227        foreach(int tch, mustComputeTimetableTeachers[ai]){
00228        //foreach(int tch, act->iTeachersList){
00229               for(int dur=0; dur<act->duration; dur++){
00230                      assert(newTeachersTimetable(tch,d,h+dur)==ai);
00231                      newTeachersTimetable(tch,d,h+dur)=oldTeachersTimetable(tch,d,h+dur);
00232               }
00233               newTeachersDayNHours(tch,d)=oldTeachersDayNHours(tch,d);
00234               newTeachersDayNGaps(tch,d)=oldTeachersDayNGaps(tch,d);
00235        }
00236 
00237        foreach(int sbg, mustComputeTimetableSubgroups[ai]){
00238        //foreach(int sbg, act->iSubgroupsList){
00239               for(int dur=0; dur<act->duration; dur++){
00240                      assert(newSubgroupsTimetable(sbg,d,h+dur)==ai);
00241                      newSubgroupsTimetable(sbg,d,h+dur)=oldSubgroupsTimetable(sbg,d,h+dur);
00242               }
00243               newSubgroupsDayNHours(sbg,d)=oldSubgroupsDayNHours(sbg,d);
00244               newSubgroupsDayNGaps(sbg,d)=oldSubgroupsDayNGaps(sbg,d);
00245               newSubgroupsDayNFirstGaps(sbg,d)=oldSubgroupsDayNFirstGaps(sbg,d);
00246        }
00247 }
00248 
00249 
00250 inline void Generate::removeAi2FromTchTimetable(int ai2)
00251 {
00252        Activity* act2=&gt.rules.internalActivitiesList[ai2];
00253        int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
00254        int h2=c.times[ai2]/gt.rules.nDaysPerWeek;
00255        
00256        for(int dur2=0; dur2<act2->duration; dur2++){
00257               assert(tchTimetable(d2,h2+dur2)==ai2);
00258               if(tchTimetable(d2,h2+dur2)==ai2)
00259                      tchTimetable(d2,h2+dur2)=-1;
00260        }
00261 }
00262 
00263 inline void Generate::removeAi2FromSbgTimetable(int ai2)
00264 {
00265        Activity* act2=&gt.rules.internalActivitiesList[ai2];
00266        int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
00267        int h2=c.times[ai2]/gt.rules.nDaysPerWeek;
00268        
00269        for(int dur2=0; dur2<act2->duration; dur2++){
00270               assert(sbgTimetable(d2,h2+dur2)==ai2);
00271               if(sbgTimetable(d2,h2+dur2)==ai2)
00272                      sbgTimetable(d2,h2+dur2)=-1;
00273        }
00274 }
00275 
00276 inline void Generate::getTchTimetable(int tch, const QList<int>& conflActivities)
00277 {
00278        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++)
00279               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00280                      int ai2=newTeachersTimetable(tch,d2,h2);
00281                      if(ai2>=0 && !conflActivities.contains(ai2))
00282                             tchTimetable(d2,h2)=ai2;
00283                      else
00284                             tchTimetable(d2,h2)=-1;
00285               }
00286               
00287        /*for(int dur=0; dur<act->duration; dur++){
00288               assert(tchTimetable(d,h+dur)==-1);
00289               tchTimetable(d,h+dur)=ai;
00290        }*/
00291 }
00292 
00293 inline void Generate::getSbgTimetable(int sbg, const QList<int>& conflActivities)
00294 {
00295        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++)
00296               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00297                      int ai2=newSubgroupsTimetable(sbg,d2,h2);
00298                      if(ai2>=0 && !conflActivities.contains(ai2))
00299                             sbgTimetable(d2,h2)=ai2;
00300                      else
00301                             sbgTimetable(d2,h2)=-1;
00302               }
00303               
00304        /*for(int dur=0; dur<act->duration; dur++){
00305               assert(sbgTimetable(d,h+dur)==-1);
00306               sbgTimetable(d,h+dur)=ai;
00307        }*/
00308 }
00309 
00310 inline void Generate::updateTchNHoursGaps(int tch, int d)
00311 {
00312        int hours=0, gaps=0;
00313        
00314        int h;
00315        for(h=0; h<gt.rules.nHoursPerDay; h++)
00316               if(tchTimetable(d,h)>=0)
00317                      break;
00318        int ng=0;
00319        for(; h<gt.rules.nHoursPerDay; h++){
00320               if(tchTimetable(d,h)>=0){
00321                      hours++;
00322                      gaps+=ng;
00323                      ng=0;
00324               }
00325               else if(!breakDayHour(d,h) && !teacherNotAvailableDayHour(tch,d,h))
00326                      ng++;
00327        }
00328        tchDayNGaps[d]=gaps;
00329        tchDayNHours[d]=hours;
00330 }
00331 
00332 inline void Generate::updateSbgNHoursGaps(int sbg, int d)
00333 {
00334        int hours=0, gaps=0, nfirstgaps=0;
00335 
00336        int h;
00337        for(h=0; h<gt.rules.nHoursPerDay; h++){
00338               if(sbgTimetable(d,h)>=0)
00339                      break;
00340               else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00341                      nfirstgaps++;
00342        }
00343        int ng=0;
00344        for(; h<gt.rules.nHoursPerDay; h++){
00345               if(sbgTimetable(d,h)>=0){
00346                      hours++;
00347                      gaps+=ng;
00348                      ng=0;
00349               }
00350               else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00351                      ng++;
00352        }
00353        sbgDayNGaps[d]=gaps;
00354        sbgDayNHours[d]=hours;
00355        if(sbgDayNHours[d]>0)
00356               sbgDayNFirstGaps[d]=nfirstgaps;
00357        else
00358               sbgDayNFirstGaps[d]=0;
00359 }
00360 
00361 inline void Generate::updateTeachersNHoursGaps(Activity* act, int ai, int d)
00362 {
00363        Q_UNUSED(act);
00364 
00365        foreach(int tch, mustComputeTimetableTeachers[ai]){
00366        //foreach(int tch, act->iTeachersList){
00367               int hours=0, gaps=0;
00368        
00369               int h;
00370               for(h=0; h<gt.rules.nHoursPerDay; h++)
00371                      if(newTeachersTimetable(tch,d,h)>=0)
00372                             break;
00373               int ng=0;
00374               for(; h<gt.rules.nHoursPerDay; h++){
00375                      if(newTeachersTimetable(tch,d,h)>=0){
00376                             hours++;
00377                             gaps+=ng;
00378                             ng=0;
00379                      }
00380                      else if(!breakDayHour(d,h) && !teacherNotAvailableDayHour(tch,d,h))
00381                             ng++;
00382               }
00383               newTeachersDayNGaps(tch,d)=gaps;
00384               newTeachersDayNHours(tch,d)=hours;
00385        }
00386 }
00387 
00388 inline void Generate::updateSubgroupsNHoursGaps(Activity* act, int ai, int d)
00389 {
00390        Q_UNUSED(act);
00391 
00392        foreach(int sbg, mustComputeTimetableSubgroups[ai]){
00393        //foreach(int sbg, act->iSubgroupsList){
00394               int hours=0, gaps=0, nfirstgaps=0;
00395 
00396               int h;
00397               for(h=0; h<gt.rules.nHoursPerDay; h++){
00398                      if(newSubgroupsTimetable(sbg,d,h)>=0)
00399                             break;
00400                      else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00401                             nfirstgaps++;
00402               }
00403               int ng=0;
00404               for(; h<gt.rules.nHoursPerDay; h++){
00405                      if(newSubgroupsTimetable(sbg,d,h)>=0){
00406                             hours++;
00407                             gaps+=ng;
00408                             ng=0;
00409                      }
00410                      else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00411                             ng++;
00412               }
00413               newSubgroupsDayNGaps(sbg,d)=gaps;
00414               newSubgroupsDayNHours(sbg,d)=hours;
00415               if(hours>0)
00416                      newSubgroupsDayNFirstGaps(sbg,d)=nfirstgaps;
00417               else
00418                      newSubgroupsDayNFirstGaps(sbg,d)=0;
00419        }
00420 }
00421 
00422 
00423 inline void Generate::teacherGetNHoursGaps(int tch)
00424 {
00425        if(!mustComputeTimetableTeacher[tch])
00426               return;
00427 
00428        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00429               newTeachersDayNHours(tch,d2)=0;
00430               newTeachersDayNGaps(tch,d2)=0;
00431        }
00432        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00433               bool countGaps=false;
00434               int ng=0;
00435               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00436                      if(newTeachersTimetable(tch,d2,h2)>=0){
00437                             newTeachersDayNHours(tch,d2)++;
00438                             if(countGaps)
00439                                    newTeachersDayNGaps(tch,d2)+=ng;
00440                             else
00441                                    countGaps=true;
00442                             ng=0;
00443                      }
00444                      else if(!breakDayHour(d2,h2) && !teacherNotAvailableDayHour(tch,d2,h2))
00445                             ng++;
00446               }
00447        }
00448 }
00449 
00450 inline void Generate::tchGetNHoursGaps(int tch)
00451 {
00452        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00453               tchDayNHours[d2]=0;
00454               tchDayNGaps[d2]=0;
00455        }
00456        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00457               bool countGaps=false;
00458               int ng=0;
00459               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00460                      if(tchTimetable(d2,h2)>=0){
00461                             tchDayNHours[d2]++;
00462                             if(countGaps)
00463                                    tchDayNGaps[d2]+=ng;
00464                             else
00465                                    countGaps=true;
00466                             ng=0;
00467                      }
00468                      else if(!breakDayHour(d2,h2) && !teacherNotAvailableDayHour(tch,d2,h2))
00469                             ng++;
00470               }
00471        }
00472 }
00473 
00474 inline bool Generate::teacherRemoveAnActivityFromBeginOrEnd(int tch, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
00475 {
00476        Q_UNUSED(tch);
00477 
00478        //remove an activity from begin or from end of any day
00479        QList<int> possibleDays;
00480        QList<bool> atBeginning;
00481        QList<int> acts;
00482        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00483               if(tchDayNHours[d2]>0){
00484                      int actIndexBegin=-1, actIndexEnd=-1;
00485                      int h2;
00486                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++){
00487                             if(tchTimetable(d2,h2)>=0){
00488                                    actIndexBegin=tchTimetable(d2,h2);
00489                                    break;
00490                             }
00491                      }
00492                      if(actIndexBegin>=0)
00493                             if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai)
00494                                    actIndexBegin=-1;
00495                      for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){
00496                             if(tchTimetable(d2,h2)>=0){
00497                                    actIndexEnd=tchTimetable(d2,h2);
00498                                    break;
00499                             }
00500                      }
00501                      if(actIndexEnd>=0)
00502                             if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai || actIndexEnd==actIndexBegin)
00503                                    actIndexEnd=-1;
00504 
00505                      if(actIndexBegin>=0){
00506                             assert(!acts.contains(actIndexBegin));
00507                             possibleDays.append(d2);
00508                             atBeginning.append(true);
00509                             acts.append(actIndexBegin);
00510                      }
00511                      if(actIndexEnd>=0){
00512                             assert(!acts.contains(actIndexEnd));
00513                             possibleDays.append(d2);
00514                             atBeginning.append(false);
00515                             acts.append(actIndexEnd);
00516                      }
00517               }
00518        }
00519                                           
00520        bool possibleBeginOrEnd=true;
00521        if(possibleDays.count()==0)
00522               possibleBeginOrEnd=false;
00523                             
00524        if(possibleBeginOrEnd){
00525               int t;
00526                                           
00527               if(level==0){
00528                      int optMinWrong=INF;
00529                      
00530                      QList<int> tl;
00531 
00532                      for(int q=0; q<acts.count(); q++){
00533                             int ai2=acts.at(q);
00534                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
00535                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
00536                             }
00537                      }
00538                      
00539                      for(int q=0; q<acts.count(); q++){
00540                             int ai2=acts.at(q);
00541                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
00542                                    tl.append(q);
00543                      }
00544                      
00545                      assert(tl.size()>=1);
00546                      int mpos=tl.at(randomKnuth(tl.size()));
00547                      
00548                      assert(mpos>=0 && mpos<acts.count());
00549                      t=mpos;
00550               }
00551               else{
00552                      t=randomKnuth(possibleDays.count());
00553               }
00554                                                         
00555               assert(t>=0 && t<possibleDays.count());
00556                                                  
00557               int d2=possibleDays.at(t);
00558               bool begin=atBeginning.at(t);
00559               int ai2=acts.at(t);
00560               
00561               removedActivity=ai2;
00562                                                  
00563               if(begin){
00564                      int h2;
00565                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
00566                             if(tchTimetable(d2,h2)>=0)
00567                                    break;
00568                      assert(h2<gt.rules.nHoursPerDay);
00569                      
00570                      assert(tchTimetable(d2,h2)==ai2);
00571                                                         
00572                      assert(!conflActivities.contains(ai2));
00573                      conflActivities.append(ai2);
00574                      nConflActivities++;
00575                      assert(nConflActivities==conflActivities.count());
00576               }
00577               else{
00578                      int h2;
00579                      for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--)
00580                             if(tchTimetable(d2,h2)>=0)
00581                                    break;
00582                      assert(h2>=0);
00583                      
00584                      assert(tchTimetable(d2,h2)==ai2);
00585                                                  
00586                      assert(!conflActivities.contains(ai2));
00587                      conflActivities.append(ai2);
00588                      nConflActivities++;
00589                      assert(nConflActivities==conflActivities.count());
00590               }
00591               
00592               return true;
00593        }
00594        else
00595               return false;
00596 }
00597 
00598 inline bool Generate::teacherRemoveAnActivityFromBeginOrEndCertainDay(int tch, int d2, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
00599 {
00600        Q_UNUSED(tch);
00601 
00602        int actIndexBegin=-1, actIndexEnd=-1;
00603        
00604        if(tchDayNHours[d2]>0){
00605               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00606                      if(tchTimetable(d2,h2)>=0){
00607                             actIndexBegin=tchTimetable(d2,h2);
00608                             break;
00609                      }
00610               }
00611               if(actIndexBegin>=0)
00612                      if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai)
00613                             actIndexBegin=-1;
00614               for(int h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){
00615                      if(tchTimetable(d2,h2)>=0){
00616                             actIndexEnd=tchTimetable(d2,h2);
00617                             break;
00618                      }
00619               }
00620               if(actIndexEnd>=0)
00621                      if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai || actIndexEnd==actIndexBegin)
00622                             actIndexEnd=-1;
00623        }
00624                                           
00625        if(actIndexEnd>=0 || actIndexBegin>=0){
00626               int ai2=-1;
00627               if(level==0){
00628                      int optMinWrong=INF;
00629 
00630                      if(actIndexBegin>=0){
00631                             if(optMinWrong>triedRemovals(actIndexBegin,c.times[actIndexBegin])){
00632                                    optMinWrong=triedRemovals(actIndexBegin,c.times[actIndexBegin]);
00633                             }
00634                             ai2=actIndexBegin;
00635                      }
00636 
00637                      if(actIndexEnd>=0){
00638                             if(optMinWrong>triedRemovals(actIndexEnd,c.times[actIndexEnd])){
00639                                    optMinWrong=triedRemovals(actIndexEnd,c.times[actIndexEnd]);
00640                             }
00641                             ai2=actIndexEnd;
00642                      }
00643                      
00644                      if(actIndexBegin>=0 && actIndexEnd>=0 && optMinWrong==triedRemovals(actIndexEnd,c.times[actIndexEnd]) &&
00645                        optMinWrong==triedRemovals(actIndexBegin,c.times[actIndexBegin])){
00646                             if(randomKnuth(2)==0)
00647                                    ai2=actIndexBegin;
00648                             else
00649                                    ai2=actIndexEnd;
00650                      }
00651               }
00652               else{
00653                      if(actIndexBegin>=0 && actIndexEnd<0)
00654                             ai2=actIndexBegin;
00655                      else if(actIndexEnd>=0 && actIndexBegin<0)
00656                             ai2=actIndexEnd;
00657                      else{
00658                             if(randomKnuth(2)==0)
00659                                    ai2=actIndexBegin;
00660                             else
00661                                    ai2=actIndexEnd;
00662                      }
00663               }
00664               assert(ai2>=0);
00665                                                         
00666               removedActivity=ai2;
00667                                                  
00668               assert(!conflActivities.contains(ai2));
00669               conflActivities.append(ai2);
00670               nConflActivities++;
00671               assert(nConflActivities==conflActivities.count());
00672               
00673               return true;
00674        }
00675        else
00676               return false;
00677 }
00678 
00679 inline bool Generate::teacherRemoveAnActivityFromAnywhere(int tch, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
00680 {
00681        Q_UNUSED(tch);
00682 
00683        //remove an activity from anywhere
00684        QList<int> acts;
00685        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00686               if(tchDayNHours[d2]>0){
00687                      int actIndex=-1;
00688                      int h2;
00689                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
00690                             if(tchTimetable(d2,h2)>=0){
00691                                    actIndex=tchTimetable(d2,h2);
00692                                    
00693                                    if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex))
00694                                           actIndex=-1;
00695 
00696                                    if(actIndex>=0){
00697                                           assert(!acts.contains(actIndex));
00698                                           acts.append(actIndex);
00699                                    }
00700                             }
00701               }
00702        }
00703                                           
00704        if(acts.count()>0){
00705               int t;
00706                                           
00707               if(level==0){
00708                      int optMinWrong=INF;
00709                      
00710                      QList<int> tl;
00711 
00712                      for(int q=0; q<acts.count(); q++){
00713                             int ai2=acts.at(q);
00714                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
00715                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
00716                             }
00717                      }
00718                      
00719                      for(int q=0; q<acts.count(); q++){
00720                             int ai2=acts.at(q);
00721                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
00722                                    tl.append(q);
00723                      }
00724                      
00725                      assert(tl.size()>=1);
00726                      int mpos=tl.at(randomKnuth(tl.size()));
00727                      
00728                      assert(mpos>=0 && mpos<acts.count());
00729                      t=mpos;
00730               }
00731               else{
00732                      t=randomKnuth(acts.count());
00733               }
00734                                                         
00735               int ai2=acts.at(t);
00736               
00737               removedActivity=ai2;
00738                                                  
00739               assert(!conflActivities.contains(ai2));
00740               conflActivities.append(ai2);
00741               nConflActivities++;
00742               assert(nConflActivities==conflActivities.count());
00743               
00744               return true;
00745        }
00746        else
00747               return false;
00748 }
00749 
00750 inline bool Generate::teacherRemoveAnActivityFromAnywhereCertainDay(int tch, int d2, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
00751 {
00752        Q_UNUSED(tch);
00753 
00754        //remove an activity from anywhere
00755        QList<int> acts;
00756        //for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00757               if(tchDayNHours[d2]>0){
00758                      int actIndex=-1;
00759                      int h2;
00760                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
00761                             if(tchTimetable(d2,h2)>=0){
00762                                    actIndex=tchTimetable(d2,h2);
00763                                    
00764                                    if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex))
00765                                           actIndex=-1;
00766 
00767                                    if(actIndex>=0){
00768                                           assert(!acts.contains(actIndex));
00769                                           acts.append(actIndex);
00770                                    }
00771                             }
00772               }
00773        //}
00774                                           
00775        if(acts.count()>0){
00776               int t;
00777                                           
00778               if(level==0){
00779                      int optMinWrong=INF;
00780                      
00781                      QList<int> tl;
00782 
00783                      for(int q=0; q<acts.count(); q++){
00784                             int ai2=acts.at(q);
00785                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
00786                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
00787                             }
00788                      }
00789                      
00790                      for(int q=0; q<acts.count(); q++){
00791                             int ai2=acts.at(q);
00792                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
00793                                    tl.append(q);
00794                      }
00795                      
00796                      assert(tl.size()>=1);
00797                      int mpos=tl.at(randomKnuth(tl.size()));
00798                      
00799                      assert(mpos>=0 && mpos<acts.count());
00800                      t=mpos;
00801               }
00802               else{
00803                      t=randomKnuth(acts.count());
00804               }
00805                                                         
00806               int ai2=acts.at(t);
00807               
00808               removedActivity=ai2;
00809                                                  
00810               assert(!conflActivities.contains(ai2));
00811               conflActivities.append(ai2);
00812               nConflActivities++;
00813               assert(nConflActivities==conflActivities.count());
00814               
00815               return true;
00816        }
00817        else
00818               return false;
00819 }
00820 
00821 inline bool Generate::teacherRemoveAnActivityFromAnywhereCertainDayCertainActivityTag(int tch, int d2, int actTag, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
00822 {
00823        Q_UNUSED(tch);
00824 
00825        //remove an activity from anywhere
00826        QList<int> acts;
00827        //for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00828               if(tchDayNHours[d2]>0){
00829                      int actIndex=-1;
00830                      int h2;
00831                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
00832                             if(tchTimetable(d2,h2)>=0){
00833                                    actIndex=tchTimetable(d2,h2);
00834                                    
00835                                    if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex) || !gt.rules.internalActivitiesList[actIndex].iActivityTagsSet.contains(actTag))
00836                                           actIndex=-1;
00837 
00838                                    if(actIndex>=0){
00839                                           assert(!acts.contains(actIndex));
00840                                           acts.append(actIndex);
00841                                    }
00842                             }
00843               }
00844        //}
00845                                           
00846        if(acts.count()>0){
00847               int t;
00848                                           
00849               if(level==0){
00850                      int optMinWrong=INF;
00851                      
00852                      QList<int> tl;
00853 
00854                      for(int q=0; q<acts.count(); q++){
00855                             int ai2=acts.at(q);
00856                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
00857                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
00858                             }
00859                      }
00860                      
00861                      for(int q=0; q<acts.count(); q++){
00862                             int ai2=acts.at(q);
00863                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
00864                                    tl.append(q);
00865                      }
00866                      
00867                      assert(tl.size()>=1);
00868                      int mpos=tl.at(randomKnuth(tl.size()));
00869                      
00870                      assert(mpos>=0 && mpos<acts.count());
00871                      t=mpos;
00872               }
00873               else{
00874                      t=randomKnuth(acts.count());
00875               }
00876                                                         
00877               int ai2=acts.at(t);
00878               
00879               removedActivity=ai2;
00880                                                  
00881               assert(!conflActivities.contains(ai2));
00882               conflActivities.append(ai2);
00883               nConflActivities++;
00884               assert(nConflActivities==conflActivities.count());
00885               
00886               return true;
00887        }
00888        else
00889               return false;
00890 }
00891 
00892 
00893 //students
00894 inline void Generate::subgroupGetNHoursGaps(int sbg)
00895 {
00896        if(!mustComputeTimetableSubgroup[sbg])
00897               return;
00898 
00899        for(int d=0; d<gt.rules.nDaysPerWeek; d++){
00900               int hours=0, gaps=0, nfirstgaps=0;
00901 
00902               int h;
00903               for(h=0; h<gt.rules.nHoursPerDay; h++){
00904                      if(newSubgroupsTimetable(sbg,d,h)>=0)
00905                             break;
00906                      else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00907                             nfirstgaps++;
00908               }
00909               int ng=0;
00910               for(; h<gt.rules.nHoursPerDay; h++){
00911                      if(newSubgroupsTimetable(sbg,d,h)>=0){
00912                             hours++;
00913                             gaps+=ng;
00914                             ng=0;
00915                      }
00916                      else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00917                             ng++;
00918               }
00919               newSubgroupsDayNGaps(sbg,d)=gaps;
00920               newSubgroupsDayNHours(sbg,d)=hours;
00921               if(hours>0)
00922                      newSubgroupsDayNFirstGaps(sbg,d)=nfirstgaps;
00923               else
00924                      newSubgroupsDayNFirstGaps(sbg,d)=0;
00925        }
00926 
00927 /*     for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00928               newSubgroupsDayNHours(sbg,d2)=0;
00929               newSubgroupsDayNGaps(sbg,d2)=0;
00930        }
00931        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00932               bool countGaps=false;
00933               int ng=0;
00934               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00935                      if(newSubgroupsTimetable(sbg,d2,h2)>=0){
00936                             newSubgroupsDayNHours(sbg,d2)++;
00937                             if(countGaps)
00938                                    newSubgroupsDayNGaps(sbg,d2)+=ng;
00939                             else
00940                                    countGaps=true;
00941                             ng=0;
00942                      }
00943                      else if(!breakDayHour(d2,h2) && !subgroupNotAvailableDayHour(sbg,d2,h2))
00944                             ng++;
00945               }
00946        }*/
00947 }
00948 
00949 inline void Generate::sbgGetNHoursGaps(int sbg)
00950 {
00951        for(int d=0; d<gt.rules.nDaysPerWeek; d++){
00952               int hours=0, gaps=0, nfirstgaps=0;
00953 
00954               int h;
00955               for(h=0; h<gt.rules.nHoursPerDay; h++){
00956                      if(sbgTimetable(d,h)>=0)
00957                             break;
00958                      else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00959                             nfirstgaps++;
00960               }
00961               int ng=0;
00962               for(; h<gt.rules.nHoursPerDay; h++){
00963                      if(sbgTimetable(d,h)>=0){
00964                             hours++;
00965                             gaps+=ng;
00966                             ng=0;
00967                      }
00968                      else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h))
00969                             ng++;
00970               }
00971        
00972               sbgDayNGaps[d]=gaps;
00973               sbgDayNHours[d]=hours;
00974               if(sbgDayNHours[d]>0)
00975                      sbgDayNFirstGaps[d]=nfirstgaps;
00976               else
00977                      sbgDayNFirstGaps[d]=0;
00978        }
00979        
00980        /*
00981        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00982               sbgDayNHours[d2]=0;
00983               sbgDayNGaps[d2]=0;
00984               sbgDayNFirstGaps[d2]=0;
00985        }
00986        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
00987               bool countGaps=false;
00988               int ng=0;
00989               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
00990               if(sbgTimetable(d2,h2)>=0){
00991                             sbgDayNHours[d2]++;
00992                             if(countGaps)
00993                                    sbgDayNGaps[d2]+=ng;
00994                             else
00995                                    countGaps=true;
00996                             ng=0;
00997                      }
00998                      else if(!breakDayHour(d2,h2) && !subgroupNotAvailableDayHour(sbg,d2,h2))
00999                             ng++;
01000               }
01001        }*/
01002 }
01003 
01004 inline bool Generate::subgroupRemoveAnActivityFromBeginOrEnd(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01005 {
01006        Q_UNUSED(sbg);
01007 
01008        //remove an activity from begin or from end of any day
01009        QList<int> possibleDays;
01010        QList<bool> atBeginning;
01011        QList<int> acts;
01012        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01013               if(sbgDayNHours[d2]>0){
01014                      int actIndexBegin=-1, actIndexEnd=-1;
01015                      int h2;
01016                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++){
01017                             if(sbgTimetable(d2,h2)>=0){
01018                                    actIndexBegin=sbgTimetable(d2,h2);
01019                                    break;
01020                             }
01021                      }
01022                      if(actIndexBegin>=0)
01023                             if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai)
01024                                    actIndexBegin=-1;
01025                      for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){
01026                             if(sbgTimetable(d2,h2)>=0){
01027                                    actIndexEnd=sbgTimetable(d2,h2);
01028                                    break;
01029                             }
01030                      }
01031                      if(actIndexEnd>=0)
01032                             if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai || actIndexEnd==actIndexBegin)
01033                                    actIndexEnd=-1;
01034 
01035                      if(actIndexBegin>=0){
01036                             assert(!acts.contains(actIndexBegin));
01037                             possibleDays.append(d2);
01038                             atBeginning.append(true);
01039                             acts.append(actIndexBegin);
01040                      }
01041                      if(actIndexEnd>=0){
01042                             assert(!acts.contains(actIndexEnd));
01043                             possibleDays.append(d2);
01044                             atBeginning.append(false);
01045                             acts.append(actIndexEnd);
01046                      }
01047               }
01048        }
01049                                           
01050        bool possibleBeginOrEnd=true;                                         
01051        if(possibleDays.count()==0)
01052               possibleBeginOrEnd=false;
01053                             
01054        if(possibleBeginOrEnd){
01055               int t;
01056                                           
01057               if(level==0){
01058                      int optMinWrong=INF;
01059                      
01060                      QList<int> tl;
01061 
01062                      for(int q=0; q<acts.count(); q++){
01063                             int ai2=acts.at(q);
01064                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
01065                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
01066                             }
01067                      }
01068                      
01069                      for(int q=0; q<acts.count(); q++){
01070                             int ai2=acts.at(q);
01071                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
01072                                    tl.append(q);
01073                      }
01074                      
01075                      assert(tl.size()>=1);
01076                      int mpos=tl.at(randomKnuth(tl.size()));
01077                      
01078                      assert(mpos>=0 && mpos<acts.count());
01079                      t=mpos;
01080               }
01081               else{
01082                      t=randomKnuth(possibleDays.count());
01083               }
01084                                                         
01085               assert(t>=0 && t<possibleDays.count());
01086                                                  
01087               int d2=possibleDays.at(t);
01088               bool begin=atBeginning.at(t);
01089               int ai2=acts.at(t);
01090               
01091               removedActivity=ai2;
01092                                                  
01093               if(begin){
01094                      int h2;
01095                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
01096                             if(sbgTimetable(d2,h2)>=0)
01097                                    break;
01098                      assert(h2<gt.rules.nHoursPerDay);
01099               
01100                      assert(sbgTimetable(d2,h2)==ai2);
01101                                                         
01102                      assert(!conflActivities.contains(ai2));
01103                      conflActivities.append(ai2);
01104                      nConflActivities++;
01105                      assert(nConflActivities==conflActivities.count());
01106               }
01107               else{
01108                      int h2;
01109                      for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--)
01110                             if(sbgTimetable(d2,h2)>=0)
01111                                    break;
01112                      assert(h2>=0);
01113                      
01114                      assert(sbgTimetable(d2,h2)==ai2);
01115                                                  
01116                      assert(!conflActivities.contains(ai2));
01117                      conflActivities.append(ai2);
01118                      nConflActivities++;
01119                      assert(nConflActivities==conflActivities.count());
01120               }
01121               
01122               return true;
01123        }
01124        else
01125               return false;
01126 }
01127 
01128 inline bool Generate::subgroupRemoveAnActivityFromBegin(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01129 {
01130        Q_UNUSED(sbg);
01131 
01132        //remove an activity from begin of any day
01133        QList<int> possibleDays;
01134        QList<int> acts;
01135        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01136               if(sbgDayNHours[d2]>0){
01137                      int actIndexBegin=-1;
01138                      int h2;
01139                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++){
01140                             if(sbgTimetable(d2,h2)>=0){
01141                                    actIndexBegin=sbgTimetable(d2,h2);
01142                                    break;
01143                             }
01144                      }
01145                      if(actIndexBegin>=0)
01146                             if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai)
01147                                    actIndexBegin=-1;
01148 
01149                      if(actIndexBegin>=0){
01150                             assert(!acts.contains(actIndexBegin));
01151                             possibleDays.append(d2);
01152                             acts.append(actIndexBegin);
01153                      }
01154               }
01155        }
01156                                           
01157        bool possibleBegin=true;
01158        if(possibleDays.count()==0)
01159               possibleBegin=false;
01160                             
01161        if(possibleBegin){
01162               int t;
01163                                           
01164               if(level==0){
01165                      int optMinWrong=INF;
01166                      
01167                      QList<int> tl;
01168 
01169                      for(int q=0; q<acts.count(); q++){
01170                             int ai2=acts.at(q);
01171                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
01172                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
01173                             }
01174                      }
01175                      
01176                      for(int q=0; q<acts.count(); q++){
01177                             int ai2=acts.at(q);
01178                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
01179                                    tl.append(q);
01180                      }
01181                      
01182                      assert(tl.size()>=1);
01183                      int mpos=tl.at(randomKnuth(tl.size()));
01184                      
01185                      assert(mpos>=0 && mpos<acts.count());
01186                      t=mpos;
01187               }
01188               else{
01189                      t=randomKnuth(possibleDays.count());
01190               }
01191                                                         
01192               assert(t>=0 && t<possibleDays.count());
01193                                                  
01194               int d2=possibleDays.at(t);
01195               int ai2=acts.at(t);
01196               
01197               removedActivity=ai2;
01198                                                  
01199               int h2;
01200               for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
01201                      if(sbgTimetable(d2,h2)>=0)
01202                             break;
01203               assert(h2<gt.rules.nHoursPerDay);
01204        
01205               assert(sbgTimetable(d2,h2)==ai2);
01206                                                  
01207               assert(!conflActivities.contains(ai2));
01208               conflActivities.append(ai2);
01209               nConflActivities++;
01210               assert(nConflActivities==conflActivities.count());
01211               
01212               return true;
01213        }
01214        else
01215               return false;
01216 }
01217 
01218 inline bool Generate::subgroupRemoveAnActivityFromBeginCertainDay(int sbg, int d2, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01219 {
01220        Q_UNUSED(sbg);
01221        Q_UNUSED(level);
01222 
01223        if(sbgDayNHours[d2]>0){
01224               int actIndexBegin=-1;
01225               int h2;
01226               for(h2=0; h2<gt.rules.nHoursPerDay; h2++){
01227                      if(sbgTimetable(d2,h2)>=0){
01228                             actIndexBegin=sbgTimetable(d2,h2);
01229                             break;
01230                      }
01231               }
01232               if(actIndexBegin>=0)
01233                      if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai)
01234                             actIndexBegin=-1;
01235 
01236               if(actIndexBegin>=0){
01237                      removedActivity=actIndexBegin;
01238        
01239                      assert(!conflActivities.contains(actIndexBegin));
01240                      conflActivities.append(actIndexBegin);
01241                      nConflActivities++;
01242                      assert(nConflActivities==conflActivities.count());
01243               
01244                      return true;
01245               }
01246               else
01247                      return false;
01248        }
01249        else
01250               return false;
01251 }
01252 
01253 inline bool Generate::subgroupRemoveAnActivityFromEnd(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01254 {
01255        Q_UNUSED(sbg);
01256 
01257        //remove an activity from begin or from end of any day
01258        QList<int> possibleDays;
01259        QList<int> acts;
01260        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01261               if(sbgDayNHours[d2]>0){
01262                      int actIndexEnd=-1;
01263                      int h2;
01264                      for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){
01265                             if(sbgTimetable(d2,h2)>=0){
01266                                    actIndexEnd=sbgTimetable(d2,h2);
01267                                    break;
01268                             }
01269                      }
01270                      if(actIndexEnd>=0)
01271                             if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai)
01272                                    actIndexEnd=-1;
01273 
01274                      if(actIndexEnd>=0){
01275                             assert(!acts.contains(actIndexEnd));
01276                             possibleDays.append(d2);
01277                             acts.append(actIndexEnd);
01278                      }
01279               }
01280        }
01281                                           
01282        bool possibleEnd=true;
01283        if(possibleDays.count()==0)
01284               possibleEnd=false;
01285                             
01286        if(possibleEnd){
01287               int t;
01288                                           
01289               if(level==0){
01290                      int optMinWrong=INF;
01291                      
01292                      QList<int> tl;
01293 
01294                      for(int q=0; q<acts.count(); q++){
01295                             int ai2=acts.at(q);
01296                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
01297                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
01298                             }
01299                      }
01300                      
01301                      for(int q=0; q<acts.count(); q++){
01302                             int ai2=acts.at(q);
01303                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
01304                                    tl.append(q);
01305                      }
01306                      
01307                      assert(tl.size()>=1);
01308                      int mpos=tl.at(randomKnuth(tl.size()));
01309                      
01310                      assert(mpos>=0 && mpos<acts.count());
01311                      t=mpos;
01312               }
01313               else{
01314                      t=randomKnuth(possibleDays.count());
01315               }
01316                                                         
01317               assert(t>=0 && t<possibleDays.count());
01318                                                  
01319               int d2=possibleDays.at(t);
01320               int ai2=acts.at(t);
01321               
01322               removedActivity=ai2;
01323                                                  
01324               int h2;
01325               for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--)
01326                      if(sbgTimetable(d2,h2)>=0)
01327                             break;
01328               assert(h2>=0);
01329               
01330               assert(sbgTimetable(d2,h2)==ai2);
01331                                                  
01332               assert(!conflActivities.contains(ai2));
01333               conflActivities.append(ai2);
01334               nConflActivities++;
01335               assert(nConflActivities==conflActivities.count());
01336               
01337               return true;
01338        }
01339        else
01340               return false;
01341 }
01342 
01343 inline bool Generate::subgroupRemoveAnActivityFromEndCertainDay(int sbg, int d2, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01344 {
01345        Q_UNUSED(sbg);
01346        Q_UNUSED(level);
01347 
01348        if(sbgDayNHours[d2]>0){
01349               int actIndexEnd=-1;
01350               int h2;
01351               for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){
01352                      if(sbgTimetable(d2,h2)>=0){
01353                             actIndexEnd=sbgTimetable(d2,h2);
01354                             break;
01355                      }
01356               }
01357               if(actIndexEnd>=0)
01358                      if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai)
01359                             actIndexEnd=-1;
01360 
01361               if(actIndexEnd>=0){
01362                      removedActivity=actIndexEnd;
01363        
01364                      assert(!conflActivities.contains(actIndexEnd));
01365                      conflActivities.append(actIndexEnd);
01366                      nConflActivities++;
01367                      assert(nConflActivities==conflActivities.count());
01368               
01369                      return true;
01370               }
01371               else
01372                      return false;
01373        }
01374        else
01375               return false;
01376 }
01377 
01378 inline bool Generate::subgroupRemoveAnActivityFromAnywhere(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01379 {
01380        Q_UNUSED(sbg);
01381 
01382        //remove an activity from anywhere
01383        QList<int> acts;
01384        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01385               if(sbgDayNHours[d2]>0){
01386                      int actIndex=-1;
01387                      int h2;
01388                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
01389                             if(sbgTimetable(d2,h2)>=0){
01390                                    actIndex=sbgTimetable(d2,h2);
01391                                    
01392                                    if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex))
01393                                           actIndex=-1;
01394 
01395                                    if(actIndex>=0){
01396                                           assert(!acts.contains(actIndex));
01397                                           acts.append(actIndex);
01398                                    }
01399                             }
01400               }
01401        }
01402                                           
01403        if(acts.count()>0){
01404               int t;
01405                                           
01406               if(level==0){
01407                      int optMinWrong=INF;
01408                      
01409                      QList<int> tl;
01410 
01411                      for(int q=0; q<acts.count(); q++){
01412                             int ai2=acts.at(q);
01413                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
01414                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
01415                             }
01416                      }
01417                      
01418                      for(int q=0; q<acts.count(); q++){
01419                             int ai2=acts.at(q);
01420                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
01421                                    tl.append(q);
01422                      }
01423                      
01424                      assert(tl.size()>=1);
01425                      int mpos=tl.at(randomKnuth(tl.size()));
01426                      
01427                      assert(mpos>=0 && mpos<acts.count());
01428                      t=mpos;
01429               }
01430               else{
01431                      t=randomKnuth(acts.count());
01432               }
01433                                                         
01434               int ai2=acts.at(t);
01435               
01436               removedActivity=ai2;
01437                                                  
01438               assert(!conflActivities.contains(ai2));
01439               conflActivities.append(ai2);
01440               nConflActivities++;
01441               assert(nConflActivities==conflActivities.count());
01442               
01443               return true;
01444        }
01445        else
01446               return false;
01447 }
01448 
01449 inline bool Generate::subgroupRemoveAnActivityFromAnywhereCertainDay(int sbg, int d2, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01450 {
01451        Q_UNUSED(sbg);
01452 
01453        //remove an activity from anywhere
01454        QList<int> acts;
01455        //for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01456               if(sbgDayNHours[d2]>0){
01457                      int actIndex=-1;
01458                      int h2;
01459                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
01460                             if(sbgTimetable(d2,h2)>=0){
01461                                    actIndex=sbgTimetable(d2,h2);
01462                                    
01463                                    if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex))
01464                                           actIndex=-1;
01465 
01466                                    if(actIndex>=0){
01467                                           assert(!acts.contains(actIndex));
01468                                           acts.append(actIndex);
01469                                    }
01470                             }
01471               }
01472        //}
01473                                           
01474        if(acts.count()>0){
01475               int t;
01476                                           
01477               if(level==0){
01478                      int optMinWrong=INF;
01479                      
01480                      QList<int> tl;
01481 
01482                      for(int q=0; q<acts.count(); q++){
01483                             int ai2=acts.at(q);
01484                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
01485                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
01486                             }
01487                      }
01488                      
01489                      for(int q=0; q<acts.count(); q++){
01490                             int ai2=acts.at(q);
01491                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
01492                                    tl.append(q);
01493                      }
01494                      
01495                      assert(tl.size()>=1);
01496                      int mpos=tl.at(randomKnuth(tl.size()));
01497                      
01498                      assert(mpos>=0 && mpos<acts.count());
01499                      t=mpos;
01500               }
01501               else{
01502                      t=randomKnuth(acts.count());
01503               }
01504                                                         
01505               int ai2=acts.at(t);
01506               
01507               removedActivity=ai2;
01508                                                  
01509               assert(!conflActivities.contains(ai2));
01510               conflActivities.append(ai2);
01511               nConflActivities++;
01512               assert(nConflActivities==conflActivities.count());
01513               
01514               return true;
01515        }
01516        else
01517               return false;
01518 }
01519 
01520 inline bool Generate::subgroupRemoveAnActivityFromAnywhereCertainDayCertainActivityTag(int sbg, int d2, int actTag, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible
01521 {
01522        Q_UNUSED(sbg);
01523 
01524        //remove an activity from anywhere
01525        QList<int> acts;
01526        //for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01527               if(sbgDayNHours[d2]>0){
01528                      int actIndex=-1;
01529                      int h2;
01530                      for(h2=0; h2<gt.rules.nHoursPerDay; h2++)
01531                             if(sbgTimetable(d2,h2)>=0){
01532                                    actIndex=sbgTimetable(d2,h2);
01533                                    
01534                                    if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex) || !gt.rules.internalActivitiesList[actIndex].iActivityTagsSet.contains(actTag))
01535                                           actIndex=-1;
01536 
01537                                    if(actIndex>=0){
01538                                           assert(!acts.contains(actIndex));
01539                                           acts.append(actIndex);
01540                                    }
01541                             }
01542               }
01543        //}
01544                                           
01545        if(acts.count()>0){
01546               int t;
01547                                           
01548               if(level==0){
01549                      int optMinWrong=INF;
01550                      
01551                      QList<int> tl;
01552 
01553                      for(int q=0; q<acts.count(); q++){
01554                             int ai2=acts.at(q);
01555                             if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
01556                                    optMinWrong=triedRemovals(ai2,c.times[ai2]);
01557                             }
01558                      }
01559                      
01560                      for(int q=0; q<acts.count(); q++){
01561                             int ai2=acts.at(q);
01562                             if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
01563                                    tl.append(q);
01564                      }
01565                      
01566                      assert(tl.size()>=1);
01567                      int mpos=tl.at(randomKnuth(tl.size()));
01568                      
01569                      assert(mpos>=0 && mpos<acts.count());
01570                      t=mpos;
01571               }
01572               else{
01573                      t=randomKnuth(acts.count());
01574               }
01575                                                         
01576               int ai2=acts.at(t);
01577               
01578               removedActivity=ai2;
01579                                                  
01580               assert(!conflActivities.contains(ai2));
01581               conflActivities.append(ai2);
01582               nConflActivities++;
01583               assert(nConflActivities==conflActivities.count());
01584               
01585               return true;
01586        }
01587        else
01588               return false;
01589 }
01590 
01591 
01592 inline bool skipRandom(double weightPercentage)
01593 {
01594        if(weightPercentage<0)
01595               return true; //non-existing constraint
01596               
01597        if(weightPercentage>=100.0)
01598               return false;
01599 
01600        double t=weightPercentage/100.0;
01601        assert(t>=0 && t<=1);
01602               
01603        t*=double(MM);
01604        int tt=int(floor(t+0.5));
01605        assert(tt>=0 && tt<=MM);
01606                                           
01607        int r=randomKnuth1MM1();
01608        assert(r>0 && r<MM); //r cannot be 0
01609        if(tt<=r)
01610               return true;
01611        else
01612               return false;
01613 }
01614 
01615 
01616 Generate::Generate()
01617 {
01618 }
01619 
01620 Generate::~Generate()
01621 {
01622 }
01623 
01624 bool Generate::precompute(QWidget* parent, QTextStream* initialOrderStream)
01625 {
01626        return processTimeSpaceConstraints(parent, initialOrderStream);
01627 }
01628 
01629 inline bool Generate::checkBuildingChanges(int sbg, int tch, const QList<int>& globalConflActivities, int rm, int level, const Activity* act, int ai, int d, int h, QList<int>& tmp_list)
01630 {
01631        assert((sbg==-1 && tch>=0) || (sbg>=0 && tch==-1));
01632        if(sbg>=0)
01633               assert(sbg<gt.rules.nInternalSubgroups);
01634        if(tch>=0)
01635               assert(tch<gt.rules.nInternalTeachers);
01636 
01637        if(sbg>=0)
01638               assert(minGapsBetweenBuildingChangesForStudentsPercentages[sbg]>=0 || maxBuildingChangesPerDayForStudentsPercentages[sbg]>=0
01639                  || maxBuildingChangesPerWeekForStudentsPercentages[sbg]>=0);
01640        if(tch>=0)
01641               assert(minGapsBetweenBuildingChangesForTeachersPercentages[tch]>=0 || maxBuildingChangesPerDayForTeachersPercentages[tch]>=0
01642                  || maxBuildingChangesPerWeekForTeachersPercentages[tch]>=0);
01643               
01644        int buildings[MAX_HOURS_PER_DAY], activities[MAX_HOURS_PER_DAY];
01645        for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
01646               int ai2;
01647               if(sbg>=0)
01648                      ai2=newSubgroupsTimetable(sbg,d,h2);
01649               else
01650                      ai2=newTeachersTimetable(tch,d,h2);
01651 
01652               if(ai2>=0 && !globalConflActivities.contains(ai2) && !tmp_list.contains(ai2)){
01653                      int rm2;
01654                      if(h2>=h && h2<h+act->duration){
01655                             assert(ai2==ai);
01656                             rm2=rm;
01657                      }
01658                      else
01659                             rm2=c.rooms[ai2];
01660                      if(rm2!=UNALLOCATED_SPACE && rm2!=UNSPECIFIED_ROOM){
01661                             assert(rm2>=0);
01662                             activities[h2]=ai2;
01663                             buildings[h2]=gt.rules.internalRoomsList[rm2]->buildingIndex;
01664                      }
01665                      else{
01666                             activities[h2]=ai2;
01667                             buildings[h2]=-1;
01668                      }
01669               }
01670               else{
01671                      buildings[h2]=-1;
01672                      activities[h2]=-1;
01673               }
01674        }
01675                      
01676        if(buildings[h]==-1) //no problem
01677               return true;
01678                      
01679        //min gaps
01680        double perc;
01681        int mg;
01682        if(sbg>=0){
01683               perc=minGapsBetweenBuildingChangesForStudentsPercentages[sbg];
01684               mg=minGapsBetweenBuildingChangesForStudentsMinGaps[sbg];
01685        }
01686        else{
01687               perc=minGapsBetweenBuildingChangesForTeachersPercentages[tch];
01688               mg=minGapsBetweenBuildingChangesForTeachersMinGaps[tch];
01689        }
01690        if(perc>=0){
01691               for(int h2=max(0, h-mg); h2<=min(h+act->duration-1+mg, gt.rules.nHoursPerDay-1); h2++)
01692                      if(!(h2>=h && h2<h+act->duration))
01693                             if(buildings[h2]!=buildings[h] && buildings[h2]!=-1){
01694                                    int ai2=activities[h2];
01695                                    assert(ai2>=0);
01696                                    if(!swappedActivities[ai2] && !(fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2])){
01697                                           if(!tmp_list.contains(ai2)){
01698                                                  tmp_list.append(ai2);
01699                                                  
01700                                                  int ha=c.times[ai2]/gt.rules.nDaysPerWeek;
01701                                                  int dura=gt.rules.internalActivitiesList[ai2].duration;
01702                                                  for(int h3=ha; h3<ha+dura; h3++){
01703                                                         assert(activities[h3]==ai2);
01704                                                         assert(buildings[h3]!=-1);
01705                                                         buildings[h3]=-1;
01706                                                         activities[h3]=-1;
01707                                                  }
01708                                           }
01709                                    }
01710                                    else{
01711                                           return false;
01712                                    }
01713                             }
01714        }
01715 
01716        //max changes per day
01717        int mc;
01718        if(sbg>=0){
01719               perc=maxBuildingChangesPerDayForStudentsPercentages[sbg];
01720               mc=maxBuildingChangesPerDayForStudentsMaxChanges[sbg];
01721        }
01722        else{
01723               perc=maxBuildingChangesPerDayForTeachersPercentages[tch];
01724               mc=maxBuildingChangesPerDayForTeachersMaxChanges[tch];
01725        }
01726        
01727        if(perc>=0){
01728               int crt_building=-1;
01729               int n_changes=0;
01730               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++)
01731                      if(buildings[h2]!=-1){
01732                             if(crt_building!=buildings[h2]){
01733                                    if(crt_building!=-1)
01734                                           n_changes++;
01735                                    crt_building=buildings[h2];
01736                             }
01737                      }
01738                                    
01739               if(n_changes>mc){ //not OK
01740                      if(level>=LEVEL_STOP_CONFLICTS_CALCULATION)
01741                             return false;
01742                                    
01743                      QList<int> removableActsList;                                  
01744                      for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
01745                             if(!(h2>=h && h2<h+act->duration))
01746                                    if(buildings[h2]!=-1 && activities[h2]>=0 && !swappedActivities[activities[h2]] && !(fixedTimeActivity[activities[h2]]&&fixedSpaceActivity[activities[h2]]))
01747                                           if(!removableActsList.contains(activities[h2])){
01748                                                  removableActsList.append(activities[h2]);
01749                                                  assert(!globalConflActivities.contains(activities[h2]));
01750                                                  assert(!tmp_list.contains(activities[h2]));
01751                                           }
01752                      }
01753                                    
01754                      for(;;){
01755                             int ai2=-1;
01756                             QList<int> optimalRemovableActs;
01757                             if(level==0){
01758                                    int nWrong=INF;
01759                                    foreach(int a, removableActsList)
01760                                           if(nWrong>triedRemovals(a,c.times[a]) ){
01761                                                  nWrong=triedRemovals(a,c.times[a]);
01762                                           }
01763                                    foreach(int a, removableActsList)
01764                                           if(nWrong==triedRemovals(a,c.times[a]))
01765                                                  optimalRemovableActs.append(a);
01766                             }
01767                             else
01768                                    optimalRemovableActs=removableActsList;
01769                                    
01770                             if(removableActsList.count()>0)
01771                                    assert(optimalRemovableActs.count()>0);
01772                                    
01773                             if(optimalRemovableActs.count()==0)
01774                                    return false;
01775                                    
01776                             ai2=optimalRemovableActs.at(randomKnuth(optimalRemovableActs.count()));
01777                             
01778                             assert(!swappedActivities[ai2]);
01779                             assert(!(fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2]));
01780                             assert(!globalConflActivities.contains(ai2));
01781                             assert(!tmp_list.contains(ai2));
01782                             assert(ai2>=0);
01783 
01784                             tmp_list.append(ai2);
01785                                           
01786                             int t=removableActsList.removeAll(ai2);
01787                             assert(t==1);
01788                                           
01789                             int ha=c.times[ai2]/gt.rules.nDaysPerWeek;
01790                             int da=gt.rules.internalActivitiesList[ai2].duration;
01791                             for(int h2=ha; h2<ha+da; h2++){
01792                                    assert(activities[h2]==ai2);
01793                                    assert(buildings[h2]!=-1);
01794                                    buildings[h2]=-1;
01795                                    activities[h2]=-1;
01796                             }
01797                                           
01798                             int crt_building=-1;
01799                             int n_changes=0;
01800                             for(int h2=0; h2<gt.rules.nHoursPerDay; h2++)
01801                                    if(buildings[h2]!=-1){
01802                                           if(crt_building!=buildings[h2]){
01803                                                  if(crt_building!=-1)
01804                                                         n_changes++;
01805                                                  crt_building=buildings[h2];
01806                                           }
01807                                    }
01808                      
01809                             if(n_changes<=mc){ //OK
01810                                    break;
01811                             }
01812                      }
01813               }
01814        }
01815        
01816        //max changes per week
01817        if(sbg>=0){
01818               perc=maxBuildingChangesPerWeekForStudentsPercentages[sbg];
01819               mc=maxBuildingChangesPerWeekForStudentsMaxChanges[sbg];
01820        }
01821        else{
01822               perc=maxBuildingChangesPerWeekForTeachersPercentages[tch];
01823               mc=maxBuildingChangesPerWeekForTeachersMaxChanges[tch];
01824        }      
01825        if(perc==-1){
01826               assert(mc==-1);
01827               return true;
01828        }
01829               
01830        //I would like to get rid of these large static variables, but making them dynamic slows down ~33% for a sample from Timisoara Economics
01831        int weekBuildings[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY], weekActivities[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];
01832        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01833               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
01834                      int ai2;
01835                      if(sbg>=0)
01836                             ai2=newSubgroupsTimetable(sbg,d2,h2);
01837                      else
01838                             ai2=newTeachersTimetable(tch,d2,h2);
01839        
01840                      if(ai2>=0 && !globalConflActivities.contains(ai2) && !tmp_list.contains(ai2)){
01841                             int rm2;
01842                             if(d==d2 && h2>=h && h2<h+act->duration){
01843                                    assert(ai2==ai);
01844                                    rm2=rm;
01845                             }
01846                             else
01847                                    rm2=c.rooms[ai2];
01848                             if(rm2!=UNALLOCATED_SPACE && rm2!=UNSPECIFIED_ROOM){
01849                                    assert(rm2>=0);
01850                                    weekActivities[d2][h2]=ai2;
01851                                    weekBuildings[d2][h2]=gt.rules.internalRoomsList[rm2]->buildingIndex;
01852                             }
01853                             else{
01854                                    weekActivities[d2][h2]=ai2;
01855                                    weekBuildings[d2][h2]=-1;
01856                             }
01857                      }
01858                      else{
01859                             weekBuildings[d2][h2]=-1;
01860                             weekActivities[d2][h2]=-1;
01861                      }
01862               }
01863        }
01864 
01865        int n_changes=0;
01866        for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01867               int crt_building=-1;
01868               for(int h2=0; h2<gt.rules.nHoursPerDay; h2++)
01869                      if(weekBuildings[d2][h2]!=-1){
01870                             if(crt_building!=weekBuildings[d2][h2]){
01871                                    if(crt_building!=-1)
01872                                           n_changes++;
01873                                    crt_building=weekBuildings[d2][h2];
01874                             }
01875                      }
01876        }
01877                                    
01878        if(n_changes>mc){ //not OK
01879               if(level>=LEVEL_STOP_CONFLICTS_CALCULATION)
01880                      return false;
01881                                    
01882               QList<int> removableActsList;                                  
01883               for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01884                      for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
01885                             if(!(d2==d && h2>=h && h2<h+act->duration))
01886                                    if(weekBuildings[d2][h2]!=-1 && weekActivities[d2][h2]>=0 && !swappedActivities[weekActivities[d2][h2]] && !(fixedTimeActivity[weekActivities[d2][h2]]&&fixedSpaceActivity[weekActivities[d2][h2]]))
01887                                           if(!removableActsList.contains(weekActivities[d2][h2])){
01888                                                  removableActsList.append(weekActivities[d2][h2]);
01889                                                  assert(!globalConflActivities.contains(weekActivities[d2][h2]));
01890                                                  assert(!tmp_list.contains(weekActivities[d2][h2]));
01891                                           }
01892                      }
01893               }
01894                                    
01895               for(;;){
01896                      int ai2=-1;
01897                      QList<int> optimalRemovableActs;
01898                      if(level==0){
01899                             int nWrong=INF;
01900                             foreach(int a, removableActsList)
01901                                    if(nWrong>triedRemovals(a,c.times[a])){
01902                                           nWrong=triedRemovals(a,c.times[a]);
01903                                    }
01904                             foreach(int a, removableActsList)
01905                                    if(nWrong==triedRemovals(a,c.times[a]))
01906                                           optimalRemovableActs.append(a);
01907                      }
01908                      else
01909                             optimalRemovableActs=removableActsList;
01910                                    
01911                      if(removableActsList.count()>0)
01912                             assert(optimalRemovableActs.count()>0);
01913                                    
01914                      if(optimalRemovableActs.count()==0)
01915                             return false;
01916                                    
01917                      ai2=optimalRemovableActs.at(randomKnuth(optimalRemovableActs.count()));
01918                             
01919                      assert(!swappedActivities[ai2]);
01920                      assert(!(fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2]));
01921                      assert(!globalConflActivities.contains(ai2));
01922                      assert(!tmp_list.contains(ai2));
01923                      assert(ai2>=0);
01924 
01925                      tmp_list.append(ai2);
01926                                           
01927                      int t=removableActsList.removeAll(ai2);
01928                      assert(t==1);
01929                                           
01930                      int ha=c.times[ai2]/gt.rules.nDaysPerWeek;
01931                      int da=c.times[ai2]%gt.rules.nDaysPerWeek;
01932                      int dura=gt.rules.internalActivitiesList[ai2].duration;
01933                      for(int h2=ha; h2<ha+dura; h2++){
01934                             assert(weekActivities[da][h2]==ai2);
01935                             assert(weekBuildings[da][h2]!=-1);
01936                             weekBuildings[da][h2]=-1;
01937                             weekActivities[da][h2]=-1;
01938                      }
01939                                           
01940                      int n_changes=0;
01941                      for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
01942                             int crt_building=-1;
01943                             for(int h2=0; h2<gt.rules.nHoursPerDay; h2++)
01944                                    if(weekBuildings[d2][h2]!=-1){
01945                                           if(crt_building!=weekBuildings[d2][h2]){
01946                                                  if(crt_building!=-1)
01947                                                         n_changes++;
01948                                                  crt_building=weekBuildings[d2][h2];
01949                                           }
01950                                    }
01951                      }
01952               
01953                      if(n_changes<=mc){ //OK
01954                             break;
01955                      }
01956               }
01957        }
01958        
01959        return true;
01960 }
01961 
01962 //2012-04-29
01963 inline bool Generate::checkActivitiesOccupyMaxDifferentRooms(const QList<int>& globalConflActivities, int rm, int level, int ai, QList<int>& tmp_list)
01964 {
01965        foreach(ActivitiesOccupyMaxDifferentRooms_item* item, aomdrListForActivity[ai]){
01966               //preliminary
01967               QSet<int> occupiedRoomsSet;
01968               foreach(int ai2, item->activitiesList)
01969                      if(ai2!=ai && !globalConflActivities.contains(ai2) && !tmp_list.contains(ai2)){
01970                             int rm2=c.rooms[ai2];
01971                             if(rm2!=UNALLOCATED_SPACE && rm2!=UNSPECIFIED_ROOM)
01972                                    if(!occupiedRoomsSet.contains(rm2)){
01973                                           occupiedRoomsSet.insert(rm2);
01974                                           if(occupiedRoomsSet.count()==item->maxDifferentRooms) //no further testing needed
01975                                                  break;
01976                                    }
01977                      }
01978                      
01979               if(!globalConflActivities.contains(ai) && !tmp_list.contains(ai)) //should be always true
01980                      if(rm!=UNALLOCATED_SPACE && rm!=UNSPECIFIED_ROOM) //should be always true
01981                             if(!occupiedRoomsSet.contains(rm))
01982                                    occupiedRoomsSet.insert(rm);
01983                      
01984               if(occupiedRoomsSet.count()<=item->maxDifferentRooms)
01985                      continue;
01986 
01987               //correction needed
01988               QList<QSet<int> > activitiesInRoom;
01989               occupiedRoomsSet.clear();
01990               QList<int> occupiedRoomsList;
01991               QHash<int, int> roomIndexInOccupiedRoomsList;
01992               QList<bool> canEmptyRoom;
01993               
01994               foreach(int ai2, item->activitiesList)
01995                      if(!globalConflActivities.contains(ai2) && !tmp_list.contains(ai2)){
01996                             int rm2;
01997                             if(ai2==ai)
01998                                    rm2=rm;
01999                             else
02000                                    rm2=c.rooms[ai2];
02001                             if(rm2!=UNALLOCATED_SPACE && rm2!=UNSPECIFIED_ROOM){
02002                                    int ind;
02003                                    if(!occupiedRoomsSet.contains(rm2)){
02004                                           occupiedRoomsSet.insert(rm2);
02005                                           occupiedRoomsList.append(rm2);
02006                                           canEmptyRoom.append(true);
02007                                           
02008                                           QSet<int> tl;
02009                                           tl.insert(ai2);
02010                                           activitiesInRoom.append(tl);
02011                                           
02012                                           ind=activitiesInRoom.count()-1;
02013                                           roomIndexInOccupiedRoomsList.insert(rm2, ind);
02014                                    }
02015                                    else{
02016                                           assert(roomIndexInOccupiedRoomsList.contains(rm2));
02017                                           ind=roomIndexInOccupiedRoomsList.value(rm2);
02018                                           assert(ind>=0 && ind<activitiesInRoom.count());
02019                                           activitiesInRoom[ind].insert(ai2);
02020                                    }
02021                                    
02022                                    if(ai2==ai || fixedTimeActivity[ai2] || swappedActivities[ai2])
02023                                           if(canEmptyRoom[ind]==true)
02024                                                  canEmptyRoom[ind]=false;
02025                             }
02026                      }
02027                      
02028               assert(occupiedRoomsSet.count()==item->maxDifferentRooms+1);
02029                      
02030               QList<int> candidates;
02031               foreach(int rm2, occupiedRoomsList){
02032                      assert(roomIndexInOccupiedRoomsList.contains(rm2));
02033                      int ind=roomIndexInOccupiedRoomsList.value(rm2);
02034                      if(canEmptyRoom.at(ind)==true)
02035                             candidates.append(ind);
02036               }
02037 
02038               if(level==0){
02039                      QList<int> finalCandidates;
02040                      
02041                      int optConflActivities=MAX_ACTIVITIES;
02042                      int optMinWrong=INF;
02043                      int optNWrong=INF;
02044                      int optMinIndexAct=gt.rules.nInternalActivities;
02045 
02046                      //phase 1
02047                      foreach(int ind, candidates){
02048                             QSet<int> activitiesForCandidate=activitiesInRoom.at(ind);
02049                             
02050                             int tmp_n_confl_acts=activitiesForCandidate.count();
02051                             int tmp_minWrong=INF;
02052                             int tmp_nWrong=0;
02053                             int tmp_minIndexAct=gt.rules.nInternalActivities;
02054                             
02055                             if(activitiesForCandidate.count()>0){
02056                                    foreach(int ai2, activitiesForCandidate){
02057                                           tmp_minWrong=min(tmp_minWrong, triedRemovals(ai2,c.times[ai2]));
02058                                           tmp_nWrong+=triedRemovals(ai2,c.times[ai2]);
02059                                           tmp_minIndexAct=min(tmp_minIndexAct, invPermutation[ai2]);
02060                                    }
02061                             }
02062                             else{
02063                                    assert(0);
02064                                    tmp_minWrong=0;
02065                                    tmp_nWrong=0;
02066                                    tmp_minIndexAct=-1;
02067                             }
02068               
02069                             if(optMinWrong>tmp_minWrong ||
02070                               (optMinWrong==tmp_minWrong && optNWrong>tmp_nWrong) ||
02071                               (optMinWrong==tmp_minWrong && optNWrong==tmp_nWrong && optConflActivities>tmp_n_confl_acts) ||
02072                               (optMinWrong==tmp_minWrong && optNWrong==tmp_nWrong && optConflActivities==tmp_n_confl_acts && optMinIndexAct>tmp_minIndexAct)){
02073                                    optConflActivities=tmp_n_confl_acts;
02074                                    optMinWrong=tmp_minWrong;
02075                                    optNWrong=tmp_nWrong;
02076                                    optMinIndexAct=tmp_minIndexAct;
02077                             }
02078                      }
02079 
02080                      //phase 2
02081                      foreach(int ind, candidates){
02082                             QSet<int> activitiesForCandidate=activitiesInRoom.at(ind);
02083                             
02084                             int tmp_n_confl_acts=activitiesForCandidate.count();
02085                             int tmp_minWrong=INF;
02086                             int tmp_nWrong=0;
02087                             int tmp_minIndexAct=gt.rules.nInternalActivities;
02088                             
02089                             if(activitiesForCandidate.count()>0){
02090                                    foreach(int ai2, activitiesForCandidate){
02091                                           tmp_minWrong=min(tmp_minWrong, triedRemovals(ai2,c.times[ai2]));
02092                                           tmp_nWrong+=triedRemovals(ai2,c.times[ai2]);
02093                                           tmp_minIndexAct=min(tmp_minIndexAct, invPermutation[ai2]);
02094                                    }
02095                             }
02096                             else{
02097                                    assert(0);
02098                                    tmp_minWrong=0;
02099                                    tmp_nWrong=0;
02100                                    tmp_minIndexAct=-1;
02101                             }
02102               
02103                             if(optMinWrong==tmp_minWrong && optNWrong==tmp_nWrong && optConflActivities==tmp_n_confl_acts && optMinIndexAct==tmp_minIndexAct){
02104                                    finalCandidates.append(ind);
02105                             }
02106                      }
02107                      
02108                      //phase 3
02109                      if(candidates.count()>0)
02110                             assert(finalCandidates.count()>0);
02111                      candidates=finalCandidates;
02112               }
02113               else{ //if(level>0)
02114                      QList<int> finalCandidates;
02115                      
02116                      int optConflActivities=MAX_ACTIVITIES;
02117 
02118                      foreach(int ind, candidates){
02119                             if(activitiesInRoom.at(ind).count()<optConflActivities){
02120                                    optConflActivities=activitiesInRoom.at(ind).count();
02121                                    finalCandidates.clear();
02122                                    finalCandidates.append(ind);
02123                             }
02124                             else if(activitiesInRoom.at(ind).count()==optConflActivities){
02125                                    finalCandidates.append(ind);
02126                             }
02127                      }
02128                      
02129                      if(candidates.count()>0)
02130                             assert(finalCandidates.count()>0);
02131                      candidates=finalCandidates;
02132               }
02133               
02134               if(candidates.count()==0)
02135                      return false;
02136               
02137               int indexToRemove=candidates.at(randomKnuth(candidates.count()));
02138               assert(canEmptyRoom.at(indexToRemove)==true);
02139               foreach(int ai2, activitiesInRoom.at(indexToRemove)){
02140                      assert(!globalConflActivities.contains(ai2) && !tmp_list.contains(ai2));
02141                      assert(ai2!=ai && !fixedTimeActivity[ai2] && !swappedActivities[ai2]);
02142                      tmp_list.append(ai2);
02143               }
02144        }
02145        
02146        return true;
02147 }
02148 
02149 inline bool Generate::chooseRoom(const QList<int>& listOfRooms, const QList<int>& globalConflActivities, int level, const Activity* act, int ai, int d, int h, int& roomSlot, int& selectedSlot, QList<int>& localConflActivities)
02150 {
02151        roomSlot=selectedSlot=UNSPECIFIED_ROOM; //if we don't find a room, return these values
02152 
02153        Q_UNUSED(ai);
02154 
02155        int optConflActivities=MAX_ACTIVITIES;
02156        int optMinWrong=INF;
02157        int optNWrong=INF;
02158        int optMinIndexAct=gt.rules.nInternalActivities;
02159        
02160        QList<QList<int> > conflActivitiesRooms;
02161        QList<int> nConflActivitiesRooms;
02162        QList<int> listedRooms;
02163        
02164        QList<int> minWrong;
02165        QList<int> nWrong;
02166        QList<int> minIndexAct;
02167                      
02168        QList<int> tmp_list;
02169        int tmp_n_confl_acts;
02170        int tmp_minWrong;
02171        int tmp_nWrong;
02172        int tmp_minIndexAct;
02173        
02174        int newtime=d+h*gt.rules.nDaysPerWeek;
02175                      
02176        foreach(int rm, listOfRooms){
02177               int dur;
02178               for(dur=0; dur<act->duration; dur++)
02179                      if(notAllowedRoomTimePercentages[rm][newtime+dur*gt.rules.nDaysPerWeek]>=0 &&
02180                       !skipRandom(notAllowedRoomTimePercentages[rm][newtime+dur*gt.rules.nDaysPerWeek]))
02181                             break;
02182                                           
02183               if(dur==act->duration){
02184                      tmp_list.clear();
02185                                    
02186                      int dur2;
02187                      for(dur2=0; dur2<act->duration; dur2++){
02188                             int ai2=roomsTimetable(rm,d,h+dur2);
02189                             if(ai2>=0){
02190                                    if(!globalConflActivities.contains(ai2)){
02191                                           if(swappedActivities[ai2] || (fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2])){
02192                                                  tmp_n_confl_acts=MAX_ACTIVITIES; //not really needed
02193                                                  break;
02194                                           }
02195                                           else{
02196                                                  if(!tmp_list.contains(ai2)){
02197                                                         tmp_list.append(ai2);
02198                                                  }
02199                                           }
02200                                    }
02201                             }
02202                      }
02203                      if(dur2==act->duration){
02204                             //see building changes
02205                             
02206                             //building changes for students
02207                             bool ok=true;
02208                             foreach(int sbg, act->iSubgroupsList){
02209                                    if(minGapsBetweenBuildingChangesForStudentsPercentages[sbg]>=0 || maxBuildingChangesPerDayForStudentsPercentages[sbg]>=0
02210                                      || maxBuildingChangesPerWeekForStudentsPercentages[sbg]>=0){
02211                                           ok=checkBuildingChanges(sbg, -1, globalConflActivities, rm, level, act, ai, d, h, tmp_list);
02212                                           if(!ok)
02213                                                  break;
02214                                    }
02215                             }
02216 
02217                             if(!ok)
02218                                    continue;
02219                      
02220                             //building changes for teachers
02221                             foreach(int tch, act->iTeachersList){
02222                                    if(minGapsBetweenBuildingChangesForTeachersPercentages[tch]>=0 || maxBuildingChangesPerDayForTeachersPercentages[tch]>=0
02223                                      || maxBuildingChangesPerWeekForTeachersPercentages[tch]>=0){
02224                                           ok=checkBuildingChanges(-1, tch, globalConflActivities, rm, level, act, ai, d, h, tmp_list);
02225                                           if(!ok)
02226                                                  break;
02227                                    }
02228                             }
02229 
02230                             if(!ok)
02231                                    continue;
02232                      
02233                             //max occupied rooms for a set of activities - 2012-04-29
02234                             if(aomdrListForActivity[ai].count()>0)
02235                                    ok=checkActivitiesOccupyMaxDifferentRooms(globalConflActivities, rm, level, ai, tmp_list);
02236                             
02237                             if(!ok)
02238                                    continue;
02239                                    
02240                             tmp_n_confl_acts=0;
02241                             
02242                             tmp_minWrong=INF;
02243                             tmp_nWrong=0;
02244                             
02245                             tmp_minIndexAct=gt.rules.nInternalActivities;
02246                             
02247                             tmp_n_confl_acts=tmp_list.count();
02248                             
02249                             if(level==0){
02250                                    if(tmp_list.count()>0){ //serious bug corrected on 2012-05-02, but it seems that it didn't affect people until now
02251                                           foreach(int ai2, tmp_list){
02252                                                  tmp_minWrong=min(tmp_minWrong, triedRemovals(ai2,c.times[ai2]));
02253                                                  tmp_nWrong+=triedRemovals(ai2,c.times[ai2]);
02254                                                  tmp_minIndexAct=min(tmp_minIndexAct, invPermutation[ai2]);
02255                                           }
02256                                    }
02257                                    else{
02258                                           tmp_minWrong=0;
02259                                           tmp_nWrong=0;
02260                                           tmp_minIndexAct=-1;
02261                                    }
02262                             }
02263                             
02264                             listedRooms.append(rm);
02265                             nConflActivitiesRooms.append(tmp_n_confl_acts);
02266                             conflActivitiesRooms.append(tmp_list);
02267                             
02268                             if(level>0){
02269                                    if(tmp_n_confl_acts<optConflActivities)
02270                                           optConflActivities=tmp_n_confl_acts;
02271                             }
02272                             else{ // if(level==0)
02273                                    minWrong.append(tmp_minWrong);
02274                                    nWrong.append(tmp_nWrong);
02275                                    minIndexAct.append(tmp_minIndexAct);
02276        
02277                                    if(optMinWrong>tmp_minWrong ||
02278                                      (optMinWrong==tmp_minWrong && optNWrong>tmp_nWrong) ||
02279                                      (optMinWrong==tmp_minWrong && optNWrong==tmp_nWrong && optConflActivities>tmp_n_confl_acts) ||
02280                                      (optMinWrong==tmp_minWrong && optNWrong==tmp_nWrong && optConflActivities==tmp_n_confl_acts && optMinIndexAct>tmp_minIndexAct)){
02281                                           optConflActivities=tmp_n_confl_acts;
02282                                           optMinWrong=tmp_minWrong;
02283                                           optNWrong=tmp_nWrong;
02284                                           optMinIndexAct=tmp_minIndexAct;
02285                                    }
02286                             }
02287                      }
02288               }
02289               else //not really needed
02290                      tmp_n_confl_acts=MAX_ACTIVITIES;
02291        }
02292               
02293        if(optConflActivities==MAX_ACTIVITIES) //roomSlot == selectedSlot == UNSPECIFIED_ROOM
02294               return false;
02295               
02296        assert(optConflActivities<MAX_ACTIVITIES);
02297        
02298        QList<int> allowedRoomsIndex;
02299 
02300        assert(listedRooms.count()==nConflActivitiesRooms.count());
02301        assert(listedRooms.count()==conflActivitiesRooms.count());
02302                             
02303        if(level>0){
02304               for(int q=0; q<listedRooms.count(); q++){
02305                      if(nConflActivitiesRooms.at(q)==optConflActivities){
02306                             allowedRoomsIndex.append(q);
02307                      }
02308               }
02309        }
02310        else{
02311               for(int q=0; q<listedRooms.count(); q++){
02312                      if(optMinWrong==minWrong.at(q) && optNWrong==nWrong.at(q) && optConflActivities==nConflActivitiesRooms.at(q) && optMinIndexAct==minIndexAct.at(q)){
02313                             allowedRoomsIndex.append(q);
02314                      }
02315               }
02316               /*if(allowedRoomsIndex.count()!=1)
02317                      cout<<"allowedRoomsIndex.count()=="<<allowedRoomsIndex.count()<<endl;
02318               assert(allowedRoomsIndex.count()==1);*/
02319        }
02320                                    
02321        assert(allowedRoomsIndex.count()>0);
02322        int q=randomKnuth(allowedRoomsIndex.count());
02323        int t=allowedRoomsIndex.at(q);
02324        assert(t>=0 && t<listedRooms.count());
02325        int r=listedRooms.at(t);
02326        assert(r>=0 && r<gt.rules.nInternalRooms);
02327        selectedSlot=r;
02328        roomSlot=r;
02329                             
02330        assert(nConflActivitiesRooms.at(t)==conflActivitiesRooms.at(t).count());
02331                             
02332        localConflActivities.clear(); 
02333                             
02334        foreach(int a, conflActivitiesRooms.at(t)){
02335               assert(!globalConflActivities.contains(a));
02336               assert(!localConflActivities.contains(a)); 
02337               localConflActivities.append(a);
02338        }
02339        
02340        return true;
02341 }
02342 
02343 inline bool Generate::getHomeRoom(const QList<int>& globalConflActivities, int level, const Activity* act, int ai, int d, int h, int& roomSlot, int& selectedSlot, QList<int>& localConflActivities)
02344 {
02345        assert(!unspecifiedHomeRoom[ai]);
02346 
02347        return chooseRoom(activitiesHomeRoomsHomeRooms[ai], globalConflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities);
02348 }
02349 
02350 inline bool Generate::getPreferredRoom(const QList<int>& globalConflActivities, int level, const Activity* act, int ai, int d, int h, int& roomSlot, int& selectedSlot, QList<int>& localConflActivities, bool& canBeUnspecifiedPreferredRoom)
02351 {
02352        assert(!unspecifiedPreferredRoom[ai]);
02353        
02354        bool unspecifiedRoom=true;
02355        QSet<int> allowedRooms;
02356        foreach(PreferredRoomsItem it, activitiesPreferredRoomsList[ai]){
02357               bool skip=skipRandom(it.percentage);
02358               
02359               if(!skip){
02360                      if(unspecifiedRoom){
02361                             unspecifiedRoom=false;
02362                             allowedRooms=it.preferredRooms;           
02363                      }
02364                      else{
02365                             allowedRooms.intersect(it.preferredRooms);
02366                      }
02367               }
02368               else{
02369                      if(unspecifiedRoom){
02370                             allowedRooms.unite(it.preferredRooms);
02371                      }
02372                      else{
02373                             //do nothing
02374                      }
02375               }
02376        }
02377        
02378        QList<int> allowedRoomsList;
02379        foreach(int rm, allowedRooms)
02380               allowedRoomsList.append(rm);
02381               
02382        canBeUnspecifiedPreferredRoom=unspecifiedRoom;
02383 
02384        return chooseRoom(allowedRoomsList, globalConflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities);
02385 }
02386 
02387 inline bool Generate::getRoom(int level, const Activity* act, int ai, int d, int h, int& roomSlot, int& selectedSlot, QList<int>& conflActivities, int& nConflActivities)
02388 {
02389        bool okp, okh;
02390        
02391        QList<int> localConflActivities;
02392        
02393        if(unspecifiedPreferredRoom[ai]){
02394               if(unspecifiedHomeRoom[ai]){
02395                      roomSlot=UNSPECIFIED_ROOM;
02396                      selectedSlot=UNSPECIFIED_ROOM;
02397                      return true;
02398               }
02399               else{
02400                      okh=getHomeRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities);
02401                      if(okh){
02402                             foreach(int t, localConflActivities){
02403                                    conflActivities.append(t);
02404                                    nConflActivities++;
02405                             }
02406                             return okh;
02407                      }
02408                      else{
02409                             okh=skipRandom(activitiesHomeRoomsPercentage[ai]);
02410                             return okh;
02411                      }
02412               }
02413        }
02414        else{
02415               bool canBeUnspecifiedPreferredRoom;
02416        
02417               okp=getPreferredRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities, canBeUnspecifiedPreferredRoom);
02418               if(okp && localConflActivities.count()==0){
02419                      /*foreach(int t, localConflActivities){
02420                             conflActivities.append(t);
02421                             nConflActivities++;
02422                      }
02423                      assert(nConflActivities==conflActivities.count());*/
02424                      return okp;
02425               }
02426               else if(okp){
02427                      if(canBeUnspecifiedPreferredRoom){ //skipRandom(activitiesPreferredRoomsPercentage[ai])){
02428                             //get a home room
02429                             if(unspecifiedHomeRoom[ai]){
02430                                    roomSlot=UNSPECIFIED_ROOM;
02431                                    selectedSlot=UNSPECIFIED_ROOM;
02432                                    return true;
02433                             }
02434                             
02435                             okh=getHomeRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities);
02436                             if(okh){
02437                                    foreach(int t, localConflActivities){
02438                                           conflActivities.append(t);
02439                                           nConflActivities++;
02440                                    }
02441                                    return okh;
02442                             }
02443                             else{
02444                                    okh=skipRandom(activitiesHomeRoomsPercentage[ai]);
02445                                    return okh;
02446                             }
02447                      }
02448                      else{
02449                             foreach(int t, localConflActivities){
02450                                    conflActivities.append(t);
02451                                    nConflActivities++;
02452                             }
02453                             assert(nConflActivities==conflActivities.count());
02454                             assert(okp==true);
02455                             return okp;
02456                             //get this preferred room
02457                      }
02458               }
02459               else{ 
02460                      if(canBeUnspecifiedPreferredRoom){ //skipRandom(activitiesPreferredRoomsPercentage[ai])){
02461                             //get a home room
02462                             if(unspecifiedHomeRoom[ai]){
02463                                    roomSlot=UNSPECIFIED_ROOM;
02464                                    selectedSlot=UNSPECIFIED_ROOM;
02465                                    return true;
02466                             }
02467                             
02468                             okh=getHomeRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities);
02469                             if(okh){
02470                                    foreach(int t, localConflActivities){
02471                                           conflActivities.append(t);
02472                                           nConflActivities++;
02473                                    }
02474                                    return okh;
02475                             }
02476                             else{
02477                                    okh=skipRandom(activitiesHomeRoomsPercentage[ai]);
02478                                    return okh;
02479                             }
02480                      }
02481                      else{
02482                             assert(okp==false);
02483                             return okp;
02484                      }
02485               }
02486        }
02487 }
02488 
02489 void Generate::generate(int maxSeconds, bool& impossible, bool& timeExceeded, bool threaded, QTextStream* maxPlacedActivityStream)
02490 {
02491        this->isThreaded=threaded;
02492 
02493        l0nWrong.resize(gt.rules.nHoursPerWeek);
02494        l0minWrong.resize(gt.rules.nHoursPerWeek);
02495        l0minIndexAct.resize(gt.rules.nHoursPerWeek);
02496 
02497        teachersTimetable.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02498        subgroupsTimetable.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02499        roomsTimetable.resize(gt.rules.nInternalRooms, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02500 
02501        newTeachersTimetable.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02502        newSubgroupsTimetable.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02503        newTeachersDayNHours.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek);
02504        newTeachersDayNGaps.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek);
02505        newSubgroupsDayNHours.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek);
02506        newSubgroupsDayNGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek);
02507        newSubgroupsDayNFirstGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek);
02508 
02509        oldTeachersTimetable.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02510        oldSubgroupsTimetable.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02511        oldTeachersDayNHours.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek);
02512        oldTeachersDayNGaps.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek);
02513        oldSubgroupsDayNHours.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek);
02514        oldSubgroupsDayNGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek);
02515        oldSubgroupsDayNFirstGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek);
02516 
02517 
02518        tchTimetable.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02519        tchDayNHours.resize(gt.rules.nDaysPerWeek);
02520        tchDayNGaps.resize(gt.rules.nDaysPerWeek);
02521 
02522        sbgTimetable.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay);
02523        sbgDayNHours.resize(gt.rules.nDaysPerWeek);
02524        sbgDayNGaps.resize(gt.rules.nDaysPerWeek);
02525        sbgDayNFirstGaps.resize(gt.rules.nDaysPerWeek);
02526        
02527        teacherActivitiesOfTheDay.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek);
02528        
02529        //2011-09-30
02530        if(haveActivitiesOccupyOrSimultaneousConstraints){
02531               activitiesAtTime.resize(gt.rules.nHoursPerWeek);
02532 
02533               slotSetOfActivities.resize(gt.rules.nHoursPerWeek);
02534               slotCanEmpty.resize(gt.rules.nHoursPerWeek);
02535        }
02536 
02537 if(threaded){
02538               mutex.lock();
02539 }
02540        c.makeUnallocated(gt.rules);
02541 
02542        nDifficultActivities=0;
02543 
02544        impossible=false;
02545        timeExceeded=false;
02546 
02547        maxncallsrandomswap=-1;
02548 
02549        impossibleActivity=false;
02550        
02551        maxActivitiesPlaced=0;
02552 
02553 if(threaded){
02554               mutex.unlock();
02555 }
02556 
02557        triedRemovals.resize(gt.rules.nInternalActivities, gt.rules.nHoursPerWeek);
02558        for(int i=0; i<gt.rules.nInternalActivities; i++)
02559               for(int j=0; j<gt.rules.nHoursPerWeek; j++)
02560                      triedRemovals(i,j)=0;
02561                      
02563        tabu_size=gt.rules.nInternalActivities*gt.rules.nHoursPerWeek;
02564        //assert(tabu_size<=MAX_TABU);
02565        crt_tabu_index=0;
02566        /*qint16 tabu_activities[MAX_TABU];
02567        qint16 tabu_times[MAX_TABU];*/
02568        tabu_activities.resize(tabu_size);
02569        tabu_times.resize(tabu_size);
02570        for(int i=0; i<tabu_size; i++)
02571               tabu_activities[i]=tabu_times[i]=-1;
02573 
02574        //abortOptimization=false; you have to take care of this before calling this function
02575 
02576        for(int i=0; i<gt.rules.nInternalActivities; i++)
02577               invPermutation[permutation[i]]=i;
02578 
02579        for(int i=0; i<gt.rules.nInternalActivities; i++)
02580               swappedActivities[permutation[i]]=false;
02581 
02582        //tzset();
02583        time_t starting_time;
02584        time(&starting_time);
02585        
02586 if(threaded){
02587               mutex.lock();
02588 }
02589        timeToHighestStage=0;
02590        searchTime=0;
02591        generationStartDateTime=QDateTime::currentDateTime();
02592 if(threaded){
02593               mutex.unlock();
02594 }
02595        
02596        //2000 was before
02597        //limitcallsrandomswap=1000; //1600, 1500 also good values, 1000 too low???
02598        limitcallsrandomswap=2*gt.rules.nInternalActivities; //???? value found practically
02599        
02600        level_limit=14; //20; //16
02601        
02602        assert(level_limit<MAX_LEVEL);
02603        
02604        for(int added_act=0; added_act<gt.rules.nInternalActivities; added_act++){
02605               prevvalue:
02606 
02607 if(threaded){
02608               mutex.lock();
02609 }
02610               if(abortOptimization){
02611 if(threaded){
02612                      mutex.unlock();
02613 }
02614                      return;
02615               }
02616               time_t crt_time;
02617               time(&crt_time);
02618               searchTime=int(crt_time-starting_time);
02619               
02620               if(searchTime>=maxSeconds){
02621 if(threaded){
02622                      mutex.unlock();
02623 }
02624                      
02625                      timeExceeded=true;
02626                      
02627                      return;
02628               }
02629 
02630               for(int i=0; i<=added_act; i++)
02631                      swappedActivities[permutation[i]]=false;
02632               for(int i=added_act+1; i<gt.rules.nInternalActivities; i++)
02633                      assert(!swappedActivities[permutation[i]]);
02634 
02635               cout<<endl<<"Trying to place activity number added_act=="<<added_act<<
02636                "\nwith id=="<<gt.rules.internalActivitiesList[permutation[added_act]].id<<
02637                ", from nInternalActivities=="<<gt.rules.nInternalActivities<<endl;
02638         
02639               //verifyUnallocated(permutation[added_act]]);
02640               //assert(c.times[permutation[added_act]]==UNALLOCATED_TIME);
02641               //assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE);
02642               if(fixedTimeActivity[permutation[added_act]] && fixedSpaceActivity[permutation[added_act]]){
02643                      assert(c.times[permutation[added_act]]==UNALLOCATED_TIME);
02644                      assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE);
02645               }
02646               else if(fixedTimeActivity[permutation[added_act]] && !fixedSpaceActivity[permutation[added_act]]){
02647                      assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE);
02648               }
02649               else if(!fixedTimeActivity[permutation[added_act]]){
02650                      assert(c.times[permutation[added_act]]==UNALLOCATED_TIME);
02651                      assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE);
02652               }
02653               else
02654                      assert(0);
02655 
02656               for(int i=0; i<added_act; i++){
02657                      if(c.times[permutation[i]]==UNALLOCATED_TIME)
02658                             cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has time unallocated"<<endl;
02659                      assert(c.times[permutation[i]]!=UNALLOCATED_TIME);
02660                      /*for(int j=0; j<gt.rules.internalActivitiesList[permutation[i]].duration; j++)
02661                             tlistSet[c.times[permutation[i]]+j*gt.rules.nDaysPerWeek].insert(permutation[i]);*/
02662 
02663                      if(c.rooms[permutation[i]]==UNALLOCATED_SPACE)
02664                             cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has room unallocated"<<endl;
02665                      assert(c.rooms[permutation[i]]!=UNALLOCATED_SPACE);
02666               }
02667 
02669               for(int i=0; i<gt.rules.nInternalRooms; i++)
02670                      for(int j=0; j<gt.rules.nDaysPerWeek; j++)
02671                             for(int k=0; k<gt.rules.nHoursPerDay; k++)
02672                                    roomsTimetable(i,j,k)=-1;
02673               for(int j=0; j<added_act; j++){
02674                      int i=permutation[j];
02675                      assert(c.rooms[i]!=UNALLOCATED_SPACE);
02676                      if(c.rooms[i]!=UNSPECIFIED_ROOM){
02677                             int rm=c.rooms[i];
02678                      
02679                             Activity* act=&gt.rules.internalActivitiesList[i];
02680                             int hour=c.times[i]/gt.rules.nDaysPerWeek;
02681                             int day=c.times[i]%gt.rules.nDaysPerWeek;
02682                             for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){
02683                                    assert(roomsTimetable(rm,day,hour+dd)==-1);
02684                                    roomsTimetable(rm,day,hour+dd)=i;
02685                             }
02686                      }
02687               }
02689                             
02690               //subgroups' timetable
02691               for(int i=0; i<gt.rules.nInternalSubgroups; i++)
02692                      for(int j=0; j<gt.rules.nDaysPerWeek; j++)
02693                             for(int k=0; k<gt.rules.nHoursPerDay; k++){
02694                                    subgroupsTimetable(i,j,k)=-1;
02695                             }
02696               for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){
02697                      int i=permutation[j];
02698                      if(j<added_act){
02699                             assert(c.times[i]!=UNALLOCATED_TIME);
02700                      }
02701                      else{
02702                             if(c.times[i]==UNALLOCATED_TIME)
02703                                    continue;
02704                      }
02705                      assert(c.times[i]!=UNALLOCATED_TIME);
02706                      Activity* act=&gt.rules.internalActivitiesList[i];
02707                      int hour=c.times[i]/gt.rules.nDaysPerWeek;
02708                      int day=c.times[i]%gt.rules.nDaysPerWeek;
02709                      foreach(int sb, act->iSubgroupsList){
02710                             for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){
02711                                    assert(subgroupsTimetable(sb,day,hour+dd)==-1);
02712                                    subgroupsTimetable(sb,day,hour+dd)=i;
02713                             }
02714                      }
02715               }
02716 
02717               //new
02718               for(int i=0; i<gt.rules.nInternalSubgroups; i++)
02719                      for(int j=0; j<gt.rules.nDaysPerWeek; j++)
02720                             for(int k=0; k<gt.rules.nHoursPerDay; k++){
02721                                    newSubgroupsTimetable(i,j,k)=-1;
02722                             }
02723               for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){
02724                      int i=permutation[j];
02725                      if(j<added_act){
02726                             assert(c.times[i]!=UNALLOCATED_TIME);
02727                      }
02728                      else{
02729                             if(c.times[i]==UNALLOCATED_TIME)
02730                                    continue;
02731                      }
02732                      assert(c.times[i]!=UNALLOCATED_TIME);
02733                      Activity* act=&gt.rules.internalActivitiesList[i];
02734                      int hour=c.times[i]/gt.rules.nDaysPerWeek;
02735                      int day=c.times[i]%gt.rules.nDaysPerWeek;
02736                      foreach(int sb, act->iSubgroupsList){
02737                             for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){
02738                                    assert(newSubgroupsTimetable(sb,day,hour+dd)==-1);
02739                                    newSubgroupsTimetable(sb,day,hour+dd)=i;
02740                             }
02741                      }
02742               }
02743 
02744               for(int i=0; i<gt.rules.nInternalSubgroups; i++)
02745                      subgroupGetNHoursGaps(i);
02746 
02747               //teachers' timetable
02748               for(int i=0; i<gt.rules.nInternalTeachers; i++)
02749                      for(int j=0; j<gt.rules.nDaysPerWeek; j++)
02750                             for(int k=0; k<gt.rules.nHoursPerDay; k++){
02751                                    teachersTimetable(i,j,k)=-1;
02752                             }
02753               for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){
02754                      int i=permutation[j];
02755                      if(j<added_act){
02756                             assert(c.times[i]!=UNALLOCATED_TIME);
02757                      }
02758                      else{
02759                             if(c.times[i]==UNALLOCATED_TIME)
02760                                    continue;
02761                      }
02762                      assert(c.times[i]!=UNALLOCATED_TIME);
02763                      Activity* act=&gt.rules.internalActivitiesList[i];
02764                      int hour=c.times[i]/gt.rules.nDaysPerWeek;
02765                      int day=c.times[i]%gt.rules.nDaysPerWeek;
02766                      foreach(int tc, act->iTeachersList){
02767                             for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){
02768                                    assert(teachersTimetable(tc,day,hour+dd)==-1);
02769                                    teachersTimetable(tc,day,hour+dd)=i;
02770                             }
02771                      }
02772               }
02773 
02774               //new
02775               for(int i=0; i<gt.rules.nInternalTeachers; i++)
02776                      for(int j=0; j<gt.rules.nDaysPerWeek; j++)
02777                             for(int k=0; k<gt.rules.nHoursPerDay; k++){
02778                                    newTeachersTimetable(i,j,k)=-1;
02779                             }
02780               for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){
02781                      int i=permutation[j];
02782                      if(j<added_act){
02783                             assert(c.times[i]!=UNALLOCATED_TIME);
02784                      }
02785                      else{
02786                             if(c.times[i]==UNALLOCATED_TIME)
02787                                    continue;
02788                      }
02789                      assert(c.times[i]!=UNALLOCATED_TIME);
02790                      Activity* act=&gt.rules.internalActivitiesList[i];
02791                      int hour=c.times[i]/gt.rules.nDaysPerWeek;
02792                      int day=c.times[i]%gt.rules.nDaysPerWeek;
02793                      foreach(int tc, act->iTeachersList){
02794                             for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){
02795                                    assert(newTeachersTimetable(tc,day,hour+dd)==-1);
02796                                    newTeachersTimetable(tc,day,hour+dd)=i;
02797                             }
02798                      }
02799               }
02800 
02801               for(int i=0; i<gt.rules.nInternalTeachers; i++)
02802                      teacherGetNHoursGaps(i);
02803               
02805               for(int i=0; i<gt.rules.nInternalTeachers; i++)
02806                      for(int j=0; j<gt.rules.nDaysPerWeek; j++)
02807                             teacherActivitiesOfTheDay(i,j).clear();
02808                                                                                                                        
02809               for(int i=0; i<gt.rules.nInternalActivities/*added_act*/; i++){
02810                      if(i<added_act){
02811                      }
02812                      else{
02813                             if(c.times[permutation[i]]==UNALLOCATED_TIME)
02814                                    continue;
02815                      }
02816                      //Activity* act=&gt.rules.internalActivitiesList[permutation[i]];
02817                      int d=c.times[permutation[i]]%gt.rules.nDaysPerWeek;
02818                                                                                                                                                                         
02819                      foreach(int j, teachersWithMaxDaysPerWeekForActivities[permutation[i]]){
02820                             assert(teacherActivitiesOfTheDay(j,d).indexOf(permutation[i])==-1);
02821                             teacherActivitiesOfTheDay(j,d).append(permutation[i]);
02822                      }
02823               }
02825               
02826               //2011-09-30
02827               if(haveActivitiesOccupyOrSimultaneousConstraints){
02828                      for(int t=0; t<gt.rules.nHoursPerWeek; t++)
02829                             activitiesAtTime[t].clear();
02830        
02831                      for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){
02832                             int i=permutation[j];
02833                             if(j<added_act){
02834                                    assert(c.times[i]!=UNALLOCATED_TIME);
02835                             }
02836                             else{
02837                                    if(c.times[i]==UNALLOCATED_TIME)
02838                                           continue;
02839                             }
02840                             assert(c.times[i]!=UNALLOCATED_TIME);
02841                             
02842                             Activity* act=&gt.rules.internalActivitiesList[i];
02843                      
02844                             for(int t=c.times[i]; t<c.times[i]+act->duration*gt.rules.nDaysPerWeek; t+=gt.rules.nDaysPerWeek){
02845                                    assert(!activitiesAtTime[t].contains(i));
02846                                    activitiesAtTime[t].insert(i);
02847                             }
02848                      }
02849               }
02851               
02852               foundGoodSwap=false;
02853        
02854               assert(!swappedActivities[permutation[added_act]]);
02855               swappedActivities[permutation[added_act]]=true;
02856 
02857               nRestore=0;
02858               ncallsrandomswap=0;
02859               randomSwap(permutation[added_act], 0);
02860               
02861               if(!foundGoodSwap){
02862                      if(impossibleActivity){
02863 if(threaded){
02864                             mutex.unlock();
02865 }
02866                             nDifficultActivities=1;
02867                             difficultActivities[0]=permutation[added_act];
02868                             
02869                             impossible=true;
02870                             
02871                             emit(impossibleToSolve());
02872                             
02873                             return;
02874                      }
02875               
02876                      //update difficult activities (activities which are placed correctly so far, together with added_act
02877                      nDifficultActivities=added_act+1;
02878                      cout<<"nDifficultActivities=="<<nDifficultActivities<<endl;
02879                      for(int j=0; j<=added_act; j++)
02880                             difficultActivities[j]=permutation[j];
02881                      
02883                      assert(conflActivitiesTimeSlot.count()>0);
02884                      
02885                      cout<<"conflActivitiesTimeSlot.count()=="<<conflActivitiesTimeSlot.count()<<endl;
02886                      foreach(int i, conflActivitiesTimeSlot){
02887                             cout<<"Confl activity id:"<<gt.rules.internalActivitiesList[i].id;
02888                             cout<<" time of this activity:"<<c.times[i];
02889                             if(c.rooms[i]!=UNSPECIFIED_ROOM)
02890                                    cout<<" room of this activity:"<<qPrintable(gt.rules.internalRoomsList[c.rooms[i]]->name)<<endl;
02891                             else
02892                                    cout<<" room of this activity: UNSPECIFIED_ROOM"<<endl;
02893                      }
02894                      //cout<<endl;
02895                      cout<<"timeSlot=="<<timeSlot<<endl;
02896                      if(roomSlot!=UNSPECIFIED_ROOM)
02897                             cout<<"roomSlot=="<<qPrintable(gt.rules.internalRoomsList[roomSlot]->name)<<endl;
02898                      else
02899                             cout<<"roomSlot==UNSPECIFIED_ROOM"<<endl;
02900 
02901                      QList<int> ok;
02902                      QList<int> confl;
02903                      for(int j=0; j<added_act; j++){
02904                             if(conflActivitiesTimeSlot.indexOf(permutation[j])!=-1){
02905                                    if(triedRemovals(permutation[j],c.times[permutation[j]])>0){
02906                                           cout<<"Warning - explored removal: id=="<<
02907                                            gt.rules.internalActivitiesList[permutation[j]].id<<", time=="<<c.times[permutation[j]]
02908                                            <<", times=="<<triedRemovals(permutation[j],c.times[permutation[j]])<<endl;
02909                                    }
02910                                    triedRemovals(permutation[j],c.times[permutation[j]])++;
02911                                    
02913                                    int a=tabu_activities[crt_tabu_index];
02914                                    int t=tabu_times[crt_tabu_index];
02915                                    if(a>=0 && t>=0){
02916                                           assert(triedRemovals(a,t)>0);
02917                                           triedRemovals(a,t)--;
02918                                           //cout<<"Removing activity with id=="<<gt.rules.internalActivitiesList[a].id<<", time=="<<t<<endl;
02919                                    }
02920                                    tabu_activities[crt_tabu_index]=permutation[j];
02921                                    tabu_times[crt_tabu_index]=c.times[permutation[j]];
02922                                    //cout<<"Inserting activity with id=="<<gt.rules.internalActivitiesList[permutation[j]].id<<", time=="<<c.times[permutation[j]]<<endl;
02923                                    crt_tabu_index=(crt_tabu_index+1)%tabu_size;
02925                             
02926                                    confl.append(permutation[j]);
02927                             }
02928                             else
02929                                    ok.append(permutation[j]);
02930                      }
02931                             
02932                      assert(confl.count()==conflActivitiesTimeSlot.count());
02933                      
02934                      int j=0;
02935                      int tmp=permutation[added_act];
02936                      foreach(int k, ok){
02937                             permutation[j]=k;
02938                             invPermutation[k]=j;
02939                             j++;
02940                      }
02941                      int q=j;
02942                      //cout<<"q=="<<q<<endl;
02943                      permutation[j]=tmp;
02944                      invPermutation[tmp]=j;
02945                      j++;
02946                      cout<<"id of permutation[j=="<<j-1<<"]=="<<gt.rules.internalActivitiesList[permutation[j-1]].id<<endl;
02947                      cout<<"conflicting:"<<endl;
02948                      foreach(int k, confl){
02949                             permutation[j]=k;
02950                             invPermutation[k]=j;
02951                             j++;
02952                             cout<<"id of permutation[j=="<<j-1<<"]=="<<gt.rules.internalActivitiesList[permutation[j-1]].id<<endl;
02953                      }
02954                      assert(j==added_act+1);
02955                      
02956                      //check
02957                      /*int pv[MAX_ACTIVITIES];
02958                      for(int i=0; i<gt.rules.nInternalActivities; i++)
02959                             pv[i]=0;
02960                      for(int i=0; i<gt.rules.nInternalActivities; i++)
02961                             pv[permutation[i]]++;
02962                      for(int i=0; i<gt.rules.nInternalActivities; i++)
02963                             assert(pv[i]==1);*/
02964                      //
02965 
02966                      cout<<"tmp represents activity with id=="<<gt.rules.internalActivitiesList[tmp].id;
02967                      cout<<" initial time: "<<c.times[tmp];
02968                      cout<<" final time: "<<timeSlot<<endl;
02969                      c.times[tmp]=timeSlot;
02970                      c.rooms[tmp]=roomSlot;
02971                      
02972                      for(int i=q+1; i<=added_act; i++){
02973                             if(!fixedTimeActivity[permutation[i]])
02974                                    c.times[permutation[i]]=UNALLOCATED_TIME;
02975                             c.rooms[permutation[i]]=UNALLOCATED_SPACE;
02976                      }
02977                      c._fitness=-1;
02978                      c.changedForMatrixCalculation=true;
02979                             
02980                      added_act=q+1;
02981 if(threaded){
02982                      mutex.unlock();
02983 }
02984        
02985                      //if(semaphorePlacedActivity){
02986                             emit(activityPlaced(q+1));
02987 if(threaded){
02988                             semaphorePlacedActivity.acquire();
02989 }
02990                      //}
02991 
02992                      goto prevvalue;
02994               }                    
02995               else{ //if foundGoodSwap==true
02996                      nPlacedActivities=added_act+1;
02997                      
02998                      if(maxActivitiesPlaced<added_act+1){
02999                             generationHighestStageDateTime=QDateTime::currentDateTime();
03000                             time_t tmp;
03001                             time(&tmp);
03002                             timeToHighestStage=int(tmp-starting_time);
03003                             
03004                             highestStageSolution.copy(gt.rules, c);
03005 
03006                             maxActivitiesPlaced=added_act+1;
03007                             
03008                             if(maxPlacedActivityStream!=NULL){
03009                                    int sec=timeToHighestStage;
03010                                    int hh=sec/3600;
03011                                    sec%=3600;
03012                                    int mm=sec/60;
03013                                    sec%=60;
03014                                    QString s=tr("At time %1 h %2 m %3 s, FET reached %4 activities placed", "h=hours, m=minutes, s=seconds. Please leave spaces between 'time', %1, h, %2, m, %3, s, so they are visible")
03015                                           .arg(hh).arg(mm).arg(sec).arg(maxActivitiesPlaced);
03016                                    //s+="\n";
03017                                    //QString s=QString("At time ")+CustomFETString::number(hh)+QString(" h ")+CustomFETString::number(mm)+QString(" m ")+CustomFETString::number(sec)
03018                                    //     +QString(" s, FET reached ")+CustomFETString::number(maxActivitiesPlaced)+QString(" activities placed\n");
03019                                    
03020                                    (*maxPlacedActivityStream)<<s<<endl;
03021                                    //(*maxPlacedActivityStream).flush();
03022                             }
03023                      }
03024                      
03025 if(threaded){
03026                      mutex.unlock();
03027 }
03028                      emit(activityPlaced(added_act+1));
03029 if(threaded){
03030                      semaphorePlacedActivity.acquire();
03031 }
03032 if(threaded){
03033                      mutex.lock();
03034 }
03035                      if(added_act==gt.rules.nInternalActivities && foundGoodSwap){
03036 if(threaded){
03037                             mutex.unlock();
03038 }
03039                             break;
03040                      }
03041                      
03042                      bool ok=true;
03043                      for(int i=0; i<=added_act; i++){
03044                             if(c.times[permutation[i]]==UNALLOCATED_TIME){
03045                                    cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has time unallocated"<<endl;
03046                                    ok=false;
03047                             }
03048                             if(c.rooms[permutation[i]]==UNALLOCATED_SPACE){
03049                                    cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has room unallocated"<<endl;
03050                                    ok=false;
03051                             }
03052                      }
03053                      assert(ok);
03054               }
03055 
03056 if(threaded){
03057               mutex.unlock();
03058 }
03059        }
03060 
03061        time_t end_time;
03062        time(&end_time);
03063        searchTime=int(end_time-starting_time);
03064        cout<<"Total searching time (seconds): "<<int(end_time-starting_time)<<endl;
03065        
03066        emit(simulationFinished());
03067        
03068        finishedSemaphore.release();
03069 }
03070 
03071 void Generate::moveActivity(int ai, int fromslot, int toslot, int fromroom, int toroom)
03072 {
03073        Activity* act=&gt.rules.internalActivitiesList[ai];
03074 
03075        //cout<<"here: id of act=="<<act->id<<", fromslot=="<<fromslot<<", toslot=="<<toslot<<endl;
03076 
03077        assert(fromslot==c.times[ai]);
03078        assert(fromroom==c.rooms[ai]);
03079        
03080        if(!fixedTimeActivity[ai] && (fromslot==UNALLOCATED_TIME || fromroom==UNALLOCATED_SPACE))
03081               assert(fromslot==UNALLOCATED_TIME && fromroom==UNALLOCATED_SPACE);
03082        if(!fixedTimeActivity[ai] && (toslot==UNALLOCATED_TIME || toroom==UNALLOCATED_SPACE))
03083               assert(toslot==UNALLOCATED_TIME && toroom==UNALLOCATED_SPACE);
03084        
03085        if(fromslot!=UNALLOCATED_TIME){
03086               int d=fromslot%gt.rules.nDaysPerWeek;
03087               int h=fromslot/gt.rules.nDaysPerWeek;
03088               
03090               int rm=c.rooms[ai];
03091               if(rm!=UNSPECIFIED_ROOM && rm!=UNALLOCATED_SPACE)
03092                      for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03093                             assert(dd+h<gt.rules.nHoursPerDay);
03094                             if(roomsTimetable(rm,d,h+dd)==ai)
03095                                    roomsTimetable(rm,d,h+dd)=-1;
03096                             else
03097                                    assert(0);
03098                      }
03100               
03101               if(fromslot!=toslot){
03102                      //timetable of students
03103                      for(int q=0; q<act->iSubgroupsList.count(); q++){
03104                             int sb=act->iSubgroupsList.at(q);  
03105                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03106                                    assert(dd+h<gt.rules.nHoursPerDay);
03107                             
03108                                    assert(subgroupsTimetable(sb,d,h+dd)==ai);
03109                                    subgroupsTimetable(sb,d,h+dd)=-1;
03110                             }
03111                      }      
03112 
03113                      foreach(int sb, mustComputeTimetableSubgroups[ai]){
03114                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03115                                    assert(dd+h<gt.rules.nHoursPerDay);
03116                             
03117                                    assert(newSubgroupsTimetable(sb,d,h+dd)==ai);
03118                                    newSubgroupsTimetable(sb,d,h+dd)=-1;
03119                             }
03120                      }
03121 
03122                      updateSubgroupsNHoursGaps(act, ai, d);
03123 
03124                      //teachers' timetable
03125                      for(int q=0; q<act->iTeachersList.count(); q++){
03126                             int tch=act->iTeachersList.at(q);  
03127                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03128                                    assert(dd+h<gt.rules.nHoursPerDay);
03129                                    
03130                                    assert(teachersTimetable(tch,d,h+dd)==ai);
03131                                    teachersTimetable(tch,d,h+dd)=-1;
03132                             }
03133                      }
03134        
03135                      foreach(int tch, mustComputeTimetableTeachers[ai]){
03136                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03137                                    assert(dd+h<gt.rules.nHoursPerDay);
03138                             
03139                                    assert(newTeachersTimetable(tch,d,h+dd)==ai);
03140                                    newTeachersTimetable(tch,d,h+dd)=-1;
03141                             }
03142                      }
03143 
03144                      updateTeachersNHoursGaps(act, ai, d);
03145               
03146                      //update teachers' list of activities for each day
03148                      foreach(int tch, teachersWithMaxDaysPerWeekForActivities[ai]){
03149                             int tt=teacherActivitiesOfTheDay(tch,d).removeAll(ai);
03150                             assert(tt==1);
03151                      }
03153                      
03154                      //2011-09-30
03155                      if(haveActivitiesOccupyOrSimultaneousConstraints){
03156                             for(int t=fromslot; t<fromslot+act->duration*gt.rules.nDaysPerWeek; t+=gt.rules.nDaysPerWeek){
03157                                    assert(activitiesAtTime[t].contains(ai));
03158                                    activitiesAtTime[t].remove(ai);
03159                             }
03160                      }
03161               }
03162        }
03163        
03164        c.times[ai]=toslot;
03165        c.rooms[ai]=toroom;
03166        c._fitness=-1;
03167        c.changedForMatrixCalculation=true;
03168        
03169        if(toslot!=UNALLOCATED_TIME){
03170               int d=toslot%gt.rules.nDaysPerWeek;
03171               int h=toslot/gt.rules.nDaysPerWeek;
03172               
03174               int rm=c.rooms[ai];
03175               if(rm!=UNSPECIFIED_ROOM && rm!=UNALLOCATED_SPACE)
03176                      for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03177                             assert(dd+h<gt.rules.nHoursPerDay);
03178                             
03179                             assert(rm!=UNALLOCATED_SPACE);
03180                             /*if(roomsTimetable(rm,d,h+dd)>=0){
03181                                    cout<<"room is: "<<qPrintable(gt.rules.internalRoomsList[rm]->name)<<endl;
03182                                    cout<<"day is "<<qPrintable(gt.rules.daysOfTheWeek[d])<<endl;
03183                                    cout<<"hour is "<<qPrintable(gt.rules.hoursOfTheDay[h+dd])<<endl;
03184                                    cout<<"roomsTimetable(rm,d,h+dd) is "<<roomsTimetable(rm,d,h+dd)<<endl;
03185                                    cout<<"and represents room "<<qPrintable(gt.rules.internalRoomsList[roomsTimetable(rm,d,h+dd)]->name)<<endl;
03186                             }*/
03187                             
03188                             assert(roomsTimetable(rm,d,h+dd)==-1);
03189                             roomsTimetable(rm,d,h+dd)=ai;
03190                      }
03192               
03193               if(fromslot!=toslot){
03194                      //compute timetable of subgroups
03195                      for(int q=0; q<act->iSubgroupsList.count(); q++){
03196                             int sb=act->iSubgroupsList.at(q);
03197                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03198                                    assert(dd+h<gt.rules.nHoursPerDay);
03199                             
03200                                    assert(subgroupsTimetable(sb,d,h+dd)==-1);
03201                                    subgroupsTimetable(sb,d,h+dd)=ai;
03202                             }
03203                      }
03204        
03205                      foreach(int sb, mustComputeTimetableSubgroups[ai]){
03206                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03207                                    assert(dd+h<gt.rules.nHoursPerDay);
03208                             
03209                                    assert(newSubgroupsTimetable(sb,d,h+dd)==-1);
03210                                    newSubgroupsTimetable(sb,d,h+dd)=ai;
03211                             }
03212                      }
03213 
03214                      updateSubgroupsNHoursGaps(act, ai, d);
03215 
03216                      //teachers' timetable
03217                      for(int q=0; q<act->iTeachersList.count(); q++){
03218                             int tch=act->iTeachersList.at(q);
03219                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03220                                    assert(dd+h<gt.rules.nHoursPerDay);
03221                             
03222                                    assert(teachersTimetable(tch,d,h+dd)==-1);
03223                                    teachersTimetable(tch,d,h+dd)=ai;
03224                             }
03225                      }
03226        
03227                      foreach(int tch, mustComputeTimetableTeachers[ai]){
03228                             for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){
03229                                    assert(dd+h<gt.rules.nHoursPerDay);
03230                             
03231                                    assert(newTeachersTimetable(tch,d,h+dd)==-1);
03232                                    newTeachersTimetable(tch,d,h+dd)=ai;
03233                             }
03234                      }
03235 
03237                      updateTeachersNHoursGaps(act, ai, d);
03238               
03239               
03240               
03241                      //update teachers' list of activities for each day
03243                      foreach(int tch, teachersWithMaxDaysPerWeekForActivities[ai]){
03244                             assert(teacherActivitiesOfTheDay(tch,d).indexOf(ai)==-1);
03245                             teacherActivitiesOfTheDay(tch,d).append(ai);
03246                      }
03248 
03249                      //2011-09-30
03250                      if(haveActivitiesOccupyOrSimultaneousConstraints){
03251                             for(int t=toslot; t<toslot+act->duration*gt.rules.nDaysPerWeek; t+=gt.rules.nDaysPerWeek){
03252                                    assert(!activitiesAtTime[t].contains(ai));
03253                                    activitiesAtTime[t].insert(ai);
03254                             }
03255                      }
03256               }
03257        }
03258 }
03259 
03260 //faster: (to avoid allocating memory at each call)
03261 #if 1
03262 
03263 static double nMinDaysBrokenL[MAX_LEVEL][MAX_HOURS_PER_WEEK];
03264 static int selectedRoomL[MAX_LEVEL][MAX_HOURS_PER_WEEK];
03265 static int permL[MAX_LEVEL][MAX_HOURS_PER_WEEK];
03266 static QList<int> conflActivitiesL[MAX_LEVEL][MAX_HOURS_PER_WEEK];
03267 //static int conflPermL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; //the permutation in increasing order of number of conflicting activities
03268 static int nConflActivitiesL[MAX_LEVEL][MAX_HOURS_PER_WEEK];
03269 static int roomSlotsL[MAX_LEVEL][MAX_HOURS_PER_WEEK];
03270 
03271 
03272 static int currentLevel;
03273 
03274 inline bool compareFunctionGenerate(int i, int j)
03275 {
03276        if(nConflActivitiesL[currentLevel][i] < nConflActivitiesL[currentLevel][j] ||
03277         (nConflActivitiesL[currentLevel][i] == nConflActivitiesL[currentLevel][j] &&
03278         nMinDaysBrokenL[currentLevel][i] < nMinDaysBrokenL[currentLevel][j]))
03279               return true;
03280        
03281        return false;
03282 }
03283 
03284 
03285 #define nMinDaysBroken                    (nMinDaysBrokenL[level])
03286 #define selectedRoom               (selectedRoomL[level])
03287 #define perm                              (permL[level])
03288 #define conflActivities                   (conflActivitiesL[level])
03289 //#define conflPerm                       (conflPermL[level])
03290 #define nConflActivities           (nConflActivitiesL[level])
03291 #define roomSlots                         (roomSlotsL[level])
03292 
03293 #endif
03294 
03295 void Generate::randomSwap(int ai, int level){
03296        //cout<<"level=="<<level<<endl;
03297        
03298        if(level==0){
03299               conflActivitiesTimeSlot.clear();
03300               timeSlot=-1;
03301 
03302               /*for(int l=0; l<level_limit; l++)
03303                      for(int i=0; i<gt.rules.nHoursPerWeek; i++){
03304                             nMinDaysBrokenL[l][i]=0;
03305                             selectedRoomL[l][i]=-1;
03306                             permL[l][i]=-1;
03307                             conflActivitiesL[l][i].clear();
03308                             conflPermL[l][i]=-1;
03309                             nConflActivitiesL[l][i]=0;
03310                             roomSlotsL[l][i]=-1;
03311                      }*/
03312        }
03313 
03314        if(level>=level_limit){
03315               return;
03316        }
03317        
03318        if(ncallsrandomswap>=limitcallsrandomswap)
03319               return;
03320               
03321        /*for(int i=0; i<gt.rules.nHoursPerWeek; i++){
03322               nMinDaysBroken[i]=0;
03323               selectedRoom[i]=-1;
03324               perm[i]=-1;
03325               conflActivities[i].clear();
03326               conflPerm[i]=-1;
03327               nConflActivities[i]=0;
03328               roomSlots[i]=-1;
03329        }*/
03330               
03331        ncallsrandomswap++;
03332        
03333        Activity* act=&gt.rules.internalActivitiesList[ai];
03334        
03335        bool updateSubgroups=(mustComputeTimetableSubgroups[ai].count()>0);
03336        bool updateTeachers=(mustComputeTimetableTeachers[ai].count()>0);
03337        
03338 #if 0
03339        double nMinDaysBroken[MAX_HOURS_PER_WEEK]; //to count for broken min days between activities constraints
03340        
03341        int selectedRoom[MAX_HOURS_PER_WEEK];
03342 #endif
03343               
03344        //cout<<"ai=="<<ai<<", corresponding to id=="<<gt.rules.internalActivitiesList[ai].id<<", level=="<<level<<endl;
03345 
03346        //generate random permutation in linear time like in CLR (Cormen, Leiserson and Rivest - Introduction to algorithms).
03347        //this is used to scan times in random order
03348 #if 0
03349        int perm[MAX_HOURS_PER_WEEK];
03350 #endif
03351 
03352        int activity_count_impossible_tries=1;
03353 
03354 again_if_impossible_activity:
03355 
03356        for(int i=0; i<gt.rules.nHoursPerWeek; i++)
03357               perm[i]=i;
03358        for(int i=0; i<gt.rules.nHoursPerWeek; i++){
03359               int t=perm[i];
03360               int r=randomKnuth(gt.rules.nHoursPerWeek-i);
03361               perm[i]=perm[i+r];
03362               perm[i+r]=t;
03363        }
03364        
03365        /*int checkPerm[MAX_HOURS_PER_WEEK];
03366        for(int i=0; i<gt.rules.nHoursPerWeek; i++)
03367               checkPerm[i]=false;
03368        for(int i=0; i<gt.rules.nHoursPerWeek; i++)
03369               checkPerm[perm[i]]=true;
03370        for(int i=0; i<gt.rules.nHoursPerWeek; i++)
03371               assert(checkPerm[i]==true);*/
03372        
03373        /*
03374        cout<<"Perm: ";
03375        for(int i=0; i<gt.rules.nHoursPerWeek; i++)
03376               cout<<", perm["<<i<<"]="<<perm[i];
03377        cout<<endl;
03378        */
03379        
03380        //record the conflicting activities for each timeslot
03381 #if 0
03382        QList<int> conflActivities[MAX_HOURS_PER_WEEK];
03383        int conflPerm[MAX_HOURS_PER_WEEK]; //the permutation in increasing order of number of conflicting activities
03384        int nConflActivities[MAX_HOURS_PER_WEEK];
03385        
03386        int roomSlots[MAX_HOURS_PER_WEEK];
03387 #endif
03388 
03389        for(int n=0; n<gt.rules.nHoursPerWeek; n++){
03390               int newtime=perm[n];
03391               
03392               if(c.times[ai]!=UNALLOCATED_TIME){
03393                      if(c.times[ai]!=newtime){
03394                             nConflActivities[newtime]=MAX_ACTIVITIES;
03395                             continue;
03396                      }
03397               }
03398 
03399               nConflActivities[newtime]=0;
03400               conflActivities[newtime].clear();
03401 
03402               int d=newtime%gt.rules.nDaysPerWeek;
03403               int h=newtime/gt.rules.nDaysPerWeek;
03404               
03405               /*if(updateSubgroups || updateTeachers){
03406                      addAiToNewTimetable(ai, act, d, h);
03407                      if(updateTeachers)
03408                             updateTeachersNHoursGaps(act, ai, d);
03409                      if(updateSubgroups)
03410                             updateSubgroupsNHoursGaps(act, ai, d);
03411               }*/
03412               
03413               nMinDaysBroken[newtime]=0.0;
03414 
03415               bool okbasictime;
03416               bool okmindays;
03417               bool okmaxdays;
03418               bool oksamestartingtime;
03419               bool oksamestartinghour;
03420               bool oksamestartingday;
03421               bool oknotoverlapping;
03422               bool oktwoactivitiesconsecutive;
03423               bool oktwoactivitiesgrouped;
03424               bool okthreeactivitiesgrouped;
03425               bool oktwoactivitiesordered;
03426               bool okactivityendsstudentsday;
03427               bool okstudentsearlymaxbeginningsatsecondhour;
03428               bool okstudentsmaxgapsperweek;
03429               bool okstudentsmaxgapsperday;
03430               bool okstudentsmaxhoursdaily;
03431               bool okstudentsmaxhourscontinuously;
03432               bool okstudentsminhoursdaily;
03433               bool okstudentsintervalmaxdaysperweek;
03434               bool okteachermaxdaysperweek;
03435               bool okteachersintervalmaxdaysperweek;
03436               bool okteachersmaxgapsperweek;
03437               bool okteachersmaxgapsperday;
03438               bool okteachersmaxhoursdaily;
03439               bool okteachersmaxhourscontinuously;
03440               bool okteachersminhoursdaily;
03441               bool okteachersmindaysperweek;
03442               bool okmingapsbetweenactivities;
03443 
03444               bool okteachersactivitytagmaxhourscontinuously;
03445               bool okstudentsactivitytagmaxhourscontinuously;
03446 
03447               bool okteachersactivitytagmaxhoursdaily;
03448               bool okstudentsactivitytagmaxhoursdaily;
03449 
03450               //2011-09-25
03451               bool okactivitiesoccupymaxtimeslotsfromselection;
03452               
03453               //2011-09-30
03454               bool okactivitiesmaxsimultaneousinselectedtimeslots;
03455               
03456               if(c.times[ai]!=UNALLOCATED_TIME)
03457                      goto skip_here_if_already_allocated_in_time;
03458 
03460 
03461               //not too late
03462               //unneeded code, because notAllowedTimesPercentages(ai,newtime)==100 now
03463               //you can comment this code, but you cannot put an assert failed, because the test is done in next section (see 13 lines below).
03464               if(h+act->duration>gt.rules.nHoursPerDay){
03465                      //if(updateSubgroups || updateTeachers)
03466                      //     removeAiFromNewTimetable(ai, act, d, h);
03467                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03468 
03469                      nConflActivities[newtime]=MAX_ACTIVITIES;
03470                      continue;
03471               }
03472               
03474 
03475               //allowed (tch&st not available, break, act(s) preferred time(s))
03476               if(!skipRandom(notAllowedTimesPercentages(ai,newtime))){
03477                      //if(updateSubgroups || updateTeachers)
03478                      //     removeAiFromNewTimetable(ai, act, d, h);
03479                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03480 
03481                      nConflActivities[newtime]=MAX_ACTIVITIES;
03482                      continue;
03483               }
03484               
03486 
03487               //care about basic time constraints
03488               okbasictime=true;
03489 
03491               //added in 5.0.0-preview30
03492               //same teacher?
03493               for(int dur=0; dur<act->duration; dur++){
03494                      assert(h+dur<gt.rules.nHoursPerDay);
03495                      //for(int q=0; q<act->iTeachersList.count(); q++){
03496                      //     int tch=act->iTeachersList.at(q);
03497                      foreach(int tch, act->iTeachersList){
03498                             if(teachersTimetable(tch,d,h+dur)>=0){
03499                                    int ai2=teachersTimetable(tch,d,h+dur);
03500                                    assert(ai2!=ai);
03501                             
03502                                    assert(activitiesConflictingPercentage(ai,ai2)==100);
03503                                    if(!skipRandom(activitiesConflictingPercentage(ai,ai2))){
03504                                           if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03505                                                  okbasictime=false;
03506                                                  goto impossiblebasictime;
03507                                           }
03508 
03509                                           if(!conflActivities[newtime].contains(ai2)){
03510                                           //if(conflActivities[newtime].indexOf(ai2)==-1){
03511                                                  //conflActivities[newtime].append(ai2);
03512                                                  
03513                                                  conflActivities[newtime].append(ai2);
03514                                                  nConflActivities[newtime]++;
03515                                                  assert(nConflActivities[newtime]==conflActivities[newtime].count());
03516                                                  //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03517                                           }
03518                                    }
03519                             }
03520                      }
03521               }
03522               //same subgroup?
03523               for(int dur=0; dur<act->duration; dur++){
03524                      assert(h+dur<gt.rules.nHoursPerDay);
03525                      //for(int q=0; q<act->iSubgroupsList.count(); q++){
03526                      //     int sbg=act->iSubgroupsList.at(q);
03527                      foreach(int sbg, act->iSubgroupsList){
03528                             if(subgroupsTimetable(sbg,d,h+dur)>=0){
03529                                    int ai2=subgroupsTimetable(sbg,d,h+dur);
03530                                    assert(ai2!=ai);
03531                      
03532                                    assert(activitiesConflictingPercentage(ai,ai2)==100);
03533                                    if(!skipRandom(activitiesConflictingPercentage(ai,ai2))){
03534                                           if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03535                                                  okbasictime=false;
03536                                                  goto impossiblebasictime;
03537                                           }
03538 
03539                                           if(!conflActivities[newtime].contains(ai2)){
03540                                           //if(conflActivities[newtime].indexOf(ai2)==-1){
03541                                                  //conflActivities[newtime].append(ai2);
03542 
03543                                                  conflActivities[newtime].append(ai2);
03544                                                  nConflActivities[newtime]++;
03545                                                  assert(nConflActivities[newtime]==conflActivities[newtime].count());
03546                                                  //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03547                                           }
03548                                    }
03549                             }
03550                      }
03551               }
03553                             
03554 impossiblebasictime:
03555               if(!okbasictime){
03556                      //if(updateSubgroups || updateTeachers)
03557                      //     removeAiFromNewTimetable(ai, act, d, h);
03558                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03559 
03560                      nConflActivities[newtime]=MAX_ACTIVITIES;
03561                      continue;
03562               }
03563                             
03564               /*foreach(int ai2, conflActivities[newtime])
03565                      assert(!swappedActivities[ai2]);*/
03566               
03568 
03569               //care about min days
03570               okmindays=true;
03571               
03572               for(int i=0; i<minDaysListOfActivities[ai].count(); i++){
03573                      int ai2=minDaysListOfActivities[ai].at(i);
03574                      int md=minDaysListOfMinDays[ai].at(i);
03575                      int ai2time=c.times[ai2];
03576                      if(ai2time!=UNALLOCATED_TIME){
03577                             int d2=ai2time%gt.rules.nDaysPerWeek;
03578                             int h2=ai2time/gt.rules.nDaysPerWeek;
03579                             if(md>abs(d-d2)){
03580                                    bool okrand=skipRandom(minDaysListOfWeightPercentages[ai].at(i));
03581                                    //if(fixedTimeActivity[ai] && minDaysListOfWeightPercentages[ai].at(i)<100.0)
03582                                    //     okrand=true;
03583                             
03584                                    //broken min days - there is a minDaysBrokenAllowancePercentage% chance to place them adjacent
03585                                    
03586                                    if(minDaysListOfConsecutiveIfSameDay[ai].at(i)==true){ //must place them adjacent if on same day
03587                                           if(okrand && 
03588                                            ( (d==d2 && (h+act->duration==h2 || h2+gt.rules.internalActivitiesList[ai2].duration==h)) || d!=d2 ) ){
03589                                                  //nMinDaysBroken[newtime]++;
03590                                                  nMinDaysBroken[newtime]+=minDaysListOfWeightPercentages[ai].at(i)/100.0;
03591                                           }
03592                                           else{
03593                                                  if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03594                                                         okmindays=false;
03595                                                         goto impossiblemindays;
03596                                                  }
03597                                                  
03598                                                  //if(conflActivities[newtime].indexOf(ai2)==-1){
03599                                                  if(!conflActivities[newtime].contains(ai2)){
03600                                                         //conflActivities[newtime].append(ai2);
03601 
03602                                                         conflActivities[newtime].append(ai2);
03603                                                         nConflActivities[newtime]++;
03604                                                         assert(nConflActivities[newtime]==conflActivities[newtime].count());
03605                                                         //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03606                                                  }
03607                                           }
03608                                    }                                  
03609                                    else{ //can place them anywhere
03610                                           if(okrand){
03611                                                  //nMinDaysBroken[newtime]++;
03612                                                  nMinDaysBroken[newtime]+=minDaysListOfWeightPercentages[ai].at(i)/100.0;
03613                                           }
03614                                           else{
03615                                                  if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03616                                                         okmindays=false;
03617                                                         goto impossiblemindays;
03618                                                  }
03619                                                  
03620                                                  //if(conflActivities[newtime].indexOf(ai2)==-1){
03621                                                  if(!conflActivities[newtime].contains(ai2)){
03622                                                         //conflActivities[newtime].append(ai2);
03623 
03624                                                         conflActivities[newtime].append(ai2);
03625                                                         nConflActivities[newtime]++;
03626                                                         assert(nConflActivities[newtime]==conflActivities[newtime].count());
03627                                                         //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03628                                                  }
03629                                           }
03630                                    }                                  
03631                             }
03632                      }
03633               }
03634 impossiblemindays:
03635               if(!okmindays){
03636                      //if(updateSubgroups || updateTeachers)
03637                      //     removeAiFromNewTimetable(ai, act, d, h);
03638                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03639 
03640                      nConflActivities[newtime]=MAX_ACTIVITIES;
03641                      continue;
03642               }
03643 
03644               /*foreach(int ai2, conflActivities[newtime])
03645                      assert(!swappedActivities[ai2]);*/
03646               
03648 
03649               //care about max days between activities
03650               okmaxdays=true;
03651               
03652               for(int i=0; i<maxDaysListOfActivities[ai].count(); i++){
03653                      int ai2=maxDaysListOfActivities[ai].at(i);
03654                      int md=maxDaysListOfMaxDays[ai].at(i);
03655                      int ai2time=c.times[ai2];
03656                      if(ai2time!=UNALLOCATED_TIME){
03657                             int d2=ai2time%gt.rules.nDaysPerWeek;
03658                             //int h2=ai2time/gt.rules.nDaysPerWeek;
03659                             if(md<abs(d-d2)){
03660                                    bool okrand=skipRandom(maxDaysListOfWeightPercentages[ai].at(i));
03661                                    if(!okrand){
03662                                           if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03663                                                  okmaxdays=false;
03664                                                  goto impossiblemaxdays;
03665                                           }
03666                                           
03667                                           if(!conflActivities[newtime].contains(ai2)){
03668                                                  conflActivities[newtime].append(ai2);
03669 
03670                                                  nConflActivities[newtime]++;
03671                                                  assert(nConflActivities[newtime]==conflActivities[newtime].count());
03672                                           }
03673                                    }
03674                             }
03675                      }
03676               }
03677 impossiblemaxdays:
03678               if(!okmaxdays){
03679                      nConflActivities[newtime]=MAX_ACTIVITIES;
03680                      continue;
03681               }
03682 
03683               /*foreach(int ai2, conflActivities[newtime])
03684                      assert(!swappedActivities[ai2]);*/
03685               
03687               //care about min gaps between activities
03688               okmingapsbetweenactivities=true;
03689               
03690               for(int i=0; i<minGapsBetweenActivitiesListOfActivities[ai].count(); i++){
03691                      int ai2=minGapsBetweenActivitiesListOfActivities[ai].at(i);
03692                      int mg=minGapsBetweenActivitiesListOfMinGaps[ai].at(i);
03693                      int ai2time=c.times[ai2];
03694                      if(ai2time!=UNALLOCATED_TIME){
03695                             int d2=ai2time%gt.rules.nDaysPerWeek;
03696                             int h2=ai2time/gt.rules.nDaysPerWeek;
03697                             int duration2=gt.rules.internalActivitiesList[ai2].duration;
03698                             bool oktmp=true;
03699                             if(d==d2){
03700                                    if(h2>=h){
03701                                           if(h+act->duration+mg > h2){
03702                                                  oktmp=false;
03703                                           }
03704                                    }
03705                                    else{
03706                                           if(h2+duration2+mg > h){
03707                                                  oktmp=false;
03708                                           }
03709                                    }
03710                             }
03711                             
03712                             if(!oktmp){
03713                                    bool okrand=skipRandom(minGapsBetweenActivitiesListOfWeightPercentages[ai].at(i));
03714                                    
03715                                    //if(fixedTimeActivity[ai] && minGapsBetweenActivitiesListOfWeightPercentages[ai].at(i)<100.0)
03716                                    //     okrand=true;
03717                                    
03718                                    if(!okrand){
03719                                           if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03720                                                  okmingapsbetweenactivities=false;
03721                                                  goto impossiblemingapsbetweenactivities;
03722                                           }
03723                                                  
03724                                           if(!conflActivities[newtime].contains(ai2)){
03725                                                  conflActivities[newtime].append(ai2);
03726                                                  nConflActivities[newtime]++;
03727                                                  assert(nConflActivities[newtime]==conflActivities[newtime].count());
03728                                           }
03729                                    }                                  
03730                             }
03731                      }
03732               }
03733 impossiblemingapsbetweenactivities:
03734               if(!okmingapsbetweenactivities){
03735                      //if(updateSubgroups || updateTeachers)
03736                      //     removeAiFromNewTimetable(ai, act, d, h);
03737                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03738 
03739                      nConflActivities[newtime]=MAX_ACTIVITIES;
03740                      continue;
03741               }
03742 
03743               /*foreach(int ai2, conflActivities[newtime])
03744                      assert(!swappedActivities[ai2]);*/
03745               
03747 
03748               //allowed from same starting time
03749               oksamestartingtime=true;
03750               
03751               for(int i=0; i<activitiesSameStartingTimeActivities[ai].count(); i++){
03752                      int ai2=activitiesSameStartingTimeActivities[ai].at(i);
03753                      double perc=activitiesSameStartingTimePercentages[ai].at(i);
03754                      if(c.times[ai2]!=UNALLOCATED_TIME){
03755                             bool sR=skipRandom(perc);
03756                             
03757                             //if(fixedTimeActivity[ai] && perc<100.0)
03758                             //     sR=true;
03759                      
03760                             if(newtime!=c.times[ai2] && !sR){
03761                                    assert(ai2!=ai);
03762                                    
03763                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03764                                           oksamestartingtime=false;
03765                                           goto impossiblesamestartingtime;
03766                                    }
03767                                    
03768                                    if(!conflActivities[newtime].contains(ai2)){
03769                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
03770                                           //conflActivities[newtime].append(ai2);
03771 
03772                                           conflActivities[newtime].append(ai2);
03773                                           nConflActivities[newtime]++;
03774                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
03775                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03776                                    }
03777                             }
03778                      }
03779               }
03780 impossiblesamestartingtime:
03781               if(!oksamestartingtime){
03782                      //if(updateSubgroups || updateTeachers)
03783                      //     removeAiFromNewTimetable(ai, act, d, h);
03784                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03785 
03786                      nConflActivities[newtime]=MAX_ACTIVITIES;
03787                      continue;
03788               }
03789               
03790               /*foreach(int ai2, conflActivities[newtime])
03791                      assert(!swappedActivities[ai2]);*/
03792               
03794 
03795               //allowed from same starting hour
03796               oksamestartinghour=true;
03797               
03798               for(int i=0; i<activitiesSameStartingHourActivities[ai].count(); i++){
03799                      int ai2=activitiesSameStartingHourActivities[ai].at(i);
03800                      double perc=activitiesSameStartingHourPercentages[ai].at(i);
03801                      if(c.times[ai2]!=UNALLOCATED_TIME){
03802                             bool sR=skipRandom(perc);
03803                             
03804                             //if(fixedTimeActivity[ai] && perc<100.0)
03805                             //     sR=true;
03806                      
03807                             if((newtime/gt.rules.nDaysPerWeek)!=(c.times[ai2]/gt.rules.nDaysPerWeek) && !sR){
03808                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03809                                           oksamestartinghour=false;
03810                                           goto impossiblesamestartinghour;
03811                                    }
03812                             
03813                                    if(!conflActivities[newtime].contains(ai2)){
03814                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
03815 
03816                                           conflActivities[newtime].append(ai2);
03817                                           nConflActivities[newtime]++;
03818                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
03819                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03820                                    }
03821                             }
03822                      }
03823               }
03824 impossiblesamestartinghour:
03825               if(!oksamestartinghour){
03826                      //if(updateSubgroups || updateTeachers)
03827                      //     removeAiFromNewTimetable(ai, act, d, h);
03828                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03829 
03830                      nConflActivities[newtime]=MAX_ACTIVITIES;
03831                      continue;
03832               }
03833               
03834               /*foreach(int ai2, conflActivities[newtime])
03835                      assert(!swappedActivities[ai2]);*/
03836               
03838 
03839               //allowed from same starting day
03840               oksamestartingday=true;
03841               
03842               for(int i=0; i<activitiesSameStartingDayActivities[ai].count(); i++){
03843                      int ai2=activitiesSameStartingDayActivities[ai].at(i);
03844                      double perc=activitiesSameStartingDayPercentages[ai].at(i);
03845                      if(c.times[ai2]!=UNALLOCATED_TIME){
03846                             bool sR=skipRandom(perc);
03847                             
03848                             //if(fixedTimeActivity[ai] && perc<100.0)
03849                             //     sR=true;
03850                      
03851                             if((newtime%gt.rules.nDaysPerWeek)!=(c.times[ai2]%gt.rules.nDaysPerWeek) && !sR){
03852                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03853                                           oksamestartingday=false;
03854                                           goto impossiblesamestartingday;
03855                                    }
03856                             
03857                                    if(!conflActivities[newtime].contains(ai2)){
03858                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
03859 
03860                                           conflActivities[newtime].append(ai2);
03861                                           nConflActivities[newtime]++;
03862                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
03863                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03864                                    }
03865                             }
03866                      }
03867               }
03868 impossiblesamestartingday:
03869               if(!oksamestartingday){
03870                      //if(updateSubgroups || updateTeachers)
03871                      //     removeAiFromNewTimetable(ai, act, d, h);
03872                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03873 
03874                      nConflActivities[newtime]=MAX_ACTIVITIES;
03875                      continue;
03876               }
03877               
03878               /*foreach(int ai2, conflActivities[newtime])
03879                      assert(!swappedActivities[ai2]);*/
03880               
03882 
03883               //allowed from not overlapping
03884               oknotoverlapping=true;
03885               
03886               for(int i=0; i<activitiesNotOverlappingActivities[ai].count(); i++){
03887                      int ai2=activitiesNotOverlappingActivities[ai].at(i);
03888                      double perc=activitiesNotOverlappingPercentages[ai].at(i);
03889                      if(c.times[ai2]!=UNALLOCATED_TIME){
03890                             int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
03891                             //int h2=c.times[ai2]/gt.rules.nDaysPerWeek;
03892                             if(d==d2){
03893                                    int st=newtime;
03894                                    int en=st+gt.rules.nDaysPerWeek*act->duration;
03895                                    int st2=c.times[ai2];
03896                                    int en2=st2+gt.rules.nDaysPerWeek*gt.rules.internalActivitiesList[ai2].duration;
03897                                    
03898                                    bool sR=skipRandom(perc);
03899                                    //if(fixedTimeActivity[ai] && perc<100.0)
03900                                    //     sR=true;
03901                                    
03902                                    if(!(en<=st2 || en2<=st) && !sR){
03903                                           assert(ai2!=ai);
03904                                           
03905                                           if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03906                                                  oknotoverlapping=false;
03907                                                  goto impossiblenotoverlapping;
03908                                           }
03909                                           
03910                                           if(!conflActivities[newtime].contains(ai2)){
03911                                           //if(conflActivities[newtime].indexOf(ai2)==-1){
03912                                                  //conflActivities[newtime].append(ai2);
03913 
03914                                                  conflActivities[newtime].append(ai2);
03915                                                  nConflActivities[newtime]++;
03916                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
03917                                                  //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03918                                           }
03919                                    }
03920                             }
03921                      }
03922               }
03923 impossiblenotoverlapping:
03924               if(!oknotoverlapping){
03925                      //if(updateSubgroups || updateTeachers)
03926                      //     removeAiFromNewTimetable(ai, act, d, h);
03927                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
03928 
03929                      nConflActivities[newtime]=MAX_ACTIVITIES;
03930                      continue;
03931               }
03932               
03933               /*foreach(int ai2, conflActivities[newtime])
03934                      assert(!swappedActivities[ai2]);*/
03935               
03937 
03938               //allowed from 2 activities consecutive
03939               oktwoactivitiesconsecutive=true;
03940               
03941               for(int i=0; i<constrTwoActivitiesConsecutiveActivities[ai].count(); i++){
03942                      //direct
03943                      int ai2=constrTwoActivitiesConsecutiveActivities[ai].at(i);
03944                      double perc=constrTwoActivitiesConsecutivePercentages[ai].at(i);
03945                      if(c.times[ai2]!=UNALLOCATED_TIME){
03946                             int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
03947                             int h2=c.times[ai2]/gt.rules.nDaysPerWeek;                            
03948                             bool ok=true;
03949                             
03950                             if(d2!=d)
03951                                    ok=false;
03952                             else if(h+act->duration > h2)
03953                                    ok=false;
03954                             else if(d==d2){
03955                                    int kk;
03956                                    for(kk=h+act->duration; kk<gt.rules.nHoursPerDay; kk++)
03957                                           if(!breakDayHour(d,kk))
03958                                                  break;
03959                                    assert(kk<=h2);
03960                                    if(kk!=h2)
03961                                           ok=false;
03962                             }
03963                             
03964                             bool sR=skipRandom(perc);
03965                             //if(fixedTimeActivity[ai] && perc<100.0)
03966                             //     sR=true;
03967                             
03968                             if(!ok && !sR){
03969                                    assert(ai2!=ai);
03970                                    
03971                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
03972                                           oktwoactivitiesconsecutive=false;
03973                                           goto impossibletwoactivitiesconsecutive;
03974                                    }
03975                                    
03976                                    if(!conflActivities[newtime].contains(ai2)){
03977                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
03978 
03979                                           conflActivities[newtime].append(ai2);
03980                                           //conflActivities[newtime].append(ai2);
03981                                           nConflActivities[newtime]++;
03982                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
03983                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
03984                                    }
03985                             }
03986                      }
03987               }
03988 
03989               for(int i=0; i<inverseConstrTwoActivitiesConsecutiveActivities[ai].count(); i++){
03990                      //inverse
03991                      int ai2=inverseConstrTwoActivitiesConsecutiveActivities[ai].at(i);
03992                      double perc=inverseConstrTwoActivitiesConsecutivePercentages[ai].at(i);
03993                      if(c.times[ai2]!=UNALLOCATED_TIME){
03994                             int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
03995                             int h2=c.times[ai2]/gt.rules.nDaysPerWeek;                            
03996                             bool ok=true;
03997                             
03998                             if(d2!=d)
03999                                    ok=false;
04000                             else if(h2+gt.rules.internalActivitiesList[ai2].duration > h)
04001                                    ok=false;
04002                             else if(d==d2){
04003                                    int kk;
04004                                    for(kk=h2+gt.rules.internalActivitiesList[ai2].duration; kk<gt.rules.nHoursPerDay; kk++)
04005                                           if(!breakDayHour(d,kk))
04006                                                  break;
04007                                    assert(kk<=h);
04008                                    if(kk!=h)
04009                                           ok=false;
04010                             }
04011                             
04012                             bool sR=skipRandom(perc);
04013                             //if(fixedTimeActivity[ai] && perc<100.0)
04014                             //     sR=true;
04015                      
04016                             if(!ok && !sR){
04017                                    assert(ai2!=ai);
04018                                    
04019                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
04020                                           oktwoactivitiesconsecutive=false;
04021                                           goto impossibletwoactivitiesconsecutive;
04022                                    }
04023                                    
04024                                    if(!conflActivities[newtime].contains(ai2)){
04025                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
04026                                           conflActivities[newtime].append(ai2);
04027                                           //conflActivities[newtime].append(ai2);
04028                                           nConflActivities[newtime]++;
04029                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04030                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04031                                    }
04032                             }
04033                      }
04034               }
04035               
04036 impossibletwoactivitiesconsecutive:
04037               if(!oktwoactivitiesconsecutive){
04038                      //if(updateSubgroups || updateTeachers)
04039                      //     removeAiFromNewTimetable(ai, act, d, h);
04040                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
04041 
04042                      nConflActivities[newtime]=MAX_ACTIVITIES;
04043                      continue;
04044               }
04045               
04046               /*foreach(int ai2, conflActivities[newtime])
04047                      assert(!swappedActivities[ai2]);*/
04048               
04050 
04051               //allowed from 2 activities grouped
04052               oktwoactivitiesgrouped=true;
04053               
04054               for(int i=0; i<constrTwoActivitiesGroupedActivities[ai].count(); i++){
04055                      //direct
04056                      int ai2=constrTwoActivitiesGroupedActivities[ai].at(i);
04057                      double perc=constrTwoActivitiesGroupedPercentages[ai].at(i);
04058                      if(c.times[ai2]!=UNALLOCATED_TIME){
04059                             int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
04060                             int h2=c.times[ai2]/gt.rules.nDaysPerWeek;                            
04061                             bool ok=true;
04062                             
04063                             if(d2!=d){
04064                                    ok=false;
04065                             }
04066                             else if(d==d2 && h2+gt.rules.internalActivitiesList[ai2].duration <= h){
04067                                    int kk;
04068                                    for(kk=h2+gt.rules.internalActivitiesList[ai2].duration; kk<gt.rules.nHoursPerDay; kk++)
04069                                           if(!breakDayHour(d2,kk))
04070                                                  break;
04071                                    assert(kk<=h);
04072                                    if(kk!=h)
04073                                           ok=false;
04074                             }
04075                             else if(d==d2 && h+act->duration <= h2){
04076                                    int kk;
04077                                    for(kk=h+act->duration; kk<gt.rules.nHoursPerDay; kk++)
04078                                           if(!breakDayHour(d,kk))
04079                                                  break;
04080                                    assert(kk<=h2);
04081                                    if(kk!=h2)
04082                                           ok=false;
04083                             }
04084                             else
04085                                    ok=false;
04086                                    
04087                             bool sR=skipRandom(perc);
04088                             //if(fixedTimeActivity[ai] && perc<100.0)
04089                             //     sR=true;
04090                             
04091                             if(!ok && !sR){
04092                                    assert(ai2!=ai);
04093                                    
04094                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
04095                                           oktwoactivitiesgrouped=false;
04096                                           goto impossibletwoactivitiesgrouped;
04097                                    }
04098                                    
04099                                    if(!conflActivities[newtime].contains(ai2)){
04100                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
04101 
04102                                           conflActivities[newtime].append(ai2);
04103                                           //conflActivities[newtime].append(ai2);
04104                                           nConflActivities[newtime]++;
04105                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04106                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04107                                    }
04108                             }
04109                      }
04110               }
04111 
04112 impossibletwoactivitiesgrouped:
04113               if(!oktwoactivitiesgrouped){
04114                      //if(updateSubgroups || updateTeachers)
04115                      //     removeAiFromNewTimetable(ai, act, d, h);
04116                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
04117 
04118                      nConflActivities[newtime]=MAX_ACTIVITIES;
04119                      continue;
04120               }
04121               
04122               /*foreach(int ai2, conflActivities[newtime])
04123                      assert(!swappedActivities[ai2]);*/
04124               
04126 
04127               //allowed from 3 activities grouped
04128               okthreeactivitiesgrouped=true;
04129               
04130               for(int i=0; i<constrThreeActivitiesGroupedActivities[ai].count(); i++){
04131                      int ai2=constrThreeActivitiesGroupedActivities[ai].at(i).first;
04132                      int ai3=constrThreeActivitiesGroupedActivities[ai].at(i).second;
04133                      double perc=constrThreeActivitiesGroupedPercentages[ai].at(i);
04134 
04135                      bool sR=skipRandom(perc);
04136                      //if(fixedTimeActivity[ai] && perc<100.0)
04137                      //     sR=true;
04138                      
04139                      int aip1=-1, aip2=-1; //ai placed
04140                      int ainp1=-1, ainp2=-1; //ai not placed
04141                      if(c.times[ai2]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai2))
04142                             ainp1=ai2;
04143                      else
04144                             aip1=ai2;
04145                      if(c.times[ai3]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai3)){
04146                             if(ainp1==-1)
04147                                    ainp1=ai3;
04148                             else
04149                                    ainp2=ai3;
04150                      }
04151                      else{
04152                             if(aip1==-1)
04153                                    aip1=ai3;
04154                             else
04155                                    aip2=ai3;
04156                      }
04157                      
04158                      int cnt=0;
04159                      if(ainp1>=0)
04160                             cnt++;
04161                      if(ainp2>=0)
04162                             cnt++;
04163                      if(aip1>=0)
04164                             cnt++;
04165                      if(aip2>=0)
04166                             cnt++;
04167                      assert(cnt==2);
04168                      
04169                      bool ok;
04170                      
04171                      if(aip1==-1){
04172                             //ok - both not placed
04173                             ok=true;
04174                      }
04175                      else if(aip2==-1){
04176                             //only one placed, one not placed
04177                             int dp1=c.times[aip1]%gt.rules.nDaysPerWeek;
04178                             int hp1=c.times[aip1]/gt.rules.nDaysPerWeek;
04179                             int durp1=gt.rules.internalActivitiesList[aip1].duration;
04180                             
04181                             int hoursBetweenThem=-1;
04182                             
04183                             if(dp1!=d)
04184                                    hoursBetweenThem=-1;
04185                             else if(dp1==d && h >= hp1+durp1){
04186                                    hoursBetweenThem=0;
04187                                    for(int kk=hp1+durp1; kk<h; kk++)
04188                                           if(!breakDayHour(d,kk)){
04189                                                  //check that the working hours are not separated by a break
04190                                                  //assertion that durp1>0, so the kk-1 >= 0
04191                                                  if(breakDayHour(d,kk-1) && hoursBetweenThem>0){
04192                                                         hoursBetweenThem=-1;
04193                                                         break;
04194                                                  }
04195 
04196                                                  hoursBetweenThem++;
04197                                           }
04198                             }
04199                             else if(dp1==d && hp1 >= h+act->duration){
04200                                    hoursBetweenThem=0;
04201                                    for(int kk=h+act->duration; kk<hp1; kk++)
04202                                           if(!breakDayHour(d,kk)){
04203                                                  //check that the working hours are not separated by a break
04204                                                  //assertion that act->duration>0, so the kk-1 >= 0
04205                                                  if(breakDayHour(d,kk-1) && hoursBetweenThem>0){
04206                                                         hoursBetweenThem=-1;
04207                                                         break;
04208                                                  }
04209 
04210                                                  hoursBetweenThem++;
04211                                           }
04212                             }
04213                             else
04214                                    hoursBetweenThem=-1;
04215                                    
04216                             assert(ainp1>=0);
04217                             if(hoursBetweenThem==0 || hoursBetweenThem==gt.rules.internalActivitiesList[ainp1].duration)
04218                                    //OK
04219                                    ok=true;
04220                             else
04221                                    //not OK
04222                                    ok=false;
04223                      }
04224                      else{
04225                             assert(aip1>=0 && aip2>=0);
04226                             //both placed
04227                             int dp1=c.times[aip1]%gt.rules.nDaysPerWeek;
04228                             int hp1=c.times[aip1]/gt.rules.nDaysPerWeek;
04229                             //int durp1=gt.rules.internalActivitiesList[aip1].duration;
04230                             
04231                             int dp2=c.times[aip2]%gt.rules.nDaysPerWeek;
04232                             int hp2=c.times[aip2]/gt.rules.nDaysPerWeek;
04233                             //int durp2=gt.rules.internalActivitiesList[aip2].duration;
04234                             
04235                             if(dp1==dp2 && dp1==d){
04236                                    int ao1=-1, ao2=-1, ao3=-1; //order them, 1 then 2 then 3
04237                                    if(h>=hp1 && h>=hp2 && hp2>=hp1){
04238                                           ao1=aip1;
04239                                           ao2=aip2;
04240                                           ao3=ai;
04241                                    }
04242                                    else if(h>=hp1 && h>=hp2 && hp1>=hp2){
04243                                           ao1=aip2;
04244                                           ao2=aip1;
04245                                           ao3=ai;
04246                                    }
04247                                    else if(hp1>=h && hp1>=hp2 && h>=hp2){
04248                                           ao1=aip2;
04249                                           ao2=ai;
04250                                           ao3=aip1;
04251                                    }
04252                                    else if(hp1>=h && hp1>=hp2 && hp2>=h){
04253                                           ao1=ai;
04254                                           ao2=aip2;
04255                                           ao3=aip1;
04256                                    }
04257                                    else if(hp2>=h && hp2>=hp1 && h>=hp1){
04258                                           ao1=aip1;
04259                                           ao2=ai;
04260                                           ao3=aip2;
04261                                    }
04262                                    else if(hp2>=h && hp2>=hp1 && hp1>=h){
04263                                           ao1=ai;
04264                                           ao2=aip1;
04265                                           ao3=aip2;
04266                                    }
04267                                    else
04268                                           assert(0);
04269 
04270                                    int do1;
04271                                    int ho1;
04272                                    int duro1;
04273 
04274                                    int do2;
04275                                    int ho2;
04276                                    int duro2;
04277 
04278                                    int do3;
04279                                    int ho3;
04280                                    //int duro3;
04281                                    
04282                                    if(ao1==ai){
04283                                           do1=d;
04284                                           ho1=h;
04285                                           duro1=act->duration;
04286                                    }
04287                                    else{
04288                                           do1=c.times[ao1]%gt.rules.nDaysPerWeek;
04289                                           ho1=c.times[ao1]/gt.rules.nDaysPerWeek;
04290                                           duro1=gt.rules.internalActivitiesList[ao1].duration;
04291                                    }
04292 
04293                                    if(ao2==ai){
04294                                           do2=d;
04295                                           ho2=h;
04296                                           duro2=act->duration;
04297                                    }
04298                                    else{
04299                                           do2=c.times[ao2]%gt.rules.nDaysPerWeek;
04300                                           ho2=c.times[ao2]/gt.rules.nDaysPerWeek;
04301                                           duro2=gt.rules.internalActivitiesList[ao2].duration;
04302                                    }
04303 
04304                                    if(ao3==ai){
04305                                           do3=d;
04306                                           ho3=h;
04307                                           //duro3=act->duration;
04308                                    }
04309                                    else{
04310                                           do3=c.times[ao3]%gt.rules.nDaysPerWeek;
04311                                           ho3=c.times[ao3]/gt.rules.nDaysPerWeek;
04312                                           //duro3=gt.rules.internalActivitiesList[ao3].duration;
04313                                    }
04314                                    
04315                                    assert(do1==do2 && do1==do3);
04316                                    if(ho1+duro1<=ho2 && ho2+duro2<=ho3){
04317                                           int hoursBetweenThem=0;
04318                                           
04319                                           for(int kk=ho1+duro1; kk<ho2; kk++)
04320                                                  if(!breakDayHour(d,kk))
04321                                                         hoursBetweenThem++;
04322                                           for(int kk=ho2+duro2; kk<ho3; kk++)
04323                                                  if(!breakDayHour(d,kk))
04324                                                         hoursBetweenThem++;
04325                                           
04326                                           if(hoursBetweenThem==0)
04327                                                  ok=true;
04328                                           else
04329                                                  ok=false;
04330                                    }
04331                                    else{
04332                                           //not OK
04333                                           ok=false;
04334                                    }
04335                             }
04336                             else{
04337                                    //not OK
04338                                    ok=false;
04339                             }
04340                      }
04341                      
04342                      bool again;//=false;
04343                      
04344                      if(!ok && !sR){
04345                             int aidisplaced=-1;
04346                      
04347                             if(aip2>=0){ //two placed activities
04348                                    again=true;
04349                             
04350                                    QList<int> acts;
04351                                    
04352                                    if(!fixedTimeActivity[aip1] && !swappedActivities[aip1])
04353                                           acts.append(aip1);
04354                                    if(!fixedTimeActivity[aip2] && !swappedActivities[aip2])
04355                                           acts.append(aip2);
04356 
04357                                    if(acts.count()==0)
04358                                           aidisplaced=-1;
04359                                    else if(acts.count()==1)
04360                                           aidisplaced=acts.at(0);
04361                                    else{
04362                                           int t;
04363                                           if(level==0){
04364                                                  int optMinWrong=INF;
04365                             
04366                                                  QList<int> tl;
04367               
04368                                                  for(int q=0; q<acts.count(); q++){
04369                                                         int tta=acts.at(q);
04370                                                         if(optMinWrong>triedRemovals(tta,c.times[tta])){
04371                                                                optMinWrong=triedRemovals(tta,c.times[tta]);
04372                                                         }
04373                                                  }
04374                                    
04375                                                  for(int q=0; q<acts.count(); q++){
04376                                                         int tta=acts.at(q);
04377                                                         if(optMinWrong==triedRemovals(tta,c.times[tta]))
04378                                                                tl.append(q);
04379                                                  }
04380                             
04381                                                  assert(tl.size()>=1);
04382                                                  int mpos=tl.at(randomKnuth(tl.size()));
04383                                    
04384                                                  assert(mpos>=0 && mpos<acts.count());
04385                                                  t=mpos;
04386                                           }
04387                                           else{
04388                                                  t=randomKnuth(acts.count());
04389                                           }
04390                                           
04391                                           aidisplaced=acts.at(t);
04392                                    }
04393                             }
04394                             else{
04395                                    again=false;
04396                                    assert(aip1>=0);
04397                                    if(!fixedTimeActivity[aip1] && !swappedActivities[aip1])
04398                                           aidisplaced=aip1;
04399                                    else
04400                                           aidisplaced=-1;
04401                             }
04402                      
04403                             assert(aidisplaced!=ai);
04404                             
04405                             if(aidisplaced==-1){
04406                                    okthreeactivitiesgrouped=false;
04407                                    goto impossiblethreeactivitiesgrouped;
04408                             }
04409                             if(fixedTimeActivity[aidisplaced] || swappedActivities[aidisplaced]){
04410                                    okthreeactivitiesgrouped=false;
04411                                    goto impossiblethreeactivitiesgrouped;
04412                             }
04413                             
04414                             assert(!conflActivities[newtime].contains(aidisplaced));
04415                             conflActivities[newtime].append(aidisplaced);
04416                             nConflActivities[newtime]++;
04417                             assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04418                             
04419                             //if !again, everything is OK, because there was one placed activity and it was eliminated
04420                             
04421                             if(again){
04422                                    aip1=-1, aip2=-1;
04423                                    ainp1=-1, ainp2=-1;
04424                                    if(c.times[ai2]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai2))
04425                                           ainp1=ai2;
04426                                    else
04427                                           aip1=ai2;
04428                                    if(c.times[ai3]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai3)){
04429                                           if(ainp1==-1)
04430                                                  ainp1=ai3;
04431                                           else
04432                                                  ainp2=ai3;
04433                                    }
04434                                    else{
04435                                           if(aip1==-1)
04436                                                  aip1=ai3;
04437                                           else
04438                                                  aip2=ai3;
04439                                    }
04440 
04441                                    assert(aip1>=0 && ainp1>=0 && aip2==-1 && ainp2==-1); //only one placed
04442                                    
04443                                    //again the procedure from above, with 1 placed
04444                                    int dp1=c.times[aip1]%gt.rules.nDaysPerWeek;
04445                                    int hp1=c.times[aip1]/gt.rules.nDaysPerWeek;
04446                                    int durp1=gt.rules.internalActivitiesList[aip1].duration;
04447                                    
04448                                    int hoursBetweenThem=-1;
04449                             
04450                                    if(dp1!=d)
04451                                           hoursBetweenThem=-1;
04452                                    else if(dp1==d && h >= hp1+durp1){
04453                                           hoursBetweenThem=0;
04454                                           for(int kk=hp1+durp1; kk<h; kk++)
04455                                                  if(!breakDayHour(d,kk)){
04456                                                         //check that the working hours are not separated by a break
04457                                                         //assertion that durp1>0, so the kk-1 >= 0
04458                                                         if(breakDayHour(d,kk-1) && hoursBetweenThem>0){
04459                                                                hoursBetweenThem=-1;
04460                                                                break;
04461                                                         }
04462 
04463                                                         hoursBetweenThem++;
04464                                                  }
04465                                    }
04466                                    else if(dp1==d && hp1 >= h+act->duration){
04467                                           hoursBetweenThem=0;
04468                                           for(int kk=h+act->duration; kk<hp1; kk++)
04469                                                  if(!breakDayHour(d,kk)){
04470                                                         //check that the working hours are not separated by a break
04471                                                         //assertion that act->duration>0, so the kk-1 >= 0
04472                                                         if(breakDayHour(d,kk-1) && hoursBetweenThem>0){
04473                                                                hoursBetweenThem=-1;
04474                                                                break;
04475                                                         }
04476 
04477                                                         hoursBetweenThem++;
04478                                                  }
04479                                    }
04480                                    else
04481                                           hoursBetweenThem=-1;
04482                                    
04483                                    assert(ainp1>=0);
04484                                    if(hoursBetweenThem==0 || hoursBetweenThem==gt.rules.internalActivitiesList[ainp1].duration)
04485                                           //OK
04486                                           ok=true;
04487                                    else
04488                                           //not OK
04489                                           ok=false;
04490                                           
04491                                    assert(!sR);
04492                                    if(!ok){
04493                                           aidisplaced=aip1;
04494                                           if(fixedTimeActivity[aidisplaced] || swappedActivities[aidisplaced]){
04495                                                  okthreeactivitiesgrouped=false;
04496                                                  goto impossiblethreeactivitiesgrouped;
04497                                           }
04498                                           
04499                                           assert(!conflActivities[newtime].contains(aidisplaced));
04500                                           conflActivities[newtime].append(aidisplaced);
04501                                           nConflActivities[newtime]++;
04502                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04503                                           
04504                                           //now it is OK, because there were two activities placed and both were eliminated
04505                                    }
04506                             } //end if(again)
04507                      }
04508               }
04509 
04510 impossiblethreeactivitiesgrouped:
04511               if(!okthreeactivitiesgrouped){
04512                      //if(updateSubgroups || updateTeachers)
04513                      //     removeAiFromNewTimetable(ai, act, d, h);
04514                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
04515 
04516                      nConflActivities[newtime]=MAX_ACTIVITIES;
04517                      continue;
04518               }
04519               
04520               /*foreach(int ai2, conflActivities[newtime])
04521                      assert(!swappedActivities[ai2]);*/
04522               
04524 
04525               //allowed from 2 activities ordered
04526               oktwoactivitiesordered=true;
04527               
04528               for(int i=0; i<constrTwoActivitiesOrderedActivities[ai].count(); i++){
04529                      //direct
04530                      int ai2=constrTwoActivitiesOrderedActivities[ai].at(i);
04531                      double perc=constrTwoActivitiesOrderedPercentages[ai].at(i);
04532                      if(c.times[ai2]!=UNALLOCATED_TIME){
04533                             int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
04534                             int h2=c.times[ai2]/gt.rules.nDaysPerWeek;                            
04535                             bool ok=true;
04536                             
04537                             if(!(d<d2 || (d==d2 && h+act->duration-1<h2)))
04538                                    ok=false;
04539                                    
04540                             bool sR=skipRandom(perc);
04541                             //if(fixedTimeActivity[ai] && perc<100.0)
04542                             //     sR=true;
04543 
04544                             if(!ok && !sR){
04545                                    assert(ai2!=ai);
04546                                    
04547                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
04548                                           oktwoactivitiesordered=false;
04549                                           goto impossibletwoactivitiesordered;
04550                                    }
04551                                    
04552                                    if(!conflActivities[newtime].contains(ai2)){
04553                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
04554 
04555                                           conflActivities[newtime].append(ai2);
04556                                           //conflActivities[newtime].append(ai2);
04557                                           nConflActivities[newtime]++;
04558                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04559                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04560                                    }
04561                             }
04562                      }
04563               }
04564 
04565               for(int i=0; i<inverseConstrTwoActivitiesOrderedActivities[ai].count(); i++){
04566                      //inverse
04567                      int ai2=inverseConstrTwoActivitiesOrderedActivities[ai].at(i);
04568                      double perc=inverseConstrTwoActivitiesOrderedPercentages[ai].at(i);
04569                      if(c.times[ai2]!=UNALLOCATED_TIME){
04570                             int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
04571                             int h2=c.times[ai2]/gt.rules.nDaysPerWeek;                            
04572                             int dur2=gt.rules.internalActivitiesList[ai2].duration;
04573                             bool ok=true;
04574                             
04575                             if(!(d2<d || (d2==d && h2+dur2-1<h)))
04576                                    ok=false;
04577                                    
04578                             bool sR=skipRandom(perc);
04579                             //if(fixedTimeActivity[ai] && perc<100.0)
04580                             //     sR=true;
04581                             
04582                             if(!ok && !sR){
04583                                    assert(ai2!=ai);
04584                                    
04585                                    if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
04586                                           oktwoactivitiesordered=false;
04587                                           goto impossibletwoactivitiesordered;
04588                                    }
04589                                    
04590                                    if(!conflActivities[newtime].contains(ai2)){
04591                                    //if(conflActivities[newtime].indexOf(ai2)==-1){
04592                                           conflActivities[newtime].append(ai2);
04593                                           //conflActivities[newtime].append(ai2);
04594                                           nConflActivities[newtime]++;
04595                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04596                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04597                                    }
04598                             }
04599                      }
04600               }
04601               
04602 impossibletwoactivitiesordered:
04603               if(!oktwoactivitiesordered){
04604                      //if(updateSubgroups || updateTeachers)
04605                      //     removeAiFromNewTimetable(ai, act, d, h);
04606                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
04607 
04608                      nConflActivities[newtime]=MAX_ACTIVITIES;
04609                      continue;
04610               }
04611               
04612               /*foreach(int ai2, conflActivities[newtime])
04613                      assert(!swappedActivities[ai2]);*/
04614               
04616 
04617               //allowed from activity ends students day
04618               okactivityendsstudentsday=true;
04619               
04620               if(haveActivityEndsStudentsDay){
04621                      //1. If current activity needs to be at the end
04622                      if(activityEndsStudentsDayPercentages[ai]>=0){
04623                             bool skip=skipRandom(activityEndsStudentsDayPercentages[ai]);
04624                             if(!skip){
04625                                    foreach(int sb, act->iSubgroupsList){
04626                                    //for(int j=0; j<gt.rules.internalActivitiesList[ai].iSubgroupsList.count(); j++){
04627                                    //     int sb=gt.rules.internalActivitiesList[ai].iSubgroupsList.at(j);
04628                                           for(int hh=h+act->duration; hh<gt.rules.nHoursPerDay; hh++){
04629                                                  int ai2=subgroupsTimetable(sb,d,hh);
04630                                                  if(ai2>=0){
04631                                                         if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
04632                                                                okactivityendsstudentsday=false;
04633                                                                goto impossibleactivityendsstudentsday;
04634                                                         }
04635                                                         
04636                                                         if(!conflActivities[newtime].contains(ai2)){
04637                                                         //if(conflActivities[newtime].indexOf(ai2)==-1){
04638                                                                //conflActivities[newtime].append(ai2);
04639                                                                conflActivities[newtime].append(ai2);
04640                                                                nConflActivities[newtime]++;
04641                                                                assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04642                                                                //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04643                                                         }
04644                                                  }
04645                                           }
04646                                    }
04647                             }
04648                      }
04649 
04650                      //2. Check activities which have to be at the end, in the same day with current activity
04651                      foreach(int sb, act->iSubgroupsList){
04652                      //for(int j=0; j<gt.rules.internalActivitiesList[ai].iSubgroupsList.count(); j++){
04653                      //     int sb=gt.rules.internalActivitiesList[ai].iSubgroupsList.at(j);
04654                             for(int hh=h-1; hh>=0; hh--){
04655                                    int ai2=subgroupsTimetable(sb,d,hh);
04656                                    if(ai2>=0)
04657                                           if(activityEndsStudentsDayPercentages[ai2]>=0){
04658                                                  bool skip=skipRandom(activityEndsStudentsDayPercentages[ai2]);
04659                                                  if(!skip){
04660                                                         if(fixedTimeActivity[ai2] || swappedActivities[ai2]){
04661                                                                okactivityendsstudentsday=false;
04662                                                                goto impossibleactivityendsstudentsday;
04663                                                         }
04664                                                         
04665                                                         if(!conflActivities[newtime].contains(ai2)){     
04666                                                         //if(conflActivities[newtime].indexOf(ai2)==-1){
04667                                                                //conflActivities[newtime].append(ai2);
04668                                                                conflActivities[newtime].append(ai2);
04669                                                                nConflActivities[newtime]++;
04670                                                                assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04671                                                                //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04672                                                         }
04673                                                  }
04674                                           }
04675                             }
04676                      }
04677               }
04678 
04679 impossibleactivityendsstudentsday:
04680               if(!okactivityendsstudentsday){
04681                      //if(updateSubgroups || updateTeachers)
04682                      //     removeAiFromNewTimetable(ai, act, d, h);
04683                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
04684 
04685                      nConflActivities[newtime]=MAX_ACTIVITIES;
04686                      continue;
04687               }
04688               
04690               if(updateSubgroups || updateTeachers){
04691                      addAiToNewTimetable(ai, act, d, h);
04692                      if(updateTeachers)
04693                             updateTeachersNHoursGaps(act, ai, d);
04694                      if(updateSubgroups)
04695                             updateSubgroupsNHoursGaps(act, ai, d);
04696               }
04698               
04699 
04701               
04703        
04705        
04706               //BEGIN students interval max days per week
04707               okstudentsintervalmaxdaysperweek=true;
04708               foreach(int sbg, act->iSubgroupsList){
04709                      double perc=-1.0;
04710                      for(int cnt=0; cnt<3; cnt++){
04711                             if(cnt==0){
04712                                    perc=subgroupsIntervalMaxDaysPerWeekPercentages1[sbg];
04713                             }
04714                             else if(cnt==1){
04715                                    perc=subgroupsIntervalMaxDaysPerWeekPercentages2[sbg];
04716                             }
04717                             else if(cnt==2){
04718                                    perc=subgroupsIntervalMaxDaysPerWeekPercentages3[sbg];
04719                             }
04720                             else
04721                                    assert(0);
04722                             
04723                             if(perc>=0){
04724                                    int maxDays=-1;
04725                                    int sth=-1;
04726                                    int endh=-1;
04727                             
04728                                    if(cnt==0){
04729                                           maxDays=subgroupsIntervalMaxDaysPerWeekMaxDays1[sbg];
04730                                           sth=subgroupsIntervalMaxDaysPerWeekIntervalStart1[sbg];
04731                                           endh=subgroupsIntervalMaxDaysPerWeekIntervalEnd1[sbg];
04732                                    }
04733                                    else if(cnt==1){
04734                                           maxDays=subgroupsIntervalMaxDaysPerWeekMaxDays2[sbg];
04735                                           sth=subgroupsIntervalMaxDaysPerWeekIntervalStart2[sbg];
04736                                           endh=subgroupsIntervalMaxDaysPerWeekIntervalEnd2[sbg];
04737                                    }
04738                                    else if(cnt==2){
04739                                           maxDays=subgroupsIntervalMaxDaysPerWeekMaxDays3[sbg];
04740                                           sth=subgroupsIntervalMaxDaysPerWeekIntervalStart3[sbg];
04741                                           endh=subgroupsIntervalMaxDaysPerWeekIntervalEnd3[sbg];
04742                                    }
04743                                    else
04744                                           assert(0);
04745 
04746                                    assert(sth>=0 && sth<gt.rules.nHoursPerDay);
04747                                    assert(endh>sth && endh<=gt.rules.nHoursPerDay);
04748                                    assert(maxDays>=0 && maxDays<=gt.rules.nDaysPerWeek);
04749                                    
04750                                    if(skipRandom(perc))
04751                                           continue;
04752                                    
04753                                    assert(perc==100.0);
04754                                    
04755                                    bool foundothers=false;
04756                                    bool foundai=false;
04757                                    for(int hh=sth; hh<endh; hh++){
04758                                           if(newSubgroupsTimetable(sbg,d,hh)==ai){
04759                                                  foundai=true;
04760                                           }
04761                                           else{
04762                                                  assert(newSubgroupsTimetable(sbg,d,hh)==subgroupsTimetable(sbg,d,hh));
04763                                                  if(newSubgroupsTimetable(sbg,d,hh)>=0){
04764                                                         if(!conflActivities[newtime].contains(newSubgroupsTimetable(sbg,d,hh))){
04765                                                                foundothers=true;
04766                                                         }
04767                                                  }
04768                                           }
04769                                    }
04770                                    int nrotherdays=0;
04771                                    for(int dd=0; dd<gt.rules.nDaysPerWeek; dd++){
04772                                           if(dd!=d){
04773                                                  for(int hh=sth; hh<endh; hh++){
04774                                                         assert(newSubgroupsTimetable(sbg,dd,hh)==subgroupsTimetable(sbg,dd,hh));
04775                                                         if(newSubgroupsTimetable(sbg,dd,hh)>=0 && !conflActivities[newtime].contains(newSubgroupsTimetable(sbg,dd,hh))){
04776                                                                nrotherdays++;
04777                                                                break;
04778                                                         }
04779                                                  }
04780                                           }
04781                                    }
04782                                    assert(nrotherdays<=maxDays); //if percentage==100%, then it is impossible to break this constraint
04783                                    if((foundai && !foundothers) && nrotherdays==maxDays){
04784                                           //increased above limit
04785                                           bool occupiedIntervalDay[MAX_DAYS_PER_WEEK];
04786                                           bool canEmptyIntervalDay[MAX_DAYS_PER_WEEK];
04787                             
04788                                           int _minWrong[MAX_DAYS_PER_WEEK];
04789                                           int _nWrong[MAX_DAYS_PER_WEEK];
04790                                           int _nConflActivities[MAX_DAYS_PER_WEEK];
04791                                           int _minIndexAct[MAX_DAYS_PER_WEEK];
04792                             
04793                                           QList<int> _activitiesForIntervalDay[MAX_DAYS_PER_WEEK];
04794 
04795                                           for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
04796                                                  if(d2==d)
04797                                                         continue;
04798                             
04799                                                  occupiedIntervalDay[d2]=false;
04800                                                  canEmptyIntervalDay[d2]=true;
04801                                    
04802                                                  _minWrong[d2]=INF;
04803                                                  _nWrong[d2]=0;
04804                                                  _nConflActivities[d2]=0;
04805                                                  _minIndexAct[d2]=gt.rules.nInternalActivities;
04806                                                  _activitiesForIntervalDay[d2].clear();
04807                                                  
04808                                                  for(int h2=sth; h2<endh; h2++){
04809                                                         int ai2=subgroupsTimetable(sbg,d2,h2);
04810                                                  //foreach(int ai2, teacherActivitiesOfTheDay(tch,d2)){
04811                                                         if(ai2>=0){
04812                                                                if(!conflActivities[newtime].contains(ai2)){
04813                                                                       occupiedIntervalDay[d2]=true;
04814                                                                       if(fixedTimeActivity[ai2] || swappedActivities[ai2])
04815                                                                              canEmptyIntervalDay[d2]=false;
04816                                                                       else if(!_activitiesForIntervalDay[d2].contains(ai2)){
04817                                                                              _minWrong[d2] = min (_minWrong[d2], triedRemovals(ai2,c.times[ai2]));
04818                                                                              _minIndexAct[d2]=min(_minIndexAct[d2], invPermutation[ai2]);
04819                                                                              _nWrong[d2]+=triedRemovals(ai2,c.times[ai2]);
04820                                                                              _nConflActivities[d2]++;
04821                                                                              _activitiesForIntervalDay[d2].append(ai2);
04822                                                                              assert(_nConflActivities[d2]==_activitiesForIntervalDay[d2].count());
04823                                                                       }
04824                                                                }
04825                                                         }
04826                                                  }
04827                                    
04828                                                  if(!occupiedIntervalDay[d2])
04829                                                         canEmptyIntervalDay[d2]=false;
04830                                           }
04831                                           occupiedIntervalDay[d]=true;
04832                                           canEmptyIntervalDay[d]=false;
04833                             
04834                                           int nOc=0;
04835                                           bool canChooseDay=false;
04836                             
04837                                           for(int j=0; j<gt.rules.nDaysPerWeek; j++)
04838                                                  if(occupiedIntervalDay[j]){
04839                                                         nOc++;
04840                                                         if(canEmptyIntervalDay[j]){
04841                                                                canChooseDay=true;
04842                                                         }
04843                                                  }
04844                                           
04845                                           //if(nOc>maxDays){
04846                                           assert(nOc==maxDays+1);
04847                                    
04848                                           if(!canChooseDay){
04849                                                  if(level==0){
04850                                                         //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
04851                                                         //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
04852                                                  }
04853                                                  okstudentsintervalmaxdaysperweek=false;
04854                                                  goto impossiblestudentsintervalmaxdaysperweek;
04855                                           }
04856                                    
04857                                           int d2=-1;
04858                                    
04859                                           if(level!=0){
04860                                                  //choose random day from those with minimum number of conflicting activities
04861                                                  QList<int> candidateDays;
04862                                           
04863                                                  int m=gt.rules.nInternalActivities;
04864                                                  
04865                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
04866                                                         if(canEmptyIntervalDay[kk])
04867                                                                if(m>_nConflActivities[kk])
04868                                                                       m=_nConflActivities[kk];
04869                                           
04870                                                  candidateDays.clear();
04871                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
04872                                                         if(canEmptyIntervalDay[kk] && m==_nConflActivities[kk])
04873                                                                candidateDays.append(kk);
04874                                                                
04875                                                  assert(candidateDays.count()>0);
04876                                                  d2=candidateDays.at(randomKnuth(candidateDays.count()));
04877                                           }
04878                                           else{ //level==0
04879                                                  QList<int> candidateDays;
04880 
04881                                                  int _mW=INF;
04882                                                  int _nW=INF;
04883                                                  int _mCA=gt.rules.nInternalActivities;
04884                                                  int _mIA=gt.rules.nInternalActivities;
04885 
04886                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
04887                                                         if(canEmptyIntervalDay[kk]){
04888                                                                if(_mW>_minWrong[kk] ||
04889                                                                 (_mW==_minWrong[kk] && _nW>_nWrong[kk]) ||
04890                                                                 (_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA>_nConflActivities[kk]) ||
04891                                                                 (_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA>_minIndexAct[kk])){
04892                                                                       _mW=_minWrong[kk];
04893                                                                       _nW=_nWrong[kk];
04894                                                                       _mCA=_nConflActivities[kk];
04895                                                                       _mIA=_minIndexAct[kk];
04896                                                                }
04897                                                         }
04898                                                         
04899                                                  assert(_mW<INF);
04900                                                  
04901                                                  candidateDays.clear();
04902                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
04903                                                         if(canEmptyIntervalDay[kk] && _mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA==_minIndexAct[kk])
04904                                                                candidateDays.append(kk);
04905                                                         
04906                                                  assert(candidateDays.count()>0);
04907                                                  d2=candidateDays.at(randomKnuth(candidateDays.count()));
04908                                           }
04909                                    
04910                                           assert(d2>=0);
04911 
04912                                           assert(_activitiesForIntervalDay[d2].count()>0);
04913 
04914                                           foreach(int ai2, _activitiesForIntervalDay[d2]){
04915                                                  assert(ai2!=ai);
04916                                                  assert(!swappedActivities[ai2]);
04917                                                  assert(!fixedTimeActivity[ai2]);
04918                                                  assert(!conflActivities[newtime].contains(ai2));
04919                                                  conflActivities[newtime].append(ai2);
04920                                                  nConflActivities[newtime]++;
04921                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
04922                                                  //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
04923                                           }
04924                                    }
04925                             }
04926                      }
04927               }
04928               //respecting students interval max days per week
04929 impossiblestudentsintervalmaxdaysperweek:
04930               if(!okstudentsintervalmaxdaysperweek){
04931                      if(updateSubgroups || updateTeachers)
04932                             removeAiFromNewTimetable(ai, act, d, h);
04933                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
04934 
04935                      nConflActivities[newtime]=MAX_ACTIVITIES;
04936                      continue;
04937               }
04938 
04940 
04941 
04943 
04944               //not breaking students early max beginnings at second hour
04945               //TODO: this should take care of students max gaps per day also. Very critical changes, so be very careful if you do them. Safer -> leave them as they are now.
04946               //see file fet-v.v.v/doc/algorithm/improve-studentsmaxgapsperday.txt for advice and (unstable) code on how to make students max gaps per day constraint perfect
04947               okstudentsearlymaxbeginningsatsecondhour=true;
04948               
04949               foreach(int sbg, act->iSubgroupsList)
04950                      if(!skipRandom(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg])){
04951                             //preliminary check
04952                             int _nHours=0;
04953                             int _nFirstGapsOne=0;
04954                             int _nFirstGapsTwo=0;
04955                             int _nGaps=0;
04956                             int _nIllegalGaps=0;
04957                             for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
04958                                    _nHours+=newSubgroupsDayNHours(sbg,d2);
04959                                    
04960                                    if(newSubgroupsDayNFirstGaps(sbg, d2)==1){
04961                                           _nFirstGapsOne++;
04962                                    }
04963                                    else if(newSubgroupsDayNFirstGaps(sbg, d2)>=2){
04964                                           _nFirstGapsTwo++;
04965                                           _nIllegalGaps++;
04966                                           _nGaps+=newSubgroupsDayNFirstGaps(sbg, d2)-2;
04967                                    }
04968                                    _nGaps+=newSubgroupsDayNGaps(sbg,d2);
04969                             }
04970                             
04971                             int _tt=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
04972                             if(_tt>=_nFirstGapsOne){
04973                                    _tt-=_nFirstGapsOne;
04974                                    _nFirstGapsOne=0;
04975                             }
04976                             else{
04977                                    _nFirstGapsOne-=_tt;
04978                                    _tt=0;
04979                             }
04980                             if(_tt>=_nFirstGapsTwo){
04981                                    _tt-=_nFirstGapsTwo;
04982                                    _nFirstGapsTwo=0;
04983                             }
04984                             else{
04985                                    _nFirstGapsTwo-=_tt;
04986                                    _tt=0;
04987                             }
04988                             
04989                             if(_nFirstGapsTwo>0){
04990                                    _nGaps+=_nFirstGapsTwo;
04991                                    _nFirstGapsTwo=0;
04992                             }
04993                             
04994                             int _nHoursGaps=0;
04995                             if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
04996                                    assert(subgroupsMaxGapsPerWeekPercentage[sbg]==100);
04997                                    if(_nGaps>subgroupsMaxGapsPerWeekMaxGaps[sbg])
04998                                           _nHoursGaps=_nGaps-subgroupsMaxGapsPerWeekMaxGaps[sbg];
04999                             }
05000                             
05001                             if(_nHours + _nFirstGapsOne + _nHoursGaps + _nIllegalGaps > nHoursPerSubgroup[sbg]){
05002                                    if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
05003                                           okstudentsearlymaxbeginningsatsecondhour=false;
05004                                           goto impossiblestudentsearlymaxbeginningsatsecondhour;
05005                                    }
05006 
05007                                    getSbgTimetable(sbg, conflActivities[newtime]);
05008                                    sbgGetNHoursGaps(sbg);
05009 
05010                                    for(;;){
05011                                           int nHours=0;
05012                                           int nFirstGapsOne=0;
05013                                           int nFirstGapsTwo=0;
05014                                           int nGaps=0;
05015                                           int nIllegalGaps=0;
05016                                           for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05017                                                  nHours+=sbgDayNHours[d2];
05018 
05019                                                  if(sbgDayNFirstGaps[d2]==1){
05020                                                         nFirstGapsOne++;
05021                                                  }
05022                                                  else if(sbgDayNFirstGaps[d2]>=2){
05023                                                         nFirstGapsTwo++;
05024                                                         nIllegalGaps++;
05025                                                         nGaps+=sbgDayNFirstGaps[d2]-2;
05026                                                  }
05027                                                  nGaps+=sbgDayNGaps[d2];
05028                                           }
05029                                           
05030                                           int tt=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05031                                           if(tt>=nFirstGapsOne){
05032                                                  tt-=nFirstGapsOne;
05033                                                  nFirstGapsOne=0;
05034                                           }
05035                                           else{
05036                                                  nFirstGapsOne-=tt;
05037                                                  tt=0;
05038                                           }
05039                                           if(tt>=nFirstGapsTwo){
05040                                                  tt-=nFirstGapsTwo;
05041                                                  nFirstGapsTwo=0;
05042                                           }
05043                                           else{
05044                                                  nFirstGapsTwo-=tt;
05045                                                  tt=0;
05046                                           }
05047                                           
05048                                           if(nFirstGapsTwo>0){
05049                                                  nGaps+=nFirstGapsTwo;
05050                                                  nFirstGapsTwo=0;
05051                                           }
05052                                           
05053                                           int nHoursGaps=0;
05054                                           if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05055                                                  assert(subgroupsMaxGapsPerWeekPercentage[sbg]==100);
05056                                                  if(nGaps>subgroupsMaxGapsPerWeekMaxGaps[sbg])
05057                                                         nHoursGaps=nGaps-subgroupsMaxGapsPerWeekMaxGaps[sbg];
05058                                           }
05059                             
05060                                           int ai2=-1;
05061                                           
05062                                           if(nHours + nFirstGapsOne + nHoursGaps + nIllegalGaps > nHoursPerSubgroup[sbg]){
05063                                                  //remove an activity
05064                                                  bool k=subgroupRemoveAnActivityFromEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05065                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05066                                                  if(!k){
05067                                                         if(level==0){
05068                                                                //this should not be displayed
05069                                                                //cout<<"WARNING - maybe bug - file "<<__FILE__<<" line "<<__LINE__<<endl;
05070                                                         }
05071                                                         okstudentsearlymaxbeginningsatsecondhour=false;
05072                                                         goto impossiblestudentsearlymaxbeginningsatsecondhour;
05073                                                  }
05074                                           }
05075                                           else{ //OK
05076                                                  break;
05077                                           }
05078                                           
05079                                           assert(ai2>=0);
05080                                           
05081                                           removeAi2FromSbgTimetable(ai2);
05082                                           updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek);
05083                                    }
05084                             }
05085                      }
05086               
05087 impossiblestudentsearlymaxbeginningsatsecondhour:
05088               if(!okstudentsearlymaxbeginningsatsecondhour){
05089                      if(updateSubgroups || updateTeachers)
05090                             removeAiFromNewTimetable(ai, act, d, h);
05091                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
05092 
05093                      nConflActivities[newtime]=MAX_ACTIVITIES;
05094                      continue;
05095               }
05096 
05098 
05100 
05101               //not breaking students max gaps per week
05102               //TODO: this should take care of students max gaps per day also. Very critical changes, so be very careful if you do them. Safer -> leave them as they are now.
05103               //see file fet-v.v.v/doc/algorithm/improve-studentsmaxgapsperday.txt for advice and (unstable) code on how to make students max gaps per day constraint perfect
05104               okstudentsmaxgapsperweek=true;
05105               
05106               foreach(int sbg, act->iSubgroupsList)
05107                      if(!skipRandom(subgroupsMaxGapsPerWeekPercentage[sbg])){
05108                      //TODO
05109                      //if(!skipRandom(subgroupsMaxGapsPerWeekPercentage[sbg])){
05110                             //assert(subgroupsMaxGapsPerWeekPercentage[sbg]==100);
05111                             
05112                             //preliminary test
05113                             int _nHours=0;
05114                             int _nGaps=0;
05115                             int _nFirstGaps=0;
05116                             for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05117                                    _nHours+=newSubgroupsDayNHours(sbg,d2);
05118                                    _nGaps+=newSubgroupsDayNGaps(sbg,d2);
05119                                    _nFirstGaps+=newSubgroupsDayNFirstGaps(sbg,d2);
05120                             }
05121                             
05122                             int _nFirstHours=0;
05123                             
05124                             if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
05125                                    assert(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]==100);
05126                                    if(_nFirstGaps>subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg])
05127                                           _nFirstHours=_nFirstGaps-subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05128                             }
05129                             
05130                             if(_nGaps+_nHours+_nFirstHours > subgroupsMaxGapsPerWeekMaxGaps[sbg] + nHoursPerSubgroup[sbg]){
05131                                    if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
05132                                           okstudentsmaxgapsperweek=false;
05133                                           goto impossiblestudentsmaxgapsperweek;
05134                                    }
05135 
05136                                    getSbgTimetable(sbg, conflActivities[newtime]);
05137                                    sbgGetNHoursGaps(sbg);
05138 
05139                                    for(;;){
05140                                           int nHours=0;
05141                                           int nGaps=0;
05142                                           int nFirstGaps=0;
05143                                           for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05144                                                  nHours+=sbgDayNHours[d2];
05145                                                  nGaps+=sbgDayNGaps[d2];
05146                                                  nFirstGaps+=sbgDayNFirstGaps[d2];
05147                                           }
05148                                           
05149                                           int ai2=-1;
05150                                                  
05151                                           int nFirstHours=0;
05152 
05153                                           if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
05154                                                  assert(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]==100);
05155                                                  if(nFirstGaps>subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg])
05156                                                         nFirstHours=nFirstGaps-subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05157                                           }
05158                                           
05159                                           if(nGaps+nHours+nFirstHours > subgroupsMaxGapsPerWeekMaxGaps[sbg] + nHoursPerSubgroup[sbg]){
05160                                                  //remove an activity
05161                                                  bool k=subgroupRemoveAnActivityFromBeginOrEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05162                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05163                                                  if(!k){
05164                                                         if(level==0){
05165                                                                //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
05166                                                                //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
05167                                                         }
05168                                                         okstudentsmaxgapsperweek=false;
05169                                                         goto impossiblestudentsmaxgapsperweek;
05170                                                  }
05171                                           }
05172                                           else{ //OK
05173                                                  break;
05174                                           }
05175                                           
05176                                           assert(ai2>=0);
05177 
05178                                           removeAi2FromSbgTimetable(ai2);
05179                                           updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek);
05180                                    }
05181                             }
05182                      }
05183               
05184 impossiblestudentsmaxgapsperweek:
05185               if(!okstudentsmaxgapsperweek){
05186                      if(updateSubgroups || updateTeachers)
05187                             removeAiFromNewTimetable(ai, act, d, h);
05188                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
05189 
05190                      nConflActivities[newtime]=MAX_ACTIVITIES;
05191                      continue;
05192               }
05193 
05195 
05197 
05199               //see file fet-v.v.v/doc/algorithm/improve-studentsmaxgapsperday.txt for advice and (unstable) code on how to make students max gaps per day constraint perfect
05200 
05201               //not causing more than subgroupsMaxGapsPerDay students gaps
05202               
05203               //TODO: improve, check
05204               
05205        okstudentsmaxgapsperday=true;
05206               
05207        if(haveStudentsMaxGapsPerDay){
05208               
05209               //okstudentsmaxgapsperday=true;
05210               foreach(int sbg, act->iSubgroupsList)
05211                      if(!skipRandom(subgroupsMaxGapsPerDayPercentage[sbg])){
05212                             assert(subgroupsMaxGapsPerDayPercentage[sbg]==100);
05213 
05214                             //preliminary test
05215                             int _total=0;
05216                             int _remnf=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05217                             bool _haveMaxBegs=(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0);
05218                             for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05219                                    _total+=newSubgroupsDayNHours(sbg,d2);
05220                                    int _g=newSubgroupsDayNGaps(sbg,d2);
05221                                    if(_haveMaxBegs){
05222                                           int _fg=newSubgroupsDayNFirstGaps(sbg,d2);
05223                                           if(_fg==0){
05224                                                  if(_g>subgroupsMaxGapsPerDayMaxGaps[sbg])
05225                                                         _total+=_g-subgroupsMaxGapsPerDayMaxGaps[sbg];
05226                                           }
05227                                           else if(_fg==1){
05228                                                  if(_remnf>0)
05229                                                         _remnf--;
05230                                                  else
05231                                                         _total++;
05232                                                  if(_g>subgroupsMaxGapsPerDayMaxGaps[sbg])
05233                                                         _total+=_g-subgroupsMaxGapsPerDayMaxGaps[sbg];
05234                                           }
05235                                           else if(_fg>=2){
05236                                                  if(_g + _fg - 1 <= subgroupsMaxGapsPerDayMaxGaps[sbg])
05237                                                         _total++;
05238                                                  else{
05239                                                         if(_remnf>0)
05240                                                                _remnf--;
05241                                                         else
05242                                                                _total++;
05243                                                         _total++;
05244                                                         assert(_g + _fg - 2 >= subgroupsMaxGapsPerDayMaxGaps[sbg]);
05245                                                         _total+=(_g + _fg - 2 - subgroupsMaxGapsPerDayMaxGaps[sbg]);
05246                                                  }
05247                                           }
05248                                           else
05249                                                  assert(0);
05250                                    }
05251                                    else{
05252                                           if(_g > subgroupsMaxGapsPerDayMaxGaps[sbg])
05253                                                  _total+=_g-subgroupsMaxGapsPerDayMaxGaps[sbg];
05254                                    }
05255                             }
05256                             
05257                             if(_total<=nHoursPerSubgroup[sbg]) //OK
05258                                    continue;
05259 
05260                             if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
05261                                    okstudentsmaxgapsperday=false;
05262                                    goto impossiblestudentsmaxgapsperday;
05263                             }
05264 
05265                             getSbgTimetable(sbg, conflActivities[newtime]);
05266                             sbgGetNHoursGaps(sbg);
05267 
05268                             for(;;){
05269                                    int total=0;
05270                                    int remnf=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05271                                    bool haveMaxBegs=(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0);
05272                                    for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05273                                           total+=sbgDayNHours[d2];
05274                                           int g=sbgDayNGaps[d2];
05275                                           if(haveMaxBegs){
05276                                                  int fg=sbgDayNFirstGaps[d2];
05277                                                  if(fg==0){
05278                                                         if(g>subgroupsMaxGapsPerDayMaxGaps[sbg])
05279                                                                total+=g-subgroupsMaxGapsPerDayMaxGaps[sbg];
05280                                                  }
05281                                                  else if(fg==1){
05282                                                         if(remnf>0)
05283                                                                remnf--;
05284                                                         else
05285                                                                total++;
05286                                                         if(g>subgroupsMaxGapsPerDayMaxGaps[sbg])
05287                                                                total+=g-subgroupsMaxGapsPerDayMaxGaps[sbg];
05288                                                  }
05289                                                  else if(fg>=2){
05290                                                         if(g + fg - 1 <= subgroupsMaxGapsPerDayMaxGaps[sbg])
05291                                                                total++;
05292                                                         else{
05293                                                                if(remnf>0)
05294                                                                       remnf--;
05295                                                                else
05296                                                                       total++;
05297                                                                total++;
05298                                                                assert(g + fg - 2 >= subgroupsMaxGapsPerDayMaxGaps[sbg]);
05299                                                                total+=(g + fg - 2 - subgroupsMaxGapsPerDayMaxGaps[sbg]);
05300                                                         }
05301                                                  }
05302                                                  else
05303                                                         assert(0);
05304                                           }
05305                                           else{
05306                                                  if(g > subgroupsMaxGapsPerDayMaxGaps[sbg])
05307                                                         total+=g-subgroupsMaxGapsPerDayMaxGaps[sbg];
05308                                           }
05309                                    }
05310                                    
05311                                    if(total<=nHoursPerSubgroup[sbg]) //OK
05312                                           break;
05313 
05314                                    //remove an activity from the beginning or from the end of a day
05315                                    //following code is identical to maxgapsperweek
05316                                    //remove an activity
05317                                    int ai2=-1;
05318                                    
05319                                    //it should also be allowed to take from anywhere, but it is risky to change now
05320                                    if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
05321                                           bool k=subgroupRemoveAnActivityFromEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05322                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05323                                           if(!k){
05324                                                  bool kk;
05325                                                  if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 && 
05326                                                   (subgroupsMaxGapsPerWeekMaxGaps[sbg]==0 || subgroupsMaxGapsPerDayMaxGaps[sbg]==0))
05327                                                         kk=false;
05328                                                  else
05329                                                         kk=subgroupRemoveAnActivityFromBegin(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05330 
05331                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05332                                                  if(!kk){
05333                                                         if(level==0){
05334                                                                //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
05335                                                                //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
05336                                                         }
05337                                                         okstudentsmaxgapsperday=false;
05338                                                         goto impossiblestudentsmaxgapsperday;
05339                                                  }
05340                                           }
05341                                    }
05342                                    else{
05343                                           bool k=subgroupRemoveAnActivityFromBeginOrEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05344                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05345                                           if(!k){
05346                                                  if(level==0){
05347                                                         //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
05348                                                         //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
05349                                                  }
05350                                                  okstudentsmaxgapsperday=false;
05351                                                  goto impossiblestudentsmaxgapsperday;
05352                                           }
05353                                    }
05354                                    
05355                                    assert(ai2>=0);
05356 
05357                                    removeAi2FromSbgTimetable(ai2);
05358                                    updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek);
05359                             }
05360                      }
05361        }
05362               
05363 impossiblestudentsmaxgapsperday:
05364               if(!okstudentsmaxgapsperday){
05365                      if(updateSubgroups || updateTeachers)
05366                             removeAiFromNewTimetable(ai, act, d, h);
05367                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
05368 
05369                      nConflActivities[newtime]=MAX_ACTIVITIES;
05370                      continue;
05371               }
05372 
05374 
05376 
05377               //to be put after max gaps and early!!! because of an assert
05378 
05379               //allowed from students max hours daily
05380               //TODO: this should take care of students max gaps per day also. Very critical changes, so be very careful if you do them. Safer -> leave them as they are now.
05381               //see file fet-v.v.v/doc/algorithm/improve-studentsmaxgapsperday.txt for advice and (unstable) code on how to make students max gaps per day constraint perfect
05382               okstudentsmaxhoursdaily=true;
05383               
05384               foreach(int sbg, act->iSubgroupsList){
05385                      for(int count=0; count<2; count++){
05386                             int limitHoursDaily;
05387                             double percentage;
05388                             if(count==0){
05389                                    limitHoursDaily=subgroupsMaxHoursDailyMaxHours1[sbg];
05390                                    percentage=subgroupsMaxHoursDailyPercentages1[sbg];
05391                             }
05392                             else{
05393                                    limitHoursDaily=subgroupsMaxHoursDailyMaxHours2[sbg];
05394                                    percentage=subgroupsMaxHoursDailyPercentages2[sbg];
05395                             }
05396                             
05397                             if(limitHoursDaily<0)
05398                                    continue;
05399                             
05400                             //if(fixedTimeActivity[ai] && percentage<100.0) //added on 21 Feb. 2009 in FET 5.9.1, to solve a bug of impossible timetables for fixed timetables
05401                             //     continue;
05402                             
05403                             bool increased;
05404                             if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
05405                                    if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05406                                           //both
05407                                           if(oldSubgroupsDayNHours(sbg,d)+oldSubgroupsDayNGaps(sbg,d)+oldSubgroupsDayNFirstGaps(sbg,d)<
05408                                             newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNGaps(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d)
05409                                             || oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d))
05410                                                  increased=true;
05411                                           else
05412                                                  increased=false;
05413                                    }
05414                                    else{
05415                                           //only at beginning
05416                                           if(oldSubgroupsDayNHours(sbg,d)+oldSubgroupsDayNFirstGaps(sbg,d)<
05417                                             newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d)
05418                                             || oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d))
05419                                                  increased=true;
05420                                           else
05421                                                  increased=false;
05422                                    }
05423                             }
05424                             else{
05425                                    if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05426                                           //only max gaps
05427                                           if(oldSubgroupsDayNHours(sbg,d)+oldSubgroupsDayNGaps(sbg,d)<
05428                                             newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNGaps(sbg,d)
05429                                             || oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d))
05430                                                  increased=true;
05431                                           else
05432                                                  increased=false;
05433                                    }
05434                                    else{
05435                                           //none
05436                                           if(oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d))
05437                                                  increased=true;
05438                                           else
05439                                                  increased=false;
05440                                    }
05441                             }
05442                      
05443                             if(limitHoursDaily>=0 && !skipRandom(percentage) && increased){
05444                                    if(limitHoursDaily<act->duration){
05445                                           okstudentsmaxhoursdaily=false;
05446                                           goto impossiblestudentsmaxhoursdaily;
05447                                    }
05448                                    
05449                                    if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 && subgroupsMaxGapsPerWeekMaxGaps[sbg]==0){
05450                                           if(newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNGaps(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d) > limitHoursDaily){
05451                                                  okstudentsmaxhoursdaily=false;
05452                                                  goto impossiblestudentsmaxhoursdaily;
05453                                           }
05454                                           else //OK
05455                                                  continue;
05456                                    }
05457                                    
05459                                    bool _ok;
05460                                    if(newSubgroupsDayNHours(sbg,d)>limitHoursDaily){
05461                                           _ok=false; //trivially
05462                                    }
05463                                    //basically, see that the gaps are enough
05464                                    else{
05465                                           if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
05466                                                  if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05467                                                         //both
05468                                                         int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05469                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05470                                                                if(d2!=d){
05471                                                                       int g=limitHoursDaily-newSubgroupsDayNHours(sbg,d2);
05472                                                                       //TODO: if g lower than 0 make g 0
05473                                                                       //but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s)
05474                                                                       g=newSubgroupsDayNFirstGaps(sbg,d2)+newSubgroupsDayNGaps(sbg,d2)-g;
05475                                                                       if(g>0)
05476                                                                              rg-=g;
05477                                                                }
05478                                                         }
05479                                                         
05480                                                         if(rg<0)
05481                                                                rg=0;
05482                                                         
05483                                                         int hg=newSubgroupsDayNGaps(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d)-rg;
05484                                                         if(hg<0)
05485                                                                hg=0;
05486                                                                
05487                                                         if(hg+newSubgroupsDayNHours(sbg,d) > limitHoursDaily){
05488                                                                _ok=false;
05489                                                         }
05490                                                         else
05491                                                                _ok=true;
05492                                                  }
05493                                                  else{
05494                                                         //only max beginnings
05495                                                         int lateBeginnings=0;
05496                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05497                                                                if(d2!=d){
05498                                                                       if(newSubgroupsDayNHours(sbg,d2)>=limitHoursDaily && newSubgroupsDayNFirstGaps(sbg,d2)==1)
05499                                                                              lateBeginnings++;
05500                                                                }
05501                                                         }
05502                                                         
05503                                                         int fg=0, ah=0; //first gaps, added hours
05504                                                         if(newSubgroupsDayNFirstGaps(sbg,d)==0){
05505                                                                fg=0;
05506                                                                ah=0;
05507                                                         }
05508                                                         else if(newSubgroupsDayNFirstGaps(sbg,d)==1){
05509                                                                fg=1;
05510                                                                ah=0;
05511                                                                if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 ||
05512                                                                 (subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]>0 &&
05513                                                                 lateBeginnings>=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]))
05514                                                                       ah+=fg;
05515                                                                
05516                                                         }
05517                                                         else if(newSubgroupsDayNFirstGaps(sbg,d)>=2){
05518                                                                fg=0;
05519                                                                ah=1;
05520                                                         }
05521                                                         
05522                                                         if(ah+newSubgroupsDayNHours(sbg,d) > limitHoursDaily){
05523                                                                _ok=false;
05524                                                         }
05525                                                         else
05526                                                                _ok=true;
05527                                                  }
05528                                           }
05529                                           else{
05530                                                  if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05531                                                         //only max gaps
05532                                                         int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg];
05533                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05534                                                                if(d2!=d){
05535                                                                       int g=limitHoursDaily-newSubgroupsDayNHours(sbg,d2);
05536                                                                       //TODO: if g lower than 0 make g 0
05537                                                                       //but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s)
05538                                                                       g=newSubgroupsDayNGaps(sbg,d2)-g;
05539                                                                       if(g>0)
05540                                                                              rg-=g;
05541                                                                }
05542                                                         }
05543                                                         
05544                                                         if(rg<0)
05545                                                                rg=0;
05546                                                         
05547                                                         int hg=newSubgroupsDayNGaps(sbg,d)-rg;
05548                                                         if(hg<0)
05549                                                                hg=0;
05550                                                                
05551                                                         if(hg+newSubgroupsDayNHours(sbg,d) > limitHoursDaily){
05552                                                                _ok=false;
05553                                                         }
05554                                                         else
05555                                                                _ok=true;
05556                                                  }
05557                                                  else{
05558                                                         //none
05559                                                         _ok=true;
05560                                                  }
05561                                           }
05562                                    }
05563                                    
05565                                    
05566                                    //preliminary test
05567                                    if(_ok){
05568                                           continue;
05569                                    }
05570                                    
05571                                    if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
05572                                           okstudentsmaxhoursdaily=false;
05573                                           goto impossiblestudentsmaxhoursdaily;
05574                                    }
05575                                    
05576                                    getSbgTimetable(sbg, conflActivities[newtime]);
05577                                    sbgGetNHoursGaps(sbg);
05578                                    
05579                                    //theoretically, it should be canTakeFromBegin = true all time and ctfAnywhere = true if max gaps per week is not 0.
05580                                    //but practically, I tried these changes and it was 30% slower for a modified german sample (with max gaps per day=1,
05581                                    //12 hours per day, removed subacts. pref. times, max hours daily 6 for students).
05582                                    bool canTakeFromBegin=(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]!=0); //-1 or >0
05583                                    bool canTakeFromEnd=true;
05584                                    bool canTakeFromAnywhere=(subgroupsMaxGapsPerWeekMaxGaps[sbg]==-1);
05585               
05586                                    for(;;){
05588                                           bool ok;
05589                                           if(sbgDayNHours[d]>limitHoursDaily){
05590                                                  ok=false;
05591                                           }
05592                                           else{
05593                                                  if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
05594                                                         if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05595                                                                //both
05596                                                                int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg];
05597                                                                for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05598                                                                       if(d2!=d){
05599                                                                              int g=limitHoursDaily-sbgDayNHours[d2];
05600                                                                              //TODO: if g lower than 0 make g 0
05601                                                                              //but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s)
05602                                                                              g=sbgDayNFirstGaps[d2]+sbgDayNGaps[d2]-g;
05603                                                                              if(g>0)
05604                                                                                     rg-=g;
05605                                                                       }
05606                                                                }
05607                                                                
05608                                                                if(rg<0)
05609                                                                       rg=0;
05610                                                                
05611                                                                int hg=sbgDayNGaps[d]+sbgDayNFirstGaps[d]-rg;
05612                                                                if(hg<0)
05613                                                                       hg=0;
05614                                                                
05615                                                                if(hg+sbgDayNHours[d] > limitHoursDaily){
05616                                                                       ok=false;
05617                                                                }
05618                                                                else
05619                                                                       ok=true;
05620                                                         }
05621                                                         else{
05622                                                                //only max beginnings
05623                                                                int lateBeginnings=0;
05624                                                                for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05625                                                                       if(d2!=d){
05626                                                                              if(sbgDayNHours[d2]>=limitHoursDaily && sbgDayNFirstGaps[d2]==1)
05627                                                                                     lateBeginnings++;
05628                                                                       }
05629                                                                }
05630                                                                
05631                                                                int fg=0, ah=0; //first gaps, added hours
05632                                                                if(sbgDayNFirstGaps[d]==0){
05633                                                                       fg=0;
05634                                                                       ah=0;
05635                                                                }
05636                                                                else if(sbgDayNFirstGaps[d]==1){
05637                                                                       fg=1;
05638                                                                       ah=0;
05639                                                                       if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 ||
05640                                                                        (subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]>0 &&
05641                                                                        lateBeginnings>=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]))
05642                                                                              ah+=fg;
05643                                                                       
05644                                                                }
05645                                                                else if(sbgDayNFirstGaps[d]>=2){
05646                                                                       fg=0;
05647                                                                       ah=1;
05648                                                                }
05649                                                         
05650                                                                if(ah+sbgDayNHours[d] > limitHoursDaily){
05651                                                                       ok=false;
05652                                                                }
05653                                                                else
05654                                                                       ok=true;
05655                                                         }
05656                                                  }
05657                                                  else{
05658                                                         if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
05659                                                                //only max gaps
05660                                                                int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg];
05661                                                                for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
05662                                                                       if(d2!=d){
05663                                                                              int g=limitHoursDaily-sbgDayNHours[d2];
05664                                                                              //TODO: if g lower than 0 make g 0
05665                                                                              //but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s)
05666                                                                              g=sbgDayNGaps[d2]-g;
05667                                                                              if(g>0)
05668                                                                                     rg-=g;
05669                                                                       }
05670                                                                }
05671                                                                
05672                                                                if(rg<0)
05673                                                                       rg=0;
05674                                                                
05675                                                                int hg=sbgDayNGaps[d]-rg;
05676                                                                if(hg<0)
05677                                                                       hg=0;
05678                                                                
05679                                                                if(hg+sbgDayNHours[d] > limitHoursDaily){
05680                                                                       ok=false;
05681                                                                }
05682                                                                else
05683                                                                       ok=true;
05684                                                         }
05685                                                         else{
05686                                                                //none
05687                                                                ok=true;
05688                                                         }
05689                                                  }
05690                                           }
05692                                    
05693                                           if(ok){
05694                                                  break;
05695                                           }
05696                                           
05697                                           int ai2=-1;
05698 
05699                                           bool kk=false;
05700                                           if(canTakeFromEnd)
05701                                                  kk=subgroupRemoveAnActivityFromEndCertainDay(sbg, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05702                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05703                                           if(!kk){
05704                                                  canTakeFromEnd=false;
05705                                                  bool k=false;
05706                                                  if(canTakeFromBegin){
05707                                                         k=subgroupRemoveAnActivityFromBeginCertainDay(sbg, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05708                                                         if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]>0)
05709                                                                canTakeFromBegin=false;
05710                                                  }
05711                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05712                                                  if(!k){
05713                                                         canTakeFromBegin=false;
05714                                                         bool ka=false;
05715                                                         if(canTakeFromAnywhere)
05716                                                                ka=subgroupRemoveAnActivityFromAnywhereCertainDay(sbg, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
05717                                                         assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05718                                                         
05719                                                         if(!ka){
05720                                                                if(level==0){
05721                                                                       /*cout<<"subgroup=="<<qPrintable(gt.rules.internalSubgroupsList[sbg]->name)<<endl;
05722                                                                       cout<<"d=="<<d<<endl;
05723                                                                       cout<<"H="<<H<<endl;
05724                                                                       cout<<"Timetable:"<<endl;
05725                                                                       for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
05726                                                                              for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++)
05727                                                                                     cout<<"\t"<<sbgTimetable(d2,h2)<<"\t";
05728                                                                              cout<<endl;
05729                                                                       }*/
05730                                                                
05731                                                                       //this should not be displayed
05732                                                                       //cout<<"WARNING - file "<<__FILE__<<" line "<<__LINE__<<endl;
05733                                                                }
05734                                                                okstudentsmaxhoursdaily=false;
05735                                                                goto impossiblestudentsmaxhoursdaily;
05736                                                         }
05737                                                  }
05738                                           }
05739               
05740                                           assert(ai2>=0);
05741 
05742                                           removeAi2FromSbgTimetable(ai2);
05743                                           updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek);
05744                                    }
05745                             }
05746                      }
05747               }
05748               
05749 impossiblestudentsmaxhoursdaily:
05750               if(!okstudentsmaxhoursdaily){
05751                      if(updateSubgroups || updateTeachers)
05752                             removeAiFromNewTimetable(ai, act, d, h);
05753                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
05754 
05755                      nConflActivities[newtime]=MAX_ACTIVITIES;
05756                      continue;
05757               }
05758                             
05760 
05761               //allowed from students max hours continuously
05762               
05763               okstudentsmaxhourscontinuously=true;
05764               
05765               foreach(int sbg, act->iSubgroupsList){
05766                      for(int count=0; count<2; count++){
05767                             int limitHoursCont;
05768                             double percentage;
05769                             if(count==0){
05770                                    limitHoursCont=subgroupsMaxHoursContinuouslyMaxHours1[sbg];
05771                                    percentage=subgroupsMaxHoursContinuouslyPercentages1[sbg];
05772                             }
05773                             else{
05774                                    limitHoursCont=subgroupsMaxHoursContinuouslyMaxHours2[sbg];
05775                                    percentage=subgroupsMaxHoursContinuouslyPercentages2[sbg];
05776                             }
05777                             
05778                             if(limitHoursCont<0) //no constraint
05779                                    continue;
05780                             
05781                             //if(fixedTimeActivity[ai] && percentage<100.0) //added on 21 Feb. 2009 in FET 5.9.1, to solve a bug of impossible timetables for fixed timetables
05782                             //     continue;
05783                             
05784                             bool increased;
05785                             int h2;
05786                             for(h2=h; h2<h+act->duration; h2++){
05787                                    assert(h2<gt.rules.nHoursPerDay);
05788                                    if(subgroupsTimetable(sbg,d,h2)==-1)
05789                                           break;
05790                             }
05791                             if(h2<h+act->duration)
05792                                    increased=true;
05793                             else
05794                                    increased=false;
05795                                    
05796                             QList<int> removableActs;
05797                                    
05798                             int nc=act->duration;
05799                             for(h2=h-1; h2>=0; h2--){
05800                                    int ai2=subgroupsTimetable(sbg,d,h2);
05801                                    assert(ai2==newSubgroupsTimetable(sbg,d,h2));
05802                                    assert(ai2!=ai);
05803                                    if(ai2>=0 && !conflActivities[newtime].contains(ai2)){
05804                                           nc++;
05805                                           
05806                                           if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
05807                                                  removableActs.append(ai2);
05808                                    }
05809                                    else
05810                                           break;
05811                             }                           
05812                             for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){
05813                                    int ai2=subgroupsTimetable(sbg,d,h2);
05814                                    assert(ai2==newSubgroupsTimetable(sbg,d,h2));
05815                                    assert(ai2!=ai);
05816                                    if(ai2>=0 && !conflActivities[newtime].contains(ai2)){
05817                                           nc++;
05818                                           
05819                                           if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
05820                                                  removableActs.append(ai2);
05821                                    }
05822                                    else
05823                                           break;
05824                             }
05825                                                                       
05826                             if(!increased && percentage==100.0)
05827                                    assert(nc<=limitHoursCont);
05828                                    
05829                             if(!increased || nc<=limitHoursCont) //OK
05830                                    continue;
05831                                    
05832                             assert(limitHoursCont>=0);
05833 
05834                             if(!skipRandom(percentage) && increased){
05835                                    if(act->duration>limitHoursCont){
05836                                           okstudentsmaxhourscontinuously=false;
05837                                           goto impossiblestudentsmaxhourscontinuously;
05838                                    }
05839                                    
05840                                    if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
05841                                           okstudentsmaxhourscontinuously=false;
05842                                           goto impossiblestudentsmaxhourscontinuously;
05843                                    }
05844                                    
05845                                    while(true){
05846                                           if(removableActs.count()==0){
05847                                                  okstudentsmaxhourscontinuously=false;
05848                                                  goto impossiblestudentsmaxhourscontinuously;
05849                                           }
05850                                           
05851                                           int j=-1;
05852                                    
05853                                           if(level==0){
05854                                                  int optMinWrong=INF;
05855                      
05856                                                  QList<int> tl;
05857 
05858                                                  for(int q=0; q<removableActs.count(); q++){
05859                                                         int ai2=removableActs.at(q);
05860                                                         if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
05861                                                                optMinWrong=triedRemovals(ai2,c.times[ai2]);
05862                                                         }
05863                                                  }
05864                             
05865                                                  for(int q=0; q<removableActs.count(); q++){
05866                                                         int ai2=removableActs.at(q);
05867                                                         if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
05868                                                                tl.append(q);
05869                                                  }
05870                      
05871                                                  assert(tl.size()>=1);
05872                                                  j=tl.at(randomKnuth(tl.size()));
05873                      
05874                                                  assert(j>=0 && j<removableActs.count());
05875                                           }
05876                                           else{
05877                                                  j=randomKnuth(removableActs.count());
05878                                           }
05879                                           
05880                                           assert(j>=0);
05881                                           
05882                                           int ai2=removableActs.at(j);
05883                                           
05884                                           int t=removableActs.removeAll(ai2);
05885                                           assert(t==1);
05886                                           
05887                                           assert(!conflActivities[newtime].contains(ai2));
05888                                           conflActivities[newtime].append(ai2);
05889                                           nConflActivities[newtime]++;
05890                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
05891                                           
05893                                           removableActs.clear();
05894                                           
05895                                           int nc=act->duration;
05896                                           int h2;
05897                                           for(h2=h-1; h2>=0; h2--){
05898                                                  int ai2=subgroupsTimetable(sbg,d,h2);
05899                                                  assert(ai2==newSubgroupsTimetable(sbg,d,h2));
05900                                                  assert(ai2!=ai);
05901                                                  if(ai2>=0 && !conflActivities[newtime].contains(ai2)){
05902                                                         nc++;
05903                                                  
05904                                                         if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
05905                                                                removableActs.append(ai2);
05906                                                  }
05907                                                  else
05908                                                         break;
05909                                           }                           
05910                                           for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){
05911                                                  int ai2=subgroupsTimetable(sbg,d,h2);
05912                                                  assert(ai2==newSubgroupsTimetable(sbg,d,h2));
05913                                                  assert(ai2!=ai);
05914                                                  if(ai2>=0 && !conflActivities[newtime].contains(ai2)){
05915                                                         nc++;
05916                                           
05917                                                         if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
05918                                                                removableActs.append(ai2);
05919                                                  }
05920                                                  else          
05921                                                         break;
05922                                           }
05923                                                                       
05924                                           if(nc<=limitHoursCont) //OK
05925                                                  break;
05927                                    }
05928                             }
05929                      }
05930               }
05931               
05932 impossiblestudentsmaxhourscontinuously:
05933               if(!okstudentsmaxhourscontinuously){
05934                      if(updateSubgroups || updateTeachers)
05935                             removeAiFromNewTimetable(ai, act, d, h);
05936                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
05937 
05938                      nConflActivities[newtime]=MAX_ACTIVITIES;
05939                      continue;
05940               }
05941                             
05943 
05944               //allowed from students activity tag max hours daily
05945               
05947               
05948               okstudentsactivitytagmaxhoursdaily=true;
05949               
05950               if(haveStudentsActivityTagMaxHoursDaily){
05951        
05952                      foreach(int sbg, act->iSubgroupsList){
05953                             for(int cnt=0; cnt<subgroupsActivityTagMaxHoursDailyMaxHours[sbg].count(); cnt++){
05954                                    int activityTag=subgroupsActivityTagMaxHoursDailyActivityTag[sbg].at(cnt);
05955                             
05956                                    if(!gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(activityTag))
05957                                           continue;
05958 
05959                                    int limitHoursDaily=subgroupsActivityTagMaxHoursDailyMaxHours[sbg].at(cnt);
05960                                    double percentage=subgroupsActivityTagMaxHoursDailyPercentage[sbg].at(cnt);
05961 
05962                                    assert(limitHoursDaily>=0);
05963                                    assert(percentage>=0);
05964                                    assert(activityTag>=0 /*&& activityTag<gt.rules.nInternalActivityTags*/);
05965 
05966                                    //if(fixedTimeActivity[ai] && percentage<100.0) //added on 21 Feb. 2009 in FET 5.9.1, to solve a bug of impossible timetables for fixed timetables
05967                                    //     continue;
05968                             
05969                                    bool increased;
05970                                    
05971                                    int nold=0, nnew=0;
05973                                    for(int h2=0; h2<h; h2++){
05974                                           if(newSubgroupsTimetable(sbg,d,h2)>=0){
05975                                                  int ai2=newSubgroupsTimetable(sbg,d,h2);
05976                                                  assert(ai2>=0 && ai2<gt.rules.nInternalActivities);
05977                                                  Activity* act=&gt.rules.internalActivitiesList[ai2];
05978                                                  if(act->iActivityTagsSet.contains(activityTag)){
05979                                                         nold++;
05980                                                         nnew++;
05981                                                  }
05982                                           }
05983                                    }
05984                                    for(int h2=h; h2<h+act->duration; h2++){
05985                                           if(oldSubgroupsTimetable(sbg,d,h2)>=0){
05986                                                  int ai2=oldSubgroupsTimetable(sbg,d,h2);
05987                                                  assert(ai2>=0 && ai2<gt.rules.nInternalActivities);
05988                                                  Activity* act=&gt.rules.internalActivitiesList[ai2];
05989                                                  if(act->iActivityTagsSet.contains(activityTag))
05990                                                         nold++;
05991                                           }
05992                                    }
05993                                    for(int h2=h; h2<h+act->duration; h2++){
05994                                           if(newSubgroupsTimetable(sbg,d,h2)>=0){
05995                                                  int ai2=newSubgroupsTimetable(sbg,d,h2);
05996                                                  assert(ai2>=0 && ai2<gt.rules.nInternalActivities);
05997                                                  Activity* act=&gt.rules.internalActivitiesList[ai2];
05998                                                  if(act->iActivityTagsSet.contains(activityTag))
05999                                                         nnew++;
06000                                           }
06001                                    }
06002                                    for(int h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){
06003                                           if(newSubgroupsTimetable(sbg,d,h2)>=0){
06004                                                  int ai2=newSubgroupsTimetable(sbg,d,h2);
06005                                                  assert(ai2>=0 && ai2<gt.rules.nInternalActivities);
06006                                                  Activity* act=&gt.rules.internalActivitiesList[ai2];
06007                                                  if(act->iActivityTagsSet.contains(activityTag)){
06008                                                         nold++;
06009                                                         nnew++;
06010                                                  }
06011                                           }
06012                                    }
06014                                    if(nold<nnew)
06015                                           increased=true;
06016                                    else
06017                                           increased=false;
06018                                           
06019                                    if(percentage==100.0)
06020                                           assert(nold<=limitHoursDaily);
06021                                    if(!increased && percentage==100.0)
06022                                           assert(nnew<=limitHoursDaily);
06023                                    
06024                                    if(!increased || nnew<=limitHoursDaily) //OK
06025                                           continue;
06026                                           
06027                                    assert(limitHoursDaily>=0);
06028        
06029                                    assert(increased);
06030                                    assert(nnew>limitHoursDaily);
06031                                    if(!skipRandom(percentage)){
06032                                           if(act->duration>limitHoursDaily){
06033                                                  okstudentsactivitytagmaxhoursdaily=false;
06034                                                  goto impossiblestudentsactivitytagmaxhoursdaily;
06035                                           }
06036                                    
06037                                           if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
06038                                                  okstudentsactivitytagmaxhoursdaily=false;
06039                                                  goto impossiblestudentsactivitytagmaxhoursdaily;
06040                                           }
06041                                    
06042                                           getSbgTimetable(sbg, conflActivities[newtime]);
06043                                           sbgGetNHoursGaps(sbg);
06044        
06045                                           while(true){
06046                                                  int ncrt=0;
06047                                                  for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
06048                                                         if(sbgTimetable(d,h2)>=0){
06049                                                                int ai2=sbgTimetable(d,h2);
06050                                                                assert(ai2>=0 && ai2<gt.rules.nInternalActivities);
06051                                                                Activity* act=&gt.rules.internalActivitiesList[ai2];
06052                                                                if(act->iActivityTagsSet.contains(activityTag))
06053                                                                       ncrt++;
06054                                                         }
06055                                                  }
06056                                                  
06057                                                  if(ncrt<=limitHoursDaily)
06058                                                         break;
06059                                           
06060                                                  int ai2=-1;
06061                                                  
06062                                                  bool ke=subgroupRemoveAnActivityFromAnywhereCertainDayCertainActivityTag(sbg, d, activityTag, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
06063                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06064                                                  
06065                                                  if(!ke){
06066                                                         if(level==0){
06067                                                                //...this is not too good, but hopefully there is no problem
06068                                                         }
06069                                                         okstudentsactivitytagmaxhoursdaily=false;
06070                                                         goto impossiblestudentsactivitytagmaxhoursdaily;
06071                                                  }
06072                                                  
06073                                                  assert(ai2>=0);
06074                                                  
06075                                                  assert(gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag));
06076                                                  
06077                                                  removeAi2FromSbgTimetable(ai2);
06078                                                  updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek);
06079                                           }
06080                                    }
06081                             }
06082                      }
06083                      
06084               }
06085               
06086 impossiblestudentsactivitytagmaxhoursdaily:
06087               if(!okstudentsactivitytagmaxhoursdaily){
06088                      if(updateSubgroups || updateTeachers)
06089                             removeAiFromNewTimetable(ai, act, d, h);
06090                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
06091 
06092                      nConflActivities[newtime]=MAX_ACTIVITIES;
06093                      continue;
06094               }
06095                             
06097 
06098               //allowed from students activity tag max hours continuously
06099               
06100               okstudentsactivitytagmaxhourscontinuously=true;
06101               
06102               if(haveStudentsActivityTagMaxHoursContinuously){
06103        
06104                      foreach(int sbg, act->iSubgroupsList){
06105                             for(int cnt=0; cnt<subgroupsActivityTagMaxHoursContinuouslyMaxHours[sbg].count(); cnt++){
06106                                    int activityTag=subgroupsActivityTagMaxHoursContinuouslyActivityTag[sbg].at(cnt);
06107                             
06108                                    //if(gt.rules.internalActivitiesList[ai].activityTagIndex!=activityTag)
06109                                    //     continue;
06110                                    if(!gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(activityTag))
06111                                           continue;
06112 
06113                                    int limitHoursCont=subgroupsActivityTagMaxHoursContinuouslyMaxHours[sbg].at(cnt);
06114                                    double percentage=subgroupsActivityTagMaxHoursContinuouslyPercentage[sbg].at(cnt);
06115 
06116                                    assert(limitHoursCont>=0);
06117                                    assert(percentage>=0);
06118                                    assert(activityTag>=0 /*&& activityTag<gt.rules.nInternalActivityTags*/);
06119 
06120                                    //if(fixedTimeActivity[ai] && percentage<100.0) //added on 21 Feb. 2009 in FET 5.9.1, to solve a bug of impossible timetables for fixed timetables
06121                                    //     continue;
06122                             
06123                                    bool increased;
06124                                    int h2;
06125                                    for(h2=h; h2<h+act->duration; h2++){
06126                                           assert(h2<gt.rules.nHoursPerDay);
06127                                           if(subgroupsTimetable(sbg,d,h2)==-1)
06128                                                  break;
06129                                           int ai2=subgroupsTimetable(sbg,d,h2);
06130                                           assert(ai2>=0);
06131                                           //if(gt.rules.internalActivitiesList[ai2].activityTagIndex!=activityTag)
06132                                           //     break;
06133                                           if(!gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag))
06134                                                  break;
06135                                    }
06136                                    if(h2<h+act->duration)
06137                                           increased=true;
06138                                    else
06139                                           increased=false;
06140                                    
06141                                    QList<int> removableActs;
06142                                           
06143                                    int nc=act->duration;
06144                                    for(h2=h-1; h2>=0; h2--){
06145                                           int ai2=subgroupsTimetable(sbg,d,h2);
06146                                           assert(ai2==newSubgroupsTimetable(sbg,d,h2));
06147                                           assert(ai2!=ai);
06148                                           if(ai2<0)
06149                                                  break;
06150                                           if(ai2>=0 && !conflActivities[newtime].contains(ai2) && 
06151                                            //gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){
06152                                            gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){
06153                                                  nc++;
06154                                                  
06155                                                  if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
06156                                                         removableActs.append(ai2);
06157                                           }
06158                                           else
06159                                                  break;
06160                                    }                           
06161                                    for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){
06162                                           int ai2=subgroupsTimetable(sbg,d,h2);
06163                                           assert(ai2==newSubgroupsTimetable(sbg,d,h2));
06164                                           assert(ai2!=ai);
06165                                           if(ai2<0)
06166                                                  break;
06167                                           if(ai2>=0 && !conflActivities[newtime].contains(ai2) && 
06168                                            //gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){
06169                                            gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){
06170                                                  nc++;
06171                                                  
06172                                                  if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
06173                                                         removableActs.append(ai2);
06174                                           }
06175                                           else
06176                                                  break;
06177                                    }
06178                                                                       
06179                                    if(!increased && percentage==100.0)
06180                                           assert(nc<=limitHoursCont);
06181                                    
06182                                    if(!increased || nc<=limitHoursCont) //OK
06183                                           continue;
06184                                           
06185                                    assert(limitHoursCont>=0);
06186        
06187                                    if(!skipRandom(percentage) && increased){
06188                                           if(act->duration>limitHoursCont){
06189                                                  okstudentsactivitytagmaxhourscontinuously=false;
06190                                                  goto impossiblestudentsactivitytagmaxhourscontinuously;
06191                                           }
06192                                    
06193                                           if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
06194                                                  okstudentsactivitytagmaxhourscontinuously=false;
06195                                                  goto impossiblestudentsactivitytagmaxhourscontinuously;
06196                                           }
06197                                    
06198                                           while(true){
06199                                                  if(removableActs.count()==0){
06200                                                         okstudentsactivitytagmaxhourscontinuously=false;
06201                                                         goto impossiblestudentsactivitytagmaxhourscontinuously;
06202                                                  }
06203                                                  
06204                                                  int j=-1;
06205                                           
06206                                                  if(level==0){
06207                                                         int optMinWrong=INF;
06208                             
06209                                                         QList<int> tl;
06210        
06211                                                         for(int q=0; q<removableActs.count(); q++){
06212                                                                int ai2=removableActs.at(q);
06213                                                                if(optMinWrong>triedRemovals(ai2,c.times[ai2])){
06214                                                                       optMinWrong=triedRemovals(ai2,c.times[ai2]);
06215                                                                }
06216                                                         }
06217                             
06218                                                         for(int q=0; q<removableActs.count(); q++){
06219                                                                int ai2=removableActs.at(q);
06220                                                                if(optMinWrong==triedRemovals(ai2,c.times[ai2]))
06221                                                                       tl.append(q);
06222                                                         }
06223                             
06224                                                         assert(tl.size()>=1);
06225                                                         j=tl.at(randomKnuth(tl.size()));
06226                             
06227                                                         assert(j>=0 && j<removableActs.count());
06228                                                  }
06229                                                  else{
06230                                                         j=randomKnuth(removableActs.count());
06231                                                  }
06232                                           
06233                                                  assert(j>=0);
06234                                                  
06235                                                  int ai2=removableActs.at(j);
06236                                                  
06237                                                  int t=removableActs.removeAll(ai2);
06238                                                  assert(t==1);
06239                                           
06240                                                  assert(!conflActivities[newtime].contains(ai2));
06241                                                  conflActivities[newtime].append(ai2);
06242                                                  nConflActivities[newtime]++;
06243                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06244                                                  
06246                                                  removableActs.clear();
06247                                                  
06248                                                  int nc=act->duration;
06249                                                  int h2;
06250                                                  for(h2=h-1; h2>=0; h2--){
06251                                                         int ai2=subgroupsTimetable(sbg,d,h2);
06252                                                         assert(ai2==newSubgroupsTimetable(sbg,d,h2));
06253                                                         assert(ai2!=ai);
06254                                                         if(ai2<0)
06255                                                                break;
06256                                                         if(ai2>=0 && !conflActivities[newtime].contains(ai2) && 
06257                                                          //gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){
06258                                                          gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){
06259                                                                nc++;
06260                                                         
06261                                                                if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
06262                                                                       removableActs.append(ai2);
06263                                                         }
06264                                                         else
06265                                                                break;
06266                                                  }                           
06267                                                  for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){
06268                                                         int ai2=subgroupsTimetable(sbg,d,h2);
06269                                                         assert(ai2==newSubgroupsTimetable(sbg,d,h2));
06270                                                         assert(ai2!=ai);
06271                                                         if(ai2<0)
06272                                                                break;
06273                                                         if(ai2>=0 && !conflActivities[newtime].contains(ai2) &&
06274                                                          //gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){
06275                                                          gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){
06276                                                                nc++;
06277                                                  
06278                                                                if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2])
06279                                                                       removableActs.append(ai2);
06280                                                         }
06281                                                         else          
06282                                                                break;
06283                                                  }
06284                                                                              
06285                                                  if(nc<=limitHoursCont) //OK
06286                                                         break;
06288                                           }
06289                                    }
06290                             }
06291                      }
06292                      
06293               }
06294               
06295 impossiblestudentsactivitytagmaxhourscontinuously:
06296               if(!okstudentsactivitytagmaxhourscontinuously){
06297                      if(updateSubgroups || updateTeachers)
06298                             removeAiFromNewTimetable(ai, act, d, h);
06299                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
06300 
06301                      nConflActivities[newtime]=MAX_ACTIVITIES;
06302                      continue;
06303               }
06304                             
06306 
06308               
06309               //TODO: this should take care of students max gaps per day also. Very critical changes, so be very careful if you do them. Safer -> leave them as they are now.
06310               //see file fet-v.v.v/doc/algorithm/improve-studentsmaxgapsperday.txt for advice and (unstable) code on how to make students max gaps per day constraint perfect
06311               okstudentsminhoursdaily=true;
06312               
06313               foreach(int sbg, act->iSubgroupsList){
06314                      if(subgroupsMinHoursDailyMinHours[sbg]>=0){
06315                             assert(subgroupsMinHoursDailyPercentages[sbg]==100);
06316                             
06317                             bool allowEmptyDays=subgroupsMinHoursDailyAllowEmptyDays[sbg];
06318                      
06319                             bool skip=skipRandom(subgroupsMinHoursDailyPercentages[sbg]);
06320                             if(!skip){
06321                                    //preliminary test
06322                                    bool _ok;
06323                                    if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
06324                                           if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
06325                                                  //both limitations
06326                                                  int remG=0, totalH=0;
06327                                                  for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06328                                                         int remGDay=newSubgroupsDayNFirstGaps(sbg,d2)+newSubgroupsDayNGaps(sbg,d2);
06329                                                         if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){
06330                                                                if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]){
06331                                                                       remGDay-=subgroupsMinHoursDailyMinHours[sbg]-newSubgroupsDayNHours(sbg,d2);
06332                                                                       totalH+=subgroupsMinHoursDailyMinHours[sbg];
06333                                                                }
06334                                                                else
06335                                                                       totalH+=newSubgroupsDayNHours(sbg,d2);
06336                                                         }
06337                                                         if(remGDay>0)
06338                                                                remG+=remGDay;
06339                                                  }
06340                                                  if((remG+totalH <= nHoursPerSubgroup[sbg]
06341                                                    +subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg])
06342                                                    && (totalH <= nHoursPerSubgroup[sbg]))
06343                                                         _ok=true;
06344                                                  else
06345                                                         _ok=false;
06346                                           }
06347                                           else{
06348                                                  //only first gaps limitation
06349                                                  int remG=0, totalH=0;
06350                                                  for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06351                                                         int remGDay=0;
06352                                                         if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){
06353                                                                if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]){
06354                                                                       remGDay=0;
06355                                                                       totalH+=subgroupsMinHoursDailyMinHours[sbg];
06356                                                                }
06357                                                                else{
06358                                                                       totalH+=newSubgroupsDayNHours(sbg,d2);
06359                                                                       if(newSubgroupsDayNFirstGaps(sbg,d2)==0)
06360                                                                              remGDay=0;
06361                                                                       else if(newSubgroupsDayNFirstGaps(sbg,d2)==1)
06362                                                                              remGDay=1;
06363                                                                       else if(newSubgroupsDayNFirstGaps(sbg,d2)>=2){
06364                                                                              remGDay=0;
06365                                                                              totalH++;
06366                                                                       }
06367                                                                }
06368                                                         }
06369                                                         if(remGDay>0)
06370                                                                remG+=remGDay;
06371                                                  }
06372                                                  if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg])
06373                                                    && (totalH <= nHoursPerSubgroup[sbg]))
06374                                                         _ok=true;
06375                                                  else
06376                                                         _ok=false;
06377                                           }
06378                                    }
06379                                    else{
06380                                           if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
06381                                                  //only max gaps per week limitation
06382                                                  int remG=0, totalH=0;
06383                                                  for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06384                                                         int remGDay=newSubgroupsDayNGaps(sbg,d2);
06385                                                         if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){
06386                                                                if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]){
06387                                                                       remGDay-=subgroupsMinHoursDailyMinHours[sbg]-newSubgroupsDayNHours(sbg,d2);
06388                                                                       totalH+=subgroupsMinHoursDailyMinHours[sbg];
06389                                                                }
06390                                                                else
06391                                                                       totalH+=newSubgroupsDayNHours(sbg,d2);
06392                                                         }
06393                                                         if(remGDay>0)
06394                                                                remG+=remGDay;
06395                                                  }
06396                                                  if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg])
06397                                                    && (totalH <= nHoursPerSubgroup[sbg]))
06398                                                         _ok=true;
06399                                                  else
06400                                                         _ok=false;
06401                                           }
06402                                           else{
06403                                                  //no limitation
06404                                                  int totalH=0;
06405                                                  for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06406                                                         if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){
06407                                                                if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg])
06408                                                                       totalH+=subgroupsMinHoursDailyMinHours[sbg];
06409                                                                else
06410                                                                       totalH+=newSubgroupsDayNHours(sbg,d2);
06411                                                         }
06412                                                  }
06413                                                  if(totalH <= nHoursPerSubgroup[sbg])
06414                                                         _ok=true;
06415                                                  else
06416                                                         _ok=false;
06417                                           }
06418                                    }
06419                                    
06420                                    if(_ok)
06421                                           continue;
06422                             
06423                                    if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
06424                                           okstudentsminhoursdaily=false;
06425                                           goto impossiblestudentsminhoursdaily;
06426                                    }
06427 
06428                                    getSbgTimetable(sbg, conflActivities[newtime]);
06429                                    sbgGetNHoursGaps(sbg);
06430               
06431                                    for(;;){
06432                                           bool ok;
06434                                           if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){
06435                                                  if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
06436                                                         //both limitations
06437                                                         int remG=0, totalH=0;
06438                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06439                                                                int remGDay=sbgDayNFirstGaps[d2]+sbgDayNGaps[d2];
06440                                                                if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){
06441                                                                       if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]){
06442                                                                              remGDay-=subgroupsMinHoursDailyMinHours[sbg]-sbgDayNHours[d2];
06443                                                                              totalH+=subgroupsMinHoursDailyMinHours[sbg];
06444                                                                       }
06445                                                                       else
06446                                                                              totalH+=sbgDayNHours[d2];
06447                                                                }
06448                                                                if(remGDay>0)
06449                                                                       remG+=remGDay;
06450                                                         }
06451                                                         if((remG+totalH <= nHoursPerSubgroup[sbg]
06452                                                           +subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg])
06453                                                           && (totalH <= nHoursPerSubgroup[sbg]))
06454                                                                ok=true;
06455                                                         else
06456                                                                ok=false;
06457                                                  }
06458                                                  else{
06459                                                         //only first gaps limitation
06460                                                         int remG=0, totalH=0;
06461                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06462                                                                int remGDay=0;
06463                                                                if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){
06464                                                                       if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]){
06465                                                                              remGDay=0;
06466                                                                              totalH+=subgroupsMinHoursDailyMinHours[sbg];
06467                                                                       }
06468                                                                       else{
06469                                                                              totalH+=sbgDayNHours[d2];
06470                                                                              if(sbgDayNFirstGaps[d2]==0)
06471                                                                                     remGDay=0;
06472                                                                              else if(sbgDayNFirstGaps[d2]==1)
06473                                                                                     remGDay=1;
06474                                                                              else if(sbgDayNFirstGaps[d2]>=2){
06475                                                                                     remGDay=0;
06476                                                                                     totalH++;
06477                                                                              }
06478                                                                       }
06479                                                                }
06480                                                                if(remGDay>0)
06481                                                                       remG+=remGDay;
06482                                                         }
06483                                                         if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg])
06484                                                           && (totalH <= nHoursPerSubgroup[sbg]))
06485                                                                ok=true;
06486                                                         else
06487                                                                ok=false;
06488                                                  }
06489                                           }
06490                                           else{
06491                                                  if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){
06492                                                         //only max gaps per week limitation
06493                                                         int remG=0, totalH=0;
06494                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06495                                                                int remGDay=sbgDayNGaps[d2];
06496                                                                if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){
06497                                                                       if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]){
06498                                                                              remGDay-=subgroupsMinHoursDailyMinHours[sbg]-sbgDayNHours[d2];
06499                                                                              totalH+=subgroupsMinHoursDailyMinHours[sbg];
06500                                                                       }
06501                                                                       else
06502                                                                              totalH+=sbgDayNHours[d2];
06503                                                                }
06504                                                                if(remGDay>0)
06505                                                                       remG+=remGDay;
06506                                                         }
06507                                                         if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg])
06508                                                           && (totalH <= nHoursPerSubgroup[sbg]))
06509                                                                ok=true;
06510                                                         else
06511                                                                ok=false;
06512                                                  }
06513                                                  else{
06514                                                         //no limitation
06515                                                         int totalH=0;
06516                                                         for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06517                                                                if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){
06518                                                                       if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg])
06519                                                                              totalH+=subgroupsMinHoursDailyMinHours[sbg];
06520                                                                       else
06521                                                                              totalH+=sbgDayNHours[d2];
06522                                                                }
06523                                                         }
06524                                                         if(totalH <= nHoursPerSubgroup[sbg])
06525                                                                ok=true;
06526                                                         else
06527                                                                ok=false;
06528                                                  }
06529                                           }
06531 
06532                                           if(ok)
06533                                                  break; //ok
06534                                                                                            
06535                                           int ai2=-1;
06536                                           
06537                                           bool kk=subgroupRemoveAnActivityFromEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
06538                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06539                                           if(!kk){
06540                                                  bool k=subgroupRemoveAnActivityFromBegin(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
06541                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06542                                                  if(!k){
06543                                                         bool ka=subgroupRemoveAnActivityFromAnywhere(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
06544                                                         assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06545                                                         
06546                                                         if(!ka){
06547                                                                if(level==0){
06548                                                                       /*cout<<"d=="<<d<<", h=="<<h<<", ai=="<<ai<<endl;
06549                                                                       for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){
06550                                                                              for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++)
06551                                                                                     cout<<"\t"<<sbgTimetable(d2,h2);
06552                                                                              cout<<endl;
06553                                                                       }*/
06554                                                                
06555                                                                       //this should not be displayed
06556                                                                       //cout<<"WARNING - unlikely situation - file "<<__FILE__<<" line "<<__LINE__<<endl;
06557                                                                }
06558                                                                okstudentsminhoursdaily=false;
06559                                                                goto impossiblestudentsminhoursdaily;
06560                                                         }
06561                                                  }
06562                                           }
06563 
06564                                           assert(ai2>=0);
06565 
06566                                           removeAi2FromSbgTimetable(ai2);
06567                                           updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek);
06568                                    }
06569                             }
06570                      }
06571               }
06572               
06573 impossiblestudentsminhoursdaily:
06574               if(!okstudentsminhoursdaily){
06575                      if(updateSubgroups || updateTeachers)
06576                             removeAiFromNewTimetable(ai, act, d, h);
06577                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
06578 
06579                      nConflActivities[newtime]=MAX_ACTIVITIES;
06580                      continue;
06581               }
06582               
06584 
06585 
06586 
06588 
06589 
06591 
06593 
06594               //not breaking the teacher max days per week constraints
06596               okteachermaxdaysperweek=true;
06597               //foreach(int tch, act->iTeachersList){
06598               foreach(int tch, teachersWithMaxDaysPerWeekForActivities[ai]){
06599                      if(skipRandom(teachersMaxDaysPerWeekWeightPercentages[tch]))
06600                             continue;
06601 
06602                      int maxDays=teachersMaxDaysPerWeekMaxDays[tch];
06603                      assert(maxDays>=0); //the list contains real information
06604                      
06605                      //preliminary test
06606                      int _nOc=0;
06607                      for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++)
06608                             //if(newTeachersDayNHours(tch,d2)>0)
06609                             
06610                             //IT IS VITAL TO USE teacherActivitiesOfTheDay as a QList<int> (tch,d2)!!!!!!!
06611                             //The order of evaluation of activities is changed,
06612                             //with activities which were moved forward and back again
06613                             //being put at the end.
06614                             //If you do not follow this, you'll get impossible timetables
06615                             //for italian sample or samples from South Africa, I am not sure which of these 2
06616                                                         
06617                             if(teacherActivitiesOfTheDay(tch,d2).count()>0 || d2==d)
06618                                    _nOc++;
06619                      if(_nOc<=maxDays)
06620                             continue; //OK, preliminary
06621                      
06622                      if(maxDays>=0){
06623                             assert(maxDays>0);
06624                             
06625                             //getTchTimetable(tch, conflActivities[newtime]);
06626                             //tchGetNHoursGaps(tch);
06627 
06628                             bool occupiedDay[MAX_DAYS_PER_WEEK];
06629                             bool canEmptyDay[MAX_DAYS_PER_WEEK];
06630                             
06631                             int _minWrong[MAX_DAYS_PER_WEEK];
06632                             int _nWrong[MAX_DAYS_PER_WEEK];
06633                             int _nConflActivities[MAX_DAYS_PER_WEEK];
06634                             int _minIndexAct[MAX_DAYS_PER_WEEK];
06635                             
06636                             QList<int> _activitiesForDay[MAX_DAYS_PER_WEEK];
06637 
06638                             for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06639                                    if(d2==d)
06640                                           continue;
06641                             
06642                                    occupiedDay[d2]=false;
06643                                    canEmptyDay[d2]=true;
06644                                    
06645                                    _minWrong[d2]=INF;
06646                                    _nWrong[d2]=0;
06647                                    _nConflActivities[d2]=0;
06648                                    _minIndexAct[d2]=gt.rules.nInternalActivities;
06649                                    _activitiesForDay[d2].clear();
06650                                    
06651                                    foreach(int ai2, teacherActivitiesOfTheDay(tch,d2)){
06652                                           if(ai2>=0){
06653                                                  if(!conflActivities[newtime].contains(ai2)){
06654                                                         occupiedDay[d2]=true;
06655                                                         if(fixedTimeActivity[ai2] || swappedActivities[ai2])
06656                                                                canEmptyDay[d2]=false;
06657                                                         else if(!_activitiesForDay[d2].contains(ai2)){
06658                                                                _minWrong[d2] = min (_minWrong[d2], triedRemovals(ai2,c.times[ai2]));
06659                                                                _minIndexAct[d2]=min(_minIndexAct[d2], invPermutation[ai2]);
06660                                                                _nWrong[d2]+=triedRemovals(ai2,c.times[ai2]);
06661                                                                _nConflActivities[d2]++;
06662                                                                _activitiesForDay[d2].append(ai2);
06663                                                                assert(_nConflActivities[d2]==_activitiesForDay[d2].count());
06664                                                         }
06665                                                  }
06666                                           }
06667                                    }
06668                                    
06669                                    if(!occupiedDay[d2])
06670                                           canEmptyDay[d2]=false;
06671                             }
06672                             occupiedDay[d]=true;
06673                             canEmptyDay[d]=false;
06674                             
06675                             int nOc=0;
06676                             bool canChooseDay=false;
06677                             
06678                             for(int j=0; j<gt.rules.nDaysPerWeek; j++)
06679                                    if(occupiedDay[j]){
06680                                           nOc++;
06681                                           if(canEmptyDay[j]){
06682                                                  canChooseDay=true;
06683                                           }
06684                                    }
06685                                           
06686                             if(nOc>maxDays){
06687                                    assert(nOc==maxDays+1);
06688                                    
06689                                    if(!canChooseDay){
06690                                           if(level==0){
06691                                                  //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
06692                                                  //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
06693                                           }
06694                                           okteachermaxdaysperweek=false;
06695                                           goto impossibleteachermaxdaysperweek;
06696                                    }
06697                                    
06698                                    int d2=-1;
06699                                    
06700                                    if(level!=0){
06701                                           //choose random day from those with minimum number of conflicting activities
06702                                           QList<int> candidateDays;
06703                                           
06704                                           int m=gt.rules.nInternalActivities;
06705                                           
06706                                           for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06707                                                  if(canEmptyDay[kk])
06708                                                         if(m>_nConflActivities[kk])
06709                                                                m=_nConflActivities[kk];
06710                                           
06711                                           candidateDays.clear();
06712                                           for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06713                                                  if(canEmptyDay[kk] && m==_nConflActivities[kk])
06714                                                         candidateDays.append(kk);
06715                                                         
06716                                           assert(candidateDays.count()>0);
06717                                           d2=candidateDays.at(randomKnuth(candidateDays.count()));
06718                                    }
06719                                    else{ //level==0
06720                                           QList<int> candidateDays;
06721 
06722                                           int _mW=INF;
06723                                           int _nW=INF;
06724                                           int _mCA=gt.rules.nInternalActivities;
06725                                           int _mIA=gt.rules.nInternalActivities;
06726 
06727                                           for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06728                                                  if(canEmptyDay[kk]){
06729                                                         if(_mW>_minWrong[kk] ||
06730                                                          (_mW==_minWrong[kk] && _nW>_nWrong[kk]) ||
06731                                                          (_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA>_nConflActivities[kk]) ||
06732                                                          (_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA>_minIndexAct[kk])){
06733                                                                _mW=_minWrong[kk];
06734                                                                _nW=_nWrong[kk];
06735                                                                _mCA=_nConflActivities[kk];
06736                                                                _mIA=_minIndexAct[kk];
06737                                                         }
06738                                                  }
06739                                                  
06740                                           assert(_mW<INF);
06741                                           
06742                                           candidateDays.clear();
06743                                           for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06744                                                  if(canEmptyDay[kk] && _mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA==_minIndexAct[kk])
06745                                                         candidateDays.append(kk);
06746                                                         
06747                                           assert(candidateDays.count()>0);
06748                                           d2=candidateDays.at(randomKnuth(candidateDays.count()));
06749                                    }
06750                                    
06751                                    assert(d2>=0);
06752 
06753                                    assert(_activitiesForDay[d2].count()>0);
06754 
06755                                    foreach(int ai2, _activitiesForDay[d2]){
06756                                           assert(ai2!=ai);
06757                                           assert(!swappedActivities[ai2]);
06758                                           assert(!fixedTimeActivity[ai2]);
06759                                           assert(!conflActivities[newtime].contains(ai2));
06760                                           conflActivities[newtime].append(ai2);
06761                                           nConflActivities[newtime]++;
06762                                           assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06763                                           //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
06764                                    }
06765                             }             
06766                      }
06767               }
06768 impossibleteachermaxdaysperweek:
06769               if(!okteachermaxdaysperweek){
06770                      if(updateSubgroups || updateTeachers)
06771                             removeAiFromNewTimetable(ai, act, d, h);
06772                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
06773 
06774                      nConflActivities[newtime]=MAX_ACTIVITIES;
06775                      continue;
06776               }
06777 
06779 
06781               //BEGIN teachers intervals max days per week
06782 
06783               okteachersintervalmaxdaysperweek=true;
06784               foreach(int tch, act->iTeachersList){
06785                      double perc=-1.0;
06786                      for(int cnt=0; cnt<3; cnt++){
06787                             if(cnt==0){
06788                                    perc=teachersIntervalMaxDaysPerWeekPercentages1[tch];
06789                             }
06790                             else if(cnt==1){
06791                                    perc=teachersIntervalMaxDaysPerWeekPercentages2[tch];
06792                             }
06793                             else if(cnt==2){
06794                                    perc=teachersIntervalMaxDaysPerWeekPercentages3[tch];
06795                             }
06796                             else
06797                                    assert(0);
06798                             
06799                             if(perc>=0){
06800                                    int maxDays=-1;
06801                                    int sth=-1;
06802                                    int endh=-1;
06803 
06804                                    if(cnt==0){
06805                                           maxDays=teachersIntervalMaxDaysPerWeekMaxDays1[tch];
06806                                           sth=teachersIntervalMaxDaysPerWeekIntervalStart1[tch];
06807                                           endh=teachersIntervalMaxDaysPerWeekIntervalEnd1[tch];
06808                                    }
06809                                    else if(cnt==1){
06810                                           maxDays=teachersIntervalMaxDaysPerWeekMaxDays2[tch];
06811                                           sth=teachersIntervalMaxDaysPerWeekIntervalStart2[tch];
06812                                           endh=teachersIntervalMaxDaysPerWeekIntervalEnd2[tch];
06813                                    }
06814                                    else if(cnt==2){
06815                                           maxDays=teachersIntervalMaxDaysPerWeekMaxDays3[tch];
06816                                           sth=teachersIntervalMaxDaysPerWeekIntervalStart3[tch];
06817                                           endh=teachersIntervalMaxDaysPerWeekIntervalEnd3[tch];
06818                                    }
06819                                    else
06820                                           assert(0);
06821                             
06822                                    assert(sth>=0 && sth<gt.rules.nHoursPerDay);
06823                                    assert(endh>sth && endh<=gt.rules.nHoursPerDay);
06824                                    assert(maxDays>=0 && maxDays<=gt.rules.nDaysPerWeek);
06825                                    
06826                                    if(skipRandom(perc))
06827                                           continue;
06828                                    
06829                                    assert(perc==100.0);
06830                                    
06831                                    bool foundothers=false;
06832                                    bool foundai=false;
06833                                    for(int hh=sth; hh<endh; hh++){
06834                                           if(newTeachersTimetable(tch,d,hh)==ai){
06835                                                  foundai=true;
06836                                           }
06837                                           else{
06838                                                  assert(newTeachersTimetable(tch,d,hh)==teachersTimetable(tch,d,hh));
06839                                                  if(newTeachersTimetable(tch,d,hh)>=0){
06840                                                         if(!conflActivities[newtime].contains(newTeachersTimetable(tch,d,hh))){
06841                                                                foundothers=true;
06842                                                         }
06843                                                  }
06844                                           }
06845                                    }
06846                                    int nrotherdays=0;
06847                                    for(int dd=0; dd<gt.rules.nDaysPerWeek; dd++){
06848                                           if(dd!=d){
06849                                                  for(int hh=sth; hh<endh; hh++){
06850                                                         assert(newTeachersTimetable(tch,dd,hh)==teachersTimetable(tch,dd,hh));
06851                                                         if(newTeachersTimetable(tch,dd,hh)>=0 && !conflActivities[newtime].contains(newTeachersTimetable(tch,dd,hh))){
06852                                                                nrotherdays++;
06853                                                                break;
06854                                                         }
06855                                                  }
06856                                           }
06857                                    }
06858                                    assert(nrotherdays<=maxDays); //if percentage==100%, then it is impossible to break this constraint
06859                                    if((foundai && !foundothers) && nrotherdays==maxDays){
06860                                           //increased above limit
06861                                           bool occupiedIntervalDay[MAX_DAYS_PER_WEEK];
06862                                           bool canEmptyIntervalDay[MAX_DAYS_PER_WEEK];
06863                             
06864                                           int _minWrong[MAX_DAYS_PER_WEEK];
06865                                           int _nWrong[MAX_DAYS_PER_WEEK];
06866                                           int _nConflActivities[MAX_DAYS_PER_WEEK];
06867                                           int _minIndexAct[MAX_DAYS_PER_WEEK];
06868                             
06869                                           QList<int> _activitiesForIntervalDay[MAX_DAYS_PER_WEEK];
06870 
06871                                           for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
06872                                                  if(d2==d)
06873                                                         continue;
06874                             
06875                                                  occupiedIntervalDay[d2]=false;
06876                                                  canEmptyIntervalDay[d2]=true;
06877                                    
06878                                                  _minWrong[d2]=INF;
06879                                                  _nWrong[d2]=0;
06880                                                  _nConflActivities[d2]=0;
06881                                                  _minIndexAct[d2]=gt.rules.nInternalActivities;
06882                                                  _activitiesForIntervalDay[d2].clear();
06883                                                  
06884                                                  for(int h2=sth; h2<endh; h2++){
06885                                                         int ai2=teachersTimetable(tch,d2,h2);
06886                                                  //foreach(int ai2, teacherActivitiesOfTheDay(tch,d2)){
06887                                                         if(ai2>=0){
06888                                                                if(!conflActivities[newtime].contains(ai2)){
06889                                                                       occupiedIntervalDay[d2]=true;
06890                                                                       if(fixedTimeActivity[ai2] || swappedActivities[ai2])
06891                                                                              canEmptyIntervalDay[d2]=false;
06892                                                                       else if(!_activitiesForIntervalDay[d2].contains(ai2)){
06893                                                                              _minWrong[d2] = min (_minWrong[d2], triedRemovals(ai2,c.times[ai2]));
06894                                                                              _minIndexAct[d2]=min(_minIndexAct[d2], invPermutation[ai2]);
06895                                                                              _nWrong[d2]+=triedRemovals(ai2,c.times[ai2]);
06896                                                                              _nConflActivities[d2]++;
06897                                                                              _activitiesForIntervalDay[d2].append(ai2);
06898                                                                              assert(_nConflActivities[d2]==_activitiesForIntervalDay[d2].count());
06899                                                                       }
06900                                                                }
06901                                                         }
06902                                                  }
06903                                    
06904                                                  if(!occupiedIntervalDay[d2])
06905                                                         canEmptyIntervalDay[d2]=false;
06906                                           }
06907                                           occupiedIntervalDay[d]=true;
06908                                           canEmptyIntervalDay[d]=false;
06909                             
06910                                           int nOc=0;
06911                                           bool canChooseDay=false;
06912                             
06913                                           for(int j=0; j<gt.rules.nDaysPerWeek; j++)
06914                                                  if(occupiedIntervalDay[j]){
06915                                                         nOc++;
06916                                                         if(canEmptyIntervalDay[j]){
06917                                                                canChooseDay=true;
06918                                                         }
06919                                                  }
06920                                           
06921                                           //if(nOc>maxDays){
06922                                           assert(nOc==maxDays+1);
06923                                    
06924                                           if(!canChooseDay){
06925                                                  if(level==0){
06926                                                         //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
06927                                                         //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
06928                                                  }
06929                                                  okteachersintervalmaxdaysperweek=false;
06930                                                  goto impossibleteachersintervalmaxdaysperweek;
06931                                           }
06932                                    
06933                                           int d2=-1;
06934                                    
06935                                           if(level!=0){
06936                                                  //choose random day from those with minimum number of conflicting activities
06937                                                  QList<int> candidateDays;
06938                                           
06939                                                  int m=gt.rules.nInternalActivities;
06940                                                  
06941                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06942                                                         if(canEmptyIntervalDay[kk])
06943                                                                if(m>_nConflActivities[kk])
06944                                                                       m=_nConflActivities[kk];
06945                                           
06946                                                  candidateDays.clear();
06947                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06948                                                         if(canEmptyIntervalDay[kk] && m==_nConflActivities[kk])
06949                                                                candidateDays.append(kk);
06950                                                                
06951                                                  assert(candidateDays.count()>0);
06952                                                  d2=candidateDays.at(randomKnuth(candidateDays.count()));
06953                                           }
06954                                           else{ //level==0
06955                                                  QList<int> candidateDays;
06956 
06957                                                  int _mW=INF;
06958                                                  int _nW=INF;
06959                                                  int _mCA=gt.rules.nInternalActivities;
06960                                                  int _mIA=gt.rules.nInternalActivities;
06961 
06962                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06963                                                         if(canEmptyIntervalDay[kk]){
06964                                                                if(_mW>_minWrong[kk] ||
06965                                                                 (_mW==_minWrong[kk] && _nW>_nWrong[kk]) ||
06966                                                                 (_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA>_nConflActivities[kk]) ||
06967                                                                 (_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA>_minIndexAct[kk])){
06968                                                                       _mW=_minWrong[kk];
06969                                                                       _nW=_nWrong[kk];
06970                                                                       _mCA=_nConflActivities[kk];
06971                                                                       _mIA=_minIndexAct[kk];
06972                                                                }
06973                                                         }
06974                                                         
06975                                                  assert(_mW<INF);
06976                                                  
06977                                                  candidateDays.clear();
06978                                                  for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++)
06979                                                         if(canEmptyIntervalDay[kk] && _mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA==_minIndexAct[kk])
06980                                                                candidateDays.append(kk);
06981                                                         
06982                                                  assert(candidateDays.count()>0);
06983                                                  d2=candidateDays.at(randomKnuth(candidateDays.count()));
06984                                           }
06985                                    
06986                                           assert(d2>=0);
06987 
06988                                           assert(_activitiesForIntervalDay[d2].count()>0);
06989 
06990                                           foreach(int ai2, _activitiesForIntervalDay[d2]){
06991                                                  assert(ai2!=ai);
06992                                                  assert(!swappedActivities[ai2]);
06993                                                  assert(!fixedTimeActivity[ai2]);
06994                                                  assert(!conflActivities[newtime].contains(ai2));
06995                                                  conflActivities[newtime].append(ai2);
06996                                                  nConflActivities[newtime]++;
06997                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
06998                                                  //addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, &gt.rules.internalActivitiesList[ai2]);
06999                                           }
07000                                    }
07001                             }
07002                      }
07003               }
07004               //respecting teachers interval max days per week
07005 impossibleteachersintervalmaxdaysperweek:
07006               if(!okteachersintervalmaxdaysperweek){
07007                      if(updateSubgroups || updateTeachers)
07008                             removeAiFromNewTimetable(ai, act, d, h);
07009                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
07010 
07011                      nConflActivities[newtime]=MAX_ACTIVITIES;
07012                      continue;
07013               }
07014 
07016 
07018 
07019               //not causing more than teachersMaxGapsPerWeek teachers gaps
07020               okteachersmaxgapsperweek=true;
07021               foreach(int tch, act->iTeachersList)
07022                      if(!skipRandom(teachersMaxGapsPerWeekPercentage[tch])){
07023                             assert(teachersMaxGapsPerWeekPercentage[tch]==100);
07024                             
07025                             //preliminary test
07026                             int _nHours=0;
07027                             int _nGaps=0;
07028                             for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
07029                                    _nHours+=newTeachersDayNHours(tch,d2);
07030                                    _nGaps+=newTeachersDayNGaps(tch,d2);
07031                             }
07032                             
07033                             if(_nGaps+_nHours > teachersMaxGapsPerWeekMaxGaps[tch]+nHoursPerTeacher[tch]){
07034                      
07035                                    if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
07036                                           okteachersmaxgapsperweek=false;
07037                                           goto impossibleteachersmaxgapsperweek;
07038                                    }
07039                                    
07040                                    getTchTimetable(tch, conflActivities[newtime]);
07041                                    tchGetNHoursGaps(tch);
07042 
07043                                    for(;;){
07044                                           int nHours=0;
07045                                           int nGaps=0;
07046                                           for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
07047                                                  nHours+=tchDayNHours[d2];
07048                                                  nGaps+=tchDayNGaps[d2];
07049                                           }
07050                                           
07051                                           int ai2=-1;
07052                                                  
07053                                           if(nGaps+nHours > teachersMaxGapsPerWeekMaxGaps[tch]+nHoursPerTeacher[tch]){
07054                                                  //remove an activity
07055                                                  bool k=teacherRemoveAnActivityFromBeginOrEnd(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
07056                                                  assert(conflActivities[newtime].count()==nConflActivities[newtime]);
07057                                                  if(!k){
07058                                                         if(level==0){
07059                                                                //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
07060                                                                //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
07061                                                         }
07062                                                         okteachersmaxgapsperweek=false;
07063                                                         goto impossibleteachersmaxgapsperweek;
07064                                                  }
07065                                           }
07066                                           else{ //OK
07067                                                  break;
07068                                           }
07069                                           
07070                                           assert(ai2>=0);
07071 
07072                                           removeAi2FromTchTimetable(ai2);
07073                                           updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek);
07074                                    }
07075                             }
07076                      }
07077               
07078 impossibleteachersmaxgapsperweek:
07079               if(!okteachersmaxgapsperweek){
07080                      if(updateSubgroups || updateTeachers)
07081                             removeAiFromNewTimetable(ai, act, d, h);
07082                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
07083 
07084                      nConflActivities[newtime]=MAX_ACTIVITIES;
07085                      continue;
07086               }
07087 
07089 
07091 
07092               //not causing more than teachersMaxGapsPerDay teachers gaps
07093               okteachersmaxgapsperday=true;
07094               foreach(int tch, act->iTeachersList)
07095                      if(!skipRandom(teachersMaxGapsPerDayPercentage[tch])){
07096                             assert(teachersMaxGapsPerDayPercentage[tch]==100);
07097 
07098                             //preliminary test
07099                             int _total=0;
07100                             for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
07101                                    _total+=newTeachersDayNHours(tch,d2);
07102                                    if(teachersMaxGapsPerDayMaxGaps[tch]<newTeachersDayNGaps(tch,d2))
07103                                           _total+=newTeachersDayNGaps(tch,d2)-teachersMaxGapsPerDayMaxGaps[tch];
07104                             }
07105                             if(_total<=nHoursPerTeacher[tch]) //OK
07106                                    continue;
07107 
07108                             if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){
07109                                    okteachersmaxgapsperday=false;
07110                                    goto impossibleteachersmaxgapsperday;
07111                             }
07112 
07113                             getTchTimetable(tch, conflActivities[newtime]);
07114                             tchGetNHoursGaps(tch);
07115 
07116                             for(;;){
07117                                    int total=0;
07118                                    for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){
07119                                           total+=tchDayNHours[d2];
07120                                           if(teachersMaxGapsPerDayMaxGaps[tch]<tchDayNGaps[d2])
07121                                                  total+=tchDayNGaps[d2]-teachersMaxGapsPerDayMaxGaps[tch];
07122                                    }
07123                                    if(total<=nHoursPerTeacher[tch]) //OK
07124                                           break;
07125                                           
07126                                    //remove an activity from the beginning or from the end of a day
07127                                    //following code is identical to maxgapsperweek
07128                                    //remove an activity
07129                                    int ai2=-1;
07130                                    
07131                                    //it should also be allowed to take from anywhere, but it is risky to change now
07132                                    bool k=teacherRemoveAnActivityFromBeginOrEnd(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2);
07133                                    assert(conflActivities[newtime].count()==nConflActivities[newtime]);
07134                                    if(!k){
07135                                           if(level==0){
07136                                                  //Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files
07137                                                  //cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl;
07138                                           }
07139                                           okteachersmaxgapsperday=false;
07140                                           goto impossibleteachersmaxgapsperday;
07141                                    }
07142                                    
07143                                    assert(ai2>=0);
07144 
07145                                    /*Activity* act2=&gt.rules.internalActivitiesList[ai2];
07146                                    int d2=c.times[ai2]%gt.rules.nDaysPerWeek;
07147                                    int h2=c.times[ai2]/gt.rules.nDaysPerWeek;
07148                                           
07149                                    for(int dur2=0; dur2<act2->duration; dur2++){
07150                                           assert(tchTimetable(d2,h2+dur2)==ai2);
07151                                           tchTimetable(d2,h2+dur2)=-1;
07152                                    }*/
07153 
07154                                    removeAi2FromTchTimetable(ai2);
07155                                    updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek);
07156                             }
07157                      }
07158               
07159 impossibleteachersmaxgapsperday:
07160               if(!okteachersmaxgapsperday){
07161                      if(updateSubgroups || updateTeachers)
07162                             removeAiFromNewTimetable(ai, act, d, h);
07163                      //removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime);
07164 
07165                      nConflActivities[newtime]=MAX_ACTIVITIES;
07166                      continue;
07167               }
07168 
07170 
07172 
07173               //allowed from teachers max hours daily
07174               
07176               
07177               okteachersmaxhoursdaily=true;
07178               
07179               foreach(int tch, act->iTeachersList){
07180                      for(int count=0; count<2; count++){
07181                             int limitHoursDaily;
07182                             double percentage;
07183                             if(count==0){
07184                                    limitHoursDaily=teachersMaxHoursDailyMaxHours1[tch];
07185                                    percentage=teachersMaxHoursDailyPercentages1[tch];
07186                             }
07187                             else{
07188                                    limitHoursDaily=teachersMaxHoursDailyMaxHours2[tch];
07189                                    percentage=teachersMaxHoursDailyPercentages2[tch];
07190                             }
07191                             
07192                             if(limitHoursDaily<0)
07193                                    continue;
07194                             
07195                             //if(fixedTimeActivity[ai] && percentage<100.0) //added on 21 Feb. 2009 in FET 5.9.1, to solve a bug of impossible timetables for fixed timetables
07196                             //     continue;
07197                             
07198                             bool increased;
07199                             if(teachersMaxGapsPerWeekPercentage[tch]>=0 || teachersMaxGapsPerDayPercentage[tch]>=0){
07200                                    if(newTeachersDayNHours(tch,d) > oldTeachersDayNHours(tch,d) 
07201                                      || newTeachersDayNHours(tch,d)+newTeachersDayNGaps(tch,d) > oldTeachersDayNHours(tch,d)+oldTeachersDayNGaps(tch,d))
07202                                           increased=true;
07203                                    else
07204                                           increased=false;
07205                             }
07206                             else{
07207                                    if(newTeachersDayNHours(tch,d) > oldTeachersDayNHours(tch,d))
07208                                           increased=true;
07209                                    else
07210                                           increased=false;
07211                             }
07212                             /*
07213                             if(newTeachersDayNHours(tch,d) > oldTeachersDayNHours(tch,d))
07214                                    increased=true;
07215                             else
07216                                    increased=false;*/
07217                      
07218                             if