Back to index

fet  5.18.0
timetablegeneratemultipleform.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           timetablegeneratemultipleform.cpp  -  description
00003                              -------------------
00004     begin                : Aug 20, 2007
00005     copyright            : (C) 2007 by Lalescu Liviu
00006     email                : Please see http://lalescu.ro/liviu/ for details about contacting Liviu Lalescu (in particular, you can find here the e-mail address)
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include "longtextmessagebox.h"
00019 
00020 #include "generate.h"
00021 
00022 #include "timetablegeneratemultipleform.h"
00023 #include "timetable_defs.h"
00024 #include "timetable.h"
00025 #include "fet.h"
00026 #include "timetableexport.h"
00027 
00028 #include <ctime>
00029 
00030 #include <QMessageBox>
00031 
00032 #include <QMutex>
00033 
00034 #include <QScrollBar>
00035 
00036 #include <QDir>
00037 
00038 extern QMutex mutex;
00039 
00040 static GenerateMultipleThread generateMultipleThread;
00041 
00042 #include <QSemaphore>
00043 
00044 static QSemaphore semaphoreTimetableFinished; 
00045 
00046 static QSemaphore semaphoreTimetableStarted;
00047 
00048 //Represents the current status of the simulation - running or stopped.
00049 extern bool simulation_running_multi;
00050 
00051 extern QSemaphore semaphorePlacedActivity;
00052 
00053 Generate genMulti;
00054 
00055 static int nTimetables;
00056 static int timeLimit;
00057 
00058 extern int maxActivitiesPlaced;
00059 
00060 extern Solution best_solution;
00061 
00062 extern QString conflictsStringTitle;
00063 extern QString conflictsString;
00064 
00065 static time_t start_time;
00066 
00067 static time_t initial_time;
00068 
00069 extern int permutation[MAX_ACTIVITIES];
00070 int savedPermutation[MAX_ACTIVITIES];
00071 
00072 void GenerateMultipleThread::run()
00073 {
00074        genMulti.abortOptimization=false;
00075        
00076        time(&initial_time);
00077 
00078        for(int i=0; i<nTimetables; i++){
00079               time(&start_time);
00080        
00081               bool impossible;
00082               bool timeExceeded;
00083               
00084               for(int qq=0; qq<gt.rules.nInternalActivities; qq++)
00085                      permutation[qq]=savedPermutation[qq];
00086                      
00087               emit(timetableStarted(i+1));
00088               semaphoreTimetableStarted.acquire();
00089 
00090               genMulti.generate(timeLimit, impossible, timeExceeded, true); //true means threaded
00091 
00092               QString s;
00093               
00094               bool ok;
00095 
00096               mutex.lock();
00097               if(genMulti.abortOptimization){
00098                      mutex.unlock();
00099                      return;
00100               }
00101               else if(impossible){
00102                      s=tr("Timetable impossible to generate");
00103                      s+=QString(".");
00104                      ok=false;
00105               }
00106               else if(timeExceeded){
00107                      s=tr("Time exceeded for current timetable");
00108 
00110                      int mact=maxActivitiesPlaced;
00111                      int mseconds=genMulti.timeToHighestStage;
00112 
00113                      bool zero=false;
00114                      if(mseconds==0)
00115                             zero=true;
00116                      int hh=mseconds/3600;
00117                      mseconds%=3600;
00118                      int mm=mseconds/60;
00119                      mseconds%=60;
00120                      int ss=mseconds;
00121 
00122                      QString tim;
00123                      if(hh>0){
00124                             tim+=" ";
00125                             tim+=tr("%1 h", "hours").arg(hh);
00126                      }
00127                      if(mm>0){
00128                             tim+=" ";
00129                             tim+=tr("%1 m", "minutes").arg(mm);
00130                      }
00131                      if(ss>0 || zero){
00132                             tim+=" ";
00133                             tim+=tr("%1 s", "seconds").arg(ss);
00134                      }
00135                      tim.remove(0, 1);
00136                      s+=QString(". ");
00137                      s+=tr("Max placed activities: %1 (at %2)", "%1 represents the maximum number of activities placed, %2 is a time interval").arg(mact).arg(tim);
00139 
00140                      s+=QString(".");
00141 
00142                      ok=false;
00143               }
00144               else{
00145                      ok=true;
00146                      
00147                      time_t finish_time;
00148                      time(&finish_time);
00149                      int seconds=int(finish_time-start_time);
00150                      int hours=seconds/3600;
00151                      seconds%=3600;
00152                      int minutes=seconds/60;
00153                      seconds%=60;
00154                      
00155                      QString tmp;
00156                      genMulti.c.fitness(gt.rules, &tmp);
00157                      
00158                      s=tr("Timetable has %1 soft conflicts factor and was generated in %2 hours, %3 minutes and %4 seconds")
00159                       .arg(CustomFETString::number(genMulti.c.conflictsTotal))
00160                       .arg(hours)
00161                       .arg(minutes)
00162                       .arg(seconds);
00163 
00164                      s+=QString(".");
00165               }
00166               mutex.unlock();
00167               
00168               emit(timetableGenerated(i+1, s, ok));
00169               semaphoreTimetableFinished.acquire();
00170        }
00171        
00172        emit(finished());
00173 }
00174 
00175 TimetableGenerateMultipleForm::TimetableGenerateMultipleForm(QWidget* parent): QDialog(parent)
00176 {
00177        setupUi(this);
00178        
00179        currentResultsTextEdit->setReadOnly(true);
00180        
00181        startPushButton->setDefault(true);
00182 
00183        connect(startPushButton, SIGNAL(clicked()), this, SLOT(start()));
00184        connect(stopPushButton, SIGNAL(clicked()), this, SLOT(stop()));
00185        connect(closePushButton, SIGNAL(clicked()), this, SLOT(closePressed()));
00186        connect(pushButton4, SIGNAL(clicked()), this, SLOT(help()));
00187 
00188        centerWidgetOnScreen(this);
00189        restoreFETDialogGeometry(this);
00190        
00191        simulation_running_multi=false;
00192 
00193        startPushButton->setEnabled(TRUE);
00194        stopPushButton->setDisabled(TRUE);
00195        closePushButton->setEnabled(TRUE);
00196        minutesGroupBox->setEnabled(TRUE);
00197        timetablesGroupBox->setEnabled(TRUE);
00198 
00199        connect(&generateMultipleThread, SIGNAL(timetableGenerated(int, const QString&, bool)),
00200               this, SLOT(timetableGenerated(int, const QString&, bool)));
00201 
00202        connect(&generateMultipleThread, SIGNAL(timetableStarted(int)),
00203               this, SLOT(timetableStarted(int)));
00204 
00205        connect(&generateMultipleThread, SIGNAL(finished()),
00206               this, SLOT(finished()));
00207 
00208        connect(&genMulti, SIGNAL(activityPlaced(int)),
00209               this, SLOT(activityPlaced(int)));
00210 }
00211 
00212 TimetableGenerateMultipleForm::~TimetableGenerateMultipleForm()
00213 {
00214        saveFETDialogGeometry(this);
00215        if(simulation_running_multi)
00216               this->stop();
00217 }
00218 
00219 void TimetableGenerateMultipleForm::help()
00220 {
00221        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
00222        
00223        if(s2.right(4)==".fet")
00224               s2=s2.left(s2.length()-4);
00225        
00226        QString destDir=OUTPUT_DIR+FILE_SEP+"timetables"+FILE_SEP+s2+"-multi";
00227 
00228        QString s=tr("You can only see generated timetables on the hard disk,"
00229         " in HTML and XML formats and soft conflicts in text format, or latest timetable in the Timetable/View menu."
00230         " It is needed that the directory"
00231         " %1 to be emptied and deleted before proceeding.").arg(QDir::toNativeSeparators(destDir))
00232         +"\n\n"
00233         +tr("Note that, for large data, each timetable might occupy more"
00234         " megabytes of hard disk space,"
00235         " so make sure you have enough space (you can check the dimension of a single timetable as a precaution).")
00236         +"\n\n"
00237         +tr("There are also saved the timetables in .fet format (data + constraints to lock the timetable), so that you can open each of them later.")
00238         +"\n\n"
00239         +tr("If you get impossible timetable, please enter menu Generate (single) and see the initial order of evaluation of activities,"
00240         " this might help.")
00241         +"\n\n"
00242         +tr("You can limit the search time, by specifying the maximum number of minutes allowed to spend for each timetable (option %1).").arg("'"+tr("Limit for each timetable")+"'")
00243         +" "+tr("The maximum and also the predefined value is %1 minutes, which means %2 hours, so virtually unlimited.").arg(60000).arg(1000)
00244         ;
00245         
00246         LongTextMessageBox::largeInformation(this, tr("FET information"), s);
00247 }
00248 
00249 void TimetableGenerateMultipleForm::start(){
00250        nTimetables=timetablesSpinBox->value();
00251        assert(nTimetables>0);
00252        timeLimit=60*minutesSpinBox->value(); //seconds
00253        assert(timeLimit>0);
00254 
00255        QDir dir;
00256        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
00257 
00258        if(s2.right(4)==".fet")
00259               s2=s2.left(s2.length()-4);
00260        
00261        QString destDir=OUTPUT_DIR+FILE_SEP+"timetables"+FILE_SEP+s2+"-multi";
00262        if(dir.exists(destDir)){
00263               QMessageBox::warning(this, tr("FET information"), tr("Directory %1 exists and might not be empty,"
00264                " (it might contain old files). You need to manually remove all contents of this directory AND the directory itself (or rename it)"
00265                " and then you can generate multiple timetables")
00266                .arg(QDir::toNativeSeparators(destDir)));
00267                
00268               return;
00269        }
00270 
00271        if(!gt.rules.internalStructureComputed){
00272               if(!gt.rules.computeInternalStructure(this)){
00273                      QMessageBox::warning(this, TimetableGenerateMultipleForm::tr("FET warning"), TimetableGenerateMultipleForm::tr("Data is wrong. Please correct and try again"));
00274                      return;
00275               }
00276        }
00277 
00278        if(!gt.rules.initialized || gt.rules.activitiesList.isEmpty()){
00279               QMessageBox::critical(this, TimetableGenerateMultipleForm::tr("FET information"),
00280                      TimetableGenerateMultipleForm::tr("You have entered simulation with uninitialized rules or 0 activities...aborting"));
00281               assert(0);
00282               exit(1);
00283               return;
00284        }
00285 
00286        currentResultsTextEdit->setPlainText("");
00287 
00288        bool ok=genMulti.precompute(this);
00289        if(!ok){
00290               currentResultsTextEdit->setPlainText(TimetableGenerateMultipleForm::tr("Cannot optimize - please modify your data"));
00291               currentResultsTextEdit->update();
00292 
00293               QMessageBox::information(this, TimetableGenerateMultipleForm::tr("FET information"),
00294                TimetableGenerateMultipleForm::tr("Your data cannot be processed - please modify it as instructed."));
00295 
00296               return;
00297        }
00298 
00299        startPushButton->setDisabled(TRUE);
00300        stopPushButton->setEnabled(TRUE);
00301        minutesGroupBox->setDisabled(TRUE);
00302        timetablesGroupBox->setDisabled(TRUE);
00303        closePushButton->setDisabled(TRUE);
00304 
00305        simulation_running_multi=true;
00306 
00307        for(int qq=0; qq<gt.rules.nInternalActivities; qq++)
00308               savedPermutation[qq]=permutation[qq];
00309               
00310        genMulti.c.makeUnallocated(gt.rules);
00311 
00312        generateMultipleThread.start();
00313 }
00314 
00315 void TimetableGenerateMultipleForm::timetableStarted(int timetable)
00316 {
00317        TimetableExport::writeRandomSeed(this, timetable, true); //true represents 'before' state
00318        
00319        semaphoreTimetableStarted.release();
00320 }
00321 
00322 void TimetableGenerateMultipleForm::timetableGenerated(int timetable, const QString& description, bool ok)
00323 {
00324        TimetableExport::writeRandomSeed(this, timetable, false); //false represents 'before' state
00325 
00326        QString s=QString("");
00327        s+=tr("Timetable no: %1 => %2").arg(timetable).arg(description);
00328        currentResultsTextEdit->appendPlainText(s);
00329 
00330        if(ok){
00331               //needed to get the conflicts string
00332               QString tmp;
00333               genMulti.c.fitness(gt.rules, &tmp);
00334        
00335               TimetableExport::getStudentsTimetable(genMulti.c);
00336               TimetableExport::getTeachersTimetable(genMulti.c);
00337               TimetableExport::getRoomsTimetable(genMulti.c);
00338 
00339               TimetableExport::writeSimulationResults(this, timetable);
00340 
00341               //update the string representing the conflicts
00342               conflictsStringTitle=tr("Soft conflicts", "Title of dialog");
00343               conflictsString = "";
00344               conflictsString+=tr("Total soft conflicts:");
00345               conflictsString+=" ";
00346               conflictsString+=CustomFETString::number(best_solution.conflictsTotal);
00347               conflictsString+="\n";
00348               conflictsString += tr("Soft conflicts listing (in decreasing order):")+"\n";
00349 
00350               foreach(QString t, best_solution.conflictsDescriptionList)
00351                      conflictsString+=t+"\n";
00352        }
00353 
00354        semaphoreTimetableFinished.release();
00355 }
00356 
00357 void TimetableGenerateMultipleForm::stop()
00358 {
00359        if(!simulation_running_multi){
00360               return;
00361        }
00362 
00363        simulation_running_multi=false;
00364 
00365        mutex.lock();
00366        genMulti.abortOptimization=true;
00367        mutex.unlock();
00368 
00369        QString s=TimetableGenerateMultipleForm::tr("Simulation interrupted!");
00370        s+="\n\n";
00371 
00372        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
00373 
00374        if(s2.right(4)==".fet")
00375               s2=s2.left(s2.length()-4);
00376        
00377        QString destDir=OUTPUT_DIR+FILE_SEP+"timetables"+FILE_SEP+s2+"-multi";
00378 
00379        time_t final_time;
00380        time(&final_time);
00381        int sec=int(final_time-initial_time);
00382        int h=sec/3600;
00383        sec%=3600;
00384        int m=sec/60;
00385        sec%=60;
00386 
00387        s+=TimetableGenerateMultipleForm::tr("The results were saved in the directory %1").arg(QDir::toNativeSeparators(destDir));
00388        s+="\n\n";
00389        s+=tr("Total searching time: %1h %2m %3s").arg(h).arg(m).arg(sec);
00390        
00391        QMessageBox::information(this, tr("FET information"), s);
00392 
00393        startPushButton->setEnabled(TRUE);
00394        stopPushButton->setDisabled(TRUE);
00395        minutesGroupBox->setEnabled(TRUE);
00396        timetablesGroupBox->setEnabled(TRUE);
00397        closePushButton->setEnabled(TRUE);
00398 }
00399 
00400 void TimetableGenerateMultipleForm::finished()
00401 {
00402        simulationFinished();
00403 }
00404 
00405 void TimetableGenerateMultipleForm::simulationFinished()
00406 {
00407        if(!simulation_running_multi){
00408               return;
00409        }
00410 
00411        simulation_running_multi=false;
00412 
00413        QString s2=INPUT_FILENAME_XML.right(INPUT_FILENAME_XML.length()-INPUT_FILENAME_XML.lastIndexOf(FILE_SEP)-1);
00414 
00415        if(s2.right(4)==".fet")
00416               s2=s2.left(s2.length()-4);
00417        
00418        QString destDir=OUTPUT_DIR+FILE_SEP+"timetables"+FILE_SEP+s2+"-multi";
00419        
00420        time_t final_time;
00421        time(&final_time);
00422        int s=int(final_time-initial_time);
00423        int h=s/3600;
00424        s%=3600;
00425        int m=s/60;
00426        s%=60;
00427 
00428        QString ms=QString("");
00429        ms+=TimetableGenerateMultipleForm::tr("Simulation terminated successfully!");
00430        ms+=QString("\n\n");
00431        ms+=TimetableGenerateMultipleForm::tr("The results were saved in the directory %1").arg(QDir::toNativeSeparators(destDir));
00432        ms+=QString("\n\n");
00433        ms+=TimetableGenerateMultipleForm::tr("Total searching time was %1h %2m %3s").arg(h).arg(m).arg(s);
00434        QMessageBox::information(this, TimetableGenerateMultipleForm::tr("FET information"), ms);
00435        
00436        startPushButton->setEnabled(TRUE);
00437        stopPushButton->setDisabled(TRUE);
00438        minutesGroupBox->setEnabled(TRUE);
00439        timetablesGroupBox->setEnabled(TRUE);
00440        closePushButton->setEnabled(TRUE);
00441 }
00442 
00443 void TimetableGenerateMultipleForm::activityPlaced(int na)
00444 {
00445        time_t finish_time;
00446        time(&finish_time);
00447        int seconds=int(finish_time-start_time);
00448        int hours=seconds/3600;
00449        seconds%=3600;
00450        int minutes=seconds/60;
00451        seconds%=60;
00452                      
00454        int mact=maxActivitiesPlaced;
00455        int mseconds=genMulti.timeToHighestStage;
00456 
00457        QString s;
00458 
00459        bool zero=false;
00460        if(mseconds==0)
00461               zero=true;
00462        int hh=mseconds/3600;
00463        mseconds%=3600;
00464        int mm=mseconds/60;
00465        mseconds%=60;
00466        int ss=mseconds;
00467 
00468        QString tim;
00469        if(hh>0){
00470               tim+=" ";
00471               tim+=tr("%1 h", "hours").arg(hh);
00472        }
00473        if(mm>0){
00474               tim+=" ";
00475               tim+=tr("%1 m", "minutes").arg(mm);
00476        }
00477        if(ss>0 || zero){
00478               tim+=" ";
00479               tim+=tr("%1 s", "seconds").arg(ss);
00480        }
00481        tim.remove(0, 1);
00482        s+=QString("\n");
00483        s+=tr("Max placed activities: %1 (at %2)", "%1 represents the maximum number of activities placed, %2 is a time interval").arg(mact).arg(tim);
00485        
00486        textLabel->setText(tr("Current timetable: %1 out of %2 activities placed, %3h %4m %5s")
00487         .arg(na)
00488         .arg(gt.rules.nInternalActivities)
00489         .arg(hours)
00490         .arg(minutes)
00491         .arg(seconds)+s);
00492        
00493        semaphorePlacedActivity.release();
00494 }
00495 
00496 void TimetableGenerateMultipleForm::closePressed()
00497 {
00498        if(!generateMultipleThread.isRunning())
00499               this->close();
00500 }