Changeset 9cda6e0f5d in tspsg
- Timestamp:
- Apr 25, 2010, 4:36:27 PM (15 years ago)
- Branches:
- 0.1.3.145-beta1-symbian, 0.1.4.170-beta2-bb10, appveyor, imgbot, master, readme
- Children:
- ca3d2a30fa
- Parents:
- 345e7b6132
- git-author:
- Oleksii Serdiuk <contacts@…> (04/25/10 16:36:27)
- git-committer:
- Oleksii Serdiuk <contacts@…> (06/29/12 19:41:31)
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
src/defaults.h
r345e7b6132 r9cda6e0f5d 65 65 //////// OUTPUT 66 66 67 //! Default for "Show solution graph" 68 #define DEF_SHOW_GRAPH true 67 69 //! Default for "Show solution steps' matrices for every solution step" 68 70 #define DEF_SHOW_MATRIX true -
src/globals.h
r345e7b6132 r9cda6e0f5d 32 32 #include <QtCore> 33 33 #include <QtGui> 34 #include <limits>35 34 36 35 // Version info … … 40 39 // TSPSG Defaults 41 40 #include "defaults.h" 41 // TSPSolver 42 #include "tspsolver.h" 42 43 #ifdef Q_OS_WIN32 43 44 // Vista/7 Eyecandy … … 80 81 #define ZKT_VERSION quint8(1) 81 82 82 /*!83 * \def INFINITY84 * \brief This value means infinity :-)85 *86 * Some libraries already have \c INFINITY defined.87 * We need to redefine it for the \c INFINITY to always have the same value.88 */89 #ifdef INFINITY90 #undef INFINITY91 #endif92 #define INFINITY std::numeric_limits<double>::infinity()93 83 //! This string represents infinite value in the table 94 84 #define INFSTR "---" -
src/mainwindow.cpp
r345e7b6132 r9cda6e0f5d 510 510 pb->setFormat(tr("Generating header")); 511 511 pd.setLabelText(tr("Generating solution output...")); 512 pd.setMaximum( n);512 pd.setMaximum(solver.getTotalSteps() + 1); 513 513 pd.setValue(0); 514 514 … … 517 517 518 518 QPainter pic; 519 pic.begin(&graph); 520 pic.setRenderHint(QPainter::Antialiasing); 519 if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) { 520 pic.begin(&graph); 521 pic.setRenderHint(QPainter::Antialiasing); 522 } 521 523 522 524 QTextDocument *doc = solutionText->document(); … … 529 531 cur.insertText(tr("Task:")); 530 532 outputMatrix(cur, matrix); 531 drawNode(pic, 0); 533 if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) 534 drawNode(pic, 0); 532 535 cur.insertHtml("<hr>"); 533 536 cur.insertBlock(fmt_paragraph); … … 537 540 538 541 SStep *step = root; 539 542 int c = n = 1; 540 543 pb->setFormat(tr("Generating step %v")); 541 while ( n < spinCities->value()) {544 while ((step->next != SStep::NoNextStep) && (c < spinCities->value())) { 542 545 if (pd.wasCanceled()) { 543 546 pd.setLabelText(tr("Cleaning up...")); … … 553 556 pd.setValue(n); 554 557 555 if (step->prNode->prNode != NULL || ((step->prNode->prNode == NULL) && (step->plNode->prNode == NULL))) { 556 if (n != spinCities->value()) { 557 cur.beginEditBlock(); 558 cur.insertBlock(fmt_paragraph); 559 cur.insertText(tr("Step #%1").arg(n++)); 560 if (settings->value("Output/ShowMatrix", DEF_SHOW_MATRIX).toBool() && (!settings->value("Output/UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT).toBool() || (settings->value("Output/UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT).toBool() && (spinCities->value() <= settings->value("Output/ShowMatrixLimit", DEF_SHOW_MATRIX_LIMIT).toInt())))) { 561 outputMatrix(cur, *step); 562 } 563 cur.insertBlock(fmt_paragraph); 564 cur.insertText(tr("Selected candidate for branching: %1.").arg(tr("(%1;%2)").arg(step->candidate.nRow + 1).arg(step->candidate.nCol + 1)), fmt_default); 565 if (!step->alts.empty()) { 566 SCandidate cand; 567 QString alts; 568 foreach(cand, step->alts) { 569 if (!alts.isEmpty()) 570 alts += ", "; 571 alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1); 572 } 573 cur.insertBlock(fmt_paragraph); 574 cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist); 575 } 576 cur.insertBlock(fmt_paragraph); 577 cur.insertText(" ", fmt_default); 578 cur.endEditBlock(); 558 cur.beginEditBlock(); 559 cur.insertBlock(fmt_paragraph); 560 cur.insertText(tr("Step #%1").arg(n)); 561 if (settings->value("Output/ShowMatrix", DEF_SHOW_MATRIX).toBool() && (!settings->value("Output/UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT).toBool() || (settings->value("Output/UseShowMatrixLimit", DEF_USE_SHOW_MATRIX_LIMIT).toBool() && (spinCities->value() <= settings->value("Output/ShowMatrixLimit", DEF_SHOW_MATRIX_LIMIT).toInt())))) { 562 outputMatrix(cur, *step); 563 } 564 cur.insertBlock(fmt_paragraph); 565 cur.insertText(tr("Selected route %1 %2 part.").arg((step->next == SStep::RightBranch) ? tr("with") : tr("without")).arg(tr("(%1;%2)").arg(step->candidate.nRow + 1).arg(step->candidate.nCol + 1)), fmt_default); 566 if (!step->alts.empty()) { 567 SStep::SCandidate cand; 568 QString alts; 569 foreach(cand, step->alts) { 570 if (!alts.isEmpty()) 571 alts += ", "; 572 alts += tr("(%1;%2)").arg(cand.nRow + 1).arg(cand.nCol + 1); 579 573 } 580 } 581 if (n < spinCities->value()) { 574 cur.insertBlock(fmt_paragraph); 575 cur.insertText(tr("%n alternate candidate(s) for branching: %1.", "", step->alts.count()).arg(alts), fmt_altlist); 576 } 577 cur.insertBlock(fmt_paragraph); 578 cur.insertText(" ", fmt_default); 579 cur.endEditBlock(); 580 581 if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) { 582 582 if (step->prNode != NULL) 583 drawNode(pic, n - 1, false, step->prNode);583 drawNode(pic, n, false, step->prNode); 584 584 if (step->plNode != NULL) 585 drawNode(pic, n - 1, true, step->plNode); 586 } 587 if (step->prNode->prNode != NULL) { 585 drawNode(pic, n, true, step->plNode); 586 } 587 n++; 588 589 if (step->next == SStep::RightBranch) { 590 c++; 588 591 step = step->prNode; 589 } else if (step-> plNode->prNode != NULL) {592 } else if (step->next == SStep::LeftBranch) { 590 593 step = step->plNode; 591 594 } else … … 617 620 } 618 621 cur.endEditBlock(); 619 pic.end(); 622 623 if (settings->value("Output/ShowGraph", DEF_SHOW_GRAPH).toBool()) { 624 pic.end(); 620 625 621 626 QImage i(graph.width() + 2, graph.height() + 2, QImage::Format_ARGB32); 622 i.fill(0);623 pic.begin(&i);624 pic.drawPicture(1, 1, graph);625 pic.end();626 doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i);627 i.fill(0); 628 pic.begin(&i); 629 pic.drawPicture(1, 1, graph); 630 pic.end(); 631 doc->addResource(QTextDocument::ImageResource, QUrl("tspsg://graph.pic"), i); 627 632 628 633 QTextImageFormat img; 629 img.setName("tspsg://graph.pic"); 630 631 cur.setPosition(imgpos); 632 cur.insertImage(img, QTextFrameFormat::FloatRight); 634 img.setName("tspsg://graph.pic"); 635 636 cur.setPosition(imgpos); 637 cur.insertImage(img, QTextFrameFormat::FloatRight); 638 } 633 639 634 640 if (settings->value("Output/ScrollToEnd", DEF_SCROLL_TO_END).toBool()) { … … 784 790 } 785 791 pic.setBackgroundMode(Qt::OpaqueMode); 786 pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, isInteger(step->price) ? QString("\n%1").arg(step->price) : QString("\n%1").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt())); 792 if (step->price != INFINITY) { 793 pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, isInteger(step->price) ? QString("\n%1").arg(step->price) : QString("\n%1").arg(step->price, 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt())); 794 } else { 795 pic.drawText(QRectF(x - r, y - r, r * 2, r * 2), Qt::AlignCenter, "\n"INFSTR); 796 } 787 797 pic.setBackgroundMode(Qt::TransparentMode); 788 798 } else { … … 790 800 } 791 801 792 if (nstep == 1) 793 pic.drawLine(QPointF(r * 2.25, r * (3 * (nstep - 1) + 2)), QPointF(x, y - r)); 794 else 795 pic.drawLine(QPointF(r * 3.5, r * (3 * (nstep - 1) + 2)), QPointF(x, y - r)); 802 if (nstep == 1) { 803 pic.drawLine(QPointF(x, y - r), QPointF(r * 2.25, y - 2 * r)); 804 } else if (nstep > 1) { 805 pic.drawLine(QPointF(x, y - r), QPointF((step->pNode->next == SStep::RightBranch) ? r * 3.5 : r, y - 2 * r)); 806 } 796 807 797 808 } … … 806 817 toggleSolutionActions(false); 807 818 808 ev->acceptProposedAction(); 819 ev->setDropAction(Qt::CopyAction); 820 ev->accept(); 809 821 } 810 822 } … … 992 1004 cur.insertText(isInteger(step.matrix.at(r).at(c)) ? QString("%1").arg(step.matrix.at(r).at(c)) : QString("%1").arg(step.matrix.at(r).at(c), 0, 'f', settings->value("Task/FractionalAccuracy", DEF_FRACTIONAL_ACCURACY).toInt()), fmt_selected); 993 1005 else { 994 S Candidate cand;1006 SStep::SCandidate cand; 995 1007 cand.nRow = r; 996 1008 cand.nCol = c; -
src/mainwindow.h
r345e7b6132 r9cda6e0f5d 34 34 #include "settingsdialog.h" 35 35 36 #include "tspsolver.h"37 36 #include "tspmodel.h" 37 38 using namespace TSPSolver; 38 39 39 40 /*! -
src/settingsdialog.cpp
r345e7b6132 r9cda6e0f5d 194 194 195 195 settings->beginGroup("Output"); 196 cbShowGraph->setChecked(settings->value("ShowGraph", DEF_SHOW_GRAPH).toBool()); 196 197 cbShowMatrix->setChecked(settings->value("ShowMatrix", DEF_SHOW_MATRIX).toBool()); 197 198 cbCitiesLimit->setEnabled(cbShowMatrix->isChecked()); … … 280 281 281 282 settings->beginGroup("Output"); 283 settings->setValue("ShowGraph", cbShowGraph->isChecked()); 282 284 settings->setValue("ShowMatrix", cbShowMatrix->isChecked()); 283 285 settings->setValue("UseShowMatrixLimit", cbShowMatrix->isChecked() && cbCitiesLimit->isChecked()); -
src/tspsolver.cpp
r345e7b6132 r9cda6e0f5d 27 27 #define MAX_DOUBLE std::numeric_limits<double>::max() 28 28 29 namespace TSPSolver { 30 29 31 /*! 30 32 * \brief Returns CTSPSolver's version ID. … … 41 43 */ 42 44 CTSPSolver::CTSPSolver(QObject *parent) 43 : QObject(parent), nCities(0), root(NULL) {}45 : QObject(parent), nCities(0), total(0), root(NULL) {} 44 46 45 47 /*! 46 48 * \brief Cleans up the object and frees up memory used by the solution tree. 47 * \param processEvents If set to \c true then \link QCoreApplication::processEvents() Q Application::processEvents(QEventLoop::ExcludeUserInputEvents)\endlink will be called from time to time while cleaning up.49 * \param processEvents If set to \c true then \link QCoreApplication::processEvents() QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents)\endlink will be called from time to time while cleaning up. 48 50 * \warning After call to this function a solution tree returned by the solve() function is no longer valid. 49 51 * \note It is not required to call this function manually. This function is always called by solve() at the beginning of the solution process. … … 53 55 void CTSPSolver::cleanup(bool processEvents) 54 56 { 57 #ifdef QAPPLICATION_H 55 58 if (!processEvents) 56 59 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 60 #endif 57 61 route.clear(); 58 62 mayNotBeOptimal = false; 59 63 if (root != NULL) 60 64 deleteTree(root, processEvents); 65 #ifdef QAPPLICATION_H 61 66 if (!processEvents) 62 67 QApplication::restoreOverrideCursor(); 68 #endif 63 69 } 64 70 … … 84 90 85 91 /*! 92 * \brief Returns a total number of steps in the current solution. 93 * \return A total number of steps or \c 0 if no solution. 94 * \note This is not always the same as the number of cities. 95 */ 96 int CTSPSolver::getTotalSteps() const 97 { 98 return total; 99 } 100 101 /*! 86 102 * \brief Indicates whether or not the solution is definitely optimal. 87 103 * \return \c true if the solution is definitely optimal, otherwise \c false. … … 105 121 SStep *CTSPSolver::solve(int numCities, const TMatrix &task) 106 122 { 107 if (numCities < = 1)123 if (numCities < 3) 108 124 return NULL; 109 125 … … 131 147 bool firstStep = true; 132 148 double check = INFINITY; 133 while (this->route.size() < nCities) { 149 total = 0; 150 while (route.size() < nCities) { 134 151 step->alts = findCandidate(step->matrix,nRow,nCol); 135 152 … … 188 205 if (right->price <= left->price) { 189 206 // Route with (nRow,nCol) path is cheaper 207 step->next = SStep::RightBranch; 190 208 step = right; 191 this->route[nRow] = nCol;192 emit routePartFound( this->route.size());209 route[nRow] = nCol; 210 emit routePartFound(route.size()); 193 211 if (firstStep) { 194 212 check = left->price; … … 197 215 } else { 198 216 // Route without (nRow,nCol) path is cheaper 217 step->next = SStep::LeftBranch; 199 218 step = left; 200 qApp->processEvents();219 QCoreApplication::processEvents(); 201 220 if (firstStep) { 202 221 check = right->price; … … 204 223 } 205 224 } 206 }207 208 route = this->route; 225 total++; 226 } 227 209 228 mayNotBeOptimal = (check < step->price); 210 229 … … 259 278 } 260 279 } 261 return r;280 return (r != MAX_DOUBLE) ? r : INFINITY; 262 281 } 263 282 … … 270 289 forever { 271 290 if (processEvents) 272 Q Application::processEvents(QEventLoop::ExcludeUserInputEvents);291 QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); 273 292 if (step->plNode != NULL) { 274 293 // We have left child node - going inside it … … 282 301 continue; 283 302 } else { 284 // We have no child nodes. Deleting current one.303 // We have no child nodes. Deleting the current one. 285 304 parent = step->pNode; 286 305 delete step; … … 305 324 } 306 325 307 QList<S Candidate> CTSPSolver::findCandidate(const TMatrix &matrix, int &nRow, int &nCol) const326 QList<SStep::SCandidate> CTSPSolver::findCandidate(const TMatrix &matrix, int &nRow, int &nCol) const 308 327 { 309 328 nRow = -1; 310 329 nCol = -1; 311 QList<S Candidate> alts;312 S Candidate cand;330 QList<SStep::SCandidate> alts; 331 SStep::SCandidate cand; 313 332 double h = -1; 314 333 double sum; 315 334 for (int r = 0; r < nCities; r++) 316 335 for (int c = 0; c < nCities; c++) 317 // if ((matrix.at(r).at(c) == 0) && !forbidden.values(r).contains(c)) {318 336 if (matrix.at(r).at(c) == 0) { 319 337 sum = findMinInRow(r,matrix,c) + findMinInCol(c,matrix,r); … … 356 374 return false; 357 375 int i = nCol; 358 while (true){359 if ((i = route [i]) == nRow)376 forever { 377 if ((i = route.value(i)) == nRow) 360 378 return true; 361 379 if (!route.contains(i)) … … 387 405 } 388 406 407 } 408 389 409 #ifdef DEBUG 390 QDebug operator<<(QDebug dbg, const T Matrix &matrix)410 QDebug operator<<(QDebug dbg, const TSPSolver::TMatrix &matrix) 391 411 { 392 412 for (int r = 0; r < matrix.count(); r++) { … … 398 418 } 399 419 400 QDebug operator<<(QDebug dbg, const SCandidate &cand)420 QDebug operator<<(QDebug dbg, const TSPSolver::SStep::SCandidate &cand) 401 421 { 402 422 dbg.nospace() << "(" << cand.nRow << ";" << cand.nCol << ")"; -
src/tspsolver.h
r345e7b6132 r9cda6e0f5d 6 6 * $URL$ 7 7 * 8 * \brief Defines #TMatrix typedef, SCandidate and SStep structs and CTSPSolver class.8 * \brief Defines TSPSolver namespace and everything needed for solving TSP tasks. 9 9 * 10 10 * <b>TSPSG: TSP Solver and Generator</b> … … 29 29 #define TSPSOLVER_H 30 30 31 #include "globals.h" 32 33 #include "tspmodel.h" 34 35 //! A matrix of city-to-city travel costs. 36 typedef QList<QList<double> > TMatrix; 31 #include <QtCore> 32 #include <limits> 37 33 38 34 /*! 39 * \brief A structure that represents a candidate for branching. 35 * \def INFINITY 36 * \brief This value means infinity :-) 37 * 38 * Some libraries already have \c INFINITY defined. 39 * We need to redefine it for the \c INFINITY to always have the same value. 40 40 */ 41 struct SCandidate { 42 int nRow; //!< A zero-based row number of the candidate 43 int nCol; //!< A zero-based column number of the candidate 41 #ifdef INFINITY 42 #undef INFINITY 43 #endif 44 #define INFINITY std::numeric_limits<double>::infinity() 44 45 45 //! Assigns default values 46 SCandidate() { 47 nCol = nRow = -1; 48 } 49 //! An operator == implementation 50 bool operator ==(const SCandidate &cand) const{51 return ((cand.nRow == nRow) && (cand.nCol == nCol)); 52 } 53 };46 /*! 47 * \brief A TSP Solver namespace. 48 * 49 * This namespace contains all the stuff required for solving TSP tasks. 50 */ 51 namespace TSPSolver { 52 53 //! A matrix of city-to-city travel costs 54 typedef QList<QList<double> > TMatrix; 54 55 55 56 /*! … … 59 60 */ 60 61 struct SStep { 62 //! A structure that represents a candidate for branching 63 struct SCandidate { 64 int nRow; //!< A zero-based row number of the candidate 65 int nCol; //!< A zero-based column number of the candidate 66 67 //! Assigns default values 68 SCandidate() { 69 nCol = nRow = -1; 70 } 71 //! An operator == implementation 72 bool operator ==(const SCandidate &cand) const { 73 return ((cand.nRow == nRow) && (cand.nCol == nCol)); 74 } 75 }; 76 77 //! An enum that describes possible selection of the next step 78 enum NextStep { 79 NoNextStep, //!< No next step (end of solution) 80 LeftBranch, //!< Left branch was selected for the next step 81 RightBranch //!< Right branch was selected for the next step 82 }; 83 61 84 TMatrix matrix; //!< This step's matrix 62 85 double price; //!< The price of travel to this step 63 SCandidate candidate; //!< A candiadate for branching in the current matrix 86 87 SCandidate candidate; //!< A candiadate for branching in the current step 64 88 QList<SCandidate> alts; //!< A list of alternative branching candidates 65 89 SStep *pNode; //!< Pointer to the parent step 66 90 SStep *plNode; //!< Pointer to the left branch step 67 91 SStep *prNode; //!< Pointer to the right branch step 92 NextStep next; //!< Indicates what branch was selected for the next step 68 93 69 94 //! Assigns default values … … 71 96 price = -1; 72 97 pNode = plNode = prNode = NULL; 98 next = NoNextStep; 73 99 } 74 100 }; … … 88 114 void cleanup(bool processEvents = false); 89 115 QString getSortedPath() const; 116 int getTotalSteps() const; 90 117 bool isOptimal() const; 91 118 SStep *solve(int numCities, const TMatrix &task); … … 105 132 private: 106 133 bool mayNotBeOptimal, canceled; 107 int nCities ;134 int nCities, total; 108 135 SStep *root; 109 136 QHash<int,int> route; … … 113 140 void deleteTree(SStep *&root, bool processEvents = false); 114 141 void denormalize(TMatrix &matrix) const; 115 QList<S Candidate> findCandidate(const TMatrix &matrix, int &nRow, int &nCol) const;142 QList<SStep::SCandidate> findCandidate(const TMatrix &matrix, int &nRow, int &nCol) const; 116 143 double findMinInCol(int nCol, const TMatrix &matrix, int exr = -1) const; 117 144 double findMinInRow(int nRow, const TMatrix &matrix, int exc = -1) const; 145 void finishRoute(); 118 146 bool hasSubCycles(int nRow, int nCol) const; 119 147 void normalize(TMatrix &matrix) const; … … 122 150 }; 123 151 152 } 153 124 154 #ifdef DEBUG 125 QDebug operator<<(QDebug dbg, const T Matrix &matrix);126 QDebug operator<<(QDebug dbg, const SCandidate &candidate);155 QDebug operator<<(QDebug dbg, const TSPSolver::TMatrix &matrix); 156 QDebug operator<<(QDebug dbg, const TSPSolver::SStep::SCandidate &candidate); 127 157 #endif // DEBUG 128 158 -
ui/settingsdialog.ui
r345e7b6132 r9cda6e0f5d 289 289 <layout class="QVBoxLayout" name="_6"> 290 290 <item> 291 <widget class="QCheckBox" name="cbShowGraph"> 292 <property name="cursor"> 293 <cursorShape>PointingHandCursor</cursorShape> 294 </property> 295 <property name="statusTip"> 296 <string>Show graphical representation of the solution</string> 297 </property> 298 <property name="text"> 299 <string>Show solution graph</string> 300 </property> 301 </widget> 302 </item> 303 <item> 291 304 <widget class="QCheckBox" name="cbShowMatrix"> 292 305 <property name="cursor">
Note: See TracChangeset
for help on using the changeset viewer.