// -*- C++ -*- // //====================================================================== // File: ir-random.c // Author: Thomas G. Dietterich // Description: Implements repeated boltzmann random probing of the // problem space. // // Copyright (c) 1995, 2000 by Thomas G. Dietterich. All Rights Reserved. // may be reproduced by any non-commercial purpose. //====================================================================== #include #include #include #include "schedule.h" #include "ir-sched.h" #include "../lib/list.h" #include "../lib/random.h" extern const int VERBOSE = 0; // set to 1 to get verbose trace output const float MinTemperature = 0.1; // temperature < MinTemperature treated as zero random RandomGenerator; // random number generator for Boltzmann Schedule * chooseChildGreedy(list & frontier) { // Choose child with smallest value for rdf(); listIterator itr(frontier); float bestRDF = INFINITY; int childIndex = 0; // print index of chosen child for debugging help Schedule * result = 0; for (itr.init(), childIndex = 0; !itr; ++itr, ++childIndex) { if (itr()->rdf() < bestRDF) { result = itr(); bestRDF = itr()->rdf(); } } cout << childIndex << endl; return result; } Schedule * chooseChildBoltzmann(list & frontier, float temperature) { // Choose child at random using boltzmann-weighted distribution unsigned int len = frontier.length(); vector cumDist(len); float totalWeight = 0.0; listIterator itr(frontier); vectorIterator citr(cumDist); for (itr.init(), citr.init(); !itr; ++itr, ++citr) { totalWeight += exp(- itr()->rdf() / temperature); citr() = totalWeight; } cumDist[len - 1] *= 2.0; // ensure that the last element is very large // so that the next loop will succeed float randomNumber = RandomGenerator.between(0.0, totalWeight); for (itr.init(), citr.init(); !itr; ++itr, ++citr) { if (randomNumber <= citr()) { cout << citr.key() << endl; // print child index for debugging return itr(); } } cerr << "Boltzmann fell off end!" << endl; abort(); } Schedule * chooseChild(list & frontier, float temperature) { int nchildren = frontier.length(); if (nchildren <= 0) { // no nodes on the frontier, quit this trial. return 0; } if (temperature < MinTemperature) return chooseChildGreedy(frontier); else return chooseChildBoltzmann(frontier, temperature); } int main() { cout << "Enter the filename containing the schedule: "; char schedname[100]; cin >> schedname; cout << "Enter a number to seed the random number generator: "; int seed; cin >> seed; RandomGenerator.setseed(seed); int NTrials; cout << "Enter the number of trials to perform: "; cin >> NTrials; float temperature = 0.01; cout << "Enter the temperature: "; cin >> temperature; IRSchedule Original; { ifstream str(schedname); str >> Original; } cout << "The schedule is:\n"; cout << Original; Schedule * BestSchedule = 0; int bestlength = INFINITY; int iteration = 0; for (int itrial = 0; itrial < NTrials; itrial++) { cout << "Beginning Trial " << itrial + 1 << endl;; cout << "Expansion# Depth Branching Factor Chosen child\n"; // initialize the frontier list frontier = Original.startingStates(); listIterator itr(frontier); Schedule * Current = 0; // current accepted schedule while (1) { cout << iteration << "\t" << (Current ? Current->depth() : 0) << "\t" << frontier.length() << "\t"; // Randomly choose a successor state from the frontier. Decide // whether to keep it. If we keep it, expand it to produce a // new frontier. Current = chooseChild(frontier, temperature); if (Current) { // delete all other children on the frontier for (itr.init(); !itr; ++itr) { if (itr() != Current) delete itr(); } // If the chosen child is a terminal node, we are done. if (Current->isTerminalState()) break; // otherwise, expand the chosen node to create the new frontier. frontier = Current->expand(); frontier.reverse(); // make the indexes match the order iteration += 1; } else break; } cout << "\nEnd of trial " << itrial + 1; if (Current) { if (Current->Length() < bestlength) { if (BestSchedule) delete BestSchedule; BestSchedule = Current; bestlength = Current->Length(); } cout << " length = " << Current->Length(); } else { cout << " failed: no children"; } cout << "\n\n"; } if (BestSchedule) { cout << "The final schedule is:\n"; cout << *BestSchedule; cout << "It has length " << bestlength << endl; // BestSchedule->gnuplot(filename); } else cout << "No feasible schedule found.\n"; return 0; }