Back to index

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