BAPS/partitioning/TV/BAPTVPartitioner.cpp

00001 #include "BAPTVPartitioner.h"
00002 
00003 using std::cout;
00004 using std::cerr;
00005 using std::endl;
00006 using std::ifstream;
00007 using std::ofstream;
00008 using std::ios;
00009 using std::setprecision;
00010 
00011 
00012 
00013 BAPTVPartitioner::BAPTVPartitioner(BAPPackage& aPackage)
00014 :  BAPPartitioner(aPackage),           // init base class
00015    mNumVes(aPackage.NumVessels()),
00016    mVes(array<TVVessel>(1, mNumVes)),
00017    mNumSect(aPackage.NumSections()),
00018    mSect(array<TVSection>(1, mNumSect)),
00019    mTrans(aPackage.Transhipments()),
00020    mDist(aPackage.Distances()),
00021    mTraceFile(mPackage.PartitioningTraceFilename()),
00022    mRuntimeAnalyzer(0),
00023    mSolnExists(false)
00024 {
00025    gettimeofday(&mStartTime, NULL);
00026    array<int>  temp;
00027    
00028    // Init vessel array with vessel objects
00029    temp = aPackage.VesselLengths();
00030    
00031    for (int i = 1; i <= mNumVes; i++)
00032    {
00033       TVVessel v(i, temp[i]);
00034       v.StartTimeZone(aPackage.StartTimeZone(i));
00035       v.EndTimeZone(aPackage.EndTimeZone(i));
00036       v.Arrival(aPackage.Arrival(i));
00037       v.Departure(aPackage.Departure(i));
00038       
00039       // find all neighbouring vessels
00040       for (int j = 1; j <= mNumVes; j++)
00041       {
00042          if (j == i) continue;         // ignore self loop
00043          
00044          if (mTrans(i, j) > 0  ||  mTrans(j, i) > 0)
00045          {
00046             v.AddNeighbour(j);
00047             v.AddTranshipment(mTrans(i, j));
00048             v.AddTranshipment(mTrans(j, i));
00049          }
00050       }
00051 
00052       v.Export(mTrans(0, i));
00053       v.Import(mTrans(i, 0));
00054       mVes[i] = v;
00055    }
00056 
00057    // Init section array with section objects
00058    temp = aPackage.SectionLengths();
00059    
00060    for (int i = 1, t = aPackage.NumTimeZones(); i <= mNumSect; i++)
00061       mSect[i] = TVSection(i, t, temp[i]);
00062 
00063    ReadParameterFile();
00064 }
00065 
00066 
00067 BAPTVPartitioner::~BAPTVPartitioner()
00068 {
00069    // nothing to do
00070 }
00071 
00072 
00073 void BAPTVPartitioner::Print(const int& aWidth,
00074                              const int& aDetail) const
00075 {
00076    cout  << "--== BAPTVPartitioner ==--" << endl
00077          << "  ID = " << ID() << endl
00078          << "  Name = " << Name() << endl
00079          << "  Number of sections = " << mNumSect
00080          << ", Number of vessels = " << mNumVes << endl
00081          << "  Random seed = " << mRandomSeed << endl
00082          << "  Transhipment = " << mTranshipment
00083          << ", Penalty = " << mPenalty << endl << endl;
00084 
00085    for (int i = 1; i <= mNumVes; i++)
00086       if (aDetail > 0)
00087          mVes[i].Print(aWidth, aDetail);
00088       else
00089          cout  << "ves " << setw(4) << i
00090                << " in sect " << setw(2) << mVes[i].Section() << endl;
00091 
00092    for (int k = 1; k <= mNumSect; k++)
00093       if (aDetail > 0)
00094          mSect[k].Print(aWidth, aDetail);
00095       else
00096       {
00097          cout  << "sect " << setw(2) << k << " with vessels: " << endl;
00098          int   i;
00099          const set<int>& V = mSect[k].Vessels();
00100          forall(i, V)
00101          {
00102             cout << i << " ";
00103          }
00104          cout << endl;
00105       }
00106 }
00107 
00108 
00109 // The Solve method is called to perform
00110 // the vessel partitioning algorithm.
00111 //   this version calls GenerateInitialSolution
00112 //    (which creates a random initial solution)
00113 //
00114 void BAPTVPartitioner::Solve()
00115 {
00116 
00117    GenerateInitialSolution();
00118    CalcInitialObjVal();
00119 
00120    gettimeofday(&mEndTime, NULL);
00121 
00122    PrintSummary();
00123    WriteSolutionFile();
00124    UpdatePackage();
00125 }
00126 
00127 
00128 void BAPTVPartitioner::PrintSummary() const
00129 {
00130    cout  << mPackage.ProjectFilename() << " --- "
00131          << mNumVes << " vessels, " << mNumSect << " sections" << endl
00132          << "Transhipment = " << mTranshipment << endl
00133          << "Penalty      = " << mPenalty << endl
00134          << "Obj Value    = " << CalcObjVal() << endl
00135          << "Time taken (sec) = "
00136          << (mEndTime.tv_sec - mStartTime.tv_sec) +
00137             (mEndTime.tv_usec - mStartTime.tv_usec) / 1000000.0
00138          << endl
00139          << endl;
00140 }
00141 
00142 
00143 
00144 void BAPTVPartitioner::InitSolution()
00145 {
00146    // Init working variables
00147    mTranshipment = 0;
00148    mPenalty = 0;
00149    mUnallocVes.clear();
00150    for (int i = 1; i <= mNumVes; i++)
00151    {
00152       mVes[i].Section(UNASSIGNED);   // all vessels unassigned
00153       mUnallocVes.insert(i);
00154    }
00155 
00156    ResetVesselDestinations();
00157 }
00158 
00159 void BAPTVPartitioner::ResetVesselDestinations()
00160 {
00161    // Add potential destination sections to each vessel
00162    for (int i = 1; i <= mNumVes; i++)
00163       for (int k = 1; k <= mNumSect; k++)
00164          if (k != mVes[i].Section())
00165             mVes[i].AddDestination(k);
00166 }
00167 
00168 
00169 void BAPTVPartitioner::CalcInitialObjVal()
00170 {
00171    ComputeObjVal(mTranshipment, mPenalty);
00172 }
00173 
00174 
00175 void BAPTVPartitioner::ComputeObjVal(unsigned long& aTrans,
00176                                      unsigned long& aPenalty) const
00177 {
00178    aTrans = aPenalty = 0;
00179 
00180    for (int v1 = 1; v1 <= mNumVes; v1++)
00181    {
00182       const int&        s1 = mVes[v1].Section();
00183       const set<int>&   neighbours = mVes[v1].Neighbours();
00184       int               v2;
00185 
00186       // Calculate inter-vessel transhipment costs
00187       forall(v2, neighbours)
00188       {
00189          if (v2 < v1) continue;
00190 
00191          const int&     s2 = mVes[v2].Section();
00192          
00193          if (s1 == UNASSIGNED  ||  s2 == UNASSIGNED)
00194             aPenalty += TotalFlow(v1, v2) * LONGDISTANCE;
00195          else
00196          {
00197             aTrans += TotalFlow(v1, v2) * D(s1, s2);
00198 //            cout  << setw(4) << v1 << setw(5) << v2
00199 //                  << setw(10) << TotalFlow(v1, v2) << " * "
00200 //                  << setw(5) << D(s1, s2) << " = "
00201 //                  << TotalFlow(v1, v2) * D(s1, s2)
00202 //                  << "     Trans = " << aTrans << endl;
00203          }
00204       }
00205 
00206       // Calculate import,export costs
00207       if (s1 == UNASSIGNED)
00208          aPenalty += (mVes[v1].Import() + mVes[v1].Export()) * LONGDISTANCE;
00209       else
00210       {
00211          aTrans += (mVes[v1].Import() + mVes[v1].Export()) * D(s1, 0);
00212 //            cout  << setw(4) << v1 << " ("
00213 //                  << setw(5) << mVes[v1].Import() << " + "
00214 //                  << setw(5) << mVes[v1].Export() << ") * "
00215 //                  << setw(5) << D(s1, 0) << " = "
00216 //                  << (mVes[v1].Import() + mVes[v1].Export()) * D(s1, 0)
00217 //                  << "     Trans = " << aTrans << endl;
00218       }
00219    }
00220 }
00221 
00222 
00223 unsigned long BAPTVPartitioner::CalcObjVal() const
00224 {
00225    unsigned long  ObjVal = mTranshipment + mPenalty;
00226 
00227    // Safeguards against overflow
00228    assert(ObjVal >= mTranshipment);
00229    assert(ObjVal >= mPenalty);
00230 
00231    return ObjVal;
00232 }
00233 
00234 unsigned int BAPTVPartitioner::TotalFlow(const int& v1, const int& v2) const
00235 {
00236    return (unsigned int) (mTrans(v1, v2) + mTrans(v2, v1));
00237 }
00238 
00239 unsigned int BAPTVPartitioner::TotalFlow(const TVVessel& v1, const TVVessel& v2) const
00240 {
00241    return (unsigned int) (mTrans(v1.ID(), v2.ID()) + mTrans(v2.ID(), v1.ID()));
00242 }
00243 
00244 unsigned int BAPTVPartitioner::D(const int& s1, const int& s2) const
00245 {
00246    if (s1 >= 0  &&  s2 >= 0)           // take port into account also
00247       return (unsigned int) mDist(s1, s2);
00248    else
00249       return LONGDISTANCE;
00250 }
00251 
00252 unsigned int BAPTVPartitioner::D(const TVSection& s1, const TVSection& s2) const
00253 {
00254    if (s1.ID() >= 0  &&  s2.ID() >= 0) // take port into account also
00255       return (unsigned int) mDist(s1.ID(), s2.ID());
00256    else
00257       return LONGDISTANCE;
00258 }
00259 
00260 
00261 void BAPTVPartitioner::UpdatePackage() const
00262 {
00263    for (int i = 1; i <= mNumVes; i++)
00264       mPackage.SectionAssignedTo(i, mVes[i].Section());
00265    
00266    mPackage.TranshipmentCost(mTranshipment);
00267 
00268    // What happened to the penalty?!?
00269 }
00270 
00271 
00272 void BAPTVPartitioner::ReadParameterFile()
00273 {
00274    string   paramFile = mPackage.ParamFilename();
00275    char     buf[255];
00276    string   token, mode = "nil";
00277    ifstream ParamFile(paramFile);
00278 
00279    if (!ParamFile)
00280    {
00281       cerr << "Cannot open parameter file: " << paramFile << endl;
00282       return;
00283    }
00284 
00285    while (!ParamFile.eof())
00286    {
00287       ParamFile.getline(buf,80);
00288 
00289 #ifdef _DEBUG
00290          cout << "tokenizing: " << buf << endl;
00291 #endif
00292 
00293       for (int i = 0; i < 80; i++)     // Convert carriage-return to space
00294          if (13 == (int) buf[i])
00295             buf[i] = ' ';
00296 
00297       if (buf[0] == ' ' || buf[0] == 0)
00298          continue;
00299 
00300       token = strtok(buf, " ");
00301 
00302 #ifdef _DEBUG
00303       cout << "token = " << token << endl;
00304 #endif
00305 
00306       if (token.length() == 0)         // empty line, ignore
00307          continue;
00308       if (token == "#")                // comment line, ignore
00309          continue; 
00310       if (token[0] == '_')             // keyword, change mode
00311          mode = token;
00312       else                             // process data based on mode
00313       {
00314          if (mode == "_RANDOM_SEED")
00315          {
00316             mRandomSeed = atoi(token);
00317             mRandom.set_seed(mRandomSeed);
00318          }  
00319          else if (mode == "_PRINT_SECTIONS")
00320          {
00321             mPrintSections = atoi(token);
00322          }
00323          else if (mode == "_PRINT_VESSELS")
00324          {
00325             mPrintVessels = atoi(token);
00326          }
00327          else if (mode == "_RUNTIME_ANALYZER")
00328          {
00329             mRuntimeAnalyzer = atoi(token);
00330          }
00331          else if (mode == "_SUMMARY")
00332          {
00333             mSummary = atoi(token);
00334          }
00335          // else nothing
00336       }  
00337    }
00338 }
00339 
00340 
00341 void BAPTVPartitioner::WriteSolutionFile() const
00342 {
00343    string   solutionFile = mPackage.PartitioningFilename(),
00344             paramFile = mPackage.ParamFilename();
00345 
00346    ofstream SolFile(solutionFile);
00347 
00348    if (!SolFile)
00349    {
00350       cerr << "Cannot create solution file: " << solutionFile << endl;
00351       return;
00352    }
00353 
00354    // Write comments
00355    // ( Date() auto-inserts a carriage-return! )
00356    SolFile  << "#" << endl
00357             << "# Solution File created by BAPTVPartitioner" << endl
00358             << "# Date = " << Date()
00359             << "# Parameter File = " << paramFile << endl
00360             << "#" << endl << endl;
00361 
00362    SolFile  << "_NUM_UNALLOCATED" << endl
00363             << mUnallocVes.size() << endl << endl;
00364 
00365    // Reads from the BAP package
00366    const int V = mNumVes;
00367 
00368    // Write solution information
00369    SolFile.setf(ios::fixed);
00370    SolFile  << "_NUM_VESSELS" << endl
00371             << V + 1 << endl           // n+1 to account for port
00372             << endl
00373             << "_OBJECTIVE_VALUE" << endl
00374             << setprecision(2) << mTranshipment + mPenalty << endl
00375             << endl
00376             << "_TRANSHIPMENT_VALUE" << endl
00377             << setprecision(2) << mTranshipment << endl
00378             << endl
00379             << "_PENALTY_VALUE" << endl
00380             << setprecision(2) << mPenalty << endl
00381             << endl
00382             << "_TIME_TAKEN" << endl
00383             << setprecision(6)
00384             << (mEndTime.tv_sec - mStartTime.tv_sec) +
00385                (mEndTime.tv_usec - mStartTime.tv_usec) / 1000000.0
00386             << endl
00387             << endl;
00388    SolFile.setf(ios::fixed, ios::floatfield);
00389 
00390    // Write allocated vessels
00391    array<int>  Arrivals = mPackage.Arrivals(),
00392                Departures = mPackage.Departures();
00393 
00394    SolFile  << "# Final Allocation Solution" << endl
00395             << "# <ves#> <sect> <wharf> <berth time> <departure time>"
00396             << endl << endl
00397             << "_ALLOCATION" << endl;
00398 
00399    SolFile  << "0 0 0 0 0" << endl;    // Write the sea port
00400 
00401    for (int i = 1; i <= V; i++)
00402       if (mVes[i].Section() > 0)
00403          SolFile  << i << " " << mVes[i].Section() << " " << -1
00404                   << " " << Arrivals[i] << " " << Departures[i]
00405                   << endl;
00406 
00407    // Write unallocated vessels, if any
00408    if (mUnallocVes.size() > 0)
00409    {
00410       SolFile  << endl << "_UNALLOCATED_VESSELS" << endl;
00411 
00412       for (int i = 1; i <= V; i++)
00413          if (mVes[i].Section() < 0)
00414             SolFile  << i << " " << -1 << " " << -1
00415                      << " " << Arrivals[i] << " " << Departures[i]
00416                      << endl;
00417    }
00418 
00419    SolFile << endl << endl;
00420 
00421    SolFile.close();
00422 }
00423 
00424 
00425 void BAPTVPartitioner::WriteTraceFile(string aStr) const
00426 {
00427    ofstream TraceFile(mTraceFile, ios::app);
00428    TraceFile  << aStr << endl;
00429    TraceFile.close();
00430 }
00431 
00432 void BAPTVPartitioner::WriteTraceFile(long aLong) const
00433 {
00434    ofstream TraceFile(mTraceFile, ios::app);
00435    TraceFile   << aLong << endl;
00436    TraceFile.close();
00437 }
00438 
00439 void BAPTVPartitioner::WriteTraceFile(long double aDouble) const
00440 {
00441    ofstream TraceFile(mTraceFile, ios::app);
00442    TraceFile.setf(ios::fixed);
00443    TraceFile  << setprecision(2) << aDouble << endl;
00444    TraceFile.close();
00445 }
00446 
00447 
00448 string BAPTVPartitioner::Date() const
00449 {
00450    //
00451    // Query date and time
00452    //
00453    struct tm   *TimePtr;
00454    time_t      Time;
00455 
00456    time(&Time);
00457    TimePtr = localtime(&Time);
00458 
00459    return string(asctime(TimePtr));
00460 }
00461 
00462 // GenerateInitialSolution creates a vessel partitioning solution. 
00463 // At the moment, it creates a random initial solution.
00464 //   Called by: Solve();
00465 //
00466 void BAPTVPartitioner::GenerateInitialSolution()
00467 {
00468    InitSolution();
00469    GenSolnRandom();
00470 }
00471 
00472 
00473 // This method actually create the random vessel partitioning
00474 // solution. Each vessel is assigned a random section
00475 // At the moment, it creates a random initial solution.
00476 //   Called by: Solve();
00477 void BAPTVPartitioner::GenSolnRandom()
00478 {
00479    // List of candidate vessels for allocation
00480    array<int>  V(1, mNumVes);
00481    
00482    for (int i = 1; i <= mNumVes; i++)
00483       V[i] = i;                        // set content to vessel ID
00484 
00485    // Loop to do actual allocation
00486    int   i, VesselsLeft = mNumVes;
00487 
00488    while (VesselsLeft > 0)
00489    {
00490       i = mRandom(1, VesselsLeft);     // randomly pick a vessel
00491       int         vIndex = V[i];
00492       TVVessel&   v = mVes[vIndex];
00493       AssignVesselToRandomSection(v);
00494       // remove assigned vessel by replacing it with last vessel
00495       V[i] = V[VesselsLeft];
00496       VesselsLeft--;
00497    }
00498 }
00499 
00500 
00501 // Assigns Vessel v to a random section
00502 //   Alg: save the candidate destination sections
00503 //        for each randomly selected section
00504 //        assign to it if there is room for it
00505 //        else remove the section.
00506 //   Note:vessel is unassigned if all sections fails.
00507 //
00508 void BAPTVPartitioner::AssignVesselToRandomSection(TVVessel& v)
00509 {
00510    // List of candidate sections to be assigned to v
00511    set<int> sectSet = v.Destinations();   // Copy, preserve original
00512    array<int> S(1, sectSet.size());       // Array of destination sections
00513    int   i = 1, k;
00514    
00515    while (!sectSet.empty())
00516    {
00517       k = sectSet.choose();
00518       sectSet.del(k);
00519       S[i++] = k;
00520    }
00521 
00522    // Loop to do actual assignment
00523    int   SectionsLeft = S.size();
00524 
00525    while (SectionsLeft > 0  &&  v.Section() == UNASSIGNED)
00526    {
00527       i = mRandom(1, SectionsLeft);  // randomly pick a section
00528       int      k = S[i];
00529       
00530       if (mSect[k].CanAccommodate(v))
00531          Assign(v, mSect[k]);
00532       else
00533          S[i--] = S[SectionsLeft--]; // remove from further consideration
00534    }
00535 }
00536 
00537 
00538 void BAPTVPartitioner::Assign(TVVessel& v, TVSection& s)
00539 {
00540    v.Section(s.ID());
00541    v.RemoveDestination(s.ID());
00542    s.Add(v);
00543    mUnallocVes.del(v.ID());
00544 }
00545 
00546 

Generated on Tue Sep 9 15:40:10 2008 for BAP by  doxygen 1.5.3