#include //#include //#include //#include #include #include #include #include //#include #include "SA_Scheduler.h" int OptType; // ob minimiert oder maximiert werden soll SA_Scheduler::SA_Scheduler(): StartT(-1.0),T(-1.0), n_iter(0), n_accepts(0), n_updates(0), total_iter(0), i_subchain(0), total_accepts(0), total_updates(0), n_dT(0), overall_iter(0), E(INFINITY), StartE(INFINITY), BestE(INFINITY), BestFlag(0), ThresholdValue(0.0), InitAccRatio(-1.0), AccRatio(-1.0), Sum(0), Sum2(0), SumRun(0), Sum2Run(0), PictureDirectory(NULL), timelimit(-1), saoutput("SA_Scheduler","SA_Output.rsc") { // debug(SA_Scheduler::Konstruktor,myrank); // std::cout << "open for_gnuplot_Energy" << std::endl; // outputfile.open("for_gnuplot_Energy", ios::app); saoutput.EnableLevelNumbers(false); saoutput.EnableIdentifier(true); saoutput.AddVariable(1,SA_INT,&BestFlag); saoutput.AddVariable(2,SA_FLOAT, &StartT); saoutput.AddVariable(3,SA_FLOAT, &T); saoutput.AddVariable(4,SA_FLOAT, &InitAccRatio); saoutput.AddVariable(5,SA_FLOAT, &AccRatio); saoutput.AddVariable(6,SA_LONG, &n_iter); saoutput.AddVariable(7,SA_LONG, &n_accepts); saoutput.AddVariable(8,SA_LONG, &n_updates); saoutput.AddVariable(9,SA_LONG, &n_dT); saoutput.AddVariable(10,SA_LONG, &total_iter); saoutput.AddVariable(11,SA_LONG, &i_subchain); saoutput.AddVariable(12,SA_LONG, &total_accepts); saoutput.AddVariable(13,SA_LONG, &total_updates); saoutput.AddVariable(14,SA_LONG, &overall_iter); saoutput.AddVariable(15,SA_FLOAT, &E); saoutput.AddVariable(16,SA_FLOAT, &StartE); saoutput.AddVariable(17,SA_FLOAT, &BestE); saoutput.AddVariable(18,SA_FLOAT, &ThresholdValue); saoutput.AddVariable(19,SA_DOUBLE, &Sum); saoutput.AddVariable(20,SA_DOUBLE, &Sum2); saoutput.AddVariable(21,SA_DOUBLE, &SumRun); saoutput.AddVariable(22,SA_DOUBLE, &Sum2Run); saoutput.AddVariable(24,SA_STRING, opttypename); saoutput.AddVariable(25,SA_LONG, &timelimit); saoutput.AddVariable(26,SA_STRING, warminguptype); StartClock(); } SA_Output *SA_Scheduler::GetSchedulerOutput() { return(&saoutput); } SA_Scheduler::~SA_Scheduler() {//debug(SA_Scheduler::Destruktor,myrank); if ( PictureDirectory != NULL) { CostFunction.close(); Temperature.close(); BestCostFunktion.close(); } // outputfile.close(); } // den SA_Scheduler nach einem SA-Lauf zuruecksetzen, Einstellungen beibehalten void SA_Scheduler::Reset() { n_iter = n_accepts = n_updates = total_iter = total_accepts = total_updates = n_dT = BestFlag = 0; AccRatio = -1.0; // if(OptType == Opt::MIN) // { // E = BestE = INFINITY; // } // else // { // E = BestE = 0; // } Sum = Sum2 = 0; } void SA_Scheduler::ResetBestE() { if(OptType == Opt::MIN) { BestE = INFINITY; } else { BestE = 0; } } // TRUE <=> a "besser" als b int SA_Scheduler::Better(float a, float b) { if(OptType == Opt::MIN) { return ab; } } // \****************************************************** // Methode TryAcceptance // - prueft, ob ein Uebergang akzeptiert wird // - Abfrage auf BestFound anschliessend moeglich // - // \****************************************************** int SA_Scheduler::TryAcceptance(float new_cost) { if ( ThresholdValue != 0 ) { float ELimit; // every solution has to be better than ELimit to be // accepted if (OptType == Opt::MIN) { ELimit = BestE+(BestE*ThresholdValue); } else { ELimit = BestE-(BestE*ThresholdValue); } if ( Better(new_cost,E) ) // accept immediatly { n_accepts++; return 1; } else if ( Better(new_cost,ELimit) && (exp(-FABS(E-new_cost)/T) > rand_float()) ) // new_cost would be accepted by standard annealing acceptance-rule // AND: new_cost must be better than a threshold-value depending on actual BestE { n_accepts++; return 1; } else { return 0; } } else // standard annealing acceptance-rule { if( (Better(new_cost,E) ) || ( exp(-FABS(E-new_cost)/T) > rand_float())) { n_accepts++; return 1; } else return 0; } } // ****************************************************** // Methode Accept - Entscheidet, in Abhaengigkeit der // aktuellen Temperatur und der berechneten Kosten, ob // mit der neuen Lösung weitergerechnet werden soll. // Abfrage auf BestFound ist anschliessend moeglich // // - if an accept happens the counter n_accepts is updated // ****************************************************** int SA_Scheduler::Accept(float new_cost) {//debug(SA_Scheduler::Accept , Getmyrank()); int acc = 0; //,bf=0; if ( TryAcceptance(new_cost) ) { // n_accepts++; // a further accept AccRatio = n_accepts / (float)n_iter; overall_iter++; // bf = BestFlag; // retten, da durch SetNewE ueberschrieben wird acc = 1; SetNewE(new_cost); // BestFlag = bf; } else LetOldE(); //outputfile << E << std::endl; return acc; } // \****************************************************** // Methode CollectSums - // Sum, Sum2, n_iter werden von allen Mitgliedern von comm // auf dem Prozess mit der Nummer 0 in comm gesammelt. // \****************************************************** ///void SA_Scheduler::CollectSubchainStatistics(MPI_Comm comm ) // eher naive Version - evtl. Verbesserung mit MPI-Datentypen ///{ ///debug(SA_Scheduler::CollectSums , myrank); /// /// int me,nproc; /// /// MPI_Comm_size(comm,&nproc); /// if (nproc == 1) /// return; // Trivialfall - comm besteht nur aus einem Prozessor - mich /// MPI_Comm_rank(comm,&me); /// /// struct /// { /// double S,S2,n,SR,S2R,nR; /// } in, out; /// in.S = Sum; /// in.S2 = Sum2; /// in.n = (float)n_iter; /// in.SR = SumRun; /// in.S2R = Sum2Run; /// in.nR = (float)total_iter; /// MPI_Reduce(&in,&out,6,MPI_DOUBLE,MPI_SUM,0,comm); /// /// if( me == 0 ) /// { /// Sum = out.S; /// Sum2 = out.S2; /// n_iter = (unsigned long) out.n; /// SumRun = out.SR; /// Sum2Run = out.S2R; /// total_iter = (unsigned long) out.nR; /// } ///} // \****************************************************** // Methode ReadConfig - Liest die Konfigurations- // daten ( geklammert mit '{' '}' ) aus dem istream // \****************************************************** int SA_Scheduler::ReadConfig(std::istream & config) {//debug(SA_Scheduler::ReadConfig, myrank); char text[BUFLEN]; config >> text; if ( strcmp(text,"{") != 0) { std::cout << "Config file section for SA_Scheduler does not begin with {!\n"; return FALSE; } while (config >> text && ( strcmp(text,"}") != 0 )) { if (strcmp(text, "picturedirectory") == 0) { config >> text; PictureDirectory = new char[strlen(text)+1]; strncpy(PictureDirectory, text, strlen(text)+1); std::strstream CostFunction_Name; CostFunction_Name << PictureDirectory << "/CostFunction" << std::ends; CostFunction.open(CostFunction_Name.str()); if ( !CostFunction ) { std::cout << "Cannot create output file "<> text; if (strcmp(text, "MAX") == 0) { OptType = Opt::MAX; BestE = 0; strcpy(opttypename,"MAX"); } else if (strcmp(text, "MIN") == 0) { OptType = Opt::MIN; BestE = INFINITY; strcpy(opttypename,"MIN"); } else { std::cout << "In SA_Scheduler::ReadConfig unrecognized keyword \""<> text; ThresholdValue = atof(text); if ( ThresholdValue < 0 || ThresholdValue > 1 ) { ThresholdValue = 0; } } else if (strcmp(text, "initialtemperature") == 0) { config >> text; SetStartT( atof(text) ); } else if (strcmp(text, "initaccratio") == 0) { config >> text; InitAccRatio = atof(text); } else if (strcmp(text, "verboselevel") == 0) { config >> text; saoutput.SetOutputLevel(atoi(text)); } else if (strcmp(text, "timelimit") == 0) { config >> text; timelimit = atol(text); } else { std::cout <<"In SA_Scheduler::ReadConfig unrecognized keyword \""< do Aarts and forget startT strcpy(warminguptype,"Aarts "); wt = 2; } else { // InitAccRatio was NOT set => check for explizit startT if (StartT == -1.0) { // neither AccRatio nor StartT where given => do Aarts with AccRatio of 0.9 wt = 3; strcpy(warminguptype,"FixedAarts "); } } saoutput.AddVariable(23,SA_STRING, PictureDirectory); return (strcmp(text,"}") == 0 ); } // \****************************************************** // Methode ShowConfig - Gibt die aktuelle Parameter // aus (nur zur Kontrolle). // \****************************************************** void SA_Scheduler::ShowConfig(std::ostream & out) {//debug(SA_Scheduler::ShowConfig , myrank); saoutput.OutputInit(); // out << "\tOptType:\t\t" << ( OptType == Opt::MIN ? "MIN" : "MAX") << std::endl; } // \****************************************************** // Methode OutputStatistics - Schreibt die Ergebnisse in die Logdatei. // Dabei werden Statistiken von einzelnen Rechnerknoten // sinngemaess zusammengefasst. // muss auf allen Prozessoren des comm aufgerufen werden! // \****************************************************** //void SA_Scheduler::OutputStatistics(std::ostream & output) //{//debug(SA_Scheduler::OutputStatistics , myrank); // saoutput.OutputFrozenYes(); /// if ( myrank >=0 ) // d.h. falls MPI initialisiert ist /// { // Beste gesehene Loesungsbewertung: /// float BestBuff; /// if ( OptType == Opt::MIN ) /// MPI_Reduce(&BestE,&BestBuff,1,MPI_FLOAT,MPI_MIN,0,comm); /// else /// MPI_Reduce(&BestE,&BestBuff,1,MPI_FLOAT,MPI_MAX,0,comm); // Anzahl der versuchten und akzeptierten Uebergaenge sowie Mittelwert der std::endloesung: /// struct /// { /// float tot_iter,tot_acc,StartE,E; /// } in,out; /// in.tot_iter = (float)total_iter; /// in.tot_acc = (float)total_accepts; /// in.StartE = StartE; /// in.E = E; /// MPI_Reduce(&in,&out,4,MPI_FLOAT,MPI_SUM,0,comm); /// int me,npr; /// MPI_Comm_rank(comm,&me); /// if ( me != 0 ) /// return; /// MPI_Comm_size(comm,&npr); /// output /// << " OT="<< ( OptType == Opt::MIN ? "MIN" : "MAX") /// << " T(0)=" << StartT /// << " T=" << T /// << " I=" << (unsigned long)out.tot_iter /// << " N_dT=" << n_dT // Anzahl der Temperaturstufen /// << " N_acc=" << (unsigned long)out.tot_acc /// << " N_upd=" << total_updates /// << " E(0)=" << out.StartE/npr /// << " E=" << out.E/npr /// << " BestE=" << BestBuff; /// } /// else /// { // output // << " OT="<< ( OptType == Opt::MIN ? "MIN" : "MAX") // << " T(0)=" << StartT // << " InitialAcceptanceRatio=" << InitAccRatio // << " T=" << T // << " I=" << total_iter // << " AllI=" << overall_iter // << " N_dT=" << n_dT // Anzahl der Temperaturstufen // << " N_acc=" << total_accepts // << " N_upd=" << total_updates // << " E(0)=" << StartE // << " E=" << E // << " BestE=" << BestE; /// } //} void SA_Scheduler::CreateLog(std::ostream & output) {//debug(SA_Scheduler::OutputStatistics , myrank); // if ( myrank >=0 ) // d.h. falls MPI initialisiert ist // { // Beste gesehene Loesungsbewertung: // float BestBuff; // if ( OptType == Opt::MIN ) // MPI_Reduce(&BestE,&BestBuff,1,MPI_FLOAT,MPI_MIN,0,comm); // else // MPI_Reduce(&BestE,&BestBuff,1,MPI_FLOAT,MPI_MAX,0,comm); // Anzahl der versuchten und akzeptierten Uebergaenge sowie Mittelwert der std::endloesung: // struct // { // float tot_iter,tot_acc,StartE,E; // } in,out; // in.tot_iter = (float)total_iter; // in.tot_acc = (float)total_accepts; // in.StartE = StartE; // in.E = E; // MPI_Reduce(&in,&out,4,MPI_FLOAT,MPI_SUM,0,comm); // int me,npr; // MPI_Comm_rank(comm,&me); // if ( me != 0 ) // return; // MPI_Comm_size(comm,&npr); // output // << " OT="<< ( OptType == Opt::MIN ? "MIN" : "MAX") // << " T(0)=" << StartT // << " T=" << T // << " I=" << (unsigned long)out.tot_iter // << " N_dT=" << n_dT // Anzahl der Temperaturstufen // << " N_acc=" << (unsigned long)out.tot_acc // << " N_upd=" << total_updates // << " E(0)=" << out.StartE/npr // << " E=" << out.E/npr // << " BestE=" << BestBuff; // } // else // { output << " OT="<< ( OptType == Opt::MIN ? "MIN" : "MAX") << " T(0)=" << StartT << " InitialAcceptanceRatio=" << InitAccRatio << " T=" << T << " I=" << total_iter << " AllI=" << overall_iter << " N_dT=" << n_dT // Anzahl der Temperaturstufen << " N_acc=" << total_accepts << " N_upd=" << total_updates << " E(0)=" << StartE << " E=" << E << " BestE=" << BestE; // } } // \****************************************************** // Methode OutputSubchainStatistics - Schreibt die Daten der Teilkette // \****************************************************** void SA_Scheduler::OutputSubchainStatistics(std::ostream & output) { saoutput.OutputEquiYes(); //debug(SA_Scheduler::OutputSubchainStatistics , myrank); // output // << " NdT=" << n_dT // << " T=" << T // << " Iter(T)=" << n_iter // << " TotIter=" < 0) ? (n_accepts*1.0 / (total_iter-i_subchain+1)) : 0; } float SA_Scheduler::GetUpdateRatio() {//debug(SA_Scheduler::GetUpdateRatio, myrank); //std::cout << "n_dT " << n_dT << " n_updates " << n_updates << " total_iter " << total_iter << " i_subchain " << i_subchain << std::endl; return (n_updates > 0) ? (n_updates*1.0 / (total_iter-i_subchain+1)) : 0; } float SA_Scheduler::GetMean() {//debug(SA_Scheduler::GetMean, myrank); return (n_iter > 0) ? (Sum/n_iter) : 0; } float SA_Scheduler::GetSigma() {//debug(SA_Scheduler::GetSigma, myrank); float d = (Sum2 - Sum*Sum/n_iter); if ( d < 0 ) { if ( n_updates > 2 ) // Falls nur wenige unterschiedliche Werte - keine Fehlermeldung ausgeben! { //std::cout <<"At "< 1) ? sqrt( (-d)/ (n_iter - 1) ) : 0; return 0; } return (n_iter > 1) ? sqrt( d/ (n_iter - 1) ) : 0; } float SA_Scheduler::GetRunMean() {//debug(SA_Scheduler::GetRunMean, myrank); return (total_iter > 0) ? (SumRun/total_iter) : 0; } double SA_Scheduler::AartsWarmingUp(SA_Problem &P, SA_Solution &s, SA_Solution &b,long Length){ std::cout << "Doing AartsWarmingUp()" << InitAccRatio << std::endl; if (InitAccRatio == -1.0) { InitAccRatio = 0.9; } float T0, dummy, NewCost, CostDiff, MeandC,SumDeltaPlus = 0; // Summe aller uphill-Uebergaenge SetNewE( P.GetCost(s) ); StartE = GetE(); unsigned int m1,m2,i; long m0; m0 = Length; T0 = 1e-10; for(m1=0,m2=0,i=0; i < m0; i++) { P.GetNeighbor(s,GetRelativeT()); NewCost = P.GetCost(s); CostDiff = NewCost - E; if (CostDiff < 0) CostDiff = -CostDiff; // the absolute value if ( Better(NewCost,E) ) { P.UpdateSolution(s); SetNewE( NewCost ); m1++; // counter for better moves } else { m2++; // counter for worther moves SumDeltaPlus += CostDiff; // ? nich vielleicht NACH der Abfrage ? if ( exp(-CostDiff/T0) > rand_float() ) { P.UpdateSolution(s); SetNewE( NewCost ); } else { P.ResetSolution(s); SetNewE( E ); } } if ( BestFound() ) P.Copy(s,b); dummy = m2*InitAccRatio - (1-InitAccRatio)*m1 ; if ( m2 > 0 && dummy != 0) { T0 = ( SumDeltaPlus/m2 ) / log( m2 / dummy ); } } return T0; } // wt = 1 : only initialtemperature given wt = 2,3 nothing or both where given int SA_Scheduler::AartsRecommended() { return(wt > 1); } void SA_Scheduler::WarmingUp(SA_Problem &P, SA_Solution &s, SA_Solution &b) { // InitAccRatio was set to 0.9 by ReadConfig if not given!!! if (AartsRecommended()) { SetStartT( AartsWarmingUp(P,s,b,UPPER_LOOP_BOUND)); } } float SA_Scheduler::GetRunSigma() {//debug(SA_Scheduler::GetRunSigma, myrank); float d = (Sum2Run - SumRun*SumRun/total_iter); if ( d < 0 ) { if ( n_updates > 2 ) // Falls nur wenige unterschiedliche Werte - keine Fehlermeldung ausgeben! { //std::cout <<"At "< 1) ? sqrt( (-d)/ (total_iter - 1) ) : 0; return 0; } return (total_iter > 1) ? sqrt( d/ (total_iter - 1) ) : 0; } void SA_Scheduler::StartClock() { starttime = clock(); } int SA_Scheduler::TimeExceeded() { if (timelimit < 0) { // no deadline (or negative one) was given return 0; } else { clock_t currenttime; currenttime = clock(); if ((currenttime-starttime)/CLOCKS_PER_SEC < timelimit) { return 0; } else { return 1; } } }