Created
May 19, 2014 15:21
-
-
Save alobato/b182209fbe127fea46c1 to your computer and use it in GitHub Desktop.
schoolar.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
QSemaphore semaphorePlacedActivity; | |
QSemaphore finishedSemaphore; | |
extern Timetable gt; | |
static bool swappedActivities[MAX_ACTIVITIES]; | |
static bool foundGoodSwap; | |
//not sure, it might be necessary 2*... or even more | |
static int restoreActIndex[4*MAX_ACTIVITIES]; //the index of the act. to restore | |
static int restoreTime[4*MAX_ACTIVITIES]; //the time when to restore | |
static int restoreRoom[4*MAX_ACTIVITIES]; //the time when to restore | |
static int nRestore; | |
static int limitcallsrandomswap; | |
const int MAX_LEVEL=31; | |
const int LEVEL_STOP_CONFLICTS_CALCULATION=MAX_LEVEL; | |
static int level_limit; | |
static int ncallsrandomswap; | |
static int maxncallsrandomswap; | |
Solution highestStageSolution; | |
//if level==0, choose best position with lowest number | |
//of conflicting activities | |
static QList<int> conflActivitiesTimeSlot; | |
static int timeSlot; | |
static int roomSlot; | |
//int triedRemovals[MAX_ACTIVITIES][MAX_HOURS_PER_WEEK]; | |
static Matrix2D<int> triedRemovals; | |
static bool impossibleActivity; | |
static int invPermutation[MAX_ACTIVITIES]; | |
const int INF=2000000000; | |
////////tabu list of tried removals (circular) | |
//const int MAX_TABU=MAX_ACTIVITIES*MAX_HOURS_PER_WEEK; | |
static int tabu_size; | |
static int crt_tabu_index; | |
/*qint16 tabu_activities[MAX_TABU]; | |
qint16 tabu_times[MAX_TABU];*/ | |
static Matrix1D<qint16> tabu_activities; | |
static Matrix1D<qint16> tabu_times; | |
//////////// | |
/*static qint16 teachersTimetable[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 subgroupsTimetable[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 roomsTimetable[MAX_ROOMS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY];*/ | |
static Matrix3D<qint16> teachersTimetable; | |
static Matrix3D<qint16> subgroupsTimetable; | |
static Matrix3D<qint16> roomsTimetable; | |
/*static qint16 newTeachersTimetable[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 newSubgroupsTimetable[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 newTeachersDayNHours[MAX_TEACHERS][MAX_DAYS_PER_WEEK]; | |
static qint16 newTeachersDayNGaps[MAX_TEACHERS][MAX_DAYS_PER_WEEK]; | |
static qint16 newSubgroupsDayNHours[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK]; | |
static qint16 newSubgroupsDayNGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK]; | |
static qint16 newSubgroupsDayNFirstGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];*/ | |
static Matrix3D<qint16> newTeachersTimetable; | |
static Matrix3D<qint16> newSubgroupsTimetable; | |
static Matrix2D<qint16> newTeachersDayNHours; | |
static Matrix2D<qint16> newTeachersDayNGaps; | |
static Matrix2D<qint16> newSubgroupsDayNHours; | |
static Matrix2D<qint16> newSubgroupsDayNGaps; | |
static Matrix2D<qint16> newSubgroupsDayNFirstGaps; | |
/*static qint16 oldTeachersTimetable[MAX_TEACHERS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 oldSubgroupsTimetable[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 oldTeachersDayNHours[MAX_TEACHERS][MAX_DAYS_PER_WEEK]; | |
static qint16 oldTeachersDayNGaps[MAX_TEACHERS][MAX_DAYS_PER_WEEK]; | |
static qint16 oldSubgroupsDayNHours[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK]; | |
static qint16 oldSubgroupsDayNGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK]; | |
static qint16 oldSubgroupsDayNFirstGaps[MAX_TOTAL_SUBGROUPS][MAX_DAYS_PER_WEEK];*/ | |
static Matrix3D<qint16> oldTeachersTimetable; | |
static Matrix3D<qint16> oldSubgroupsTimetable; | |
static Matrix2D<qint16> oldTeachersDayNHours; | |
static Matrix2D<qint16> oldTeachersDayNGaps; | |
static Matrix2D<qint16> oldSubgroupsDayNHours; | |
static Matrix2D<qint16> oldSubgroupsDayNGaps; | |
static Matrix2D<qint16> oldSubgroupsDayNFirstGaps; | |
/*static qint16 tchTimetable[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 tchDayNHours[MAX_DAYS_PER_WEEK]; | |
static qint16 tchDayNGaps[MAX_DAYS_PER_WEEK]; | |
static qint16 sbgTimetable[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
static qint16 sbgDayNHours[MAX_DAYS_PER_WEEK]; | |
static qint16 sbgDayNGaps[MAX_DAYS_PER_WEEK]; | |
static qint16 sbgDayNFirstGaps[MAX_DAYS_PER_WEEK];*/ | |
static Matrix2D<qint16> tchTimetable; | |
static Matrix1D<qint16> tchDayNHours; | |
static Matrix1D<qint16> tchDayNGaps; | |
static Matrix2D<qint16> sbgTimetable; | |
static Matrix1D<qint16> sbgDayNHours; | |
static Matrix1D<qint16> sbgDayNGaps; | |
static Matrix1D<qint16> sbgDayNFirstGaps; | |
//static QList<int> teacherActivitiesOfTheDay[MAX_TEACHERS][MAX_DAYS_PER_WEEK]; | |
static Matrix2D<QList<int> > teacherActivitiesOfTheDay; | |
int maxActivitiesPlaced; | |
QDateTime generationStartDateTime; | |
QDateTime generationHighestStageDateTime; | |
const int MAX_RETRIES_FOR_AN_ACTIVITY_AT_LEVEL_0=400000; | |
//used at level 0 | |
static Matrix1D<int> l0nWrong; | |
static Matrix1D<int> l0minWrong; | |
static Matrix1D<int> l0minIndexAct; | |
inline int max(qint16 a, int b){ | |
if(int(a)>=b) | |
return int(a); | |
else | |
return b; | |
} | |
inline void Generate::addAiToNewTimetable(int ai, const Activity* act, int d, int h) | |
{ | |
//foreach(int tch, act->iTeachersList){ | |
foreach(int tch, mustComputeTimetableTeachers[ai]){ | |
for(int dur=0; dur<act->duration; dur++){ | |
oldTeachersTimetable(tch,d,h+dur)=newTeachersTimetable(tch,d,h+dur); | |
newTeachersTimetable(tch,d,h+dur)=ai; | |
} | |
oldTeachersDayNHours(tch,d)=newTeachersDayNHours(tch,d); | |
oldTeachersDayNGaps(tch,d)=newTeachersDayNGaps(tch,d); | |
} | |
//foreach(int sbg, act->iSubgroupsList){ | |
foreach(int sbg, mustComputeTimetableSubgroups[ai]){ | |
for(int dur=0; dur<act->duration; dur++){ | |
oldSubgroupsTimetable(sbg,d,h+dur)=newSubgroupsTimetable(sbg,d,h+dur); | |
newSubgroupsTimetable(sbg,d,h+dur)=ai; | |
} | |
oldSubgroupsDayNHours(sbg,d)=newSubgroupsDayNHours(sbg,d); | |
oldSubgroupsDayNGaps(sbg,d)=newSubgroupsDayNGaps(sbg,d); | |
oldSubgroupsDayNFirstGaps(sbg,d)=newSubgroupsDayNFirstGaps(sbg,d); | |
} | |
} | |
inline void Generate::removeAiFromNewTimetable(int ai, const Activity* act, int d, int h) | |
{ | |
foreach(int tch, mustComputeTimetableTeachers[ai]){ | |
//foreach(int tch, act->iTeachersList){ | |
for(int dur=0; dur<act->duration; dur++){ | |
assert(newTeachersTimetable(tch,d,h+dur)==ai); | |
newTeachersTimetable(tch,d,h+dur)=oldTeachersTimetable(tch,d,h+dur); | |
} | |
newTeachersDayNHours(tch,d)=oldTeachersDayNHours(tch,d); | |
newTeachersDayNGaps(tch,d)=oldTeachersDayNGaps(tch,d); | |
} | |
foreach(int sbg, mustComputeTimetableSubgroups[ai]){ | |
//foreach(int sbg, act->iSubgroupsList){ | |
for(int dur=0; dur<act->duration; dur++){ | |
assert(newSubgroupsTimetable(sbg,d,h+dur)==ai); | |
newSubgroupsTimetable(sbg,d,h+dur)=oldSubgroupsTimetable(sbg,d,h+dur); | |
} | |
newSubgroupsDayNHours(sbg,d)=oldSubgroupsDayNHours(sbg,d); | |
newSubgroupsDayNGaps(sbg,d)=oldSubgroupsDayNGaps(sbg,d); | |
newSubgroupsDayNFirstGaps(sbg,d)=oldSubgroupsDayNFirstGaps(sbg,d); | |
} | |
} | |
inline void Generate::removeAi2FromTchTimetable(int ai2) | |
{ | |
Activity* act2=>.rules.internalActivitiesList[ai2]; | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
for(int dur2=0; dur2<act2->duration; dur2++){ | |
assert(tchTimetable(d2,h2+dur2)==ai2); | |
if(tchTimetable(d2,h2+dur2)==ai2) | |
tchTimetable(d2,h2+dur2)=-1; | |
} | |
} | |
inline void Generate::removeAi2FromSbgTimetable(int ai2) | |
{ | |
Activity* act2=>.rules.internalActivitiesList[ai2]; | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
for(int dur2=0; dur2<act2->duration; dur2++){ | |
assert(sbgTimetable(d2,h2+dur2)==ai2); | |
if(sbgTimetable(d2,h2+dur2)==ai2) | |
sbgTimetable(d2,h2+dur2)=-1; | |
} | |
} | |
inline void Generate::getTchTimetable(int tch, const QList<int>& conflActivities) | |
{ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=newTeachersTimetable(tch,d2,h2); | |
if(ai2>=0 && !conflActivities.contains(ai2)) | |
tchTimetable(d2,h2)=ai2; | |
else | |
tchTimetable(d2,h2)=-1; | |
} | |
/*for(int dur=0; dur<act->duration; dur++){ | |
assert(tchTimetable(d,h+dur)==-1); | |
tchTimetable(d,h+dur)=ai; | |
}*/ | |
} | |
inline void Generate::getSbgTimetable(int sbg, const QList<int>& conflActivities) | |
{ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=newSubgroupsTimetable(sbg,d2,h2); | |
if(ai2>=0 && !conflActivities.contains(ai2)) | |
sbgTimetable(d2,h2)=ai2; | |
else | |
sbgTimetable(d2,h2)=-1; | |
} | |
/*for(int dur=0; dur<act->duration; dur++){ | |
assert(sbgTimetable(d,h+dur)==-1); | |
sbgTimetable(d,h+dur)=ai; | |
}*/ | |
} | |
inline void Generate::updateTchNHoursGaps(int tch, int d) | |
{ | |
int hours=0, gaps=0; | |
int h; | |
for(h=0; h<gt.rules.nHoursPerDay; h++) | |
if(tchTimetable(d,h)>=0) | |
break; | |
int ng=0; | |
for(; h<gt.rules.nHoursPerDay; h++){ | |
if(tchTimetable(d,h)>=0){ | |
hours++; | |
gaps+=ng; | |
ng=0; | |
} | |
else if(!breakDayHour(d,h) && !teacherNotAvailableDayHour(tch,d,h)) | |
ng++; | |
} | |
tchDayNGaps[d]=gaps; | |
tchDayNHours[d]=hours; | |
} | |
inline void Generate::updateSbgNHoursGaps(int sbg, int d) | |
{ | |
int hours=0, gaps=0, nfirstgaps=0; | |
int h; | |
for(h=0; h<gt.rules.nHoursPerDay; h++){ | |
if(sbgTimetable(d,h)>=0) | |
break; | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
nfirstgaps++; | |
} | |
int ng=0; | |
for(; h<gt.rules.nHoursPerDay; h++){ | |
if(sbgTimetable(d,h)>=0){ | |
hours++; | |
gaps+=ng; | |
ng=0; | |
} | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
ng++; | |
} | |
sbgDayNGaps[d]=gaps; | |
sbgDayNHours[d]=hours; | |
if(sbgDayNHours[d]>0) | |
sbgDayNFirstGaps[d]=nfirstgaps; | |
else | |
sbgDayNFirstGaps[d]=0; | |
} | |
inline void Generate::updateTeachersNHoursGaps(Activity* act, int ai, int d) | |
{ | |
Q_UNUSED(act); | |
foreach(int tch, mustComputeTimetableTeachers[ai]){ | |
//foreach(int tch, act->iTeachersList){ | |
int hours=0, gaps=0; | |
int h; | |
for(h=0; h<gt.rules.nHoursPerDay; h++) | |
if(newTeachersTimetable(tch,d,h)>=0) | |
break; | |
int ng=0; | |
for(; h<gt.rules.nHoursPerDay; h++){ | |
if(newTeachersTimetable(tch,d,h)>=0){ | |
hours++; | |
gaps+=ng; | |
ng=0; | |
} | |
else if(!breakDayHour(d,h) && !teacherNotAvailableDayHour(tch,d,h)) | |
ng++; | |
} | |
newTeachersDayNGaps(tch,d)=gaps; | |
newTeachersDayNHours(tch,d)=hours; | |
} | |
} | |
inline void Generate::updateSubgroupsNHoursGaps(Activity* act, int ai, int d) | |
{ | |
Q_UNUSED(act); | |
foreach(int sbg, mustComputeTimetableSubgroups[ai]){ | |
//foreach(int sbg, act->iSubgroupsList){ | |
int hours=0, gaps=0, nfirstgaps=0; | |
int h; | |
for(h=0; h<gt.rules.nHoursPerDay; h++){ | |
if(newSubgroupsTimetable(sbg,d,h)>=0) | |
break; | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
nfirstgaps++; | |
} | |
int ng=0; | |
for(; h<gt.rules.nHoursPerDay; h++){ | |
if(newSubgroupsTimetable(sbg,d,h)>=0){ | |
hours++; | |
gaps+=ng; | |
ng=0; | |
} | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
ng++; | |
} | |
newSubgroupsDayNGaps(sbg,d)=gaps; | |
newSubgroupsDayNHours(sbg,d)=hours; | |
if(hours>0) | |
newSubgroupsDayNFirstGaps(sbg,d)=nfirstgaps; | |
else | |
newSubgroupsDayNFirstGaps(sbg,d)=0; | |
} | |
} | |
inline void Generate::teacherGetNHoursGaps(int tch) | |
{ | |
if(!mustComputeTimetableTeacher[tch]) | |
return; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
newTeachersDayNHours(tch,d2)=0; | |
newTeachersDayNGaps(tch,d2)=0; | |
} | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
bool countGaps=false; | |
int ng=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(newTeachersTimetable(tch,d2,h2)>=0){ | |
newTeachersDayNHours(tch,d2)++; | |
if(countGaps) | |
newTeachersDayNGaps(tch,d2)+=ng; | |
else | |
countGaps=true; | |
ng=0; | |
} | |
else if(!breakDayHour(d2,h2) && !teacherNotAvailableDayHour(tch,d2,h2)) | |
ng++; | |
} | |
} | |
} | |
inline void Generate::tchGetNHoursGaps(int tch) | |
{ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
tchDayNHours[d2]=0; | |
tchDayNGaps[d2]=0; | |
} | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
bool countGaps=false; | |
int ng=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(tchTimetable(d2,h2)>=0){ | |
tchDayNHours[d2]++; | |
if(countGaps) | |
tchDayNGaps[d2]+=ng; | |
else | |
countGaps=true; | |
ng=0; | |
} | |
else if(!breakDayHour(d2,h2) && !teacherNotAvailableDayHour(tch,d2,h2)) | |
ng++; | |
} | |
} | |
} | |
inline bool Generate::teacherRemoveAnActivityFromBeginOrEnd(int tch, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible | |
{ | |
Q_UNUSED(tch); | |
//remove an activity from begin or from end of any day | |
QList<int> possibleDays; | |
QList<bool> atBeginning; | |
QList<int> acts; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(tchDayNHours[d2]>0){ | |
int actIndexBegin=-1, actIndexEnd=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(tchTimetable(d2,h2)>=0){ | |
actIndexBegin=tchTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexBegin>=0) | |
if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai) | |
actIndexBegin=-1; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){ | |
if(tchTimetable(d2,h2)>=0){ | |
actIndexEnd=tchTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexEnd>=0) | |
if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai || actIndexEnd==actIndexBegin) | |
actIndexEnd=-1; | |
if(actIndexBegin>=0){ | |
assert(!acts.contains(actIndexBegin)); | |
possibleDays.append(d2); | |
atBeginning.append(true); | |
acts.append(actIndexBegin); | |
} | |
if(actIndexEnd>=0){ | |
assert(!acts.contains(actIndexEnd)); | |
possibleDays.append(d2); | |
atBeginning.append(false); | |
acts.append(actIndexEnd); | |
} | |
} | |
} | |
bool possibleBeginOrEnd=true; | |
if(possibleDays.count()==0) | |
possibleBeginOrEnd=false; | |
if(possibleBeginOrEnd){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(possibleDays.count()); | |
} | |
assert(t>=0 && t<possibleDays.count()); | |
int d2=possibleDays.at(t); | |
bool begin=atBeginning.at(t); | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
if(begin){ | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(tchTimetable(d2,h2)>=0) | |
break; | |
assert(h2<gt.rules.nHoursPerDay); | |
assert(tchTimetable(d2,h2)==ai2); | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
} | |
else{ | |
int h2; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--) | |
if(tchTimetable(d2,h2)>=0) | |
break; | |
assert(h2>=0); | |
assert(tchTimetable(d2,h2)==ai2); | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
} | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(tch); | |
int actIndexBegin=-1, actIndexEnd=-1; | |
if(tchDayNHours[d2]>0){ | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(tchTimetable(d2,h2)>=0){ | |
actIndexBegin=tchTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexBegin>=0) | |
if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai) | |
actIndexBegin=-1; | |
for(int h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){ | |
if(tchTimetable(d2,h2)>=0){ | |
actIndexEnd=tchTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexEnd>=0) | |
if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai || actIndexEnd==actIndexBegin) | |
actIndexEnd=-1; | |
} | |
if(actIndexEnd>=0 || actIndexBegin>=0){ | |
int ai2=-1; | |
if(level==0){ | |
int optMinWrong=INF; | |
if(actIndexBegin>=0){ | |
if(optMinWrong>triedRemovals(actIndexBegin,c.times[actIndexBegin])){ | |
optMinWrong=triedRemovals(actIndexBegin,c.times[actIndexBegin]); | |
} | |
ai2=actIndexBegin; | |
} | |
if(actIndexEnd>=0){ | |
if(optMinWrong>triedRemovals(actIndexEnd,c.times[actIndexEnd])){ | |
optMinWrong=triedRemovals(actIndexEnd,c.times[actIndexEnd]); | |
} | |
ai2=actIndexEnd; | |
} | |
if(actIndexBegin>=0 && actIndexEnd>=0 && optMinWrong==triedRemovals(actIndexEnd,c.times[actIndexEnd]) && | |
optMinWrong==triedRemovals(actIndexBegin,c.times[actIndexBegin])){ | |
if(randomKnuth(2)==0) | |
ai2=actIndexBegin; | |
else | |
ai2=actIndexEnd; | |
} | |
} | |
else{ | |
if(actIndexBegin>=0 && actIndexEnd<0) | |
ai2=actIndexBegin; | |
else if(actIndexEnd>=0 && actIndexBegin<0) | |
ai2=actIndexEnd; | |
else{ | |
if(randomKnuth(2)==0) | |
ai2=actIndexBegin; | |
else | |
ai2=actIndexEnd; | |
} | |
} | |
assert(ai2>=0); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
inline bool Generate::teacherRemoveAnActivityFromAnywhere(int tch, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible | |
{ | |
Q_UNUSED(tch); | |
//remove an activity from anywhere | |
QList<int> acts; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(tchDayNHours[d2]>0){ | |
int actIndex=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(tchTimetable(d2,h2)>=0){ | |
actIndex=tchTimetable(d2,h2); | |
if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex)) | |
actIndex=-1; | |
if(actIndex>=0){ | |
assert(!acts.contains(actIndex)); | |
acts.append(actIndex); | |
} | |
} | |
} | |
} | |
if(acts.count()>0){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(tch); | |
//remove an activity from anywhere | |
QList<int> acts; | |
//for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(tchDayNHours[d2]>0){ | |
int actIndex=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(tchTimetable(d2,h2)>=0){ | |
actIndex=tchTimetable(d2,h2); | |
if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex)) | |
actIndex=-1; | |
if(actIndex>=0){ | |
assert(!acts.contains(actIndex)); | |
acts.append(actIndex); | |
} | |
} | |
} | |
//} | |
if(acts.count()>0){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(tch); | |
//remove an activity from anywhere | |
QList<int> acts; | |
//for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(tchDayNHours[d2]>0){ | |
int actIndex=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(tchTimetable(d2,h2)>=0){ | |
actIndex=tchTimetable(d2,h2); | |
if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex) || !gt.rules.internalActivitiesList[actIndex].iActivityTagsSet.contains(actTag)) | |
actIndex=-1; | |
if(actIndex>=0){ | |
assert(!acts.contains(actIndex)); | |
acts.append(actIndex); | |
} | |
} | |
} | |
//} | |
if(acts.count()>0){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
//students | |
inline void Generate::subgroupGetNHoursGaps(int sbg) | |
{ | |
if(!mustComputeTimetableSubgroup[sbg]) | |
return; | |
for(int d=0; d<gt.rules.nDaysPerWeek; d++){ | |
int hours=0, gaps=0, nfirstgaps=0; | |
int h; | |
for(h=0; h<gt.rules.nHoursPerDay; h++){ | |
if(newSubgroupsTimetable(sbg,d,h)>=0) | |
break; | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
nfirstgaps++; | |
} | |
int ng=0; | |
for(; h<gt.rules.nHoursPerDay; h++){ | |
if(newSubgroupsTimetable(sbg,d,h)>=0){ | |
hours++; | |
gaps+=ng; | |
ng=0; | |
} | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
ng++; | |
} | |
newSubgroupsDayNGaps(sbg,d)=gaps; | |
newSubgroupsDayNHours(sbg,d)=hours; | |
if(hours>0) | |
newSubgroupsDayNFirstGaps(sbg,d)=nfirstgaps; | |
else | |
newSubgroupsDayNFirstGaps(sbg,d)=0; | |
} | |
/* for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
newSubgroupsDayNHours(sbg,d2)=0; | |
newSubgroupsDayNGaps(sbg,d2)=0; | |
} | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
bool countGaps=false; | |
int ng=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(newSubgroupsTimetable(sbg,d2,h2)>=0){ | |
newSubgroupsDayNHours(sbg,d2)++; | |
if(countGaps) | |
newSubgroupsDayNGaps(sbg,d2)+=ng; | |
else | |
countGaps=true; | |
ng=0; | |
} | |
else if(!breakDayHour(d2,h2) && !subgroupNotAvailableDayHour(sbg,d2,h2)) | |
ng++; | |
} | |
}*/ | |
} | |
inline void Generate::sbgGetNHoursGaps(int sbg) | |
{ | |
for(int d=0; d<gt.rules.nDaysPerWeek; d++){ | |
int hours=0, gaps=0, nfirstgaps=0; | |
int h; | |
for(h=0; h<gt.rules.nHoursPerDay; h++){ | |
if(sbgTimetable(d,h)>=0) | |
break; | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
nfirstgaps++; | |
} | |
int ng=0; | |
for(; h<gt.rules.nHoursPerDay; h++){ | |
if(sbgTimetable(d,h)>=0){ | |
hours++; | |
gaps+=ng; | |
ng=0; | |
} | |
else if(!breakDayHour(d,h) && !subgroupNotAvailableDayHour(sbg,d,h)) | |
ng++; | |
} | |
sbgDayNGaps[d]=gaps; | |
sbgDayNHours[d]=hours; | |
if(sbgDayNHours[d]>0) | |
sbgDayNFirstGaps[d]=nfirstgaps; | |
else | |
sbgDayNFirstGaps[d]=0; | |
} | |
/* | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
sbgDayNHours[d2]=0; | |
sbgDayNGaps[d2]=0; | |
sbgDayNFirstGaps[d2]=0; | |
} | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
bool countGaps=false; | |
int ng=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(sbgTimetable(d2,h2)>=0){ | |
sbgDayNHours[d2]++; | |
if(countGaps) | |
sbgDayNGaps[d2]+=ng; | |
else | |
countGaps=true; | |
ng=0; | |
} | |
else if(!breakDayHour(d2,h2) && !subgroupNotAvailableDayHour(sbg,d2,h2)) | |
ng++; | |
} | |
}*/ | |
} | |
inline bool Generate::subgroupRemoveAnActivityFromBeginOrEnd(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible | |
{ | |
Q_UNUSED(sbg); | |
//remove an activity from begin or from end of any day | |
QList<int> possibleDays; | |
QList<bool> atBeginning; | |
QList<int> acts; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(sbgDayNHours[d2]>0){ | |
int actIndexBegin=-1, actIndexEnd=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndexBegin=sbgTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexBegin>=0) | |
if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai) | |
actIndexBegin=-1; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){ | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndexEnd=sbgTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexEnd>=0) | |
if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai || actIndexEnd==actIndexBegin) | |
actIndexEnd=-1; | |
if(actIndexBegin>=0){ | |
assert(!acts.contains(actIndexBegin)); | |
possibleDays.append(d2); | |
atBeginning.append(true); | |
acts.append(actIndexBegin); | |
} | |
if(actIndexEnd>=0){ | |
assert(!acts.contains(actIndexEnd)); | |
possibleDays.append(d2); | |
atBeginning.append(false); | |
acts.append(actIndexEnd); | |
} | |
} | |
} | |
bool possibleBeginOrEnd=true; | |
if(possibleDays.count()==0) | |
possibleBeginOrEnd=false; | |
if(possibleBeginOrEnd){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(possibleDays.count()); | |
} | |
assert(t>=0 && t<possibleDays.count()); | |
int d2=possibleDays.at(t); | |
bool begin=atBeginning.at(t); | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
if(begin){ | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(sbgTimetable(d2,h2)>=0) | |
break; | |
assert(h2<gt.rules.nHoursPerDay); | |
assert(sbgTimetable(d2,h2)==ai2); | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
} | |
else{ | |
int h2; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--) | |
if(sbgTimetable(d2,h2)>=0) | |
break; | |
assert(h2>=0); | |
assert(sbgTimetable(d2,h2)==ai2); | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
} | |
return true; | |
} | |
else | |
return false; | |
} | |
inline bool Generate::subgroupRemoveAnActivityFromBegin(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible | |
{ | |
Q_UNUSED(sbg); | |
//remove an activity from begin of any day | |
QList<int> possibleDays; | |
QList<int> acts; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(sbgDayNHours[d2]>0){ | |
int actIndexBegin=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndexBegin=sbgTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexBegin>=0) | |
if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai) | |
actIndexBegin=-1; | |
if(actIndexBegin>=0){ | |
assert(!acts.contains(actIndexBegin)); | |
possibleDays.append(d2); | |
acts.append(actIndexBegin); | |
} | |
} | |
} | |
bool possibleBegin=true; | |
if(possibleDays.count()==0) | |
possibleBegin=false; | |
if(possibleBegin){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(possibleDays.count()); | |
} | |
assert(t>=0 && t<possibleDays.count()); | |
int d2=possibleDays.at(t); | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(sbgTimetable(d2,h2)>=0) | |
break; | |
assert(h2<gt.rules.nHoursPerDay); | |
assert(sbgTimetable(d2,h2)==ai2); | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(sbg); | |
Q_UNUSED(level); | |
if(sbgDayNHours[d2]>0){ | |
int actIndexBegin=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndexBegin=sbgTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexBegin>=0) | |
if(fixedTimeActivity[actIndexBegin] || swappedActivities[actIndexBegin] || actIndexBegin==ai) | |
actIndexBegin=-1; | |
if(actIndexBegin>=0){ | |
removedActivity=actIndexBegin; | |
assert(!conflActivities.contains(actIndexBegin)); | |
conflActivities.append(actIndexBegin); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
else | |
return false; | |
} | |
inline bool Generate::subgroupRemoveAnActivityFromEnd(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible | |
{ | |
Q_UNUSED(sbg); | |
//remove an activity from begin or from end of any day | |
QList<int> possibleDays; | |
QList<int> acts; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(sbgDayNHours[d2]>0){ | |
int actIndexEnd=-1; | |
int h2; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){ | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndexEnd=sbgTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexEnd>=0) | |
if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai) | |
actIndexEnd=-1; | |
if(actIndexEnd>=0){ | |
assert(!acts.contains(actIndexEnd)); | |
possibleDays.append(d2); | |
acts.append(actIndexEnd); | |
} | |
} | |
} | |
bool possibleEnd=true; | |
if(possibleDays.count()==0) | |
possibleEnd=false; | |
if(possibleEnd){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(possibleDays.count()); | |
} | |
assert(t>=0 && t<possibleDays.count()); | |
int d2=possibleDays.at(t); | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
int h2; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--) | |
if(sbgTimetable(d2,h2)>=0) | |
break; | |
assert(h2>=0); | |
assert(sbgTimetable(d2,h2)==ai2); | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(sbg); | |
Q_UNUSED(level); | |
if(sbgDayNHours[d2]>0){ | |
int actIndexEnd=-1; | |
int h2; | |
for(h2=gt.rules.nHoursPerDay-1; h2>=0; h2--){ | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndexEnd=sbgTimetable(d2,h2); | |
break; | |
} | |
} | |
if(actIndexEnd>=0) | |
if(fixedTimeActivity[actIndexEnd] || swappedActivities[actIndexEnd] || actIndexEnd==ai) | |
actIndexEnd=-1; | |
if(actIndexEnd>=0){ | |
removedActivity=actIndexEnd; | |
assert(!conflActivities.contains(actIndexEnd)); | |
conflActivities.append(actIndexEnd); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
else | |
return false; | |
} | |
inline bool Generate::subgroupRemoveAnActivityFromAnywhere(int sbg, int level, int ai, QList<int>& conflActivities, int& nConflActivities, int& removedActivity) //returns true if successful, false if impossible | |
{ | |
Q_UNUSED(sbg); | |
//remove an activity from anywhere | |
QList<int> acts; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(sbgDayNHours[d2]>0){ | |
int actIndex=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndex=sbgTimetable(d2,h2); | |
if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex)) | |
actIndex=-1; | |
if(actIndex>=0){ | |
assert(!acts.contains(actIndex)); | |
acts.append(actIndex); | |
} | |
} | |
} | |
} | |
if(acts.count()>0){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(sbg); | |
//remove an activity from anywhere | |
QList<int> acts; | |
//for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(sbgDayNHours[d2]>0){ | |
int actIndex=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndex=sbgTimetable(d2,h2); | |
if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex)) | |
actIndex=-1; | |
if(actIndex>=0){ | |
assert(!acts.contains(actIndex)); | |
acts.append(actIndex); | |
} | |
} | |
} | |
//} | |
if(acts.count()>0){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
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 | |
{ | |
Q_UNUSED(sbg); | |
//remove an activity from anywhere | |
QList<int> acts; | |
//for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(sbgDayNHours[d2]>0){ | |
int actIndex=-1; | |
int h2; | |
for(h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(sbgTimetable(d2,h2)>=0){ | |
actIndex=sbgTimetable(d2,h2); | |
if(fixedTimeActivity[actIndex] || swappedActivities[actIndex] || actIndex==ai || acts.contains(actIndex) || !gt.rules.internalActivitiesList[actIndex].iActivityTagsSet.contains(actTag)) | |
actIndex=-1; | |
if(actIndex>=0){ | |
assert(!acts.contains(actIndex)); | |
acts.append(actIndex); | |
} | |
} | |
} | |
//} | |
if(acts.count()>0){ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int ai2=acts.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
int ai2=acts.at(t); | |
removedActivity=ai2; | |
assert(!conflActivities.contains(ai2)); | |
conflActivities.append(ai2); | |
nConflActivities++; | |
assert(nConflActivities==conflActivities.count()); | |
return true; | |
} | |
else | |
return false; | |
} | |
inline bool skipRandom(double weightPercentage) | |
{ | |
if(weightPercentage<0) | |
return true; //non-existing constraint | |
if(weightPercentage>=100.0) | |
return false; | |
double t=weightPercentage/100.0; | |
assert(t>=0 && t<=1); | |
t*=double(MM); | |
int tt=int(floor(t+0.5)); | |
assert(tt>=0 && tt<=MM); | |
int r=randomKnuth1MM1(); | |
assert(r>0 && r<MM); //r cannot be 0 | |
if(tt<=r) | |
return true; | |
else | |
return false; | |
} | |
Generate::Generate() | |
{ | |
} | |
Generate::~Generate() | |
{ | |
} | |
bool Generate::precompute(QTextStream* initialOrderStream) | |
{ | |
return processTimeSpaceConstraints(initialOrderStream); | |
} | |
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) | |
{ | |
assert((sbg==-1 && tch>=0) || (sbg>=0 && tch==-1)); | |
if(sbg>=0) | |
assert(sbg<gt.rules.nInternalSubgroups); | |
if(tch>=0) | |
assert(tch<gt.rules.nInternalTeachers); | |
if(sbg>=0) | |
assert(minGapsBetweenBuildingChangesForStudentsPercentages[sbg]>=0 || maxBuildingChangesPerDayForStudentsPercentages[sbg]>=0 | |
|| maxBuildingChangesPerWeekForStudentsPercentages[sbg]>=0); | |
if(tch>=0) | |
assert(minGapsBetweenBuildingChangesForTeachersPercentages[tch]>=0 || maxBuildingChangesPerDayForTeachersPercentages[tch]>=0 | |
|| maxBuildingChangesPerWeekForTeachersPercentages[tch]>=0); | |
int buildings[MAX_HOURS_PER_DAY], activities[MAX_HOURS_PER_DAY]; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2; | |
if(sbg>=0) | |
ai2=newSubgroupsTimetable(sbg,d,h2); | |
else | |
ai2=newTeachersTimetable(tch,d,h2); | |
if(ai2>=0 && !globalConflActivities.contains(ai2) && !tmp_list.contains(ai2)){ | |
int rm2; | |
if(h2>=h && h2<h+act->duration){ | |
assert(ai2==ai); | |
rm2=rm; | |
} | |
else | |
rm2=c.rooms[ai2]; | |
if(rm2!=UNALLOCATED_SPACE && rm2!=UNSPECIFIED_ROOM){ | |
assert(rm2>=0); | |
activities[h2]=ai2; | |
buildings[h2]=gt.rules.internalRoomsList[rm2]->buildingIndex; | |
} | |
else{ | |
activities[h2]=ai2; | |
buildings[h2]=-1; | |
} | |
} | |
else{ | |
buildings[h2]=-1; | |
activities[h2]=-1; | |
} | |
} | |
if(buildings[h]==-1) //no problem | |
return true; | |
//min gaps | |
double perc; | |
int mg; | |
if(sbg>=0){ | |
perc=minGapsBetweenBuildingChangesForStudentsPercentages[sbg]; | |
mg=minGapsBetweenBuildingChangesForStudentsMinGaps[sbg]; | |
} | |
else{ | |
perc=minGapsBetweenBuildingChangesForTeachersPercentages[tch]; | |
mg=minGapsBetweenBuildingChangesForTeachersMinGaps[tch]; | |
} | |
if(perc>=0){ | |
for(int h2=max(0, h-mg); h2<=min(h+act->duration-1+mg, gt.rules.nHoursPerDay-1); h2++) | |
if(!(h2>=h && h2<h+act->duration)) | |
if(buildings[h2]!=buildings[h] && buildings[h2]!=-1){ | |
int ai2=activities[h2]; | |
assert(ai2>=0); | |
if(!swappedActivities[ai2] && !(fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2])){ | |
if(!tmp_list.contains(ai2)){ | |
tmp_list.append(ai2); | |
int ha=c.times[ai2]/gt.rules.nDaysPerWeek; | |
int dura=gt.rules.internalActivitiesList[ai2].duration; | |
for(int h3=ha; h3<ha+dura; h3++){ | |
assert(activities[h3]==ai2); | |
assert(buildings[h3]!=-1); | |
buildings[h3]=-1; | |
activities[h3]=-1; | |
} | |
} | |
} | |
else{ | |
return false; | |
} | |
} | |
} | |
//max changes per day | |
int mc; | |
if(sbg>=0){ | |
perc=maxBuildingChangesPerDayForStudentsPercentages[sbg]; | |
mc=maxBuildingChangesPerDayForStudentsMaxChanges[sbg]; | |
} | |
else{ | |
perc=maxBuildingChangesPerDayForTeachersPercentages[tch]; | |
mc=maxBuildingChangesPerDayForTeachersMaxChanges[tch]; | |
} | |
if(perc>=0){ | |
int crt_building=-1; | |
int n_changes=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(buildings[h2]!=-1){ | |
if(crt_building!=buildings[h2]){ | |
if(crt_building!=-1) | |
n_changes++; | |
crt_building=buildings[h2]; | |
} | |
} | |
if(n_changes>mc){ //not OK | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION) | |
return false; | |
QList<int> removableActsList; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(!(h2>=h && h2<h+act->duration)) | |
if(buildings[h2]!=-1 && activities[h2]>=0 && !swappedActivities[activities[h2]] && !(fixedTimeActivity[activities[h2]]&&fixedSpaceActivity[activities[h2]])) | |
if(!removableActsList.contains(activities[h2])){ | |
removableActsList.append(activities[h2]); | |
assert(!globalConflActivities.contains(activities[h2])); | |
assert(!tmp_list.contains(activities[h2])); | |
} | |
} | |
for(;;){ | |
int ai2=-1; | |
QList<int> optimalRemovableActs; | |
if(level==0){ | |
int nWrong=INF; | |
foreach(int a, removableActsList) | |
if(nWrong>triedRemovals(a,c.times[a]) ){ | |
nWrong=triedRemovals(a,c.times[a]); | |
} | |
foreach(int a, removableActsList) | |
if(nWrong==triedRemovals(a,c.times[a])) | |
optimalRemovableActs.append(a); | |
} | |
else | |
optimalRemovableActs=removableActsList; | |
if(removableActsList.count()>0) | |
assert(optimalRemovableActs.count()>0); | |
if(optimalRemovableActs.count()==0) | |
return false; | |
ai2=optimalRemovableActs.at(randomKnuth(optimalRemovableActs.count())); | |
assert(!swappedActivities[ai2]); | |
assert(!(fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2])); | |
assert(!globalConflActivities.contains(ai2)); | |
assert(!tmp_list.contains(ai2)); | |
assert(ai2>=0); | |
tmp_list.append(ai2); | |
int t=removableActsList.removeAll(ai2); | |
assert(t==1); | |
int ha=c.times[ai2]/gt.rules.nDaysPerWeek; | |
int da=gt.rules.internalActivitiesList[ai2].duration; | |
for(int h2=ha; h2<ha+da; h2++){ | |
assert(activities[h2]==ai2); | |
assert(buildings[h2]!=-1); | |
buildings[h2]=-1; | |
activities[h2]=-1; | |
} | |
int crt_building=-1; | |
int n_changes=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(buildings[h2]!=-1){ | |
if(crt_building!=buildings[h2]){ | |
if(crt_building!=-1) | |
n_changes++; | |
crt_building=buildings[h2]; | |
} | |
} | |
if(n_changes<=mc){ //OK | |
break; | |
} | |
} | |
} | |
} | |
//max changes per week | |
if(sbg>=0){ | |
perc=maxBuildingChangesPerWeekForStudentsPercentages[sbg]; | |
mc=maxBuildingChangesPerWeekForStudentsMaxChanges[sbg]; | |
} | |
else{ | |
perc=maxBuildingChangesPerWeekForTeachersPercentages[tch]; | |
mc=maxBuildingChangesPerWeekForTeachersMaxChanges[tch]; | |
} | |
if(perc==-1){ | |
assert(mc==-1); | |
return true; | |
} | |
//I would like to get rid of these large static variables, but making them dynamic slows down ~33% for a sample from Timisoara Economics | |
int weekBuildings[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY], weekActivities[MAX_DAYS_PER_WEEK][MAX_HOURS_PER_DAY]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2; | |
if(sbg>=0) | |
ai2=newSubgroupsTimetable(sbg,d2,h2); | |
else | |
ai2=newTeachersTimetable(tch,d2,h2); | |
if(ai2>=0 && !globalConflActivities.contains(ai2) && !tmp_list.contains(ai2)){ | |
int rm2; | |
if(d==d2 && h2>=h && h2<h+act->duration){ | |
assert(ai2==ai); | |
rm2=rm; | |
} | |
else | |
rm2=c.rooms[ai2]; | |
if(rm2!=UNALLOCATED_SPACE && rm2!=UNSPECIFIED_ROOM){ | |
assert(rm2>=0); | |
weekActivities[d2][h2]=ai2; | |
weekBuildings[d2][h2]=gt.rules.internalRoomsList[rm2]->buildingIndex; | |
} | |
else{ | |
weekActivities[d2][h2]=ai2; | |
weekBuildings[d2][h2]=-1; | |
} | |
} | |
else{ | |
weekBuildings[d2][h2]=-1; | |
weekActivities[d2][h2]=-1; | |
} | |
} | |
} | |
int n_changes=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int crt_building=-1; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(weekBuildings[d2][h2]!=-1){ | |
if(crt_building!=weekBuildings[d2][h2]){ | |
if(crt_building!=-1) | |
n_changes++; | |
crt_building=weekBuildings[d2][h2]; | |
} | |
} | |
} | |
if(n_changes>mc){ //not OK | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION) | |
return false; | |
QList<int> removableActsList; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(!(d2==d && h2>=h && h2<h+act->duration)) | |
if(weekBuildings[d2][h2]!=-1 && weekActivities[d2][h2]>=0 && !swappedActivities[weekActivities[d2][h2]] && !(fixedTimeActivity[weekActivities[d2][h2]]&&fixedSpaceActivity[weekActivities[d2][h2]])) | |
if(!removableActsList.contains(weekActivities[d2][h2])){ | |
removableActsList.append(weekActivities[d2][h2]); | |
assert(!globalConflActivities.contains(weekActivities[d2][h2])); | |
assert(!tmp_list.contains(weekActivities[d2][h2])); | |
} | |
} | |
} | |
for(;;){ | |
int ai2=-1; | |
QList<int> optimalRemovableActs; | |
if(level==0){ | |
int nWrong=INF; | |
foreach(int a, removableActsList) | |
if(nWrong>triedRemovals(a,c.times[a])){ | |
nWrong=triedRemovals(a,c.times[a]); | |
} | |
foreach(int a, removableActsList) | |
if(nWrong==triedRemovals(a,c.times[a])) | |
optimalRemovableActs.append(a); | |
} | |
else | |
optimalRemovableActs=removableActsList; | |
if(removableActsList.count()>0) | |
assert(optimalRemovableActs.count()>0); | |
if(optimalRemovableActs.count()==0) | |
return false; | |
ai2=optimalRemovableActs.at(randomKnuth(optimalRemovableActs.count())); | |
assert(!swappedActivities[ai2]); | |
assert(!(fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2])); | |
assert(!globalConflActivities.contains(ai2)); | |
assert(!tmp_list.contains(ai2)); | |
assert(ai2>=0); | |
tmp_list.append(ai2); | |
int t=removableActsList.removeAll(ai2); | |
assert(t==1); | |
int ha=c.times[ai2]/gt.rules.nDaysPerWeek; | |
int da=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int dura=gt.rules.internalActivitiesList[ai2].duration; | |
for(int h2=ha; h2<ha+dura; h2++){ | |
assert(weekActivities[da][h2]==ai2); | |
assert(weekBuildings[da][h2]!=-1); | |
weekBuildings[da][h2]=-1; | |
weekActivities[da][h2]=-1; | |
} | |
int n_changes=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int crt_building=-1; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++) | |
if(weekBuildings[d2][h2]!=-1){ | |
if(crt_building!=weekBuildings[d2][h2]){ | |
if(crt_building!=-1) | |
n_changes++; | |
crt_building=weekBuildings[d2][h2]; | |
} | |
} | |
} | |
if(n_changes<=mc){ //OK | |
break; | |
} | |
} | |
} | |
return true; | |
} | |
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) | |
{ | |
roomSlot=selectedSlot=UNSPECIFIED_ROOM; //if we don't find a room, return these values | |
Q_UNUSED(ai); | |
int optConflActivities=MAX_ACTIVITIES; | |
int optMinWrong=INF; | |
int optNWrong=INF; | |
QList<QList<int> > conflActivitiesRooms; | |
QList<int> nConflActivitiesRooms; | |
QList<int> listedRooms; | |
QList<int> minWrong; | |
QList<int> nWrong; | |
QList<int> minIndexAct; | |
QList<int> tmp_list; | |
int tmp_n_confl_acts; | |
int tmp_minWrong; | |
int tmp_nWrong; | |
int newtime=d+h*gt.rules.nDaysPerWeek; | |
foreach(int rm, listOfRooms){ | |
int dur; | |
for(dur=0; dur<act->duration; dur++) | |
if(notAllowedRoomTimePercentages[rm][newtime+dur*gt.rules.nDaysPerWeek]>=0 && | |
!skipRandom(notAllowedRoomTimePercentages[rm][newtime+dur*gt.rules.nDaysPerWeek])) | |
break; | |
if(dur==act->duration){ | |
tmp_list.clear(); | |
int dur2; | |
for(dur2=0; dur2<act->duration; dur2++){ | |
int ai2=roomsTimetable(rm,d,h+dur2); | |
if(ai2>=0){ | |
if(!globalConflActivities.contains(ai2)){ | |
if(swappedActivities[ai2] || (fixedTimeActivity[ai2]&&fixedSpaceActivity[ai2])){ | |
tmp_n_confl_acts=MAX_ACTIVITIES; //not really needed | |
break; | |
} | |
else{ | |
if(!tmp_list.contains(ai2)){ | |
tmp_list.append(ai2); | |
} | |
} | |
} | |
} | |
} | |
if(dur2==act->duration){ | |
//see building changes | |
//building changes for students | |
bool ok=true; | |
foreach(int sbg, act->iSubgroupsList){ | |
if(minGapsBetweenBuildingChangesForStudentsPercentages[sbg]>=0 || maxBuildingChangesPerDayForStudentsPercentages[sbg]>=0 | |
|| maxBuildingChangesPerWeekForStudentsPercentages[sbg]>=0){ | |
ok=checkBuildingChanges(sbg, -1, globalConflActivities, rm, level, act, ai, d, h, tmp_list); | |
if(!ok) | |
break; | |
} | |
} | |
if(!ok) | |
continue; | |
foreach(int tch, act->iTeachersList){ | |
if(minGapsBetweenBuildingChangesForTeachersPercentages[tch]>=0 || maxBuildingChangesPerDayForTeachersPercentages[tch]>=0 | |
|| maxBuildingChangesPerWeekForTeachersPercentages[tch]>=0){ | |
ok=checkBuildingChanges(-1, tch, globalConflActivities, rm, level, act, ai, d, h, tmp_list); | |
if(!ok) | |
break; | |
} | |
} | |
if(!ok) | |
continue; | |
tmp_n_confl_acts=0; | |
tmp_minWrong=INF; | |
tmp_nWrong=0; | |
tmp_n_confl_acts=tmp_list.count(); | |
if(level==0){ | |
foreach(int ai2, tmp_list){ | |
tmp_minWrong=min(tmp_minWrong, triedRemovals(ai2,c.times[ai2])); | |
tmp_nWrong+=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
listedRooms.append(rm); | |
nConflActivitiesRooms.append(tmp_n_confl_acts); | |
conflActivitiesRooms.append(tmp_list); | |
if(level>0){ | |
if(tmp_n_confl_acts<optConflActivities) | |
optConflActivities=tmp_n_confl_acts; | |
} | |
else{ // if(level==0) | |
minWrong.append(tmp_minWrong); | |
nWrong.append(tmp_nWrong); | |
if(optMinWrong>tmp_minWrong || | |
(optMinWrong==tmp_minWrong && optNWrong>tmp_nWrong) || | |
(optMinWrong==tmp_minWrong && optNWrong==tmp_nWrong && optConflActivities>tmp_n_confl_acts)){ | |
optConflActivities=tmp_n_confl_acts; | |
optMinWrong=tmp_minWrong; | |
optNWrong=tmp_nWrong; | |
} | |
} | |
} | |
} | |
else //not really needed | |
tmp_n_confl_acts=MAX_ACTIVITIES; | |
} | |
if(optConflActivities==MAX_ACTIVITIES) //roomSlot == selectedSlot == UNSPECIFIED_ROOM | |
return false; | |
assert(optConflActivities<MAX_ACTIVITIES); | |
QList<int> allowedRoomsIndex; | |
assert(listedRooms.count()==nConflActivitiesRooms.count()); | |
assert(listedRooms.count()==conflActivitiesRooms.count()); | |
if(level>0){ | |
for(int q=0; q<listedRooms.count(); q++){ | |
if(nConflActivitiesRooms.at(q)==optConflActivities){ | |
allowedRoomsIndex.append(q); | |
} | |
} | |
} | |
else{ | |
for(int q=0; q<listedRooms.count(); q++){ | |
if(optMinWrong==minWrong.at(q) && optNWrong==nWrong.at(q) && nConflActivitiesRooms.at(q)==optConflActivities){ | |
allowedRoomsIndex.append(q); | |
} | |
} | |
/*if(allowedRoomsIndex.count()!=1) | |
cout<<"allowedRoomsIndex.count()=="<<allowedRoomsIndex.count()<<endl; | |
assert(allowedRoomsIndex.count()==1);*/ | |
} | |
assert(allowedRoomsIndex.count()>0); | |
int q=randomKnuth(allowedRoomsIndex.count()); | |
int t=allowedRoomsIndex.at(q); | |
assert(t>=0 && t<listedRooms.count()); | |
int r=listedRooms.at(t); | |
assert(r>=0 && r<gt.rules.nInternalRooms); | |
selectedSlot=r; | |
roomSlot=r; | |
assert(nConflActivitiesRooms.at(t)==conflActivitiesRooms.at(t).count()); | |
localConflActivities.clear(); /////Liviu: added 22 august 2008, nasty crash bug fix | |
foreach(int a, conflActivitiesRooms.at(t)){ | |
assert(!globalConflActivities.contains(a)); | |
assert(!localConflActivities.contains(a)); ///////////Liviu: added 22 august 2008 | |
localConflActivities.append(a); | |
} | |
return true; | |
} | |
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) | |
{ | |
assert(!unspecifiedHomeRoom[ai]); | |
return chooseRoom(activitiesHomeRoomsHomeRooms[ai], globalConflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities); | |
} | |
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) | |
{ | |
assert(!unspecifiedPreferredRoom[ai]); | |
bool unspecifiedRoom=true; | |
QSet<int> allowedRooms; | |
foreach(PreferredRoomsItem it, activitiesPreferredRoomsList[ai]){ | |
bool skip=skipRandom(it.percentage); | |
if(!skip){ | |
if(unspecifiedRoom){ | |
unspecifiedRoom=false; | |
allowedRooms=it.preferredRooms; | |
} | |
else{ | |
allowedRooms.intersect(it.preferredRooms); | |
} | |
} | |
else{ | |
if(unspecifiedRoom){ | |
allowedRooms.unite(it.preferredRooms); | |
} | |
else{ | |
//do nothing | |
} | |
} | |
} | |
QList<int> allowedRoomsList; | |
foreach(int rm, allowedRooms) | |
allowedRoomsList.append(rm); | |
canBeUnspecifiedPreferredRoom=unspecifiedRoom; | |
return chooseRoom(allowedRoomsList, globalConflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities); | |
} | |
inline bool Generate::getRoom(int level, const Activity* act, int ai, int d, int h, int& roomSlot, int& selectedSlot, QList<int>& conflActivities, int& nConflActivities) | |
{ | |
bool okp, okh; | |
QList<int> localConflActivities; | |
if(unspecifiedPreferredRoom[ai]){ | |
if(unspecifiedHomeRoom[ai]){ | |
roomSlot=UNSPECIFIED_ROOM; | |
selectedSlot=UNSPECIFIED_ROOM; | |
return true; | |
} | |
else{ | |
okh=getHomeRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities); | |
if(okh){ | |
foreach(int t, localConflActivities){ | |
conflActivities.append(t); | |
nConflActivities++; | |
} | |
return okh; | |
} | |
else{ | |
okh=skipRandom(activitiesHomeRoomsPercentage[ai]); | |
return okh; | |
} | |
} | |
} | |
else{ | |
bool canBeUnspecifiedPreferredRoom; | |
okp=getPreferredRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities, canBeUnspecifiedPreferredRoom); | |
if(okp && localConflActivities.count()==0){ | |
/*foreach(int t, localConflActivities){ | |
conflActivities.append(t); | |
nConflActivities++; | |
} | |
assert(nConflActivities==conflActivities.count());*/ | |
return okp; | |
} | |
else if(okp){ | |
if(canBeUnspecifiedPreferredRoom){ //skipRandom(activitiesPreferredRoomsPercentage[ai])){ | |
//get a home room | |
if(unspecifiedHomeRoom[ai]){ | |
roomSlot=UNSPECIFIED_ROOM; | |
selectedSlot=UNSPECIFIED_ROOM; | |
return true; | |
} | |
okh=getHomeRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities); | |
if(okh){ | |
foreach(int t, localConflActivities){ | |
conflActivities.append(t); | |
nConflActivities++; | |
} | |
return okh; | |
} | |
else{ | |
okh=skipRandom(activitiesHomeRoomsPercentage[ai]); | |
return okh; | |
} | |
} | |
else{ | |
foreach(int t, localConflActivities){ | |
conflActivities.append(t); | |
nConflActivities++; | |
} | |
assert(nConflActivities==conflActivities.count()); | |
assert(okp==true); | |
return okp; | |
//get this preferred room | |
} | |
} | |
else{ //!ok from preferred room, search a home room | |
if(canBeUnspecifiedPreferredRoom){ //skipRandom(activitiesPreferredRoomsPercentage[ai])){ | |
//get a home room | |
if(unspecifiedHomeRoom[ai]){ | |
roomSlot=UNSPECIFIED_ROOM; | |
selectedSlot=UNSPECIFIED_ROOM; | |
return true; | |
} | |
okh=getHomeRoom(conflActivities, level, act, ai, d, h, roomSlot, selectedSlot, localConflActivities); | |
if(okh){ | |
foreach(int t, localConflActivities){ | |
conflActivities.append(t); | |
nConflActivities++; | |
} | |
return okh; | |
} | |
else{ | |
okh=skipRandom(activitiesHomeRoomsPercentage[ai]); | |
return okh; | |
} | |
} | |
else{ | |
assert(okp==false); | |
return okp; | |
} | |
} | |
} | |
} | |
void Generate::generate(int maxSeconds, bool& impossible, bool& timeExceeded, bool threaded, QTextStream* maxPlacedActivityStream) | |
{ | |
l0nWrong.resize(gt.rules.nHoursPerWeek); | |
l0minWrong.resize(gt.rules.nHoursPerWeek); | |
l0minIndexAct.resize(gt.rules.nHoursPerWeek); | |
teachersTimetable.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
subgroupsTimetable.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
roomsTimetable.resize(gt.rules.nInternalRooms, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
newTeachersTimetable.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
newSubgroupsTimetable.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
newTeachersDayNHours.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek); | |
newTeachersDayNGaps.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek); | |
newSubgroupsDayNHours.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek); | |
newSubgroupsDayNGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek); | |
newSubgroupsDayNFirstGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek); | |
oldTeachersTimetable.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
oldSubgroupsTimetable.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
oldTeachersDayNHours.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek); | |
oldTeachersDayNGaps.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek); | |
oldSubgroupsDayNHours.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek); | |
oldSubgroupsDayNGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek); | |
oldSubgroupsDayNFirstGaps.resize(gt.rules.nInternalSubgroups, gt.rules.nDaysPerWeek); | |
tchTimetable.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
tchDayNHours.resize(gt.rules.nDaysPerWeek); | |
tchDayNGaps.resize(gt.rules.nDaysPerWeek); | |
sbgTimetable.resize(gt.rules.nDaysPerWeek, gt.rules.nHoursPerDay); | |
sbgDayNHours.resize(gt.rules.nDaysPerWeek); | |
sbgDayNGaps.resize(gt.rules.nDaysPerWeek); | |
sbgDayNFirstGaps.resize(gt.rules.nDaysPerWeek); | |
teacherActivitiesOfTheDay.resize(gt.rules.nInternalTeachers, gt.rules.nDaysPerWeek); | |
if(threaded){ | |
mutex.lock(); | |
} | |
c.makeUnallocated(gt.rules); | |
nDifficultActivities=0; | |
impossible=false; | |
timeExceeded=false; | |
maxncallsrandomswap=-1; | |
impossibleActivity=false; | |
maxActivitiesPlaced=0; | |
if(threaded){ | |
mutex.unlock(); | |
} | |
triedRemovals.resize(gt.rules.nInternalActivities, gt.rules.nHoursPerWeek); | |
for(int i=0; i<gt.rules.nInternalActivities; i++) | |
for(int j=0; j<gt.rules.nHoursPerWeek; j++) | |
triedRemovals(i,j)=0; | |
////////init tabu | |
tabu_size=gt.rules.nInternalActivities*gt.rules.nHoursPerWeek; | |
//assert(tabu_size<=MAX_TABU); | |
crt_tabu_index=0; | |
/*qint16 tabu_activities[MAX_TABU]; | |
qint16 tabu_times[MAX_TABU];*/ | |
tabu_activities.resize(tabu_size); | |
tabu_times.resize(tabu_size); | |
for(int i=0; i<tabu_size; i++) | |
tabu_activities[i]=tabu_times[i]=-1; | |
///////////////// | |
//abortOptimization=false; you have to take care of this before calling this function | |
for(int i=0; i<gt.rules.nInternalActivities; i++) | |
invPermutation[permutation[i]]=i; | |
for(int i=0; i<gt.rules.nInternalActivities; i++) | |
swappedActivities[permutation[i]]=false; | |
//tzset(); | |
time_t starting_time; | |
time(&starting_time); | |
if(threaded){ | |
mutex.lock(); | |
} | |
timeToHighestStage=0; | |
searchTime=0; | |
generationStartDateTime=QDateTime::currentDateTime(); | |
if(threaded){ | |
mutex.unlock(); | |
} | |
//2000 was before | |
//limitcallsrandomswap=1000; //1600, 1500 also good values, 1000 too low??? | |
limitcallsrandomswap=2*gt.rules.nInternalActivities; //???? value found practically | |
level_limit=14; //20; //16 | |
assert(level_limit<MAX_LEVEL); | |
for(int added_act=0; added_act<gt.rules.nInternalActivities; added_act++){ | |
prevvalue: | |
if(threaded){ | |
mutex.lock(); | |
} | |
if(abortOptimization){ | |
if(threaded){ | |
mutex.unlock(); | |
} | |
return; | |
} | |
time_t crt_time; | |
time(&crt_time); | |
searchTime=int(crt_time-starting_time); | |
if(searchTime>=maxSeconds){ | |
if(threaded){ | |
mutex.unlock(); | |
} | |
timeExceeded=true; | |
return; | |
} | |
for(int i=0; i<=added_act; i++) | |
swappedActivities[permutation[i]]=false; | |
for(int i=added_act+1; i<gt.rules.nInternalActivities; i++) | |
assert(!swappedActivities[permutation[i]]); | |
cout<<endl<<"Trying to place activity number added_act=="<<added_act<< | |
"\nwith id=="<<gt.rules.internalActivitiesList[permutation[added_act]].id<< | |
", from nInternalActivities=="<<gt.rules.nInternalActivities<<endl; | |
//verifyUnallocated(permutation[added_act]]); | |
//assert(c.times[permutation[added_act]]==UNALLOCATED_TIME); | |
//assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE); | |
if(fixedTimeActivity[permutation[added_act]] && fixedSpaceActivity[permutation[added_act]]){ | |
assert(c.times[permutation[added_act]]==UNALLOCATED_TIME); | |
assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE); | |
} | |
else if(fixedTimeActivity[permutation[added_act]] && !fixedSpaceActivity[permutation[added_act]]){ | |
assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE); | |
} | |
else if(!fixedTimeActivity[permutation[added_act]]){ | |
assert(c.times[permutation[added_act]]==UNALLOCATED_TIME); | |
assert(c.rooms[permutation[added_act]]==UNALLOCATED_SPACE); | |
} | |
else | |
assert(0); | |
for(int i=0; i<added_act; i++){ | |
if(c.times[permutation[i]]==UNALLOCATED_TIME) | |
cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has time unallocated"<<endl; | |
assert(c.times[permutation[i]]!=UNALLOCATED_TIME); | |
/*for(int j=0; j<gt.rules.internalActivitiesList[permutation[i]].duration; j++) | |
tlistSet[c.times[permutation[i]]+j*gt.rules.nDaysPerWeek].insert(permutation[i]);*/ | |
if(c.rooms[permutation[i]]==UNALLOCATED_SPACE) | |
cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has room unallocated"<<endl; | |
assert(c.rooms[permutation[i]]!=UNALLOCATED_SPACE); | |
} | |
///////////////rooms' timetable | |
for(int i=0; i<gt.rules.nInternalRooms; i++) | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
for(int k=0; k<gt.rules.nHoursPerDay; k++) | |
roomsTimetable(i,j,k)=-1; | |
for(int j=0; j<added_act; j++){ | |
int i=permutation[j]; | |
assert(c.rooms[i]!=UNALLOCATED_SPACE); | |
if(c.rooms[i]!=UNSPECIFIED_ROOM){ | |
int rm=c.rooms[i]; | |
Activity* act=>.rules.internalActivitiesList[i]; | |
int hour=c.times[i]/gt.rules.nDaysPerWeek; | |
int day=c.times[i]%gt.rules.nDaysPerWeek; | |
for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){ | |
assert(roomsTimetable(rm,day,hour+dd)==-1); | |
roomsTimetable(rm,day,hour+dd)=i; | |
} | |
} | |
} | |
/////////////////////////////// | |
//subgroups' timetable | |
for(int i=0; i<gt.rules.nInternalSubgroups; i++) | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
for(int k=0; k<gt.rules.nHoursPerDay; k++){ | |
subgroupsTimetable(i,j,k)=-1; | |
} | |
for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){ | |
int i=permutation[j]; | |
if(j<added_act){ | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
} | |
else{ | |
if(c.times[i]==UNALLOCATED_TIME) | |
continue; | |
} | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
Activity* act=>.rules.internalActivitiesList[i]; | |
int hour=c.times[i]/gt.rules.nDaysPerWeek; | |
int day=c.times[i]%gt.rules.nDaysPerWeek; | |
foreach(int sb, act->iSubgroupsList){ | |
for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){ | |
assert(subgroupsTimetable(sb,day,hour+dd)==-1); | |
subgroupsTimetable(sb,day,hour+dd)=i; | |
} | |
} | |
} | |
//new | |
for(int i=0; i<gt.rules.nInternalSubgroups; i++) | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
for(int k=0; k<gt.rules.nHoursPerDay; k++){ | |
newSubgroupsTimetable(i,j,k)=-1; | |
} | |
for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){ | |
int i=permutation[j]; | |
if(j<added_act){ | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
} | |
else{ | |
if(c.times[i]==UNALLOCATED_TIME) | |
continue; | |
} | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
Activity* act=>.rules.internalActivitiesList[i]; | |
int hour=c.times[i]/gt.rules.nDaysPerWeek; | |
int day=c.times[i]%gt.rules.nDaysPerWeek; | |
foreach(int sb, act->iSubgroupsList){ | |
for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){ | |
assert(newSubgroupsTimetable(sb,day,hour+dd)==-1); | |
newSubgroupsTimetable(sb,day,hour+dd)=i; | |
} | |
} | |
} | |
for(int i=0; i<gt.rules.nInternalSubgroups; i++) | |
subgroupGetNHoursGaps(i); | |
//teachers' timetable | |
for(int i=0; i<gt.rules.nInternalTeachers; i++) | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
for(int k=0; k<gt.rules.nHoursPerDay; k++){ | |
teachersTimetable(i,j,k)=-1; | |
} | |
for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){ | |
int i=permutation[j]; | |
if(j<added_act){ | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
} | |
else{ | |
if(c.times[i]==UNALLOCATED_TIME) | |
continue; | |
} | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
Activity* act=>.rules.internalActivitiesList[i]; | |
int hour=c.times[i]/gt.rules.nDaysPerWeek; | |
int day=c.times[i]%gt.rules.nDaysPerWeek; | |
foreach(int tc, act->iTeachersList){ | |
for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){ | |
assert(teachersTimetable(tc,day,hour+dd)==-1); | |
teachersTimetable(tc,day,hour+dd)=i; | |
} | |
} | |
} | |
//new | |
for(int i=0; i<gt.rules.nInternalTeachers; i++) | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
for(int k=0; k<gt.rules.nHoursPerDay; k++){ | |
newTeachersTimetable(i,j,k)=-1; | |
} | |
for(int j=0; j<gt.rules.nInternalActivities/*added_act*/; j++){ | |
int i=permutation[j]; | |
if(j<added_act){ | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
} | |
else{ | |
if(c.times[i]==UNALLOCATED_TIME) | |
continue; | |
} | |
assert(c.times[i]!=UNALLOCATED_TIME); | |
Activity* act=>.rules.internalActivitiesList[i]; | |
int hour=c.times[i]/gt.rules.nDaysPerWeek; | |
int day=c.times[i]%gt.rules.nDaysPerWeek; | |
foreach(int tc, act->iTeachersList){ | |
for(int dd=0; dd<act->duration && hour+dd<gt.rules.nHoursPerDay; dd++){ | |
assert(newTeachersTimetable(tc,day,hour+dd)==-1); | |
newTeachersTimetable(tc,day,hour+dd)=i; | |
} | |
} | |
} | |
for(int i=0; i<gt.rules.nInternalTeachers; i++) | |
teacherGetNHoursGaps(i); | |
//////////////care for teachers max days per week | |
for(int i=0; i<gt.rules.nInternalTeachers; i++) | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
teacherActivitiesOfTheDay(i,j).clear(); | |
for(int i=0; i<gt.rules.nInternalActivities/*added_act*/; i++){ | |
if(i<added_act){ | |
} | |
else{ | |
if(c.times[permutation[i]]==UNALLOCATED_TIME) | |
continue; | |
} | |
//Activity* act=>.rules.internalActivitiesList[permutation[i]]; | |
int d=c.times[permutation[i]]%gt.rules.nDaysPerWeek; | |
foreach(int j, teachersWithMaxDaysPerWeekForActivities[permutation[i]]){ | |
assert(teacherActivitiesOfTheDay(j,d).indexOf(permutation[i])==-1); | |
teacherActivitiesOfTheDay(j,d).append(permutation[i]); | |
} | |
} | |
////////////// | |
foundGoodSwap=false; | |
assert(!swappedActivities[permutation[added_act]]); | |
swappedActivities[permutation[added_act]]=true; | |
nRestore=0; | |
ncallsrandomswap=0; | |
randomSwap(permutation[added_act], 0); | |
if(!foundGoodSwap){ | |
if(impossibleActivity){ | |
if(threaded){ | |
mutex.unlock(); | |
} | |
nDifficultActivities=1; | |
difficultActivities[0]=permutation[added_act]; | |
impossible=true; | |
//emit(impossibleToSolve()); | |
return; | |
} | |
//update difficult activities (activities which are placed correctly so far, together with added_act | |
nDifficultActivities=added_act+1; | |
cout<<"nDifficultActivities=="<<nDifficultActivities<<endl; | |
for(int j=0; j<=added_act; j++) | |
difficultActivities[j]=permutation[j]; | |
////////////////////// | |
assert(conflActivitiesTimeSlot.count()>0); | |
cout<<"conflActivitiesTimeSlot.count()=="<<conflActivitiesTimeSlot.count()<<endl; | |
foreach(int i, conflActivitiesTimeSlot){ | |
cout<<"Confl activity id:"<<gt.rules.internalActivitiesList[i].id; | |
cout<<" time of this activity:"<<c.times[i]; | |
if(c.rooms[i]!=UNSPECIFIED_ROOM) | |
cout<<" room of this activity:"<<qPrintable(gt.rules.internalRoomsList[c.rooms[i]]->name)<<endl; | |
else | |
cout<<" room of this activity: UNSPECIFIED_ROOM"<<endl; | |
} | |
//cout<<endl; | |
cout<<"timeSlot=="<<timeSlot<<endl; | |
if(roomSlot!=UNSPECIFIED_ROOM) | |
cout<<"roomSlot=="<<qPrintable(gt.rules.internalRoomsList[roomSlot]->name)<<endl; | |
else | |
cout<<"roomSlot==UNSPECIFIED_ROOM"<<endl; | |
QList<int> ok; | |
QList<int> confl; | |
for(int j=0; j<added_act; j++){ | |
if(conflActivitiesTimeSlot.indexOf(permutation[j])!=-1){ | |
if(triedRemovals(permutation[j],c.times[permutation[j]])>0){ | |
cout<<"Warning - explored removal: id=="<< | |
gt.rules.internalActivitiesList[permutation[j]].id<<", time=="<<c.times[permutation[j]] | |
<<", times=="<<triedRemovals(permutation[j],c.times[permutation[j]])<<endl; | |
} | |
triedRemovals(permutation[j],c.times[permutation[j]])++; | |
/////update tabu | |
int a=tabu_activities[crt_tabu_index]; | |
int t=tabu_times[crt_tabu_index]; | |
if(a>=0 && t>=0){ | |
assert(triedRemovals(a,t)>0); | |
triedRemovals(a,t)--; | |
//cout<<"Removing activity with id=="<<gt.rules.internalActivitiesList[a].id<<", time=="<<t<<endl; | |
} | |
tabu_activities[crt_tabu_index]=permutation[j]; | |
tabu_times[crt_tabu_index]=c.times[permutation[j]]; | |
//cout<<"Inserting activity with id=="<<gt.rules.internalActivitiesList[permutation[j]].id<<", time=="<<c.times[permutation[j]]<<endl; | |
crt_tabu_index=(crt_tabu_index+1)%tabu_size; | |
//////////////// | |
confl.append(permutation[j]); | |
} | |
else | |
ok.append(permutation[j]); | |
} | |
assert(confl.count()==conflActivitiesTimeSlot.count()); | |
int j=0; | |
int tmp=permutation[added_act]; | |
foreach(int k, ok){ | |
permutation[j]=k; | |
invPermutation[k]=j; | |
j++; | |
} | |
int q=j; | |
//cout<<"q=="<<q<<endl; | |
permutation[j]=tmp; | |
invPermutation[tmp]=j; | |
j++; | |
cout<<"id of permutation[j=="<<j-1<<"]=="<<gt.rules.internalActivitiesList[permutation[j-1]].id<<endl; | |
cout<<"conflicting:"<<endl; | |
foreach(int k, confl){ | |
permutation[j]=k; | |
invPermutation[k]=j; | |
j++; | |
cout<<"id of permutation[j=="<<j-1<<"]=="<<gt.rules.internalActivitiesList[permutation[j-1]].id<<endl; | |
} | |
assert(j==added_act+1); | |
//check | |
/*int pv[MAX_ACTIVITIES]; | |
for(int i=0; i<gt.rules.nInternalActivities; i++) | |
pv[i]=0; | |
for(int i=0; i<gt.rules.nInternalActivities; i++) | |
pv[permutation[i]]++; | |
for(int i=0; i<gt.rules.nInternalActivities; i++) | |
assert(pv[i]==1);*/ | |
// | |
cout<<"tmp represents activity with id=="<<gt.rules.internalActivitiesList[tmp].id; | |
cout<<" initial time: "<<c.times[tmp]; | |
cout<<" final time: "<<timeSlot<<endl; | |
c.times[tmp]=timeSlot; | |
c.rooms[tmp]=roomSlot; | |
for(int i=q+1; i<=added_act; i++){ | |
if(!fixedTimeActivity[permutation[i]]) | |
c.times[permutation[i]]=UNALLOCATED_TIME; | |
c.rooms[permutation[i]]=UNALLOCATED_SPACE; | |
} | |
c._fitness=-1; | |
c.changedForMatrixCalculation=true; | |
added_act=q+1; | |
if(threaded){ | |
mutex.unlock(); | |
} | |
//if(semaphorePlacedActivity){ | |
//emit(activityPlaced(q+1)); | |
if(threaded){ | |
semaphorePlacedActivity.acquire(); | |
} | |
//} | |
goto prevvalue; | |
////////////////////// | |
} | |
else{ //if foundGoodSwap==true | |
nPlacedActivities=added_act+1; | |
if(maxActivitiesPlaced<added_act+1){ | |
generationHighestStageDateTime=QDateTime::currentDateTime(); | |
time_t tmp; | |
time(&tmp); | |
timeToHighestStage=int(tmp-starting_time); | |
highestStageSolution.copy(gt.rules, c); | |
maxActivitiesPlaced=added_act+1; | |
if(maxPlacedActivityStream!=NULL){ | |
int sec=timeToHighestStage; | |
int hh=sec/3600; | |
sec%=3600; | |
int mm=sec/60; | |
sec%=60; | |
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") | |
.arg(hh).arg(mm).arg(sec).arg(maxActivitiesPlaced); | |
//s+="\n"; | |
//QString s=QString("At time ")+QString::number(hh)+QString(" h ")+QString::number(mm)+QString(" m ")+QString::number(sec) | |
// +QString(" s, FET reached ")+QString::number(maxActivitiesPlaced)+QString(" activities placed\n"); | |
(*maxPlacedActivityStream)<<s<<endl; | |
//(*maxPlacedActivityStream).flush(); | |
} | |
} | |
if(threaded){ | |
mutex.unlock(); | |
} | |
//emit(activityPlaced(added_act+1)); | |
if(threaded){ | |
semaphorePlacedActivity.acquire(); | |
} | |
if(threaded){ | |
mutex.lock(); | |
} | |
if(added_act==gt.rules.nInternalActivities && foundGoodSwap){ | |
if(threaded){ | |
mutex.unlock(); | |
} | |
break; | |
} | |
bool ok=true; | |
for(int i=0; i<=added_act; i++){ | |
if(c.times[permutation[i]]==UNALLOCATED_TIME){ | |
cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has time unallocated"<<endl; | |
ok=false; | |
} | |
if(c.rooms[permutation[i]]==UNALLOCATED_SPACE){ | |
cout<<"ERROR: act with id=="<<gt.rules.internalActivitiesList[permutation[i]].id<<" has room unallocated"<<endl; | |
ok=false; | |
} | |
} | |
assert(ok); | |
} | |
if(threaded){ | |
mutex.unlock(); | |
} | |
} | |
/* | |
if(threaded){ | |
mutex.lock(); | |
} | |
//c.write(gt.rules, "chromo.dat"); | |
if(threaded){ | |
mutex.unlock(); | |
}*/ | |
time_t end_time; | |
time(&end_time); | |
searchTime=int(end_time-starting_time); | |
cout<<"Total searching time (seconds): "<<int(end_time-starting_time)<<endl; | |
//emit(simulationFinished()); | |
finishedSemaphore.release(); | |
} | |
void Generate::moveActivity(int ai, int fromslot, int toslot, int fromroom, int toroom) | |
{ | |
Activity* act=>.rules.internalActivitiesList[ai]; | |
//cout<<"here: id of act=="<<act->id<<", fromslot=="<<fromslot<<", toslot=="<<toslot<<endl; | |
assert(fromslot==c.times[ai]); | |
assert(fromroom==c.rooms[ai]); | |
if(!fixedTimeActivity[ai] && (fromslot==UNALLOCATED_TIME || fromroom==UNALLOCATED_SPACE)) | |
assert(fromslot==UNALLOCATED_TIME && fromroom==UNALLOCATED_SPACE); | |
if(!fixedTimeActivity[ai] && (toslot==UNALLOCATED_TIME || toroom==UNALLOCATED_SPACE)) | |
assert(toslot==UNALLOCATED_TIME && toroom==UNALLOCATED_SPACE); | |
if(fromslot!=UNALLOCATED_TIME){ | |
int d=fromslot%gt.rules.nDaysPerWeek; | |
int h=fromslot/gt.rules.nDaysPerWeek; | |
////////////////rooms | |
int rm=c.rooms[ai]; | |
if(rm!=UNSPECIFIED_ROOM && rm!=UNALLOCATED_SPACE) | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
if(roomsTimetable(rm,d,h+dd)==ai) | |
roomsTimetable(rm,d,h+dd)=-1; | |
else | |
assert(0); | |
} | |
///////////////////// | |
if(fromslot!=toslot){ | |
//timetable of students | |
for(int q=0; q<act->iSubgroupsList.count(); q++){ | |
int sb=act->iSubgroupsList.at(q); | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(subgroupsTimetable(sb,d,h+dd)==ai); | |
subgroupsTimetable(sb,d,h+dd)=-1; | |
} | |
} | |
foreach(int sb, mustComputeTimetableSubgroups[ai]){ | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(newSubgroupsTimetable(sb,d,h+dd)==ai); | |
newSubgroupsTimetable(sb,d,h+dd)=-1; | |
} | |
} | |
updateSubgroupsNHoursGaps(act, ai, d); | |
//teachers' timetable | |
for(int q=0; q<act->iTeachersList.count(); q++){ | |
int tch=act->iTeachersList.at(q); | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(teachersTimetable(tch,d,h+dd)==ai); | |
teachersTimetable(tch,d,h+dd)=-1; | |
} | |
} | |
foreach(int tch, mustComputeTimetableTeachers[ai]){ | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(newTeachersTimetable(tch,d,h+dd)==ai); | |
newTeachersTimetable(tch,d,h+dd)=-1; | |
} | |
} | |
updateTeachersNHoursGaps(act, ai, d); | |
//update teachers' list of activities for each day | |
///////////////// | |
foreach(int tch, teachersWithMaxDaysPerWeekForActivities[ai]){ | |
int tt=teacherActivitiesOfTheDay(tch,d).removeAll(ai); | |
assert(tt==1); | |
} | |
///////////////// | |
} | |
} | |
c.times[ai]=toslot; | |
c.rooms[ai]=toroom; | |
c._fitness=-1; | |
c.changedForMatrixCalculation=true; | |
if(toslot!=UNALLOCATED_TIME){ | |
int d=toslot%gt.rules.nDaysPerWeek; | |
int h=toslot/gt.rules.nDaysPerWeek; | |
////////////////rooms | |
int rm=c.rooms[ai]; | |
if(rm!=UNSPECIFIED_ROOM && rm!=UNALLOCATED_SPACE) | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(rm!=UNALLOCATED_SPACE); | |
/*if(roomsTimetable(rm,d,h+dd)>=0){ | |
cout<<"room is: "<<qPrintable(gt.rules.internalRoomsList[rm]->name)<<endl; | |
cout<<"day is "<<qPrintable(gt.rules.daysOfTheWeek[d])<<endl; | |
cout<<"hour is "<<qPrintable(gt.rules.hoursOfTheDay[h+dd])<<endl; | |
cout<<"roomsTimetable(rm,d,h+dd) is "<<roomsTimetable(rm,d,h+dd)<<endl; | |
cout<<"and represents room "<<qPrintable(gt.rules.internalRoomsList[roomsTimetable(rm,d,h+dd)]->name)<<endl; | |
}*/ | |
assert(roomsTimetable(rm,d,h+dd)==-1); | |
roomsTimetable(rm,d,h+dd)=ai; | |
} | |
///////////////////// | |
if(fromslot!=toslot){ | |
//compute timetable of subgroups | |
for(int q=0; q<act->iSubgroupsList.count(); q++){ | |
int sb=act->iSubgroupsList.at(q); | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(subgroupsTimetable(sb,d,h+dd)==-1); | |
subgroupsTimetable(sb,d,h+dd)=ai; | |
} | |
} | |
foreach(int sb, mustComputeTimetableSubgroups[ai]){ | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(newSubgroupsTimetable(sb,d,h+dd)==-1); | |
newSubgroupsTimetable(sb,d,h+dd)=ai; | |
} | |
} | |
updateSubgroupsNHoursGaps(act, ai, d); | |
//teachers' timetable | |
for(int q=0; q<act->iTeachersList.count(); q++){ | |
int tch=act->iTeachersList.at(q); | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(teachersTimetable(tch,d,h+dd)==-1); | |
teachersTimetable(tch,d,h+dd)=ai; | |
} | |
} | |
foreach(int tch, mustComputeTimetableTeachers[ai]){ | |
for(int dd=0; dd<gt.rules.internalActivitiesList[ai].duration; dd++){ | |
assert(dd+h<gt.rules.nHoursPerDay); | |
assert(newTeachersTimetable(tch,d,h+dd)==-1); | |
newTeachersTimetable(tch,d,h+dd)=ai; | |
} | |
} | |
////////// | |
updateTeachersNHoursGaps(act, ai, d); | |
//update teachers' list of activities for each day | |
///////////////// | |
foreach(int tch, teachersWithMaxDaysPerWeekForActivities[ai]){ | |
assert(teacherActivitiesOfTheDay(tch,d).indexOf(ai)==-1); | |
teacherActivitiesOfTheDay(tch,d).append(ai); | |
} | |
///////////////// | |
} | |
} | |
} | |
//faster: (to avoid allocating memory at each call) | |
#if 1 | |
static double nMinDaysBrokenL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; | |
static int selectedRoomL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; | |
static int permL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; | |
static QList<int> conflActivitiesL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; | |
//static int conflPermL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; //the permutation in increasing order of number of conflicting activities | |
static int nConflActivitiesL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; | |
static int roomSlotsL[MAX_LEVEL][MAX_HOURS_PER_WEEK]; | |
static int currentLevel; | |
inline bool compareFunctionGenerate(int i, int j) | |
{ | |
if(nConflActivitiesL[currentLevel][i] < nConflActivitiesL[currentLevel][j] || | |
(nConflActivitiesL[currentLevel][i] == nConflActivitiesL[currentLevel][j] && | |
nMinDaysBrokenL[currentLevel][i] < nMinDaysBrokenL[currentLevel][j])) | |
return true; | |
return false; | |
} | |
#define nMinDaysBroken (nMinDaysBrokenL[level]) | |
#define selectedRoom (selectedRoomL[level]) | |
#define perm (permL[level]) | |
#define conflActivities (conflActivitiesL[level]) | |
//#define conflPerm (conflPermL[level]) | |
#define nConflActivities (nConflActivitiesL[level]) | |
#define roomSlots (roomSlotsL[level]) | |
#endif | |
void Generate::randomSwap(int ai, int level){ | |
//cout<<"level=="<<level<<endl; | |
if(level==0){ | |
conflActivitiesTimeSlot.clear(); | |
timeSlot=-1; | |
/*for(int l=0; l<level_limit; l++) | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++){ | |
nMinDaysBrokenL[l][i]=0; | |
selectedRoomL[l][i]=-1; | |
permL[l][i]=-1; | |
conflActivitiesL[l][i].clear(); | |
conflPermL[l][i]=-1; | |
nConflActivitiesL[l][i]=0; | |
roomSlotsL[l][i]=-1; | |
}*/ | |
} | |
if(level>=level_limit){ | |
return; | |
} | |
if(ncallsrandomswap>=limitcallsrandomswap) | |
return; | |
/*for(int i=0; i<gt.rules.nHoursPerWeek; i++){ | |
nMinDaysBroken[i]=0; | |
selectedRoom[i]=-1; | |
perm[i]=-1; | |
conflActivities[i].clear(); | |
conflPerm[i]=-1; | |
nConflActivities[i]=0; | |
roomSlots[i]=-1; | |
}*/ | |
ncallsrandomswap++; | |
Activity* act=>.rules.internalActivitiesList[ai]; | |
bool updateSubgroups=(mustComputeTimetableSubgroups[ai].count()>0); | |
bool updateTeachers=(mustComputeTimetableTeachers[ai].count()>0); | |
#if 0 | |
double nMinDaysBroken[MAX_HOURS_PER_WEEK]; //to count for broken min days between activities constraints | |
int selectedRoom[MAX_HOURS_PER_WEEK]; | |
#endif | |
//cout<<"ai=="<<ai<<", corresponding to id=="<<gt.rules.internalActivitiesList[ai].id<<", level=="<<level<<endl; | |
//generate random permutation in linear time like in CLR (Cormen, Leiserson and Rivest - Introduction to algorithms). | |
//this is used to scan times in random order | |
#if 0 | |
int perm[MAX_HOURS_PER_WEEK]; | |
#endif | |
int activity_count_impossible_tries=1; | |
again_if_impossible_activity: | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
perm[i]=i; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++){ | |
int t=perm[i]; | |
int r=randomKnuth(gt.rules.nHoursPerWeek-i); | |
perm[i]=perm[i+r]; | |
perm[i+r]=t; | |
} | |
/*int checkPerm[MAX_HOURS_PER_WEEK]; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
checkPerm[i]=false; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
checkPerm[perm[i]]=true; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
assert(checkPerm[i]==true);*/ | |
/* | |
cout<<"Perm: "; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
cout<<", perm["<<i<<"]="<<perm[i]; | |
cout<<endl; | |
*/ | |
//record the conflicting activities for each timeslot | |
#if 0 | |
QList<int> conflActivities[MAX_HOURS_PER_WEEK]; | |
int conflPerm[MAX_HOURS_PER_WEEK]; //the permutation in increasing order of number of conflicting activities | |
int nConflActivities[MAX_HOURS_PER_WEEK]; | |
int roomSlots[MAX_HOURS_PER_WEEK]; | |
#endif | |
for(int n=0; n<gt.rules.nHoursPerWeek; n++){ | |
int newtime=perm[n]; | |
if(c.times[ai]!=UNALLOCATED_TIME){ | |
if(c.times[ai]!=newtime){ | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
} | |
nConflActivities[newtime]=0; | |
conflActivities[newtime].clear(); | |
int d=newtime%gt.rules.nDaysPerWeek; | |
int h=newtime/gt.rules.nDaysPerWeek; | |
/*if(updateSubgroups || updateTeachers){ | |
addAiToNewTimetable(ai, act, d, h); | |
if(updateTeachers) | |
updateTeachersNHoursGaps(act, ai, d); | |
if(updateSubgroups) | |
updateSubgroupsNHoursGaps(act, ai, d); | |
}*/ | |
nMinDaysBroken[newtime]=0.0; | |
bool okbasictime; | |
bool okmindays; | |
bool okmaxdays; | |
bool oksamestartingtime; | |
bool oksamestartinghour; | |
bool oksamestartingday; | |
bool oknotoverlapping; | |
bool oktwoactivitiesconsecutive; | |
bool oktwoactivitiesgrouped; | |
bool okthreeactivitiesgrouped; | |
bool oktwoactivitiesordered; | |
bool okactivityendsstudentsday; | |
bool okstudentsearlymaxbeginningsatsecondhour; | |
bool okstudentsmaxgapsperweek; | |
bool okstudentsmaxgapsperday; | |
bool okstudentsmaxhoursdaily; | |
bool okstudentsmaxhourscontinuously; | |
bool okstudentsminhoursdaily; | |
bool okstudentsintervalmaxdaysperweek; | |
bool okteachermaxdaysperweek; | |
bool okteachersintervalmaxdaysperweek; | |
bool okteachersmaxgapsperweek; | |
bool okteachersmaxgapsperday; | |
bool okteachersmaxhoursdaily; | |
bool okteachersmaxhourscontinuously; | |
bool okteachersminhoursdaily; | |
bool okteachersmindaysperweek; | |
bool okmingapsbetweenactivities; | |
bool okteachersactivitytagmaxhourscontinuously; | |
bool okstudentsactivitytagmaxhourscontinuously; | |
bool okteachersactivitytagmaxhoursdaily; | |
bool okstudentsactivitytagmaxhoursdaily; | |
if(c.times[ai]!=UNALLOCATED_TIME) | |
goto skip_here_if_already_allocated_in_time; | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//not too late | |
//unneeded code, because notAllowedTimesPercentages(ai,newtime)==100 now | |
//you can comment this code, but you cannot put an assert failed, because the test is done in next section (see 13 lines below). | |
if(h+act->duration>gt.rules.nHoursPerDay){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed (tch&st not available, break, act(s) preferred time(s)) | |
if(!skipRandom(notAllowedTimesPercentages(ai,newtime))){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//care about basic time constraints | |
okbasictime=true; | |
/////////////////////////////////// | |
//added in 5.0.0-preview30 | |
//same teacher? | |
for(int dur=0; dur<act->duration; dur++){ | |
assert(h+dur<gt.rules.nHoursPerDay); | |
//for(int q=0; q<act->iTeachersList.count(); q++){ | |
// int tch=act->iTeachersList.at(q); | |
foreach(int tch, act->iTeachersList){ | |
if(teachersTimetable(tch,d,h+dur)>=0){ | |
int ai2=teachersTimetable(tch,d,h+dur); | |
assert(ai2!=ai); | |
assert(activitiesConflictingPercentage(ai,ai2)==100); | |
if(!skipRandom(activitiesConflictingPercentage(ai,ai2))){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okbasictime=false; | |
goto impossiblebasictime; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
//same subgroup? | |
for(int dur=0; dur<act->duration; dur++){ | |
assert(h+dur<gt.rules.nHoursPerDay); | |
//for(int q=0; q<act->iSubgroupsList.count(); q++){ | |
// int sbg=act->iSubgroupsList.at(q); | |
foreach(int sbg, act->iSubgroupsList){ | |
if(subgroupsTimetable(sbg,d,h+dur)>=0){ | |
int ai2=subgroupsTimetable(sbg,d,h+dur); | |
assert(ai2!=ai); | |
assert(activitiesConflictingPercentage(ai,ai2)==100); | |
if(!skipRandom(activitiesConflictingPercentage(ai,ai2))){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okbasictime=false; | |
goto impossiblebasictime; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
/////////////////////////////////// | |
impossiblebasictime: | |
if(!okbasictime){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//care about min days | |
okmindays=true; | |
for(int i=0; i<minDaysListOfActivities[ai].count(); i++){ | |
int ai2=minDaysListOfActivities[ai].at(i); | |
int md=minDaysListOfMinDays[ai].at(i); | |
int ai2time=c.times[ai2]; | |
if(ai2time!=UNALLOCATED_TIME){ | |
int d2=ai2time%gt.rules.nDaysPerWeek; | |
int h2=ai2time/gt.rules.nDaysPerWeek; | |
if(md>abs(d-d2)){ | |
bool okrand=skipRandom(minDaysListOfWeightPercentages[ai].at(i)); | |
//if(fixedTimeActivity[ai] && minDaysListOfWeightPercentages[ai].at(i)<100.0) | |
// okrand=true; | |
//broken min days - there is a minDaysBrokenAllowancePercentage% chance to place them adjacent | |
if(minDaysListOfConsecutiveIfSameDay[ai].at(i)==true){ //must place them adjacent if on same day | |
if(okrand && | |
( (d==d2 && (h+act->duration==h2 || h2+gt.rules.internalActivitiesList[ai2].duration==h)) || d!=d2 ) ){ | |
//nMinDaysBroken[newtime]++; | |
nMinDaysBroken[newtime]+=minDaysListOfWeightPercentages[ai].at(i)/100.0; | |
} | |
else{ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okmindays=false; | |
goto impossiblemindays; | |
} | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
if(!conflActivities[newtime].contains(ai2)){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
else{ //can place them anywhere | |
if(okrand){ | |
//nMinDaysBroken[newtime]++; | |
nMinDaysBroken[newtime]+=minDaysListOfWeightPercentages[ai].at(i)/100.0; | |
} | |
else{ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okmindays=false; | |
goto impossiblemindays; | |
} | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
if(!conflActivities[newtime].contains(ai2)){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
} | |
impossiblemindays: | |
if(!okmindays){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//care about max days between activities | |
okmaxdays=true; | |
for(int i=0; i<maxDaysListOfActivities[ai].count(); i++){ | |
int ai2=maxDaysListOfActivities[ai].at(i); | |
int md=maxDaysListOfMaxDays[ai].at(i); | |
int ai2time=c.times[ai2]; | |
if(ai2time!=UNALLOCATED_TIME){ | |
int d2=ai2time%gt.rules.nDaysPerWeek; | |
//int h2=ai2time/gt.rules.nDaysPerWeek; | |
if(md<abs(d-d2)){ | |
bool okrand=skipRandom(maxDaysListOfWeightPercentages[ai].at(i)); | |
if(!okrand){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okmaxdays=false; | |
goto impossiblemaxdays; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
} | |
} | |
} | |
} | |
} | |
impossiblemaxdays: | |
if(!okmaxdays){ | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//care about min gaps between activities | |
okmingapsbetweenactivities=true; | |
for(int i=0; i<minGapsBetweenActivitiesListOfActivities[ai].count(); i++){ | |
int ai2=minGapsBetweenActivitiesListOfActivities[ai].at(i); | |
int mg=minGapsBetweenActivitiesListOfMinGaps[ai].at(i); | |
int ai2time=c.times[ai2]; | |
if(ai2time!=UNALLOCATED_TIME){ | |
int d2=ai2time%gt.rules.nDaysPerWeek; | |
int h2=ai2time/gt.rules.nDaysPerWeek; | |
int duration2=gt.rules.internalActivitiesList[ai2].duration; | |
bool oktmp=true; | |
if(d==d2){ | |
if(h2>=h){ | |
if(h+act->duration+mg > h2){ | |
oktmp=false; | |
} | |
} | |
else{ | |
if(h2+duration2+mg > h){ | |
oktmp=false; | |
} | |
} | |
} | |
if(!oktmp){ | |
bool okrand=skipRandom(minGapsBetweenActivitiesListOfWeightPercentages[ai].at(i)); | |
//if(fixedTimeActivity[ai] && minGapsBetweenActivitiesListOfWeightPercentages[ai].at(i)<100.0) | |
// okrand=true; | |
if(!okrand){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okmingapsbetweenactivities=false; | |
goto impossiblemingapsbetweenactivities; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
} | |
} | |
} | |
} | |
} | |
impossiblemingapsbetweenactivities: | |
if(!okmingapsbetweenactivities){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from same starting time | |
oksamestartingtime=true; | |
for(int i=0; i<activitiesSameStartingTimeActivities[ai].count(); i++){ | |
int ai2=activitiesSameStartingTimeActivities[ai].at(i); | |
double perc=activitiesSameStartingTimePercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(newtime!=c.times[ai2] && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oksamestartingtime=false; | |
goto impossiblesamestartingtime; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossiblesamestartingtime: | |
if(!oksamestartingtime){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from same starting hour | |
oksamestartinghour=true; | |
for(int i=0; i<activitiesSameStartingHourActivities[ai].count(); i++){ | |
int ai2=activitiesSameStartingHourActivities[ai].at(i); | |
double perc=activitiesSameStartingHourPercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if((newtime/gt.rules.nDaysPerWeek)!=(c.times[ai2]/gt.rules.nDaysPerWeek) && !sR){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oksamestartinghour=false; | |
goto impossiblesamestartinghour; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossiblesamestartinghour: | |
if(!oksamestartinghour){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from same starting day | |
oksamestartingday=true; | |
for(int i=0; i<activitiesSameStartingDayActivities[ai].count(); i++){ | |
int ai2=activitiesSameStartingDayActivities[ai].at(i); | |
double perc=activitiesSameStartingDayPercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if((newtime%gt.rules.nDaysPerWeek)!=(c.times[ai2]%gt.rules.nDaysPerWeek) && !sR){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oksamestartingday=false; | |
goto impossiblesamestartingday; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossiblesamestartingday: | |
if(!oksamestartingday){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from not overlapping | |
oknotoverlapping=true; | |
for(int i=0; i<activitiesNotOverlappingActivities[ai].count(); i++){ | |
int ai2=activitiesNotOverlappingActivities[ai].at(i); | |
double perc=activitiesNotOverlappingPercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
//int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
if(d==d2){ | |
int st=newtime; | |
int en=st+gt.rules.nDaysPerWeek*act->duration; | |
int st2=c.times[ai2]; | |
int en2=st2+gt.rules.nDaysPerWeek*gt.rules.internalActivitiesList[ai2].duration; | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(!(en<=st2 || en2<=st) && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oknotoverlapping=false; | |
goto impossiblenotoverlapping; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
impossiblenotoverlapping: | |
if(!oknotoverlapping){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from 2 activities consecutive | |
oktwoactivitiesconsecutive=true; | |
for(int i=0; i<constrTwoActivitiesConsecutiveActivities[ai].count(); i++){ | |
//direct | |
int ai2=constrTwoActivitiesConsecutiveActivities[ai].at(i); | |
double perc=constrTwoActivitiesConsecutivePercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
bool ok=true; | |
if(d2!=d) | |
ok=false; | |
else if(h+act->duration > h2) | |
ok=false; | |
else if(d==d2){ | |
int kk; | |
for(kk=h+act->duration; kk<gt.rules.nHoursPerDay; kk++) | |
if(!breakDayHour(d,kk)) | |
break; | |
assert(kk<=h2); | |
if(kk!=h2) | |
ok=false; | |
} | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(!ok && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oktwoactivitiesconsecutive=false; | |
goto impossibletwoactivitiesconsecutive; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
//conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
for(int i=0; i<inverseConstrTwoActivitiesConsecutiveActivities[ai].count(); i++){ | |
//inverse | |
int ai2=inverseConstrTwoActivitiesConsecutiveActivities[ai].at(i); | |
double perc=inverseConstrTwoActivitiesConsecutivePercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
bool ok=true; | |
if(d2!=d) | |
ok=false; | |
else if(h2+gt.rules.internalActivitiesList[ai2].duration > h) | |
ok=false; | |
else if(d==d2){ | |
int kk; | |
for(kk=h2+gt.rules.internalActivitiesList[ai2].duration; kk<gt.rules.nHoursPerDay; kk++) | |
if(!breakDayHour(d,kk)) | |
break; | |
assert(kk<=h); | |
if(kk!=h) | |
ok=false; | |
} | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(!ok && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oktwoactivitiesconsecutive=false; | |
goto impossibletwoactivitiesconsecutive; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
//conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossibletwoactivitiesconsecutive: | |
if(!oktwoactivitiesconsecutive){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from 2 activities grouped | |
oktwoactivitiesgrouped=true; | |
for(int i=0; i<constrTwoActivitiesGroupedActivities[ai].count(); i++){ | |
//direct | |
int ai2=constrTwoActivitiesGroupedActivities[ai].at(i); | |
double perc=constrTwoActivitiesGroupedPercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
bool ok=true; | |
if(d2!=d){ | |
ok=false; | |
} | |
else if(d==d2 && h2+gt.rules.internalActivitiesList[ai2].duration <= h){ | |
int kk; | |
for(kk=h2+gt.rules.internalActivitiesList[ai2].duration; kk<gt.rules.nHoursPerDay; kk++) | |
if(!breakDayHour(d2,kk)) | |
break; | |
assert(kk<=h); | |
if(kk!=h) | |
ok=false; | |
} | |
else if(d==d2 && h+act->duration <= h2){ | |
int kk; | |
for(kk=h+act->duration; kk<gt.rules.nHoursPerDay; kk++) | |
if(!breakDayHour(d,kk)) | |
break; | |
assert(kk<=h2); | |
if(kk!=h2) | |
ok=false; | |
} | |
else | |
ok=false; | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(!ok && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oktwoactivitiesgrouped=false; | |
goto impossibletwoactivitiesgrouped; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
//conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossibletwoactivitiesgrouped: | |
if(!oktwoactivitiesgrouped){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from 3 activities grouped | |
okthreeactivitiesgrouped=true; | |
for(int i=0; i<constrThreeActivitiesGroupedActivities[ai].count(); i++){ | |
int ai2=constrThreeActivitiesGroupedActivities[ai].at(i).first; | |
int ai3=constrThreeActivitiesGroupedActivities[ai].at(i).second; | |
double perc=constrThreeActivitiesGroupedPercentages[ai].at(i); | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
int aip1=-1, aip2=-1; //ai placed | |
int ainp1=-1, ainp2=-1; //ai not placed | |
if(c.times[ai2]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai2)) | |
ainp1=ai2; | |
else | |
aip1=ai2; | |
if(c.times[ai3]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai3)){ | |
if(ainp1==-1) | |
ainp1=ai3; | |
else | |
ainp2=ai3; | |
} | |
else{ | |
if(aip1==-1) | |
aip1=ai3; | |
else | |
aip2=ai3; | |
} | |
int cnt=0; | |
if(ainp1>=0) | |
cnt++; | |
if(ainp2>=0) | |
cnt++; | |
if(aip1>=0) | |
cnt++; | |
if(aip2>=0) | |
cnt++; | |
assert(cnt==2); | |
bool ok; | |
if(aip1==-1){ | |
//ok - both not placed | |
ok=true; | |
} | |
else if(aip2==-1){ | |
//only one placed, one not placed | |
int dp1=c.times[aip1]%gt.rules.nDaysPerWeek; | |
int hp1=c.times[aip1]/gt.rules.nDaysPerWeek; | |
int durp1=gt.rules.internalActivitiesList[aip1].duration; | |
int hoursBetweenThem=-1; | |
if(dp1!=d) | |
hoursBetweenThem=-1; | |
else if(dp1==d && h >= hp1+durp1){ | |
hoursBetweenThem=0; | |
for(int kk=hp1+durp1; kk<h; kk++) | |
if(!breakDayHour(d,kk)){ | |
//check that the working hours are not separated by a break | |
//assertion that durp1>0, so the kk-1 >= 0 | |
if(breakDayHour(d,kk-1) && hoursBetweenThem>0){ | |
hoursBetweenThem=-1; | |
break; | |
} | |
hoursBetweenThem++; | |
} | |
} | |
else if(dp1==d && hp1 >= h+act->duration){ | |
hoursBetweenThem=0; | |
for(int kk=h+act->duration; kk<hp1; kk++) | |
if(!breakDayHour(d,kk)){ | |
//check that the working hours are not separated by a break | |
//assertion that act->duration>0, so the kk-1 >= 0 | |
if(breakDayHour(d,kk-1) && hoursBetweenThem>0){ | |
hoursBetweenThem=-1; | |
break; | |
} | |
hoursBetweenThem++; | |
} | |
} | |
else | |
hoursBetweenThem=-1; | |
assert(ainp1>=0); | |
if(hoursBetweenThem==0 || hoursBetweenThem==gt.rules.internalActivitiesList[ainp1].duration) | |
//OK | |
ok=true; | |
else | |
//not OK | |
ok=false; | |
} | |
else{ | |
assert(aip1>=0 && aip2>=0); | |
//both placed | |
int dp1=c.times[aip1]%gt.rules.nDaysPerWeek; | |
int hp1=c.times[aip1]/gt.rules.nDaysPerWeek; | |
//int durp1=gt.rules.internalActivitiesList[aip1].duration; | |
int dp2=c.times[aip2]%gt.rules.nDaysPerWeek; | |
int hp2=c.times[aip2]/gt.rules.nDaysPerWeek; | |
//int durp2=gt.rules.internalActivitiesList[aip2].duration; | |
if(dp1==dp2 && dp1==d){ | |
int ao1=-1, ao2=-1, ao3=-1; //order them, 1 then 2 then 3 | |
if(h>=hp1 && h>=hp2 && hp2>=hp1){ | |
ao1=aip1; | |
ao2=aip2; | |
ao3=ai; | |
} | |
else if(h>=hp1 && h>=hp2 && hp1>=hp2){ | |
ao1=aip2; | |
ao2=aip1; | |
ao3=ai; | |
} | |
else if(hp1>=h && hp1>=hp2 && h>=hp2){ | |
ao1=aip2; | |
ao2=ai; | |
ao3=aip1; | |
} | |
else if(hp1>=h && hp1>=hp2 && hp2>=h){ | |
ao1=ai; | |
ao2=aip2; | |
ao3=aip1; | |
} | |
else if(hp2>=h && hp2>=hp1 && h>=hp1){ | |
ao1=aip1; | |
ao2=ai; | |
ao3=aip2; | |
} | |
else if(hp2>=h && hp2>=hp1 && hp1>=h){ | |
ao1=ai; | |
ao2=aip1; | |
ao3=aip2; | |
} | |
else | |
assert(0); | |
int do1; | |
int ho1; | |
int duro1; | |
int do2; | |
int ho2; | |
int duro2; | |
int do3; | |
int ho3; | |
//int duro3; | |
if(ao1==ai){ | |
do1=d; | |
ho1=h; | |
duro1=act->duration; | |
} | |
else{ | |
do1=c.times[ao1]%gt.rules.nDaysPerWeek; | |
ho1=c.times[ao1]/gt.rules.nDaysPerWeek; | |
duro1=gt.rules.internalActivitiesList[ao1].duration; | |
} | |
if(ao2==ai){ | |
do2=d; | |
ho2=h; | |
duro2=act->duration; | |
} | |
else{ | |
do2=c.times[ao2]%gt.rules.nDaysPerWeek; | |
ho2=c.times[ao2]/gt.rules.nDaysPerWeek; | |
duro2=gt.rules.internalActivitiesList[ao2].duration; | |
} | |
if(ao3==ai){ | |
do3=d; | |
ho3=h; | |
//duro3=act->duration; | |
} | |
else{ | |
do3=c.times[ao3]%gt.rules.nDaysPerWeek; | |
ho3=c.times[ao3]/gt.rules.nDaysPerWeek; | |
//duro3=gt.rules.internalActivitiesList[ao3].duration; | |
} | |
assert(do1==do2 && do1==do3); | |
if(ho1+duro1<=ho2 && ho2+duro2<=ho3){ | |
int hoursBetweenThem=0; | |
for(int kk=ho1+duro1; kk<ho2; kk++) | |
if(!breakDayHour(d,kk)) | |
hoursBetweenThem++; | |
for(int kk=ho2+duro2; kk<ho3; kk++) | |
if(!breakDayHour(d,kk)) | |
hoursBetweenThem++; | |
if(hoursBetweenThem==0) | |
ok=true; | |
else | |
ok=false; | |
} | |
else{ | |
//not OK | |
ok=false; | |
} | |
} | |
else{ | |
//not OK | |
ok=false; | |
} | |
} | |
bool again;//=false; | |
if(!ok && !sR){ | |
int aidisplaced=-1; | |
if(aip2>=0){ //two placed activities | |
again=true; | |
QList<int> acts; | |
if(!fixedTimeActivity[aip1] && !swappedActivities[aip1]) | |
acts.append(aip1); | |
if(!fixedTimeActivity[aip2] && !swappedActivities[aip2]) | |
acts.append(aip2); | |
if(acts.count()==0) | |
aidisplaced=-1; | |
else if(acts.count()==1) | |
aidisplaced=acts.at(0); | |
else{ | |
int t; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<acts.count(); q++){ | |
int tta=acts.at(q); | |
if(optMinWrong>triedRemovals(tta,c.times[tta])){ | |
optMinWrong=triedRemovals(tta,c.times[tta]); | |
} | |
} | |
for(int q=0; q<acts.count(); q++){ | |
int tta=acts.at(q); | |
if(optMinWrong==triedRemovals(tta,c.times[tta])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
int mpos=tl.at(randomKnuth(tl.size())); | |
assert(mpos>=0 && mpos<acts.count()); | |
t=mpos; | |
} | |
else{ | |
t=randomKnuth(acts.count()); | |
} | |
aidisplaced=acts.at(t); | |
} | |
} | |
else{ | |
again=false; | |
assert(aip1>=0); | |
if(!fixedTimeActivity[aip1] && !swappedActivities[aip1]) | |
aidisplaced=aip1; | |
else | |
aidisplaced=-1; | |
} | |
assert(aidisplaced!=ai); | |
if(aidisplaced==-1){ | |
okthreeactivitiesgrouped=false; | |
goto impossiblethreeactivitiesgrouped; | |
} | |
if(fixedTimeActivity[aidisplaced] || swappedActivities[aidisplaced]){ | |
okthreeactivitiesgrouped=false; | |
goto impossiblethreeactivitiesgrouped; | |
} | |
assert(!conflActivities[newtime].contains(aidisplaced)); | |
conflActivities[newtime].append(aidisplaced); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//if !again, everything is OK, because there was one placed activity and it was eliminated | |
if(again){ | |
aip1=-1, aip2=-1; | |
ainp1=-1, ainp2=-1; | |
if(c.times[ai2]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai2)) | |
ainp1=ai2; | |
else | |
aip1=ai2; | |
if(c.times[ai3]==UNALLOCATED_TIME || conflActivities[newtime].contains(ai3)){ | |
if(ainp1==-1) | |
ainp1=ai3; | |
else | |
ainp2=ai3; | |
} | |
else{ | |
if(aip1==-1) | |
aip1=ai3; | |
else | |
aip2=ai3; | |
} | |
assert(aip1>=0 && ainp1>=0 && aip2==-1 && ainp2==-1); //only one placed | |
//again the procedure from above, with 1 placed | |
int dp1=c.times[aip1]%gt.rules.nDaysPerWeek; | |
int hp1=c.times[aip1]/gt.rules.nDaysPerWeek; | |
int durp1=gt.rules.internalActivitiesList[aip1].duration; | |
int hoursBetweenThem=-1; | |
if(dp1!=d) | |
hoursBetweenThem=-1; | |
else if(dp1==d && h >= hp1+durp1){ | |
hoursBetweenThem=0; | |
for(int kk=hp1+durp1; kk<h; kk++) | |
if(!breakDayHour(d,kk)){ | |
//check that the working hours are not separated by a break | |
//assertion that durp1>0, so the kk-1 >= 0 | |
if(breakDayHour(d,kk-1) && hoursBetweenThem>0){ | |
hoursBetweenThem=-1; | |
break; | |
} | |
hoursBetweenThem++; | |
} | |
} | |
else if(dp1==d && hp1 >= h+act->duration){ | |
hoursBetweenThem=0; | |
for(int kk=h+act->duration; kk<hp1; kk++) | |
if(!breakDayHour(d,kk)){ | |
//check that the working hours are not separated by a break | |
//assertion that act->duration>0, so the kk-1 >= 0 | |
if(breakDayHour(d,kk-1) && hoursBetweenThem>0){ | |
hoursBetweenThem=-1; | |
break; | |
} | |
hoursBetweenThem++; | |
} | |
} | |
else | |
hoursBetweenThem=-1; | |
assert(ainp1>=0); | |
if(hoursBetweenThem==0 || hoursBetweenThem==gt.rules.internalActivitiesList[ainp1].duration) | |
//OK | |
ok=true; | |
else | |
//not OK | |
ok=false; | |
assert(!sR); | |
if(!ok){ | |
aidisplaced=aip1; | |
if(fixedTimeActivity[aidisplaced] || swappedActivities[aidisplaced]){ | |
okthreeactivitiesgrouped=false; | |
goto impossiblethreeactivitiesgrouped; | |
} | |
assert(!conflActivities[newtime].contains(aidisplaced)); | |
conflActivities[newtime].append(aidisplaced); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//now it is OK, because there were two activities placed and both were eliminated | |
} | |
} //end if(again) | |
} | |
} | |
impossiblethreeactivitiesgrouped: | |
if(!okthreeactivitiesgrouped){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from 2 activities ordered | |
oktwoactivitiesordered=true; | |
for(int i=0; i<constrTwoActivitiesOrderedActivities[ai].count(); i++){ | |
//direct | |
int ai2=constrTwoActivitiesOrderedActivities[ai].at(i); | |
double perc=constrTwoActivitiesOrderedPercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
bool ok=true; | |
if(!(d<d2 || (d==d2 && h+act->duration-1<h2))) | |
ok=false; | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(!ok && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oktwoactivitiesordered=false; | |
goto impossibletwoactivitiesordered; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
//conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
for(int i=0; i<inverseConstrTwoActivitiesOrderedActivities[ai].count(); i++){ | |
//inverse | |
int ai2=inverseConstrTwoActivitiesOrderedActivities[ai].at(i); | |
double perc=inverseConstrTwoActivitiesOrderedPercentages[ai].at(i); | |
if(c.times[ai2]!=UNALLOCATED_TIME){ | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
int dur2=gt.rules.internalActivitiesList[ai2].duration; | |
bool ok=true; | |
if(!(d2<d || (d2==d && h2+dur2-1<h))) | |
ok=false; | |
bool sR=skipRandom(perc); | |
//if(fixedTimeActivity[ai] && perc<100.0) | |
// sR=true; | |
if(!ok && !sR){ | |
assert(ai2!=ai); | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
oktwoactivitiesordered=false; | |
goto impossibletwoactivitiesordered; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
conflActivities[newtime].append(ai2); | |
//conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossibletwoactivitiesordered: | |
if(!oktwoactivitiesordered){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from activity ends students day | |
okactivityendsstudentsday=true; | |
if(haveActivityEndsStudentsDay){ | |
//1. If current activity needs to be at the end | |
if(activityEndsStudentsDayPercentages[ai]>=0){ | |
bool skip=skipRandom(activityEndsStudentsDayPercentages[ai]); | |
if(!skip){ | |
foreach(int sb, act->iSubgroupsList){ | |
//for(int j=0; j<gt.rules.internalActivitiesList[ai].iSubgroupsList.count(); j++){ | |
// int sb=gt.rules.internalActivitiesList[ai].iSubgroupsList.at(j); | |
for(int hh=h+act->duration; hh<gt.rules.nHoursPerDay; hh++){ | |
int ai2=subgroupsTimetable(sb,d,hh); | |
if(ai2>=0){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okactivityendsstudentsday=false; | |
goto impossibleactivityendsstudentsday; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
} | |
//2. Check activities which have to be at the end, in the same day with current activity | |
foreach(int sb, act->iSubgroupsList){ | |
//for(int j=0; j<gt.rules.internalActivitiesList[ai].iSubgroupsList.count(); j++){ | |
// int sb=gt.rules.internalActivitiesList[ai].iSubgroupsList.at(j); | |
for(int hh=h-1; hh>=0; hh--){ | |
int ai2=subgroupsTimetable(sb,d,hh); | |
if(ai2>=0) | |
if(activityEndsStudentsDayPercentages[ai2]>=0){ | |
bool skip=skipRandom(activityEndsStudentsDayPercentages[ai2]); | |
if(!skip){ | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]){ | |
okactivityendsstudentsday=false; | |
goto impossibleactivityendsstudentsday; | |
} | |
if(!conflActivities[newtime].contains(ai2)){ | |
//if(conflActivities[newtime].indexOf(ai2)==-1){ | |
//conflActivities[newtime].append(ai2); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
} | |
impossibleactivityendsstudentsday: | |
if(!okactivityendsstudentsday){ | |
//if(updateSubgroups || updateTeachers) | |
// removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////////////////////////// | |
if(updateSubgroups || updateTeachers){ | |
addAiToNewTimetable(ai, act, d, h); | |
if(updateTeachers) | |
updateTeachersNHoursGaps(act, ai, d); | |
if(updateSubgroups) | |
updateSubgroupsNHoursGaps(act, ai, d); | |
} | |
////////////////////////////////////////////////// | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
////////////STUDENTS//////////////// | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//BEGIN students interval max days per week | |
okstudentsintervalmaxdaysperweek=true; | |
foreach(int sbg, act->iSubgroupsList){ | |
double perc=-1.0; | |
for(int cnt=0; cnt<3; cnt++){ | |
if(cnt==0){ | |
perc=subgroupsIntervalMaxDaysPerWeekPercentages1[sbg]; | |
} | |
else if(cnt==1){ | |
perc=subgroupsIntervalMaxDaysPerWeekPercentages2[sbg]; | |
} | |
else if(cnt==2){ | |
perc=subgroupsIntervalMaxDaysPerWeekPercentages3[sbg]; | |
} | |
else | |
assert(0); | |
if(perc>=0){ | |
int maxDays=-1; | |
int sth=-1; | |
int endh=-1; | |
if(cnt==0){ | |
maxDays=subgroupsIntervalMaxDaysPerWeekMaxDays1[sbg]; | |
sth=subgroupsIntervalMaxDaysPerWeekIntervalStart1[sbg]; | |
endh=subgroupsIntervalMaxDaysPerWeekIntervalEnd1[sbg]; | |
} | |
else if(cnt==1){ | |
maxDays=subgroupsIntervalMaxDaysPerWeekMaxDays2[sbg]; | |
sth=subgroupsIntervalMaxDaysPerWeekIntervalStart2[sbg]; | |
endh=subgroupsIntervalMaxDaysPerWeekIntervalEnd2[sbg]; | |
} | |
else if(cnt==2){ | |
maxDays=subgroupsIntervalMaxDaysPerWeekMaxDays3[sbg]; | |
sth=subgroupsIntervalMaxDaysPerWeekIntervalStart3[sbg]; | |
endh=subgroupsIntervalMaxDaysPerWeekIntervalEnd3[sbg]; | |
} | |
else | |
assert(0); | |
assert(sth>=0 && sth<gt.rules.nHoursPerDay); | |
assert(endh>sth && endh<=gt.rules.nHoursPerDay); | |
assert(maxDays>=0 && maxDays<=gt.rules.nDaysPerWeek); | |
if(skipRandom(perc)) | |
continue; | |
assert(perc==100.0); | |
bool foundothers=false; | |
bool foundai=false; | |
for(int hh=sth; hh<endh; hh++){ | |
if(newSubgroupsTimetable(sbg,d,hh)==ai){ | |
foundai=true; | |
} | |
else{ | |
assert(newSubgroupsTimetable(sbg,d,hh)==subgroupsTimetable(sbg,d,hh)); | |
if(newSubgroupsTimetable(sbg,d,hh)>=0){ | |
if(!conflActivities[newtime].contains(newSubgroupsTimetable(sbg,d,hh))){ | |
foundothers=true; | |
} | |
} | |
} | |
} | |
int nrotherdays=0; | |
for(int dd=0; dd<gt.rules.nDaysPerWeek; dd++){ | |
if(dd!=d){ | |
for(int hh=sth; hh<endh; hh++){ | |
assert(newSubgroupsTimetable(sbg,dd,hh)==subgroupsTimetable(sbg,dd,hh)); | |
if(newSubgroupsTimetable(sbg,dd,hh)>=0 && !conflActivities[newtime].contains(newSubgroupsTimetable(sbg,dd,hh))){ | |
nrotherdays++; | |
break; | |
} | |
} | |
} | |
} | |
assert(nrotherdays<=maxDays); //if percentage==100%, then it is impossible to break this constraint | |
if((foundai && !foundothers) && nrotherdays==maxDays){ | |
//increased above limit | |
bool occupiedIntervalDay[MAX_DAYS_PER_WEEK]; | |
bool canEmptyIntervalDay[MAX_DAYS_PER_WEEK]; | |
int _minWrong[MAX_DAYS_PER_WEEK]; | |
int _nWrong[MAX_DAYS_PER_WEEK]; | |
int _nConflActivities[MAX_DAYS_PER_WEEK]; | |
int _minIndexAct[MAX_DAYS_PER_WEEK]; | |
QList<int> _activitiesForIntervalDay[MAX_DAYS_PER_WEEK]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2==d) | |
continue; | |
occupiedIntervalDay[d2]=false; | |
canEmptyIntervalDay[d2]=true; | |
_minWrong[d2]=INF; | |
_nWrong[d2]=0; | |
_nConflActivities[d2]=0; | |
_minIndexAct[d2]=gt.rules.nInternalActivities; | |
_activitiesForIntervalDay[d2].clear(); | |
for(int h2=sth; h2<endh; h2++){ | |
int ai2=subgroupsTimetable(sbg,d2,h2); | |
//foreach(int ai2, teacherActivitiesOfTheDay(tch,d2)){ | |
if(ai2>=0){ | |
if(!conflActivities[newtime].contains(ai2)){ | |
occupiedIntervalDay[d2]=true; | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]) | |
canEmptyIntervalDay[d2]=false; | |
else if(!_activitiesForIntervalDay[d2].contains(ai2)){ | |
_minWrong[d2] = min (_minWrong[d2], triedRemovals(ai2,c.times[ai2])); | |
_minIndexAct[d2]=min(_minIndexAct[d2], invPermutation[ai2]); | |
_nWrong[d2]+=triedRemovals(ai2,c.times[ai2]); | |
_nConflActivities[d2]++; | |
_activitiesForIntervalDay[d2].append(ai2); | |
assert(_nConflActivities[d2]==_activitiesForIntervalDay[d2].count()); | |
} | |
} | |
} | |
} | |
if(!occupiedIntervalDay[d2]) | |
canEmptyIntervalDay[d2]=false; | |
} | |
occupiedIntervalDay[d]=true; | |
canEmptyIntervalDay[d]=false; | |
int nOc=0; | |
bool canChooseDay=false; | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
if(occupiedIntervalDay[j]){ | |
nOc++; | |
if(canEmptyIntervalDay[j]){ | |
canChooseDay=true; | |
} | |
} | |
//if(nOc>maxDays){ | |
assert(nOc==maxDays+1); | |
if(!canChooseDay){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsintervalmaxdaysperweek=false; | |
goto impossiblestudentsintervalmaxdaysperweek; | |
} | |
int d2=-1; | |
if(level!=0){ | |
//choose random day from those with minimum number of conflicting activities | |
QList<int> candidateDays; | |
int m=gt.rules.nInternalActivities; | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk]) | |
if(m>_nConflActivities[kk]) | |
m=_nConflActivities[kk]; | |
candidateDays.clear(); | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk] && m==_nConflActivities[kk]) | |
candidateDays.append(kk); | |
assert(candidateDays.count()>0); | |
d2=candidateDays.at(randomKnuth(candidateDays.count())); | |
} | |
else{ //level==0 | |
QList<int> candidateDays; | |
int _mW=INF; | |
int _nW=INF; | |
int _mCA=gt.rules.nInternalActivities; | |
int _mIA=gt.rules.nInternalActivities; | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk]){ | |
if(_mW>_minWrong[kk] || | |
(_mW==_minWrong[kk] && _nW>_nWrong[kk]) || | |
(_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA>_nConflActivities[kk]) || | |
(_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA>_minIndexAct[kk])){ | |
_mW=_minWrong[kk]; | |
_nW=_nWrong[kk]; | |
_mCA=_nConflActivities[kk]; | |
_mIA=_minIndexAct[kk]; | |
} | |
} | |
assert(_mW<INF); | |
candidateDays.clear(); | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk] && _mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA==_minIndexAct[kk]) | |
candidateDays.append(kk); | |
assert(candidateDays.count()>0); | |
d2=candidateDays.at(randomKnuth(candidateDays.count())); | |
} | |
assert(d2>=0); | |
assert(_activitiesForIntervalDay[d2].count()>0); | |
foreach(int ai2, _activitiesForIntervalDay[d2]){ | |
assert(ai2!=ai); | |
assert(!swappedActivities[ai2]); | |
assert(!fixedTimeActivity[ai2]); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
//respecting students interval max days per week | |
impossiblestudentsintervalmaxdaysperweek: | |
if(!okstudentsintervalmaxdaysperweek){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END students interval max days per week | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//not breaking students early max beginnings at second hour | |
//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. | |
//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 | |
okstudentsearlymaxbeginningsatsecondhour=true; | |
foreach(int sbg, act->iSubgroupsList) | |
if(!skipRandom(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg])){ | |
//preliminary check | |
int _nHours=0; | |
int _nFirstGapsOne=0; | |
int _nFirstGapsTwo=0; | |
int _nGaps=0; | |
int _nIllegalGaps=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
_nHours+=newSubgroupsDayNHours(sbg,d2); | |
if(newSubgroupsDayNFirstGaps(sbg, d2)==1){ | |
_nFirstGapsOne++; | |
} | |
else if(newSubgroupsDayNFirstGaps(sbg, d2)>=2){ | |
_nFirstGapsTwo++; | |
_nIllegalGaps++; | |
_nGaps+=newSubgroupsDayNFirstGaps(sbg, d2)-2; | |
} | |
_nGaps+=newSubgroupsDayNGaps(sbg,d2); | |
} | |
int _tt=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
if(_tt>=_nFirstGapsOne){ | |
_tt-=_nFirstGapsOne; | |
_nFirstGapsOne=0; | |
} | |
else{ | |
_nFirstGapsOne-=_tt; | |
_tt=0; | |
} | |
if(_tt>=_nFirstGapsTwo){ | |
_tt-=_nFirstGapsTwo; | |
_nFirstGapsTwo=0; | |
} | |
else{ | |
_nFirstGapsTwo-=_tt; | |
_tt=0; | |
} | |
if(_nFirstGapsTwo>0){ | |
_nGaps+=_nFirstGapsTwo; | |
_nFirstGapsTwo=0; | |
} | |
int _nHoursGaps=0; | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
assert(subgroupsMaxGapsPerWeekPercentage[sbg]==100); | |
if(_nGaps>subgroupsMaxGapsPerWeekMaxGaps[sbg]) | |
_nHoursGaps=_nGaps-subgroupsMaxGapsPerWeekMaxGaps[sbg]; | |
} | |
if(_nHours + _nFirstGapsOne + _nHoursGaps + _nIllegalGaps > nHoursPerSubgroup[sbg]){ | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsearlymaxbeginningsatsecondhour=false; | |
goto impossiblestudentsearlymaxbeginningsatsecondhour; | |
} | |
getSbgTimetable(sbg, conflActivities[newtime]); | |
sbgGetNHoursGaps(sbg); | |
for(;;){ | |
int nHours=0; | |
int nFirstGapsOne=0; | |
int nFirstGapsTwo=0; | |
int nGaps=0; | |
int nIllegalGaps=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
nHours+=sbgDayNHours[d2]; | |
if(sbgDayNFirstGaps[d2]==1){ | |
nFirstGapsOne++; | |
} | |
else if(sbgDayNFirstGaps[d2]>=2){ | |
nFirstGapsTwo++; | |
nIllegalGaps++; | |
nGaps+=sbgDayNFirstGaps[d2]-2; | |
} | |
nGaps+=sbgDayNGaps[d2]; | |
} | |
int tt=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
if(tt>=nFirstGapsOne){ | |
tt-=nFirstGapsOne; | |
nFirstGapsOne=0; | |
} | |
else{ | |
nFirstGapsOne-=tt; | |
tt=0; | |
} | |
if(tt>=nFirstGapsTwo){ | |
tt-=nFirstGapsTwo; | |
nFirstGapsTwo=0; | |
} | |
else{ | |
nFirstGapsTwo-=tt; | |
tt=0; | |
} | |
if(nFirstGapsTwo>0){ | |
nGaps+=nFirstGapsTwo; | |
nFirstGapsTwo=0; | |
} | |
int nHoursGaps=0; | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
assert(subgroupsMaxGapsPerWeekPercentage[sbg]==100); | |
if(nGaps>subgroupsMaxGapsPerWeekMaxGaps[sbg]) | |
nHoursGaps=nGaps-subgroupsMaxGapsPerWeekMaxGaps[sbg]; | |
} | |
int ai2=-1; | |
if(nHours + nFirstGapsOne + nHoursGaps + nIllegalGaps > nHoursPerSubgroup[sbg]){ | |
//remove an activity | |
bool k=subgroupRemoveAnActivityFromEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
if(level==0){ | |
//this should not be displayed | |
//cout<<"WARNING - maybe bug - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsearlymaxbeginningsatsecondhour=false; | |
goto impossiblestudentsearlymaxbeginningsatsecondhour; | |
} | |
} | |
else{ //OK | |
break; | |
} | |
assert(ai2>=0); | |
removeAi2FromSbgTimetable(ai2); | |
updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
impossiblestudentsearlymaxbeginningsatsecondhour: | |
if(!okstudentsearlymaxbeginningsatsecondhour){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END students early max beginnings at second hour | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//not breaking students max gaps per week | |
//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. | |
//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 | |
okstudentsmaxgapsperweek=true; | |
foreach(int sbg, act->iSubgroupsList) | |
if(!skipRandom(subgroupsMaxGapsPerWeekPercentage[sbg])){ | |
//TODO | |
//if(!skipRandom(subgroupsMaxGapsPerWeekPercentage[sbg])){ | |
//assert(subgroupsMaxGapsPerWeekPercentage[sbg]==100); | |
//preliminary test | |
int _nHours=0; | |
int _nGaps=0; | |
int _nFirstGaps=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
_nHours+=newSubgroupsDayNHours(sbg,d2); | |
_nGaps+=newSubgroupsDayNGaps(sbg,d2); | |
_nFirstGaps+=newSubgroupsDayNFirstGaps(sbg,d2); | |
} | |
int _nFirstHours=0; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
assert(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]==100); | |
if(_nFirstGaps>subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]) | |
_nFirstHours=_nFirstGaps-subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
} | |
if(_nGaps+_nHours+_nFirstHours > subgroupsMaxGapsPerWeekMaxGaps[sbg] + nHoursPerSubgroup[sbg]){ | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsmaxgapsperweek=false; | |
goto impossiblestudentsmaxgapsperweek; | |
} | |
getSbgTimetable(sbg, conflActivities[newtime]); | |
sbgGetNHoursGaps(sbg); | |
for(;;){ | |
int nHours=0; | |
int nGaps=0; | |
int nFirstGaps=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
nHours+=sbgDayNHours[d2]; | |
nGaps+=sbgDayNGaps[d2]; | |
nFirstGaps+=sbgDayNFirstGaps[d2]; | |
} | |
int ai2=-1; | |
int nFirstHours=0; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
assert(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]==100); | |
if(nFirstGaps>subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]) | |
nFirstHours=nFirstGaps-subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
} | |
if(nGaps+nHours+nFirstHours > subgroupsMaxGapsPerWeekMaxGaps[sbg] + nHoursPerSubgroup[sbg]){ | |
//remove an activity | |
bool k=subgroupRemoveAnActivityFromBeginOrEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsmaxgapsperweek=false; | |
goto impossiblestudentsmaxgapsperweek; | |
} | |
} | |
else{ //OK | |
break; | |
} | |
assert(ai2>=0); | |
removeAi2FromSbgTimetable(ai2); | |
updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
impossiblestudentsmaxgapsperweek: | |
if(!okstudentsmaxgapsperweek){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END students max gaps per week | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//!!!NOT PERFECT constraint, in other places may be improved, like in min/max hours daily. | |
//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 | |
//not causing more than subgroupsMaxGapsPerDay students gaps | |
//TODO: improve, check | |
okstudentsmaxgapsperday=true; | |
if(haveStudentsMaxGapsPerDay){ | |
//okstudentsmaxgapsperday=true; | |
foreach(int sbg, act->iSubgroupsList) | |
if(!skipRandom(subgroupsMaxGapsPerDayPercentage[sbg])){ | |
assert(subgroupsMaxGapsPerDayPercentage[sbg]==100); | |
//preliminary test | |
int _total=0; | |
int _remnf=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
bool _haveMaxBegs=(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0); | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
_total+=newSubgroupsDayNHours(sbg,d2); | |
int _g=newSubgroupsDayNGaps(sbg,d2); | |
if(_haveMaxBegs){ | |
int _fg=newSubgroupsDayNFirstGaps(sbg,d2); | |
if(_fg==0){ | |
if(_g>subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
_total+=_g-subgroupsMaxGapsPerDayMaxGaps[sbg]; | |
} | |
else if(_fg==1){ | |
if(_remnf>0) | |
_remnf--; | |
else | |
_total++; | |
if(_g>subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
_total+=_g-subgroupsMaxGapsPerDayMaxGaps[sbg]; | |
} | |
else if(_fg>=2){ | |
if(_g + _fg - 1 <= subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
_total++; | |
else{ | |
if(_remnf>0) | |
_remnf--; | |
else | |
_total++; | |
_total++; | |
assert(_g + _fg - 2 >= subgroupsMaxGapsPerDayMaxGaps[sbg]); | |
_total+=(_g + _fg - 2 - subgroupsMaxGapsPerDayMaxGaps[sbg]); | |
} | |
} | |
else | |
assert(0); | |
} | |
else{ | |
if(_g > subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
_total+=_g-subgroupsMaxGapsPerDayMaxGaps[sbg]; | |
} | |
} | |
if(_total<=nHoursPerSubgroup[sbg]) //OK | |
continue; | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsmaxgapsperday=false; | |
goto impossiblestudentsmaxgapsperday; | |
} | |
getSbgTimetable(sbg, conflActivities[newtime]); | |
sbgGetNHoursGaps(sbg); | |
for(;;){ | |
int total=0; | |
int remnf=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
bool haveMaxBegs=(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0); | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
total+=sbgDayNHours[d2]; | |
int g=sbgDayNGaps[d2]; | |
if(haveMaxBegs){ | |
int fg=sbgDayNFirstGaps[d2]; | |
if(fg==0){ | |
if(g>subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
total+=g-subgroupsMaxGapsPerDayMaxGaps[sbg]; | |
} | |
else if(fg==1){ | |
if(remnf>0) | |
remnf--; | |
else | |
total++; | |
if(g>subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
total+=g-subgroupsMaxGapsPerDayMaxGaps[sbg]; | |
} | |
else if(fg>=2){ | |
if(g + fg - 1 <= subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
total++; | |
else{ | |
if(remnf>0) | |
remnf--; | |
else | |
total++; | |
total++; | |
assert(g + fg - 2 >= subgroupsMaxGapsPerDayMaxGaps[sbg]); | |
total+=(g + fg - 2 - subgroupsMaxGapsPerDayMaxGaps[sbg]); | |
} | |
} | |
else | |
assert(0); | |
} | |
else{ | |
if(g > subgroupsMaxGapsPerDayMaxGaps[sbg]) | |
total+=g-subgroupsMaxGapsPerDayMaxGaps[sbg]; | |
} | |
} | |
if(total<=nHoursPerSubgroup[sbg]) //OK | |
break; | |
//remove an activity from the beginning or from the end of a day | |
//following code is identical to maxgapsperweek | |
//remove an activity | |
int ai2=-1; | |
//it should also be allowed to take from anywhere, but it is risky to change now | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
bool k=subgroupRemoveAnActivityFromEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
bool kk; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 && | |
(subgroupsMaxGapsPerWeekMaxGaps[sbg]==0 || subgroupsMaxGapsPerDayMaxGaps[sbg]==0)) | |
kk=false; | |
else | |
kk=subgroupRemoveAnActivityFromBegin(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!kk){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsmaxgapsperday=false; | |
goto impossiblestudentsmaxgapsperday; | |
} | |
} | |
} | |
else{ | |
bool k=subgroupRemoveAnActivityFromBeginOrEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsmaxgapsperday=false; | |
goto impossiblestudentsmaxgapsperday; | |
} | |
} | |
assert(ai2>=0); | |
removeAi2FromSbgTimetable(ai2); | |
updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
impossiblestudentsmaxgapsperday: | |
if(!okstudentsmaxgapsperday){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END max gaps per day | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//to be put after max gaps and early!!! because of an assert | |
//allowed from students max hours daily | |
//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. | |
//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 | |
okstudentsmaxhoursdaily=true; | |
foreach(int sbg, act->iSubgroupsList){ | |
for(int count=0; count<2; count++){ | |
int limitHoursDaily; | |
double percentage; | |
if(count==0){ | |
limitHoursDaily=subgroupsMaxHoursDailyMaxHours1[sbg]; | |
percentage=subgroupsMaxHoursDailyPercentages1[sbg]; | |
} | |
else{ | |
limitHoursDaily=subgroupsMaxHoursDailyMaxHours2[sbg]; | |
percentage=subgroupsMaxHoursDailyPercentages2[sbg]; | |
} | |
if(limitHoursDaily<0) | |
continue; | |
//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 | |
// continue; | |
bool increased; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//both | |
if(oldSubgroupsDayNHours(sbg,d)+oldSubgroupsDayNGaps(sbg,d)+oldSubgroupsDayNFirstGaps(sbg,d)< | |
newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNGaps(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d) | |
|| oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d)) | |
increased=true; | |
else | |
increased=false; | |
} | |
else{ | |
//only at beginning | |
if(oldSubgroupsDayNHours(sbg,d)+oldSubgroupsDayNFirstGaps(sbg,d)< | |
newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d) | |
|| oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d)) | |
increased=true; | |
else | |
increased=false; | |
} | |
} | |
else{ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//only max gaps | |
if(oldSubgroupsDayNHours(sbg,d)+oldSubgroupsDayNGaps(sbg,d)< | |
newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNGaps(sbg,d) | |
|| oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d)) | |
increased=true; | |
else | |
increased=false; | |
} | |
else{ | |
//none | |
if(oldSubgroupsDayNHours(sbg,d)<newSubgroupsDayNHours(sbg,d)) | |
increased=true; | |
else | |
increased=false; | |
} | |
} | |
if(limitHoursDaily>=0 && !skipRandom(percentage) && increased){ | |
if(limitHoursDaily<act->duration){ | |
okstudentsmaxhoursdaily=false; | |
goto impossiblestudentsmaxhoursdaily; | |
} | |
if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 && subgroupsMaxGapsPerWeekMaxGaps[sbg]==0){ | |
if(newSubgroupsDayNHours(sbg,d)+newSubgroupsDayNGaps(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d) > limitHoursDaily){ | |
okstudentsmaxhoursdaily=false; | |
goto impossiblestudentsmaxhoursdaily; | |
} | |
else //OK | |
continue; | |
} | |
//////////////////////////new | |
bool _ok; | |
if(newSubgroupsDayNHours(sbg,d)>limitHoursDaily){ | |
_ok=false; //trivially | |
} | |
//basically, see that the gaps are enough | |
else{ | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//both | |
int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
int g=limitHoursDaily-newSubgroupsDayNHours(sbg,d2); | |
//TODO: if g lower than 0 make g 0 | |
//but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s) | |
g=newSubgroupsDayNFirstGaps(sbg,d2)+newSubgroupsDayNGaps(sbg,d2)-g; | |
if(g>0) | |
rg-=g; | |
} | |
} | |
if(rg<0) | |
rg=0; | |
int hg=newSubgroupsDayNGaps(sbg,d)+newSubgroupsDayNFirstGaps(sbg,d)-rg; | |
if(hg<0) | |
hg=0; | |
if(hg+newSubgroupsDayNHours(sbg,d) > limitHoursDaily){ | |
_ok=false; | |
} | |
else | |
_ok=true; | |
} | |
else{ | |
//only max beginnings | |
int lateBeginnings=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
if(newSubgroupsDayNHours(sbg,d2)>=limitHoursDaily && newSubgroupsDayNFirstGaps(sbg,d2)==1) | |
lateBeginnings++; | |
} | |
} | |
int fg=0, ah=0; //first gaps, added hours | |
if(newSubgroupsDayNFirstGaps(sbg,d)==0){ | |
fg=0; | |
ah=0; | |
} | |
else if(newSubgroupsDayNFirstGaps(sbg,d)==1){ | |
fg=1; | |
ah=0; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 || | |
(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]>0 && | |
lateBeginnings>=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg])) | |
ah+=fg; | |
} | |
else if(newSubgroupsDayNFirstGaps(sbg,d)>=2){ | |
fg=0; | |
ah=1; | |
} | |
if(ah+newSubgroupsDayNHours(sbg,d) > limitHoursDaily){ | |
_ok=false; | |
} | |
else | |
_ok=true; | |
} | |
} | |
else{ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//only max gaps | |
int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
int g=limitHoursDaily-newSubgroupsDayNHours(sbg,d2); | |
//TODO: if g lower than 0 make g 0 | |
//but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s) | |
g=newSubgroupsDayNGaps(sbg,d2)-g; | |
if(g>0) | |
rg-=g; | |
} | |
} | |
if(rg<0) | |
rg=0; | |
int hg=newSubgroupsDayNGaps(sbg,d)-rg; | |
if(hg<0) | |
hg=0; | |
if(hg+newSubgroupsDayNHours(sbg,d) > limitHoursDaily){ | |
_ok=false; | |
} | |
else | |
_ok=true; | |
} | |
else{ | |
//none | |
_ok=true; | |
} | |
} | |
} | |
///////////////////////////// | |
//preliminary test | |
if(_ok){ | |
continue; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsmaxhoursdaily=false; | |
goto impossiblestudentsmaxhoursdaily; | |
} | |
getSbgTimetable(sbg, conflActivities[newtime]); | |
sbgGetNHoursGaps(sbg); | |
//theoretically, it should be canTakeFromBegin = true all time and ctfAnywhere = true if max gaps per week is not 0. | |
//but practically, I tried these changes and it was 30% slower for a modified german sample (with max gaps per day=1, | |
//12 hours per day, removed subacts. pref. times, max hours daily 6 for students). | |
bool canTakeFromBegin=(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]!=0); //-1 or >0 | |
bool canTakeFromEnd=true; | |
bool canTakeFromAnywhere=(subgroupsMaxGapsPerWeekMaxGaps[sbg]==-1); | |
for(;;){ | |
//////////////////////////new | |
bool ok; | |
if(sbgDayNHours[d]>limitHoursDaily){ | |
ok=false; | |
} | |
else{ | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//both | |
int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
int g=limitHoursDaily-sbgDayNHours[d2]; | |
//TODO: if g lower than 0 make g 0 | |
//but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s) | |
g=sbgDayNFirstGaps[d2]+sbgDayNGaps[d2]-g; | |
if(g>0) | |
rg-=g; | |
} | |
} | |
if(rg<0) | |
rg=0; | |
int hg=sbgDayNGaps[d]+sbgDayNFirstGaps[d]-rg; | |
if(hg<0) | |
hg=0; | |
if(hg+sbgDayNHours[d] > limitHoursDaily){ | |
ok=false; | |
} | |
else | |
ok=true; | |
} | |
else{ | |
//only max beginnings | |
int lateBeginnings=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
if(sbgDayNHours[d2]>=limitHoursDaily && sbgDayNFirstGaps[d2]==1) | |
lateBeginnings++; | |
} | |
} | |
int fg=0, ah=0; //first gaps, added hours | |
if(sbgDayNFirstGaps[d]==0){ | |
fg=0; | |
ah=0; | |
} | |
else if(sbgDayNFirstGaps[d]==1){ | |
fg=1; | |
ah=0; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]==0 || | |
(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]>0 && | |
lateBeginnings>=subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg])) | |
ah+=fg; | |
} | |
else if(sbgDayNFirstGaps[d]>=2){ | |
fg=0; | |
ah=1; | |
} | |
if(ah+sbgDayNHours[d] > limitHoursDaily){ | |
ok=false; | |
} | |
else | |
ok=true; | |
} | |
} | |
else{ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//only max gaps | |
int rg=subgroupsMaxGapsPerWeekMaxGaps[sbg]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
int g=limitHoursDaily-sbgDayNHours[d2]; | |
//TODO: if g lower than 0 make g 0 | |
//but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s) | |
g=sbgDayNGaps[d2]-g; | |
if(g>0) | |
rg-=g; | |
} | |
} | |
if(rg<0) | |
rg=0; | |
int hg=sbgDayNGaps[d]-rg; | |
if(hg<0) | |
hg=0; | |
if(hg+sbgDayNHours[d] > limitHoursDaily){ | |
ok=false; | |
} | |
else | |
ok=true; | |
} | |
else{ | |
//none | |
ok=true; | |
} | |
} | |
} | |
///////////////////////////// | |
if(ok){ | |
break; | |
} | |
int ai2=-1; | |
bool kk=false; | |
if(canTakeFromEnd) | |
kk=subgroupRemoveAnActivityFromEndCertainDay(sbg, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!kk){ | |
canTakeFromEnd=false; | |
bool k=false; | |
if(canTakeFromBegin){ | |
k=subgroupRemoveAnActivityFromBeginCertainDay(sbg, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
if(subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]>0) | |
canTakeFromBegin=false; | |
} | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
canTakeFromBegin=false; | |
bool ka=false; | |
if(canTakeFromAnywhere) | |
ka=subgroupRemoveAnActivityFromAnywhereCertainDay(sbg, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ka){ | |
if(level==0){ | |
/*cout<<"subgroup=="<<qPrintable(gt.rules.internalSubgroupsList[sbg]->name)<<endl; | |
cout<<"d=="<<d<<endl; | |
cout<<"H="<<H<<endl; | |
cout<<"Timetable:"<<endl; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
cout<<"\t"<<sbgTimetable(d2,h2)<<"\t"; | |
cout<<endl; | |
}*/ | |
//this should not be displayed | |
//cout<<"WARNING - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsmaxhoursdaily=false; | |
goto impossiblestudentsmaxhoursdaily; | |
} | |
} | |
} | |
assert(ai2>=0); | |
removeAi2FromSbgTimetable(ai2); | |
updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
impossiblestudentsmaxhoursdaily: | |
if(!okstudentsmaxhoursdaily){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from students max hours continuously | |
okstudentsmaxhourscontinuously=true; | |
foreach(int sbg, act->iSubgroupsList){ | |
for(int count=0; count<2; count++){ | |
int limitHoursCont; | |
double percentage; | |
if(count==0){ | |
limitHoursCont=subgroupsMaxHoursContinuouslyMaxHours1[sbg]; | |
percentage=subgroupsMaxHoursContinuouslyPercentages1[sbg]; | |
} | |
else{ | |
limitHoursCont=subgroupsMaxHoursContinuouslyMaxHours2[sbg]; | |
percentage=subgroupsMaxHoursContinuouslyPercentages2[sbg]; | |
} | |
if(limitHoursCont<0) //no constraint | |
continue; | |
//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 | |
// continue; | |
bool increased; | |
int h2; | |
for(h2=h; h2<h+act->duration; h2++){ | |
assert(h2<gt.rules.nHoursPerDay); | |
if(subgroupsTimetable(sbg,d,h2)==-1) | |
break; | |
} | |
if(h2<h+act->duration) | |
increased=true; | |
else | |
increased=false; | |
QList<int> removableActs; | |
int nc=act->duration; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(!increased && percentage==100.0) | |
assert(nc<=limitHoursCont); | |
if(!increased || nc<=limitHoursCont) //OK | |
continue; | |
assert(limitHoursCont>=0); | |
if(!skipRandom(percentage) && increased){ | |
if(act->duration>limitHoursCont){ | |
okstudentsmaxhourscontinuously=false; | |
goto impossiblestudentsmaxhourscontinuously; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsmaxhourscontinuously=false; | |
goto impossiblestudentsmaxhourscontinuously; | |
} | |
while(true){ | |
if(removableActs.count()==0){ | |
okstudentsmaxhourscontinuously=false; | |
goto impossiblestudentsmaxhourscontinuously; | |
} | |
int j=-1; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
j=tl.at(randomKnuth(tl.size())); | |
assert(j>=0 && j<removableActs.count()); | |
} | |
else{ | |
j=randomKnuth(removableActs.count()); | |
} | |
assert(j>=0); | |
int ai2=removableActs.at(j); | |
int t=removableActs.removeAll(ai2); | |
assert(t==1); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//////////// | |
removableActs.clear(); | |
int nc=act->duration; | |
int h2; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(nc<=limitHoursCont) //OK | |
break; | |
//////////// | |
} | |
} | |
} | |
} | |
impossiblestudentsmaxhourscontinuously: | |
if(!okstudentsmaxhourscontinuously){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from students activity tag max hours daily | |
//!!!NOT PERFECT, there is room for improvement | |
okstudentsactivitytagmaxhoursdaily=true; | |
if(haveStudentsActivityTagMaxHoursDaily){ | |
foreach(int sbg, act->iSubgroupsList){ | |
for(int cnt=0; cnt<subgroupsActivityTagMaxHoursDailyMaxHours[sbg].count(); cnt++){ | |
int activityTag=subgroupsActivityTagMaxHoursDailyActivityTag[sbg].at(cnt); | |
if(!gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(activityTag)) | |
continue; | |
int limitHoursDaily=subgroupsActivityTagMaxHoursDailyMaxHours[sbg].at(cnt); | |
double percentage=subgroupsActivityTagMaxHoursDailyPercentage[sbg].at(cnt); | |
assert(limitHoursDaily>=0); | |
assert(percentage>=0); | |
assert(activityTag>=0 /*&& activityTag<gt.rules.nInternalActivityTags*/); | |
//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 | |
// continue; | |
bool increased; | |
int nold=0, nnew=0; | |
/////////// | |
for(int h2=0; h2<h; h2++){ | |
if(newSubgroupsTimetable(sbg,d,h2)>=0){ | |
int ai2=newSubgroupsTimetable(sbg,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)){ | |
nold++; | |
nnew++; | |
} | |
} | |
} | |
for(int h2=h; h2<h+act->duration; h2++){ | |
if(oldSubgroupsTimetable(sbg,d,h2)>=0){ | |
int ai2=oldSubgroupsTimetable(sbg,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)) | |
nold++; | |
} | |
} | |
for(int h2=h; h2<h+act->duration; h2++){ | |
if(newSubgroupsTimetable(sbg,d,h2)>=0){ | |
int ai2=newSubgroupsTimetable(sbg,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)) | |
nnew++; | |
} | |
} | |
for(int h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
if(newSubgroupsTimetable(sbg,d,h2)>=0){ | |
int ai2=newSubgroupsTimetable(sbg,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)){ | |
nold++; | |
nnew++; | |
} | |
} | |
} | |
///////// | |
if(nold<nnew) | |
increased=true; | |
else | |
increased=false; | |
if(percentage==100.0) | |
assert(nold<=limitHoursDaily); | |
if(!increased && percentage==100.0) | |
assert(nnew<=limitHoursDaily); | |
if(!increased || nnew<=limitHoursDaily) //OK | |
continue; | |
assert(limitHoursDaily>=0); | |
assert(increased); | |
assert(nnew>limitHoursDaily); | |
if(!skipRandom(percentage)){ | |
if(act->duration>limitHoursDaily){ | |
okstudentsactivitytagmaxhoursdaily=false; | |
goto impossiblestudentsactivitytagmaxhoursdaily; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsactivitytagmaxhoursdaily=false; | |
goto impossiblestudentsactivitytagmaxhoursdaily; | |
} | |
getSbgTimetable(sbg, conflActivities[newtime]); | |
sbgGetNHoursGaps(sbg); | |
while(true){ | |
int ncrt=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(sbgTimetable(d,h2)>=0){ | |
int ai2=sbgTimetable(d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)) | |
ncrt++; | |
} | |
} | |
if(ncrt<=limitHoursDaily) | |
break; | |
int ai2=-1; | |
bool ke=subgroupRemoveAnActivityFromAnywhereCertainDayCertainActivityTag(sbg, d, activityTag, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ke){ | |
if(level==0){ | |
//...this is not too good, but hopefully there is no problem | |
} | |
okstudentsactivitytagmaxhoursdaily=false; | |
goto impossiblestudentsactivitytagmaxhoursdaily; | |
} | |
assert(ai2>=0); | |
assert(gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)); | |
removeAi2FromSbgTimetable(ai2); | |
updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
} | |
impossiblestudentsactivitytagmaxhoursdaily: | |
if(!okstudentsactivitytagmaxhoursdaily){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from students activity tag max hours continuously | |
okstudentsactivitytagmaxhourscontinuously=true; | |
if(haveStudentsActivityTagMaxHoursContinuously){ | |
foreach(int sbg, act->iSubgroupsList){ | |
for(int cnt=0; cnt<subgroupsActivityTagMaxHoursContinuouslyMaxHours[sbg].count(); cnt++){ | |
int activityTag=subgroupsActivityTagMaxHoursContinuouslyActivityTag[sbg].at(cnt); | |
//if(gt.rules.internalActivitiesList[ai].activityTagIndex!=activityTag) | |
// continue; | |
if(!gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(activityTag)) | |
continue; | |
int limitHoursCont=subgroupsActivityTagMaxHoursContinuouslyMaxHours[sbg].at(cnt); | |
double percentage=subgroupsActivityTagMaxHoursContinuouslyPercentage[sbg].at(cnt); | |
assert(limitHoursCont>=0); | |
assert(percentage>=0); | |
assert(activityTag>=0 /*&& activityTag<gt.rules.nInternalActivityTags*/); | |
//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 | |
// continue; | |
bool increased; | |
int h2; | |
for(h2=h; h2<h+act->duration; h2++){ | |
assert(h2<gt.rules.nHoursPerDay); | |
if(subgroupsTimetable(sbg,d,h2)==-1) | |
break; | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2>=0); | |
//if(gt.rules.internalActivitiesList[ai2].activityTagIndex!=activityTag) | |
// break; | |
if(!gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)) | |
break; | |
} | |
if(h2<h+act->duration) | |
increased=true; | |
else | |
increased=false; | |
QList<int> removableActs; | |
int nc=act->duration; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
//gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
//gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(!increased && percentage==100.0) | |
assert(nc<=limitHoursCont); | |
if(!increased || nc<=limitHoursCont) //OK | |
continue; | |
assert(limitHoursCont>=0); | |
if(!skipRandom(percentage) && increased){ | |
if(act->duration>limitHoursCont){ | |
okstudentsactivitytagmaxhourscontinuously=false; | |
goto impossiblestudentsactivitytagmaxhourscontinuously; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsactivitytagmaxhourscontinuously=false; | |
goto impossiblestudentsactivitytagmaxhourscontinuously; | |
} | |
while(true){ | |
if(removableActs.count()==0){ | |
okstudentsactivitytagmaxhourscontinuously=false; | |
goto impossiblestudentsactivitytagmaxhourscontinuously; | |
} | |
int j=-1; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
j=tl.at(randomKnuth(tl.size())); | |
assert(j>=0 && j<removableActs.count()); | |
} | |
else{ | |
j=randomKnuth(removableActs.count()); | |
} | |
assert(j>=0); | |
int ai2=removableActs.at(j); | |
int t=removableActs.removeAll(ai2); | |
assert(t==1); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//////////// | |
removableActs.clear(); | |
int nc=act->duration; | |
int h2; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
//gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=subgroupsTimetable(sbg,d,h2); | |
assert(ai2==newSubgroupsTimetable(sbg,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
//gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(nc<=limitHoursCont) //OK | |
break; | |
//////////// | |
} | |
} | |
} | |
} | |
} | |
impossiblestudentsactivitytagmaxhourscontinuously: | |
if(!okstudentsactivitytagmaxhourscontinuously){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
/////////begin students min hours daily | |
//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. | |
//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 | |
okstudentsminhoursdaily=true; | |
foreach(int sbg, act->iSubgroupsList){ | |
if(subgroupsMinHoursDailyMinHours[sbg]>=0){ | |
assert(subgroupsMinHoursDailyPercentages[sbg]==100); | |
bool allowEmptyDays=subgroupsMinHoursDailyAllowEmptyDays[sbg]; | |
bool skip=skipRandom(subgroupsMinHoursDailyPercentages[sbg]); | |
if(!skip){ | |
//preliminary test | |
bool _ok; | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//both limitations | |
int remG=0, totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=newSubgroupsDayNFirstGaps(sbg,d2)+newSubgroupsDayNGaps(sbg,d2); | |
if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){ | |
if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]){ | |
remGDay-=subgroupsMinHoursDailyMinHours[sbg]-newSubgroupsDayNHours(sbg,d2); | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
} | |
else | |
totalH+=newSubgroupsDayNHours(sbg,d2); | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if((remG+totalH <= nHoursPerSubgroup[sbg] | |
+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg]) | |
&& (totalH <= nHoursPerSubgroup[sbg])) | |
_ok=true; | |
else | |
_ok=false; | |
} | |
else{ | |
//only first gaps limitation | |
int remG=0, totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=0; | |
if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){ | |
if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]){ | |
remGDay=0; | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
} | |
else{ | |
totalH+=newSubgroupsDayNHours(sbg,d2); | |
if(newSubgroupsDayNFirstGaps(sbg,d2)==0) | |
remGDay=0; | |
else if(newSubgroupsDayNFirstGaps(sbg,d2)==1) | |
remGDay=1; | |
else if(newSubgroupsDayNFirstGaps(sbg,d2)>=2){ | |
remGDay=0; | |
totalH++; | |
} | |
} | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]) | |
&& (totalH <= nHoursPerSubgroup[sbg])) | |
_ok=true; | |
else | |
_ok=false; | |
} | |
} | |
else{ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//only max gaps per week limitation | |
int remG=0, totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=newSubgroupsDayNGaps(sbg,d2); | |
if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){ | |
if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]){ | |
remGDay-=subgroupsMinHoursDailyMinHours[sbg]-newSubgroupsDayNHours(sbg,d2); | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
} | |
else | |
totalH+=newSubgroupsDayNHours(sbg,d2); | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg]) | |
&& (totalH <= nHoursPerSubgroup[sbg])) | |
_ok=true; | |
else | |
_ok=false; | |
} | |
else{ | |
//no limitation | |
int totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(/*1*/ !allowEmptyDays || newSubgroupsDayNHours(sbg,d2)>0){ | |
if(newSubgroupsDayNHours(sbg,d2)<subgroupsMinHoursDailyMinHours[sbg]) | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
else | |
totalH+=newSubgroupsDayNHours(sbg,d2); | |
} | |
} | |
if(totalH <= nHoursPerSubgroup[sbg]) | |
_ok=true; | |
else | |
_ok=false; | |
} | |
} | |
if(_ok) | |
continue; | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okstudentsminhoursdaily=false; | |
goto impossiblestudentsminhoursdaily; | |
} | |
getSbgTimetable(sbg, conflActivities[newtime]); | |
sbgGetNHoursGaps(sbg); | |
for(;;){ | |
bool ok; | |
//////////////////////////// | |
if(subgroupsEarlyMaxBeginningsAtSecondHourPercentage[sbg]>=0){ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//both limitations | |
int remG=0, totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=sbgDayNFirstGaps[d2]+sbgDayNGaps[d2]; | |
if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){ | |
if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]){ | |
remGDay-=subgroupsMinHoursDailyMinHours[sbg]-sbgDayNHours[d2]; | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
} | |
else | |
totalH+=sbgDayNHours[d2]; | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if((remG+totalH <= nHoursPerSubgroup[sbg] | |
+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg]) | |
&& (totalH <= nHoursPerSubgroup[sbg])) | |
ok=true; | |
else | |
ok=false; | |
} | |
else{ | |
//only first gaps limitation | |
int remG=0, totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=0; | |
if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){ | |
if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]){ | |
remGDay=0; | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
} | |
else{ | |
totalH+=sbgDayNHours[d2]; | |
if(sbgDayNFirstGaps[d2]==0) | |
remGDay=0; | |
else if(sbgDayNFirstGaps[d2]==1) | |
remGDay=1; | |
else if(sbgDayNFirstGaps[d2]>=2){ | |
remGDay=0; | |
totalH++; | |
} | |
} | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsEarlyMaxBeginningsAtSecondHourMaxBeginnings[sbg]) | |
&& (totalH <= nHoursPerSubgroup[sbg])) | |
ok=true; | |
else | |
ok=false; | |
} | |
} | |
else{ | |
if(subgroupsMaxGapsPerWeekPercentage[sbg]>=0){ | |
//only max gaps per week limitation | |
int remG=0, totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=sbgDayNGaps[d2]; | |
if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){ | |
if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]){ | |
remGDay-=subgroupsMinHoursDailyMinHours[sbg]-sbgDayNHours[d2]; | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
} | |
else | |
totalH+=sbgDayNHours[d2]; | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if((remG+totalH <= nHoursPerSubgroup[sbg]+subgroupsMaxGapsPerWeekMaxGaps[sbg]) | |
&& (totalH <= nHoursPerSubgroup[sbg])) | |
ok=true; | |
else | |
ok=false; | |
} | |
else{ | |
//no limitation | |
int totalH=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(/*1*/ !allowEmptyDays || sbgDayNHours[d2]>0){ | |
if(sbgDayNHours[d2]<subgroupsMinHoursDailyMinHours[sbg]) | |
totalH+=subgroupsMinHoursDailyMinHours[sbg]; | |
else | |
totalH+=sbgDayNHours[d2]; | |
} | |
} | |
if(totalH <= nHoursPerSubgroup[sbg]) | |
ok=true; | |
else | |
ok=false; | |
} | |
} | |
//////////////////////////// | |
if(ok) | |
break; //ok | |
int ai2=-1; | |
bool kk=subgroupRemoveAnActivityFromEnd(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!kk){ | |
bool k=subgroupRemoveAnActivityFromBegin(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
bool ka=subgroupRemoveAnActivityFromAnywhere(sbg, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ka){ | |
if(level==0){ | |
/*cout<<"d=="<<d<<", h=="<<h<<", ai=="<<ai<<endl; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
cout<<"\t"<<sbgTimetable(d2,h2); | |
cout<<endl; | |
}*/ | |
//this should not be displayed | |
//cout<<"WARNING - unlikely situation - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okstudentsminhoursdaily=false; | |
goto impossiblestudentsminhoursdaily; | |
} | |
} | |
} | |
assert(ai2>=0); | |
removeAi2FromSbgTimetable(ai2); | |
updateSbgNHoursGaps(sbg, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
impossiblestudentsminhoursdaily: | |
if(!okstudentsminhoursdaily){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/////////end students(s) min hours daily | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
////////////TEACHERS//////////////// | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//not breaking the teacher max days per week constraints | |
////////////////////////////BEGIN max days per week for teachers | |
okteachermaxdaysperweek=true; | |
//foreach(int tch, act->iTeachersList){ | |
foreach(int tch, teachersWithMaxDaysPerWeekForActivities[ai]){ | |
if(skipRandom(teachersMaxDaysPerWeekWeightPercentages[tch])) | |
continue; | |
int maxDays=teachersMaxDaysPerWeekMaxDays[tch]; | |
assert(maxDays>=0); //the list contains real information | |
//preliminary test | |
int _nOc=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
//if(newTeachersDayNHours(tch,d2)>0) | |
//IT IS VITAL TO USE teacherActivitiesOfTheDay as a QList<int> (tch,d2)!!!!!!! | |
//The order of evaluation of activities is changed, | |
//with activities which were moved forward and back again | |
//being put at the end. | |
//If you do not follow this, you'll get impossible timetables | |
//for italian sample or samples from South Africa, I am not sure which of these 2 | |
if(teacherActivitiesOfTheDay(tch,d2).count()>0 || d2==d) | |
_nOc++; | |
if(_nOc<=maxDays) | |
continue; //OK, preliminary | |
if(maxDays>=0){ | |
assert(maxDays>0); | |
//getTchTimetable(tch, conflActivities[newtime]); | |
//tchGetNHoursGaps(tch); | |
bool occupiedDay[MAX_DAYS_PER_WEEK]; | |
bool canEmptyDay[MAX_DAYS_PER_WEEK]; | |
int _minWrong[MAX_DAYS_PER_WEEK]; | |
int _nWrong[MAX_DAYS_PER_WEEK]; | |
int _nConflActivities[MAX_DAYS_PER_WEEK]; | |
int _minIndexAct[MAX_DAYS_PER_WEEK]; | |
QList<int> _activitiesForDay[MAX_DAYS_PER_WEEK]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2==d) | |
continue; | |
occupiedDay[d2]=false; | |
canEmptyDay[d2]=true; | |
_minWrong[d2]=INF; | |
_nWrong[d2]=0; | |
_nConflActivities[d2]=0; | |
_minIndexAct[d2]=gt.rules.nInternalActivities; | |
_activitiesForDay[d2].clear(); | |
foreach(int ai2, teacherActivitiesOfTheDay(tch,d2)){ | |
if(ai2>=0){ | |
if(!conflActivities[newtime].contains(ai2)){ | |
occupiedDay[d2]=true; | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]) | |
canEmptyDay[d2]=false; | |
else if(!_activitiesForDay[d2].contains(ai2)){ | |
_minWrong[d2] = min (_minWrong[d2], triedRemovals(ai2,c.times[ai2])); | |
_minIndexAct[d2]=min(_minIndexAct[d2], invPermutation[ai2]); | |
_nWrong[d2]+=triedRemovals(ai2,c.times[ai2]); | |
_nConflActivities[d2]++; | |
_activitiesForDay[d2].append(ai2); | |
assert(_nConflActivities[d2]==_activitiesForDay[d2].count()); | |
} | |
} | |
} | |
} | |
if(!occupiedDay[d2]) | |
canEmptyDay[d2]=false; | |
} | |
occupiedDay[d]=true; | |
canEmptyDay[d]=false; | |
int nOc=0; | |
bool canChooseDay=false; | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
if(occupiedDay[j]){ | |
nOc++; | |
if(canEmptyDay[j]){ | |
canChooseDay=true; | |
} | |
} | |
if(nOc>maxDays){ | |
assert(nOc==maxDays+1); | |
if(!canChooseDay){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachermaxdaysperweek=false; | |
goto impossibleteachermaxdaysperweek; | |
} | |
int d2=-1; | |
if(level!=0){ | |
//choose random day from those with minimum number of conflicting activities | |
QList<int> candidateDays; | |
int m=gt.rules.nInternalActivities; | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyDay[kk]) | |
if(m>_nConflActivities[kk]) | |
m=_nConflActivities[kk]; | |
candidateDays.clear(); | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyDay[kk] && m==_nConflActivities[kk]) | |
candidateDays.append(kk); | |
assert(candidateDays.count()>0); | |
d2=candidateDays.at(randomKnuth(candidateDays.count())); | |
} | |
else{ //level==0 | |
QList<int> candidateDays; | |
int _mW=INF; | |
int _nW=INF; | |
int _mCA=gt.rules.nInternalActivities; | |
int _mIA=gt.rules.nInternalActivities; | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyDay[kk]){ | |
if(_mW>_minWrong[kk] || | |
(_mW==_minWrong[kk] && _nW>_nWrong[kk]) || | |
(_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA>_nConflActivities[kk]) || | |
(_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA>_minIndexAct[kk])){ | |
_mW=_minWrong[kk]; | |
_nW=_nWrong[kk]; | |
_mCA=_nConflActivities[kk]; | |
_mIA=_minIndexAct[kk]; | |
} | |
} | |
assert(_mW<INF); | |
candidateDays.clear(); | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyDay[kk] && _mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA==_minIndexAct[kk]) | |
candidateDays.append(kk); | |
assert(candidateDays.count()>0); | |
d2=candidateDays.at(randomKnuth(candidateDays.count())); | |
} | |
assert(d2>=0); | |
assert(_activitiesForDay[d2].count()>0); | |
foreach(int ai2, _activitiesForDay[d2]){ | |
assert(ai2!=ai); | |
assert(!swappedActivities[ai2]); | |
assert(!fixedTimeActivity[ai2]); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
impossibleteachermaxdaysperweek: | |
if(!okteachermaxdaysperweek){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END max days per week | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//BEGIN teachers intervals max days per week | |
okteachersintervalmaxdaysperweek=true; | |
foreach(int tch, act->iTeachersList){ | |
double perc=-1.0; | |
for(int cnt=0; cnt<3; cnt++){ | |
if(cnt==0){ | |
perc=teachersIntervalMaxDaysPerWeekPercentages1[tch]; | |
} | |
else if(cnt==1){ | |
perc=teachersIntervalMaxDaysPerWeekPercentages2[tch]; | |
} | |
else if(cnt==2){ | |
perc=teachersIntervalMaxDaysPerWeekPercentages3[tch]; | |
} | |
else | |
assert(0); | |
if(perc>=0){ | |
int maxDays=-1; | |
int sth=-1; | |
int endh=-1; | |
if(cnt==0){ | |
maxDays=teachersIntervalMaxDaysPerWeekMaxDays1[tch]; | |
sth=teachersIntervalMaxDaysPerWeekIntervalStart1[tch]; | |
endh=teachersIntervalMaxDaysPerWeekIntervalEnd1[tch]; | |
} | |
else if(cnt==1){ | |
maxDays=teachersIntervalMaxDaysPerWeekMaxDays2[tch]; | |
sth=teachersIntervalMaxDaysPerWeekIntervalStart2[tch]; | |
endh=teachersIntervalMaxDaysPerWeekIntervalEnd2[tch]; | |
} | |
else if(cnt==2){ | |
maxDays=teachersIntervalMaxDaysPerWeekMaxDays3[tch]; | |
sth=teachersIntervalMaxDaysPerWeekIntervalStart3[tch]; | |
endh=teachersIntervalMaxDaysPerWeekIntervalEnd3[tch]; | |
} | |
else | |
assert(0); | |
assert(sth>=0 && sth<gt.rules.nHoursPerDay); | |
assert(endh>sth && endh<=gt.rules.nHoursPerDay); | |
assert(maxDays>=0 && maxDays<=gt.rules.nDaysPerWeek); | |
if(skipRandom(perc)) | |
continue; | |
assert(perc==100.0); | |
bool foundothers=false; | |
bool foundai=false; | |
for(int hh=sth; hh<endh; hh++){ | |
if(newTeachersTimetable(tch,d,hh)==ai){ | |
foundai=true; | |
} | |
else{ | |
assert(newTeachersTimetable(tch,d,hh)==teachersTimetable(tch,d,hh)); | |
if(newTeachersTimetable(tch,d,hh)>=0){ | |
if(!conflActivities[newtime].contains(newTeachersTimetable(tch,d,hh))){ | |
foundothers=true; | |
} | |
} | |
} | |
} | |
int nrotherdays=0; | |
for(int dd=0; dd<gt.rules.nDaysPerWeek; dd++){ | |
if(dd!=d){ | |
for(int hh=sth; hh<endh; hh++){ | |
assert(newTeachersTimetable(tch,dd,hh)==teachersTimetable(tch,dd,hh)); | |
if(newTeachersTimetable(tch,dd,hh)>=0 && !conflActivities[newtime].contains(newTeachersTimetable(tch,dd,hh))){ | |
nrotherdays++; | |
break; | |
} | |
} | |
} | |
} | |
assert(nrotherdays<=maxDays); //if percentage==100%, then it is impossible to break this constraint | |
if((foundai && !foundothers) && nrotherdays==maxDays){ | |
//increased above limit | |
bool occupiedIntervalDay[MAX_DAYS_PER_WEEK]; | |
bool canEmptyIntervalDay[MAX_DAYS_PER_WEEK]; | |
int _minWrong[MAX_DAYS_PER_WEEK]; | |
int _nWrong[MAX_DAYS_PER_WEEK]; | |
int _nConflActivities[MAX_DAYS_PER_WEEK]; | |
int _minIndexAct[MAX_DAYS_PER_WEEK]; | |
QList<int> _activitiesForIntervalDay[MAX_DAYS_PER_WEEK]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2==d) | |
continue; | |
occupiedIntervalDay[d2]=false; | |
canEmptyIntervalDay[d2]=true; | |
_minWrong[d2]=INF; | |
_nWrong[d2]=0; | |
_nConflActivities[d2]=0; | |
_minIndexAct[d2]=gt.rules.nInternalActivities; | |
_activitiesForIntervalDay[d2].clear(); | |
for(int h2=sth; h2<endh; h2++){ | |
int ai2=teachersTimetable(tch,d2,h2); | |
//foreach(int ai2, teacherActivitiesOfTheDay(tch,d2)){ | |
if(ai2>=0){ | |
if(!conflActivities[newtime].contains(ai2)){ | |
occupiedIntervalDay[d2]=true; | |
if(fixedTimeActivity[ai2] || swappedActivities[ai2]) | |
canEmptyIntervalDay[d2]=false; | |
else if(!_activitiesForIntervalDay[d2].contains(ai2)){ | |
_minWrong[d2] = min (_minWrong[d2], triedRemovals(ai2,c.times[ai2])); | |
_minIndexAct[d2]=min(_minIndexAct[d2], invPermutation[ai2]); | |
_nWrong[d2]+=triedRemovals(ai2,c.times[ai2]); | |
_nConflActivities[d2]++; | |
_activitiesForIntervalDay[d2].append(ai2); | |
assert(_nConflActivities[d2]==_activitiesForIntervalDay[d2].count()); | |
} | |
} | |
} | |
} | |
if(!occupiedIntervalDay[d2]) | |
canEmptyIntervalDay[d2]=false; | |
} | |
occupiedIntervalDay[d]=true; | |
canEmptyIntervalDay[d]=false; | |
int nOc=0; | |
bool canChooseDay=false; | |
for(int j=0; j<gt.rules.nDaysPerWeek; j++) | |
if(occupiedIntervalDay[j]){ | |
nOc++; | |
if(canEmptyIntervalDay[j]){ | |
canChooseDay=true; | |
} | |
} | |
//if(nOc>maxDays){ | |
assert(nOc==maxDays+1); | |
if(!canChooseDay){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachersintervalmaxdaysperweek=false; | |
goto impossibleteachersintervalmaxdaysperweek; | |
} | |
int d2=-1; | |
if(level!=0){ | |
//choose random day from those with minimum number of conflicting activities | |
QList<int> candidateDays; | |
int m=gt.rules.nInternalActivities; | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk]) | |
if(m>_nConflActivities[kk]) | |
m=_nConflActivities[kk]; | |
candidateDays.clear(); | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk] && m==_nConflActivities[kk]) | |
candidateDays.append(kk); | |
assert(candidateDays.count()>0); | |
d2=candidateDays.at(randomKnuth(candidateDays.count())); | |
} | |
else{ //level==0 | |
QList<int> candidateDays; | |
int _mW=INF; | |
int _nW=INF; | |
int _mCA=gt.rules.nInternalActivities; | |
int _mIA=gt.rules.nInternalActivities; | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk]){ | |
if(_mW>_minWrong[kk] || | |
(_mW==_minWrong[kk] && _nW>_nWrong[kk]) || | |
(_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA>_nConflActivities[kk]) || | |
(_mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA>_minIndexAct[kk])){ | |
_mW=_minWrong[kk]; | |
_nW=_nWrong[kk]; | |
_mCA=_nConflActivities[kk]; | |
_mIA=_minIndexAct[kk]; | |
} | |
} | |
assert(_mW<INF); | |
candidateDays.clear(); | |
for(int kk=0; kk<gt.rules.nDaysPerWeek; kk++) | |
if(canEmptyIntervalDay[kk] && _mW==_minWrong[kk] && _nW==_nWrong[kk] && _mCA==_nConflActivities[kk] && _mIA==_minIndexAct[kk]) | |
candidateDays.append(kk); | |
assert(candidateDays.count()>0); | |
d2=candidateDays.at(randomKnuth(candidateDays.count())); | |
} | |
assert(d2>=0); | |
assert(_activitiesForIntervalDay[d2].count()>0); | |
foreach(int ai2, _activitiesForIntervalDay[d2]){ | |
assert(ai2!=ai); | |
assert(!swappedActivities[ai2]); | |
assert(!fixedTimeActivity[ai2]); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//addConflActivity(conflActivities[newtime], nConflActivities[newtime], ai2, >.rules.internalActivitiesList[ai2]); | |
} | |
} | |
} | |
} | |
} | |
//respecting teachers interval max days per week | |
impossibleteachersintervalmaxdaysperweek: | |
if(!okteachersintervalmaxdaysperweek){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END teachers interval max days per week | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//not causing more than teachersMaxGapsPerWeek teachers gaps | |
okteachersmaxgapsperweek=true; | |
foreach(int tch, act->iTeachersList) | |
if(!skipRandom(teachersMaxGapsPerWeekPercentage[tch])){ | |
assert(teachersMaxGapsPerWeekPercentage[tch]==100); | |
//preliminary test | |
int _nHours=0; | |
int _nGaps=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
_nHours+=newTeachersDayNHours(tch,d2); | |
_nGaps+=newTeachersDayNGaps(tch,d2); | |
} | |
if(_nGaps+_nHours > teachersMaxGapsPerWeekMaxGaps[tch]+nHoursPerTeacher[tch]){ | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersmaxgapsperweek=false; | |
goto impossibleteachersmaxgapsperweek; | |
} | |
getTchTimetable(tch, conflActivities[newtime]); | |
tchGetNHoursGaps(tch); | |
for(;;){ | |
int nHours=0; | |
int nGaps=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
nHours+=tchDayNHours[d2]; | |
nGaps+=tchDayNGaps[d2]; | |
} | |
int ai2=-1; | |
if(nGaps+nHours > teachersMaxGapsPerWeekMaxGaps[tch]+nHoursPerTeacher[tch]){ | |
//remove an activity | |
bool k=teacherRemoveAnActivityFromBeginOrEnd(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachersmaxgapsperweek=false; | |
goto impossibleteachersmaxgapsperweek; | |
} | |
} | |
else{ //OK | |
break; | |
} | |
assert(ai2>=0); | |
removeAi2FromTchTimetable(ai2); | |
updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
impossibleteachersmaxgapsperweek: | |
if(!okteachersmaxgapsperweek){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END max gaps per week | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//not causing more than teachersMaxGapsPerDay teachers gaps | |
okteachersmaxgapsperday=true; | |
foreach(int tch, act->iTeachersList) | |
if(!skipRandom(teachersMaxGapsPerDayPercentage[tch])){ | |
assert(teachersMaxGapsPerDayPercentage[tch]==100); | |
//preliminary test | |
int _total=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
_total+=newTeachersDayNHours(tch,d2); | |
if(teachersMaxGapsPerDayMaxGaps[tch]<newTeachersDayNGaps(tch,d2)) | |
_total+=newTeachersDayNGaps(tch,d2)-teachersMaxGapsPerDayMaxGaps[tch]; | |
} | |
if(_total<=nHoursPerTeacher[tch]) //OK | |
continue; | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersmaxgapsperday=false; | |
goto impossibleteachersmaxgapsperday; | |
} | |
getTchTimetable(tch, conflActivities[newtime]); | |
tchGetNHoursGaps(tch); | |
for(;;){ | |
int total=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
total+=tchDayNHours[d2]; | |
if(teachersMaxGapsPerDayMaxGaps[tch]<tchDayNGaps[d2]) | |
total+=tchDayNGaps[d2]-teachersMaxGapsPerDayMaxGaps[tch]; | |
} | |
if(total<=nHoursPerTeacher[tch]) //OK | |
break; | |
//remove an activity from the beginning or from the end of a day | |
//following code is identical to maxgapsperweek | |
//remove an activity | |
int ai2=-1; | |
//it should also be allowed to take from anywhere, but it is risky to change now | |
bool k=teacherRemoveAnActivityFromBeginOrEnd(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachersmaxgapsperday=false; | |
goto impossibleteachersmaxgapsperday; | |
} | |
assert(ai2>=0); | |
/*Activity* act2=>.rules.internalActivitiesList[ai2]; | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
for(int dur2=0; dur2<act2->duration; dur2++){ | |
assert(tchTimetable(d2,h2+dur2)==ai2); | |
tchTimetable(d2,h2+dur2)=-1; | |
}*/ | |
removeAi2FromTchTimetable(ai2); | |
updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
impossibleteachersmaxgapsperday: | |
if(!okteachersmaxgapsperday){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
////////////////////////////END max gaps per day | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from teachers max hours daily | |
//!!!after max gaps per week and max gaps per day | |
okteachersmaxhoursdaily=true; | |
foreach(int tch, act->iTeachersList){ | |
for(int count=0; count<2; count++){ | |
int limitHoursDaily; | |
double percentage; | |
if(count==0){ | |
limitHoursDaily=teachersMaxHoursDailyMaxHours1[tch]; | |
percentage=teachersMaxHoursDailyPercentages1[tch]; | |
} | |
else{ | |
limitHoursDaily=teachersMaxHoursDailyMaxHours2[tch]; | |
percentage=teachersMaxHoursDailyPercentages2[tch]; | |
} | |
if(limitHoursDaily<0) | |
continue; | |
//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 | |
// continue; | |
bool increased; | |
if(teachersMaxGapsPerWeekPercentage[tch]>=0 || teachersMaxGapsPerDayPercentage[tch]>=0){ | |
if(newTeachersDayNHours(tch,d) > oldTeachersDayNHours(tch,d) | |
|| newTeachersDayNHours(tch,d)+newTeachersDayNGaps(tch,d) > oldTeachersDayNHours(tch,d)+oldTeachersDayNGaps(tch,d)) | |
increased=true; | |
else | |
increased=false; | |
} | |
else{ | |
if(newTeachersDayNHours(tch,d) > oldTeachersDayNHours(tch,d)) | |
increased=true; | |
else | |
increased=false; | |
} | |
/* | |
if(newTeachersDayNHours(tch,d) > oldTeachersDayNHours(tch,d)) | |
increased=true; | |
else | |
increased=false;*/ | |
if(limitHoursDaily>=0 && !skipRandom(percentage) && increased){ | |
if(limitHoursDaily<act->duration){ | |
okteachersmaxhoursdaily=false; | |
goto impossibleteachersmaxhoursdaily; | |
} | |
//preliminary test | |
//basically, see that the gaps are enough | |
bool _ok; | |
if(newTeachersDayNHours(tch,d)>limitHoursDaily){ | |
_ok=false; | |
} | |
else{ | |
if(teachersMaxGapsPerWeekPercentage[tch]>=0){ | |
int rg=teachersMaxGapsPerWeekMaxGaps[tch]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
int g=limitHoursDaily-newTeachersDayNHours(tch,d2); | |
//TODO: if g lower than 0 make g 0 | |
//but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s) | |
g=newTeachersDayNGaps(tch,d2)-g; | |
if(g>0) | |
rg-=g; | |
} | |
} | |
if(rg<0) | |
rg=0; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
if(rg>teachersMaxGapsPerDayMaxGaps[tch]) | |
rg=teachersMaxGapsPerDayMaxGaps[tch]; | |
int hg=newTeachersDayNGaps(tch,d)-rg; | |
if(hg<0) | |
hg=0; | |
if(hg+newTeachersDayNHours(tch,d) > limitHoursDaily){ | |
_ok=false; | |
} | |
else | |
_ok=true; | |
} | |
else{ | |
int rg=newTeachersDayNGaps(tch,d); | |
int hg=rg; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
if(rg>teachersMaxGapsPerDayMaxGaps[tch]) | |
rg=teachersMaxGapsPerDayMaxGaps[tch]; | |
hg-=rg; | |
if(hg+newTeachersDayNHours(tch,d) > limitHoursDaily) | |
_ok=false; | |
else | |
_ok=true; | |
} | |
} | |
if(_ok){ | |
continue; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersmaxhoursdaily=false; | |
goto impossibleteachersmaxhoursdaily; | |
} | |
getTchTimetable(tch, conflActivities[newtime]); | |
tchGetNHoursGaps(tch); | |
for(;;){ | |
//basically, see that the gaps are enough | |
bool ok; | |
if(tchDayNHours[d]>limitHoursDaily){ | |
ok=false; | |
} | |
else{ | |
if(teachersMaxGapsPerWeekPercentage[tch]>=0){ | |
int rg=teachersMaxGapsPerWeekMaxGaps[tch]; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
if(d2!=d){ | |
int g=limitHoursDaily-tchDayNHours[d2]; | |
//TODO: if g lower than 0 make g 0 | |
//but with this change, speed decreases for test 25_2_2008_1.fet (private Greek sample from my80s) | |
g=tchDayNGaps[d2]-g; | |
if(g>0) | |
rg-=g; | |
} | |
} | |
if(rg<0) | |
rg=0; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
if(rg>teachersMaxGapsPerDayMaxGaps[tch]) | |
rg=teachersMaxGapsPerDayMaxGaps[tch]; | |
int hg=tchDayNGaps[d]-rg; | |
if(hg<0) | |
hg=0; | |
if(hg+tchDayNHours[d] > limitHoursDaily){ | |
ok=false; | |
} | |
else | |
ok=true; | |
} | |
else{ | |
int rg=tchDayNGaps[d]; | |
int hg=rg; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
if(rg>teachersMaxGapsPerDayMaxGaps[tch]) | |
rg=teachersMaxGapsPerDayMaxGaps[tch]; | |
hg-=rg; | |
if(hg+tchDayNHours[d] > limitHoursDaily) | |
ok=false; | |
else | |
ok=true; | |
} | |
} | |
if(ok){ | |
break; | |
} | |
int ai2=-1; | |
bool k=teacherRemoveAnActivityFromBeginOrEndCertainDay(tch, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
bool ka=teacherRemoveAnActivityFromAnywhereCertainDay(tch, d, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ka){ | |
if(level==0){ | |
/*cout<<"d=="<<d<<", h=="<<h<<", teacher=="<<qPrintable(gt.rules.internalTeachersList[tch]->name); | |
cout<<", ai=="<<ai<<endl; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
cout<<"\t"<<tchTimetable(d2,h2)<<"\t"; | |
cout<<endl; | |
} | |
cout<<endl; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
cout<<"\t"<<newTeachersTimetable(tch,d2,h2)<<"\t"; | |
cout<<endl; | |
}*/ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachersmaxhoursdaily=false; | |
goto impossibleteachersmaxhoursdaily; | |
} | |
} | |
assert(ai2>=0); | |
removeAi2FromTchTimetable(ai2); | |
updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
impossibleteachersmaxhoursdaily: | |
if(!okteachersmaxhoursdaily){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from teachers max hours continuously | |
okteachersmaxhourscontinuously=true; | |
foreach(int tch, act->iTeachersList){ | |
for(int count=0; count<2; count++){ | |
int limitHoursCont; | |
double percentage; | |
if(count==0){ | |
limitHoursCont=teachersMaxHoursContinuouslyMaxHours1[tch]; | |
percentage=teachersMaxHoursContinuouslyPercentages1[tch]; | |
} | |
else{ | |
limitHoursCont=teachersMaxHoursContinuouslyMaxHours2[tch]; | |
percentage=teachersMaxHoursContinuouslyPercentages2[tch]; | |
} | |
if(limitHoursCont<0) //no constraint | |
continue; | |
//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 | |
// continue; | |
bool increased; | |
int h2; | |
for(h2=h; h2<h+act->duration; h2++){ | |
assert(h2<gt.rules.nHoursPerDay); | |
if(teachersTimetable(tch,d,h2)==-1) | |
break; | |
} | |
if(h2<h+act->duration) | |
increased=true; | |
else | |
increased=false; | |
QList<int> removableActs; | |
int nc=act->duration; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=teachersTimetable(tch,d,h2); | |
/*if(ai2!=newTeachersTimetable(tch,d,h2)){ | |
cout<<"ai=="<<ai<<", d=="<<d<<", h=="<<h<<endl; | |
cout<<"teachersTimetable(tch,d,h2)=="<<teachersTimetable(tch,d,h2)<<endl; | |
cout<<"newTeachersTimetable(tch,d,h2)=="<<newTeachersTimetable(tch,d,h2)<<endl; | |
}*/ | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(!increased && percentage==100.0) | |
assert(nc<=limitHoursCont); | |
if(!increased || nc<=limitHoursCont) //OK | |
continue; | |
assert(limitHoursCont>=0); | |
if(!skipRandom(percentage) && increased){ | |
if(act->duration>limitHoursCont){ | |
okteachersmaxhourscontinuously=false; | |
goto impossibleteachersmaxhourscontinuously; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersmaxhourscontinuously=false; | |
goto impossibleteachersmaxhourscontinuously; | |
} | |
while(true){ | |
if(removableActs.count()==0){ | |
okteachersmaxhourscontinuously=false; | |
goto impossibleteachersmaxhourscontinuously; | |
} | |
int j=-1; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
j=tl.at(randomKnuth(tl.size())); | |
assert(j>=0 && j<removableActs.count()); | |
} | |
else{ | |
j=randomKnuth(removableActs.count()); | |
} | |
assert(j>=0); | |
int ai2=removableActs.at(j); | |
int t=removableActs.removeAll(ai2); | |
assert(t==1); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//////////// | |
removableActs.clear(); | |
int nc=act->duration; | |
int h2; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(nc<=limitHoursCont) //OK | |
break; | |
//////////// | |
} | |
} | |
} | |
} | |
impossibleteachersmaxhourscontinuously: | |
if(!okteachersmaxhourscontinuously){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from teachers activity tag max hours daily | |
//!!!NOT PERFECT, there is room for improvement | |
okteachersactivitytagmaxhoursdaily=true; | |
if(haveTeachersActivityTagMaxHoursDaily){ | |
foreach(int tch, act->iTeachersList){ | |
for(int cnt=0; cnt<teachersActivityTagMaxHoursDailyMaxHours[tch].count(); cnt++){ | |
int activityTag=teachersActivityTagMaxHoursDailyActivityTag[tch].at(cnt); | |
if(!gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(activityTag)) | |
continue; | |
int limitHoursDaily=teachersActivityTagMaxHoursDailyMaxHours[tch].at(cnt); | |
double percentage=teachersActivityTagMaxHoursDailyPercentage[tch].at(cnt); | |
assert(limitHoursDaily>=0); | |
assert(percentage>=0); | |
assert(activityTag>=0 /*&& activityTag<gt.rules.nInternalActivityTags*/); | |
//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 | |
// continue; | |
bool increased; | |
int nold=0, nnew=0; | |
/////////// | |
for(int h2=0; h2<h; h2++){ | |
if(newTeachersTimetable(tch,d,h2)>=0){ | |
int ai2=newTeachersTimetable(tch,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)){ | |
nold++; | |
nnew++; | |
} | |
} | |
} | |
for(int h2=h; h2<h+act->duration; h2++){ | |
if(oldTeachersTimetable(tch,d,h2)>=0){ | |
int ai2=oldTeachersTimetable(tch,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)) | |
nold++; | |
} | |
} | |
for(int h2=h; h2<h+act->duration; h2++){ | |
if(newTeachersTimetable(tch,d,h2)>=0){ | |
int ai2=newTeachersTimetable(tch,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)) | |
nnew++; | |
} | |
} | |
for(int h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
if(newTeachersTimetable(tch,d,h2)>=0){ | |
int ai2=newTeachersTimetable(tch,d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)){ | |
nold++; | |
nnew++; | |
} | |
} | |
} | |
///////// | |
if(nold<nnew) | |
increased=true; | |
else | |
increased=false; | |
if(percentage==100.0) | |
assert(nold<=limitHoursDaily); | |
if(!increased && percentage==100.0) | |
assert(nnew<=limitHoursDaily); | |
if(!increased || nnew<=limitHoursDaily) //OK | |
continue; | |
assert(limitHoursDaily>=0); | |
assert(increased); | |
assert(nnew>limitHoursDaily); | |
if(!skipRandom(percentage)){ | |
if(act->duration>limitHoursDaily){ | |
okteachersactivitytagmaxhoursdaily=false; | |
goto impossibleteachersactivitytagmaxhoursdaily; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersactivitytagmaxhoursdaily=false; | |
goto impossibleteachersactivitytagmaxhoursdaily; | |
} | |
getTchTimetable(tch, conflActivities[newtime]); | |
tchGetNHoursGaps(tch); | |
while(true){ | |
int ncrt=0; | |
for(int h2=0; h2<gt.rules.nHoursPerDay; h2++){ | |
if(tchTimetable(d,h2)>=0){ | |
int ai2=tchTimetable(d,h2); | |
assert(ai2>=0 && ai2<gt.rules.nInternalActivities); | |
Activity* act=>.rules.internalActivitiesList[ai2]; | |
if(act->iActivityTagsSet.contains(activityTag)) | |
ncrt++; | |
} | |
} | |
if(ncrt<=limitHoursDaily) | |
break; | |
int ai2=-1; | |
bool ke=teacherRemoveAnActivityFromAnywhereCertainDayCertainActivityTag(tch, d, activityTag, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ke){ | |
if(level==0){ | |
//...this is not too good, but hopefully there is no problem | |
} | |
okteachersactivitytagmaxhoursdaily=false; | |
goto impossibleteachersactivitytagmaxhoursdaily; | |
} | |
assert(ai2>=0); | |
assert(gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)); | |
removeAi2FromTchTimetable(ai2); | |
updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
} | |
impossibleteachersactivitytagmaxhoursdaily: | |
if(!okteachersactivitytagmaxhoursdaily){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
//allowed from teachers activity tag max hours continuously | |
okteachersactivitytagmaxhourscontinuously=true; | |
if(haveTeachersActivityTagMaxHoursContinuously){ | |
foreach(int tch, act->iTeachersList){ | |
for(int cnt=0; cnt<teachersActivityTagMaxHoursContinuouslyMaxHours[tch].count(); cnt++){ | |
int activityTag=teachersActivityTagMaxHoursContinuouslyActivityTag[tch].at(cnt); | |
//if(gt.rules.internalActivitiesList[ai].activityTagIndex!=activityTag) | |
// continue; | |
if(!gt.rules.internalActivitiesList[ai].iActivityTagsSet.contains(activityTag)) | |
continue; | |
int limitHoursCont=teachersActivityTagMaxHoursContinuouslyMaxHours[tch].at(cnt); | |
double percentage=teachersActivityTagMaxHoursContinuouslyPercentage[tch].at(cnt); | |
assert(limitHoursCont>=0); | |
assert(percentage>=0); | |
assert(activityTag>=0/* && activityTag<gt.rules.nInternalActivityTags*/); | |
//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 | |
// continue; | |
bool increased; | |
int h2; | |
for(h2=h; h2<h+act->duration; h2++){ | |
assert(h2<gt.rules.nHoursPerDay); | |
if(teachersTimetable(tch,d,h2)==-1) | |
break; | |
int ai2=teachersTimetable(tch,d,h2); | |
//if(gt.rules.internalActivitiesList[ai2].activityTagIndex!=activityTag) | |
// break; | |
if(!gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)) | |
break; | |
} | |
if(h2<h+act->duration) | |
increased=true; | |
else | |
increased=false; | |
QList<int> removableActs; | |
int nc=act->duration; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
//gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
//gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(!increased && percentage==100.0) | |
assert(nc<=limitHoursCont); | |
if(!increased || nc<=limitHoursCont) //OK | |
continue; | |
assert(limitHoursCont>=0); | |
if(!skipRandom(percentage) && increased){ | |
if(act->duration>limitHoursCont){ | |
okteachersactivitytagmaxhourscontinuously=false; | |
goto impossibleteachersactivitytagmaxhourscontinuously; | |
} | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersactivitytagmaxhourscontinuously=false; | |
goto impossibleteachersactivitytagmaxhourscontinuously; | |
} | |
while(true){ | |
if(removableActs.count()==0){ | |
okteachersactivitytagmaxhourscontinuously=false; | |
goto impossibleteachersactivitytagmaxhourscontinuously; | |
} | |
int j=-1; | |
if(level==0){ | |
int optMinWrong=INF; | |
QList<int> tl; | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong>triedRemovals(ai2,c.times[ai2])){ | |
optMinWrong=triedRemovals(ai2,c.times[ai2]); | |
} | |
} | |
for(int q=0; q<removableActs.count(); q++){ | |
int ai2=removableActs.at(q); | |
if(optMinWrong==triedRemovals(ai2,c.times[ai2])) | |
tl.append(q); | |
} | |
assert(tl.size()>=1); | |
j=tl.at(randomKnuth(tl.size())); | |
assert(j>=0 && j<removableActs.count()); | |
} | |
else{ | |
j=randomKnuth(removableActs.count()); | |
} | |
assert(j>=0); | |
int ai2=removableActs.at(j); | |
int t=removableActs.removeAll(ai2); | |
assert(t==1); | |
assert(!conflActivities[newtime].contains(ai2)); | |
conflActivities[newtime].append(ai2); | |
nConflActivities[newtime]++; | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
//////////// | |
removableActs.clear(); | |
int nc=act->duration; | |
int h2; | |
for(h2=h-1; h2>=0; h2--){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
// gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
for(h2=h+act->duration; h2<gt.rules.nHoursPerDay; h2++){ | |
int ai2=teachersTimetable(tch,d,h2); | |
assert(ai2==newTeachersTimetable(tch,d,h2)); | |
assert(ai2!=ai); | |
if(ai2<0) | |
break; | |
if(ai2>=0 && !conflActivities[newtime].contains(ai2) && | |
// gt.rules.internalActivitiesList[ai2].activityTagIndex==activityTag){ | |
gt.rules.internalActivitiesList[ai2].iActivityTagsSet.contains(activityTag)){ | |
nc++; | |
if(!removableActs.contains(ai2) && !fixedTimeActivity[ai2] && !swappedActivities[ai2]) | |
removableActs.append(ai2); | |
} | |
else | |
break; | |
} | |
if(nc<=limitHoursCont) //OK | |
break; | |
//////////// | |
} | |
} | |
} | |
} | |
} | |
impossibleteachersactivitytagmaxhourscontinuously: | |
if(!okteachersactivitytagmaxhourscontinuously){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
/////////begin teacher(s) min hours daily | |
//I think it is best to put this routine after max days per week | |
//Added on 11 September 2009: takes care of teachers min days per week | |
okteachersminhoursdaily=true; | |
foreach(int tch, act->iTeachersList){ | |
if(teachersMinHoursDailyMinHours[tch]>=0){ | |
assert(teachersMinHoursDailyPercentages[tch]==100); | |
bool skip=skipRandom(teachersMinHoursDailyPercentages[tch]); | |
if(!skip){ | |
//preliminary test | |
bool _ok; | |
if(teachersMaxGapsPerWeekPercentage[tch]==-1){ | |
int _reqHours=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
if(newTeachersDayNHours(tch,d2)>0){ | |
_usedDays++; | |
if(teachersMaxGapsPerDayPercentage[tch]==-1){ | |
_reqHours+=max(newTeachersDayNHours(tch,d2), teachersMinHoursDailyMinHours[tch]); | |
} | |
else{ | |
int nh=max(0, newTeachersDayNGaps(tch,d2)-teachersMaxGapsPerDayMaxGaps[tch]); | |
_reqHours+=max(newTeachersDayNHours(tch,d2)+nh, teachersMinHoursDailyMinHours[tch]); | |
} | |
} | |
if(teachersMinDaysPerWeekPercentages[tch]>=0){ | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
_reqHours+=(_md-_usedDays)*teachersMinHoursDailyMinHours[tch]; | |
} | |
if(_reqHours <= nHoursPerTeacher[tch]) | |
_ok=true; //ok | |
else | |
_ok=false; | |
} | |
else{ | |
int remG=0; | |
int totalH=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=newTeachersDayNGaps(tch,d2); | |
int h=newTeachersDayNHours(tch,d2); | |
if(h>0){ | |
_usedDays++; | |
} | |
int addh; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
addh=max(0, remGDay-teachersMaxGapsPerDayMaxGaps[tch]); | |
else | |
addh=0; | |
remGDay-=addh; | |
assert(remGDay>=0); | |
h+=addh; | |
if(h>0){ | |
if(h<teachersMinHoursDailyMinHours[tch]){ | |
remGDay-=teachersMinHoursDailyMinHours[tch]-h; | |
totalH+=teachersMinHoursDailyMinHours[tch]; | |
} | |
else | |
totalH+=h; | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if(teachersMinDaysPerWeekPercentages[tch]>=0){ | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
totalH+=(_md-_usedDays)*teachersMinHoursDailyMinHours[tch]; | |
} | |
if(remG+totalH<=nHoursPerTeacher[tch]+teachersMaxGapsPerWeekMaxGaps[tch] | |
&& totalH<=nHoursPerTeacher[tch]) | |
_ok=true; | |
else | |
_ok=false; | |
} | |
if(_ok) | |
continue; | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersminhoursdaily=false; | |
goto impossibleteachersminhoursdaily; | |
} | |
getTchTimetable(tch, conflActivities[newtime]); | |
tchGetNHoursGaps(tch); | |
for(;;){ | |
bool ok; | |
if(teachersMaxGapsPerWeekPercentage[tch]==-1){ | |
int _reqHours=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
if(tchDayNHours[d2]>0){ | |
_usedDays++; | |
if(teachersMaxGapsPerDayPercentage[tch]==-1){ | |
_reqHours+=max(tchDayNHours[d2], teachersMinHoursDailyMinHours[tch]); | |
} | |
else{ | |
int nh=max(0, tchDayNGaps[d2]-teachersMaxGapsPerDayMaxGaps[tch]); | |
_reqHours+=max(tchDayNHours[d2]+nh, teachersMinHoursDailyMinHours[tch]); | |
} | |
} | |
if(teachersMinDaysPerWeekPercentages[tch]>=0){ | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
_reqHours+=(_md-_usedDays)*teachersMinHoursDailyMinHours[tch]; | |
} | |
if(_reqHours <= nHoursPerTeacher[tch]) | |
ok=true; //ok | |
else | |
ok=false; | |
} | |
else{ | |
int remG=0; | |
int totalH=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=tchDayNGaps[d2]; | |
int h=tchDayNHours[d2]; | |
if(h>0) | |
_usedDays++; | |
int addh; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
addh=max(0, remGDay-teachersMaxGapsPerDayMaxGaps[tch]); | |
else | |
addh=0; | |
remGDay-=addh; | |
assert(remGDay>=0); | |
h+=addh; | |
if(h>0){ | |
if(h<teachersMinHoursDailyMinHours[tch]){ | |
remGDay-=teachersMinHoursDailyMinHours[tch]-h; | |
totalH+=teachersMinHoursDailyMinHours[tch]; | |
} | |
else | |
totalH+=h; | |
} | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
if(teachersMinDaysPerWeekPercentages[tch]>=0){ | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
totalH+=(_md-_usedDays)*teachersMinHoursDailyMinHours[tch]; | |
} | |
if(remG+totalH<=nHoursPerTeacher[tch]+teachersMaxGapsPerWeekMaxGaps[tch] | |
&& totalH<=nHoursPerTeacher[tch]) | |
ok=true; | |
else | |
ok=false; | |
} | |
if(ok) | |
break; | |
int ai2=-1; | |
bool k=teacherRemoveAnActivityFromBeginOrEnd(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
bool ka=teacherRemoveAnActivityFromAnywhere(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ka){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachersminhoursdaily=false; | |
goto impossibleteachersminhoursdaily; | |
} | |
} | |
assert(ai2>=0); | |
/*Activity* act2=>.rules.internalActivitiesList[ai2]; | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
for(int dur2=0; dur2<act2->duration; dur2++){ | |
assert(tchTimetable(d2,h2+dur2)==ai2); | |
tchTimetable(d2,h2+dur2)=-1; | |
}*/ | |
removeAi2FromTchTimetable(ai2); | |
updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
impossibleteachersminhoursdaily: | |
if(!okteachersminhoursdaily){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/////////end teacher(s) min hours daily | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
/////////begin teacher(s) min days per week | |
//Put this routine after min hours daily | |
//Added on 11 September 2009 | |
okteachersmindaysperweek=true; | |
foreach(int tch, act->iTeachersList){ | |
if(teachersMinDaysPerWeekMinDays[tch]>=0 && teachersMinHoursDailyMinHours[tch]==-1){ //no need to recheck, if min hours daily is set, because I tested above. | |
assert(teachersMinDaysPerWeekPercentages[tch]==100); | |
bool skip=skipRandom(teachersMinDaysPerWeekPercentages[tch]); | |
if(!skip){ | |
//preliminary test | |
bool _ok; | |
if(teachersMaxGapsPerWeekPercentage[tch]==-1){ | |
int _reqHours=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
if(newTeachersDayNHours(tch,d2)>0){ | |
_usedDays++; | |
if(teachersMaxGapsPerDayPercentage[tch]==-1){ | |
_reqHours+=newTeachersDayNHours(tch,d2); | |
} | |
else{ | |
int nh=max(0, newTeachersDayNGaps(tch,d2)-teachersMaxGapsPerDayMaxGaps[tch]); | |
_reqHours+=newTeachersDayNHours(tch,d2)+nh; | |
} | |
} | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
_reqHours+=(_md-_usedDays)*1; //one hour per day minimum | |
if(_reqHours <= nHoursPerTeacher[tch]) | |
_ok=true; //ok | |
else | |
_ok=false; | |
} | |
else{ | |
int remG=0; | |
int totalH=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=newTeachersDayNGaps(tch,d2); | |
int h=newTeachersDayNHours(tch,d2); | |
if(h>0){ | |
_usedDays++; | |
} | |
int addh; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
addh=max(0, remGDay-teachersMaxGapsPerDayMaxGaps[tch]); | |
else | |
addh=0; | |
remGDay-=addh; | |
assert(remGDay>=0); | |
h+=addh; | |
if(h>0) | |
totalH+=h; | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
totalH+=(_md-_usedDays)*1; //min 1 hour per day | |
if(remG+totalH<=nHoursPerTeacher[tch]+teachersMaxGapsPerWeekMaxGaps[tch] | |
&& totalH<=nHoursPerTeacher[tch]) | |
_ok=true; | |
else | |
_ok=false; | |
} | |
if(_ok) | |
continue; | |
if(level>=LEVEL_STOP_CONFLICTS_CALCULATION){ | |
okteachersmindaysperweek=false; | |
goto impossibleteachersmindaysperweek; | |
} | |
getTchTimetable(tch, conflActivities[newtime]); | |
tchGetNHoursGaps(tch); | |
for(;;){ | |
bool ok; | |
if(teachersMaxGapsPerWeekPercentage[tch]==-1){ | |
int _reqHours=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++) | |
if(tchDayNHours[d2]>0){ | |
_usedDays++; | |
if(teachersMaxGapsPerDayPercentage[tch]==-1){ | |
_reqHours+=tchDayNHours[d2]; | |
} | |
else{ | |
int nh=max(0, tchDayNGaps[d2]-teachersMaxGapsPerDayMaxGaps[tch]); | |
_reqHours+=tchDayNHours[d2]+nh; | |
} | |
} | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
_reqHours+=(_md-_usedDays)*1; //min 1 hour for each day | |
if(_reqHours <= nHoursPerTeacher[tch]) | |
ok=true; //ok | |
else | |
ok=false; | |
} | |
else{ | |
int remG=0; | |
int totalH=0; | |
int _usedDays=0; | |
for(int d2=0; d2<gt.rules.nDaysPerWeek; d2++){ | |
int remGDay=tchDayNGaps[d2]; | |
int h=tchDayNHours[d2]; | |
if(h>0) | |
_usedDays++; | |
int addh; | |
if(teachersMaxGapsPerDayPercentage[tch]>=0) | |
addh=max(0, remGDay-teachersMaxGapsPerDayMaxGaps[tch]); | |
else | |
addh=0; | |
remGDay-=addh; | |
assert(remGDay>=0); | |
h+=addh; | |
if(h>0) | |
totalH+=h; | |
if(remGDay>0) | |
remG+=remGDay; | |
} | |
assert(_usedDays>=0 && _usedDays<=gt.rules.nDaysPerWeek); | |
assert(teachersMinDaysPerWeekPercentages[tch]==100.0); | |
int _md=teachersMinDaysPerWeekMinDays[tch]; | |
assert(_md>=0); | |
if(_md>_usedDays) | |
totalH+=(_md-_usedDays)*1; //min 1 hour each day | |
if(remG+totalH<=nHoursPerTeacher[tch]+teachersMaxGapsPerWeekMaxGaps[tch] | |
&& totalH<=nHoursPerTeacher[tch]) | |
ok=true; | |
else | |
ok=false; | |
} | |
if(ok) | |
break; | |
int ai2=-1; | |
bool k=teacherRemoveAnActivityFromBeginOrEnd(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!k){ | |
bool ka=teacherRemoveAnActivityFromAnywhere(tch, level, ai, conflActivities[newtime], nConflActivities[newtime], ai2); | |
assert(conflActivities[newtime].count()==nConflActivities[newtime]); | |
if(!ka){ | |
if(level==0){ | |
//Liviu: inactivated from version 5.12.4 (7 Feb. 2010), because it may take too long for some files | |
//cout<<"WARNING - mb - file "<<__FILE__<<" line "<<__LINE__<<endl; | |
} | |
okteachersmindaysperweek=false; | |
goto impossibleteachersmindaysperweek; | |
} | |
} | |
assert(ai2>=0); | |
/*Activity* act2=>.rules.internalActivitiesList[ai2]; | |
int d2=c.times[ai2]%gt.rules.nDaysPerWeek; | |
int h2=c.times[ai2]/gt.rules.nDaysPerWeek; | |
for(int dur2=0; dur2<act2->duration; dur2++){ | |
assert(tchTimetable(d2,h2+dur2)==ai2); | |
tchTimetable(d2,h2+dur2)=-1; | |
}*/ | |
removeAi2FromTchTimetable(ai2); | |
updateTchNHoursGaps(tch, c.times[ai2]%gt.rules.nDaysPerWeek); | |
} | |
} | |
} | |
} | |
impossibleteachersmindaysperweek: | |
if(!okteachersmindaysperweek){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/////////end teacher(s) min days per week | |
///////////////////////////////////////////////////////////////////////////////////////////// | |
skip_here_if_already_allocated_in_time: | |
//////////////////rooms | |
bool okroomnotavailable=getRoom(level, act, ai, d, h, roomSlots[newtime], selectedRoom[newtime], conflActivities[newtime], nConflActivities[newtime]); | |
//impossibleroomnotavailable: | |
if(!okroomnotavailable){ | |
if(c.times[ai]==UNALLOCATED_TIME){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
} | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
nConflActivities[newtime]=MAX_ACTIVITIES; | |
continue; | |
} | |
/////////////////////// | |
if(c.times[ai]==UNALLOCATED_TIME){ | |
if(updateSubgroups || updateTeachers) | |
removeAiFromNewTimetable(ai, act, d, h); | |
} | |
//removeConflActivities(conflActivities[newtime], nConflActivities[newtime], act, newtime); | |
#if 0&0&0 | |
//sort activities in decreasing order of difficulty. | |
//if the index of the activity in "permutation" is smaller, the act. is more difficult | |
QList<int> sorted; | |
QList<int> conflActs=conflActivities[newtime]; | |
while(conflActs.count()>0){ | |
int m=gt.rules.nInternalActivities; | |
int j=-1; | |
for(int k=0; k<conflActs.count(); k++){ | |
int a=conflActs.at(k); | |
if(invPermutation[a]<m){ | |
m=invPermutation[a]; | |
j=k; | |
} | |
} | |
assert(j>=0); | |
sorted.append(conflActs.at(j)); | |
int a=conflActs.at(j); | |
int t=conflActs.removeAll(a); | |
assert(t==1); | |
} | |
assert(sorted.count()==conflActivities[newtime].count()); | |
conflActivities[newtime]=sorted; | |
/* | |
for(int k=0; k<conflActivities[newtime].count()-1; k++){ | |
int a1=conflActivities[newtime].at(k); | |
int a2=conflActivities[newtime].at(k+1); | |
int i1, i2; | |
for(i1=0; i1<gt.rules.nInternalActivities; i1++) | |
if(permutation[i1]==a1) | |
break; | |
assert(i1<gt.rules.nInternalActivities); | |
for(i2=0; i2<gt.rules.nInternalActivities; i2++) | |
if(permutation[i2]==a2) | |
break; | |
assert(i2<gt.rules.nInternalActivities); | |
assert(i1<i2); | |
}*/ | |
#endif | |
/////////////////////////////// | |
//5.0.0-preview28 | |
//no conflicting activities for this timeslot - place the activity and return | |
if(nConflActivities[newtime]==0 && nMinDaysBroken[newtime]==0.0){ | |
assert(c.times[ai]==UNALLOCATED_TIME || (fixedTimeActivity[ai]&&!fixedSpaceActivity[ai])); | |
if(c.times[ai]!=UNALLOCATED_TIME && fixedTimeActivity[ai] && !fixedSpaceActivity[ai]) | |
assert(c.times[ai]==newtime); | |
assert(conflActivities[newtime].count()==0); | |
restoreActIndex[nRestore]=ai; | |
restoreTime[nRestore]=c.times[ai]; | |
restoreRoom[nRestore]=c.rooms[ai]; | |
nRestore++; | |
//5.0.0-preview25 | |
assert(swappedActivities[ai]); | |
moveActivity(ai, c.times[ai], newtime, c.rooms[ai], selectedRoom[newtime]); | |
foundGoodSwap=true; | |
return; | |
} | |
/////////////////////////////// | |
assert(nConflActivities[newtime]==conflActivities[newtime].count()); | |
} | |
//for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
// conflPerm[perm[i]]=perm[i]; | |
//DEPRECATED | |
//Sorting - O(n^2) - should be improved? | |
//The sorting below is not stable (I hope I am not mistaking) - but this should not be a problem. | |
/* for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
for(int j=i+1; j<gt.rules.nHoursPerWeek; j++) | |
if(nConflActivities[conflPerm[perm[i]]]>nConflActivities[conflPerm[perm[j]]] | |
|| (nConflActivities[conflPerm[perm[i]]]==nConflActivities[conflPerm[perm[j]]] | |
&& nMinDaysBroken[conflPerm[perm[i]]]>nMinDaysBroken[conflPerm[perm[j]]] )){ | |
int t=conflPerm[perm[i]]; | |
conflPerm[perm[i]]=conflPerm[perm[j]]; | |
conflPerm[perm[j]]=t; | |
}*/ | |
//O(n*log(n)) stable sorting | |
currentLevel=level; | |
qStableSort(perm+0, perm+gt.rules.nHoursPerWeek, compareFunctionGenerate); | |
/*cout<<"perm[i]: "; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
cout<<perm[i]<<" "; | |
cout<<endl; | |
cout<<"conflPerm[perm[i]]: "; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
cout<<conflPerm[perm[i]]<<" "; | |
cout<<endl; | |
cout<<"nConflActivities[i]: "; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
cout<<nConflActivities[i]<<" "; | |
cout<<endl; | |
assert(0);*/ | |
for(int i=1; i<gt.rules.nHoursPerWeek; i++){ | |
assert( (nConflActivities[perm[i-1]]<nConflActivities[perm[i]]) | |
|| ( (nConflActivities[perm[i-1]]==nConflActivities[perm[i]]) && | |
(nMinDaysBroken[perm[i-1]]<=nMinDaysBroken[perm[i]]) ) ); | |
} | |
/*for(int i=0; i<gt.rules.nHoursPerWeek; i++){ | |
int newtime=conflPerm[perm[i]]; | |
if(nConflActivities[newtime]!=MAX_ACTIVITIES) | |
foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]); | |
}*/ | |
if(level==0 && (nConflActivities[perm[0]]==MAX_ACTIVITIES)){ | |
if(activity_count_impossible_tries<MAX_RETRIES_FOR_AN_ACTIVITY_AT_LEVEL_0){ | |
activity_count_impossible_tries++; | |
goto again_if_impossible_activity; | |
} | |
else{ | |
cout<<__FILE__<<" line "<<__LINE__<<"- WARNING - after retrying for "<<MAX_RETRIES_FOR_AN_ACTIVITY_AT_LEVEL_0 | |
<<" times - no possible timeslots for activity with id=="<<gt.rules.internalActivitiesList[ai].id<<endl; | |
} | |
} | |
if(level==0){ | |
/*Matrix1D<int> l0nWrong; | |
Matrix1D<int> l0minWrong; | |
Matrix1D<int> l0minIndexAct; | |
l0nWrong.resize(gt.rules.nHoursPerWeek); | |
l0minWrong.resize(gt.rules.nHoursPerWeek); | |
l0minIndexAct.resize(gt.rules.nHoursPerWeek);*/ | |
/*int nWrong[MAX_HOURS_PER_WEEK]; | |
int minWrong[MAX_HOURS_PER_WEEK]; | |
int minIndexAct[MAX_HOURS_PER_WEEK];*/ | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++){ | |
l0nWrong[i]=INF; | |
l0minWrong[i]=INF; | |
l0minIndexAct[i]=gt.rules.nInternalActivities; | |
} | |
QList<int> tim; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++) | |
if(nConflActivities[perm[i]]>0 && nConflActivities[perm[i]]<MAX_ACTIVITIES | |
&& roomSlots[perm[i]]!=UNALLOCATED_SPACE) | |
tim.append(perm[i]); | |
if(tim.count()==0 && nConflActivities[perm[0]]==MAX_ACTIVITIES){ | |
cout<<"optimizetime.cpp line 2712 - WARNING - no possible timeslots for activity with id=="<< | |
gt.rules.internalActivitiesList[ai].id<<endl; | |
impossibleActivity=true; | |
} | |
if(tim.count()>0){ | |
foreach(int i, tim){ | |
int cnt=0; | |
int m=gt.rules.nInternalActivities; | |
foreach(int aii, conflActivities[i]){ | |
if(triedRemovals(aii,c.times[aii])>0) | |
cnt+=triedRemovals(aii,c.times[aii]); | |
if(l0minWrong[i]>triedRemovals(aii,c.times[aii])) | |
l0minWrong[i]=triedRemovals(aii,c.times[aii]); | |
int j=invPermutation[aii]; | |
if(m>j) | |
m=j; | |
} | |
l0nWrong[i]=cnt; | |
l0minIndexAct[i]=m; | |
} | |
int optMinIndex=gt.rules.nInternalActivities; | |
int optNWrong=INF; | |
int optMinWrong=INF; | |
int optNConflActs=gt.rules.nInternalActivities; | |
int j=-1; | |
//bool chooseRandom = (randomKnuth()%20 == 0); | |
foreach(int i, tim){ | |
//choose a random time out of these with minimum number of wrongly replaced activities | |
if(optMinWrong>l0minWrong[i] | |
|| (optMinWrong==l0minWrong[i] && optNWrong>l0nWrong[i]) | |
|| (optMinWrong==l0minWrong[i] && optNWrong==l0nWrong[i] && optNConflActs>nConflActivities[i]) | |
|| (optMinWrong==l0minWrong[i] && optNWrong==l0nWrong[i] && optNConflActs==nConflActivities[i] && optMinIndex>l0minIndexAct[i])){ | |
optNWrong=l0nWrong[i]; | |
optMinWrong=l0minWrong[i]; | |
optNConflActs=nConflActivities[i]; | |
optMinIndex=l0minIndexAct[i]; | |
j=i; | |
} | |
} | |
assert(j>=0); | |
QList<int> tim2; | |
foreach(int i, tim) | |
if(optNWrong==l0nWrong[i] && l0minWrong[i]==optMinWrong && optNConflActs==nConflActivities[i] && optMinIndex==l0minIndexAct[i]) | |
tim2.append(i); | |
assert(tim2.count()>0); | |
int rnd=randomKnuth(tim2.count()); | |
j=tim2.at(rnd); | |
assert(j>=0); | |
timeSlot=j; | |
assert(roomSlots[j]!=UNALLOCATED_SPACE); | |
roomSlot=roomSlots[j]; | |
//conflActivitiesTimeSlot=conflActivities[timeSlot]; | |
conflActivitiesTimeSlot.clear(); | |
foreach(int a, conflActivities[timeSlot]) | |
conflActivitiesTimeSlot.append(a); | |
} | |
} | |
//int nExplored=0; | |
for(int i=0; i<gt.rules.nHoursPerWeek; i++){ | |
int newtime=perm[i]; //the considered time | |
if(nConflActivities[newtime]>=MAX_ACTIVITIES) | |
break; | |
assert(c.times[ai]==UNALLOCATED_TIME || (fixedTimeActivity[ai]&&!fixedSpaceActivity[ai])); | |
//no conflicting activities for this timeslot - place the activity and return | |
if(nConflActivities[newtime]==0){ | |
assert(c.times[ai]==UNALLOCATED_TIME || (fixedTimeActivity[ai]&&!fixedSpaceActivity[ai])); | |
if(c.times[ai]!=UNALLOCATED_TIME && fixedTimeActivity[ai] && !fixedSpaceActivity[ai]) | |
assert(c.times[ai]==newtime); | |
assert(conflActivities[newtime].count()==0); | |
restoreActIndex[nRestore]=ai; | |
restoreTime[nRestore]=c.times[ai]; | |
restoreRoom[nRestore]=c.rooms[ai]; | |
nRestore++; | |
//5.0.0-preview25 | |
assert(swappedActivities[ai]); | |
moveActivity(ai, c.times[ai], newtime, c.rooms[ai], selectedRoom[newtime]); | |
foundGoodSwap=true; | |
return; | |
} | |
else{ | |
/*foreach(int ai2, conflActivities[newtime]) | |
assert(!swappedActivities[ai2]);*/ | |
if(level==level_limit-1){ | |
//cout<<"level_limit-1==level=="<<level<<", for activity with id "<<gt.rules.internalActivitiesList[ai].id<<" returning"<<endl; | |
foundGoodSwap=false; | |
break; | |
} | |
if(ncallsrandomswap>=limitcallsrandomswap){ | |
foundGoodSwap=false; | |
break; | |
} | |
/* | |
//sort activities in decreasing order of difficulty. | |
//if the index of the activity in "permutation" is smaller, the act. is more difficult | |
QList<int> sorted; | |
QList<int> conflActs=conflActivities[newtime]; | |
while(conflActs.count()>0){ | |
int m=gt.rules.nInternalActivities; | |
int j=-1; | |
for(int k=0; k<conflActs.count(); k++){ | |
int a=conflActs.at(k); | |
if(invPermutation[a]<m){ | |
m=invPermutation[a]; | |
j=k; | |
} | |
} | |
assert(j>=0); | |
sorted.append(conflActs.at(j)); | |
int a=conflActs.at(j); | |
int t=conflActs.removeAll(a); | |
assert(t==1); | |
} | |
assert(sorted.count()==conflActivities[newtime].count()); | |
conflActivities[newtime]=sorted;*/ | |
int ok=true; | |
//cout<<"LEVEL=="<<level<<", for activity ai with id=="<<gt.rules.internalActivitiesList[ai].id<<", list of conflActivities ids: "; | |
foreach(int a, conflActivities[newtime]){ | |
//cout<<gt.rules.internalActivitiesList[a].id<<" "; | |
if(swappedActivities[a]){ | |
assert(0); | |
//cout<<"here "; | |
ok=false; | |
break; | |
} | |
assert(!(fixedTimeActivity[a] && fixedSpaceActivity[a])); | |
} | |
//cout<<endl; | |
if(!ok){ | |
assert(0); | |
continue; | |
} | |
//////////////place it at a new time | |
int oldNRestore=nRestore; | |
//////////////// | |
QList<int> oldacts; | |
QList<int> oldtimes; | |
QList<int> oldrooms; | |
if(1 /*ok*/){ | |
assert(conflActivities[newtime].size()>0); | |
foreach(int a, conflActivities[newtime]){ | |
//cout<<"Level=="<<level<<", conflicting act. id=="<<gt.rules.internalActivitiesList[a].id<<", old time=="<<c.times[a]<<endl; | |
restoreActIndex[nRestore]=a; | |
restoreTime[nRestore]=c.times[a]; | |
restoreRoom[nRestore]=c.rooms[a]; | |
nRestore++; | |
oldacts.append(a); | |
oldtimes.append(c.times[a]); | |
oldrooms.append(c.rooms[a]); | |
assert(c.times[a]!=UNALLOCATED_TIME); | |
assert(c.rooms[a]!=UNALLOCATED_SPACE); | |
int nt=UNALLOCATED_TIME; | |
if(fixedTimeActivity[a]&&!fixedSpaceActivity[a]) | |
nt=c.times[a]; | |
//cout<<"level=="<<level<<", unallocating activity with id=="<<gt.rules.internalActivitiesList[a].id<<endl; | |
moveActivity(a, c.times[a], nt, c.rooms[a], UNALLOCATED_SPACE); | |
//swappedActivities[a]=true; | |
} | |
} | |
assert(oldacts.count()==conflActivities[newtime].count()); | |
assert(oldtimes.count()==conflActivities[newtime].count()); | |
assert(oldrooms.count()==conflActivities[newtime].count()); | |
//////////////// | |
int oldtime=c.times[ai]; | |
int oldroom=c.rooms[ai]; | |
//if(c.times[ai]!=UNALLOCATED_TIME){ | |
restoreActIndex[nRestore]=ai; | |
restoreTime[nRestore]=oldtime; | |
restoreRoom[nRestore]=oldroom; | |
nRestore++; | |
//} | |
//cout<<"Level=="<<level<<", act. id=="<<gt.rules.internalActivitiesList[ai].id<<", old time=="<<c.times[ai]<<endl; | |
moveActivity(ai, oldtime, newtime, oldroom, selectedRoom[newtime]); | |
//cout<<"level=="<<level<<", activity with id=="<<gt.rules.internalActivitiesList[ai].id<< | |
// " goes from time: "<<oldtime<<" to time: "<<newtime<<endl; | |
////////////////// | |
if(1) | |
foreach(int a, conflActivities[newtime]) | |
swappedActivities[a]=true; | |
foundGoodSwap=false; | |
ok=false; | |
if(1){ | |
assert(conflActivities[newtime].size()>0); | |
ok=true; | |
foreach(int a, conflActivities[newtime]){ | |
randomSwap(a, level+1); | |
if(!foundGoodSwap){ | |
ok=false; | |
break; | |
} | |
assert(c.times[a]!=UNALLOCATED_TIME); | |
assert(foundGoodSwap); | |
foundGoodSwap=false; | |
} | |
} | |
if(ok){ | |
foreach(int a, conflActivities[newtime]) | |
assert(c.times[a]!=UNALLOCATED_TIME); | |
assert(c.times[ai]!=UNALLOCATED_TIME); | |
foundGoodSwap=true; | |
return; | |
} | |
/*if(1) | |
foreach(int a, conflActivities[newtime]) | |
swappedActivities[a]=false;*/ | |
//////////////restore times from the restore list | |
for(int j=nRestore-1; j>=oldNRestore; j--){ | |
//assert(c.times[ai]!=UNALLOCATED_TIME); | |
int aii=restoreActIndex[j]; | |
oldtime=restoreTime[j]; | |
oldroom=restoreRoom[j]; | |
/*if(aii!=ai) | |
cout<<"Level=="<<level<<", activity with id=="<<gt.rules.internalActivitiesList[aii].id<<" should change swapped state from true to false"<<endl; | |
else | |
cout<<"Level=="<<level<<", activity with id=="<<gt.rules.internalActivitiesList[aii].id<<" should remain swapped==true"<<endl; | |
*/ | |
if(aii!=ai){ | |
//assert(swappedActivities[aii]); | |
swappedActivities[aii]=false; | |
} | |
else{ | |
assert(swappedActivities[aii]); | |
//swappedActivities[aii]=false; | |
} | |
//assert(oldtime!=UNALLOCATED_TIME); | |
//cout<<"level=="<<level<<", activity with id=="<<gt.rules.internalActivitiesList[aii].id<< | |
// " restored from time: "<<c.times[aii]<<" to time: "<<oldtime<<endl; | |
moveActivity(aii, c.times[aii], oldtime, c.rooms[aii], oldroom); | |
//cout<<"Level=="<<level<<", act. id=="<<gt.rules.internalActivitiesList[ai].id<<", restoring old time=="<<c.times[ai]<<endl; | |
//assert(oldtime!=UNALLOCATED_TIME); | |
} | |
nRestore=oldNRestore; | |
////////////////////////////// | |
foreach(int a, conflActivities[newtime]){ | |
assert(c.times[a]!=UNALLOCATED_TIME); | |
assert(c.rooms[a]!=UNALLOCATED_SPACE); | |
assert(!swappedActivities[a]); | |
assert(!(fixedTimeActivity[a] && fixedSpaceActivity[a])); | |
} | |
////////////////////////////// | |
assert(!foundGoodSwap); | |
if(level>=5) //7 also might be used? This is a value found practically, has no theoretical meaning probably | |
return; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment