util/src/gui/graphicsview/qsimplex_p.cpp
changeset 7 f7bc934e204c
equal deleted inserted replaced
3:41300fa6a67c 7:f7bc934e204c
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qsimplex_p.h"
       
    43 
       
    44 #include <QtCore/qset.h>
       
    45 #include <QtCore/qdebug.h>
       
    46 
       
    47 #include <stdlib.h>
       
    48 
       
    49 QT_BEGIN_NAMESPACE
       
    50 
       
    51 /*!
       
    52   \internal
       
    53   \class QSimplex
       
    54 
       
    55   The QSimplex class is a Linear Programming problem solver based on the two-phase
       
    56   simplex method.
       
    57 
       
    58   It takes a set of QSimplexConstraints as its restrictive constraints and an
       
    59   additional QSimplexConstraint as its objective function. Then methods to maximize
       
    60   and minimize the problem solution are provided.
       
    61 
       
    62   The two-phase simplex method is based on the following steps:
       
    63   First phase:
       
    64   1.a) Modify the original, complex, and possibly not feasible problem, into a new,
       
    65        easy to solve problem.
       
    66   1.b) Set as the objective of the new problem, a feasible solution for the original
       
    67        complex problem.
       
    68   1.c) Run simplex to optimize the modified problem and check whether a solution for
       
    69        the original problem exists.
       
    70 
       
    71   Second phase:
       
    72   2.a) Go back to the original problem with the feasibl (but not optimal) solution
       
    73        found in the first phase.
       
    74   2.b) Set the original objective.
       
    75   3.c) Run simplex to optimize the original problem towards its optimal solution.
       
    76 */
       
    77 
       
    78 /*!
       
    79   \internal
       
    80 */
       
    81 QSimplex::QSimplex() : objective(0), rows(0), columns(0), firstArtificial(0), matrix(0)
       
    82 {
       
    83 }
       
    84 
       
    85 /*!
       
    86   \internal
       
    87 */
       
    88 QSimplex::~QSimplex()
       
    89 {
       
    90     clearDataStructures();
       
    91 }
       
    92 
       
    93 /*!
       
    94   \internal
       
    95 */
       
    96 void QSimplex::clearDataStructures()
       
    97 {
       
    98     if (matrix == 0)
       
    99         return;
       
   100 
       
   101     // Matrix
       
   102     rows = 0;
       
   103     columns = 0;
       
   104     firstArtificial = 0;
       
   105     free(matrix);
       
   106     matrix = 0;
       
   107 
       
   108     // Constraints
       
   109     for (int i = 0; i < constraints.size(); ++i) {
       
   110         delete constraints[i]->helper.first;
       
   111         delete constraints[i]->artificial;
       
   112         delete constraints[i];
       
   113     }
       
   114     constraints.clear();
       
   115 
       
   116     // Other
       
   117     variables.clear();
       
   118     objective = 0;
       
   119 }
       
   120 
       
   121 /*!
       
   122   \internal
       
   123   Sets the new constraints in the simplex solver and returns whether the problem
       
   124   is feasible.
       
   125 
       
   126   This method sets the new constraints, normalizes them, creates the simplex matrix
       
   127   and runs the first simplex phase.
       
   128 */
       
   129 bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints)
       
   130 {
       
   131     ////////////////////////////
       
   132     // Reset to initial state //
       
   133     ////////////////////////////
       
   134     clearDataStructures();
       
   135 
       
   136     if (newConstraints.isEmpty())
       
   137         return true;    // we are ok with no constraints
       
   138 
       
   139     // Make deep copy of constraints. We need this copy because we may change
       
   140     // them in the simplification method.
       
   141     for (int i = 0; i < newConstraints.size(); ++i) {
       
   142         QSimplexConstraint *c = new QSimplexConstraint;
       
   143         c->constant = newConstraints[i]->constant;
       
   144         c->ratio = newConstraints[i]->ratio;
       
   145         c->variables = newConstraints[i]->variables;
       
   146         constraints << c;
       
   147     }
       
   148 
       
   149     // Remove constraints of type Var == K and replace them for their value.
       
   150     if (!simplifyConstraints(&constraints)) {
       
   151         qWarning() << "QSimplex: No feasible solution!";
       
   152         clearDataStructures();
       
   153         return false;
       
   154     }
       
   155 
       
   156     ///////////////////////////////////////
       
   157     // Prepare variables and constraints //
       
   158     ///////////////////////////////////////
       
   159 
       
   160     // Set Variables direct mapping.
       
   161     // "variables" is a list that provides a stable, indexed list of all variables
       
   162     // used in this problem.
       
   163     QSet<QSimplexVariable *> variablesSet;
       
   164     for (int i = 0; i < constraints.size(); ++i)
       
   165         variablesSet += \
       
   166             QSet<QSimplexVariable *>::fromList(constraints[i]->variables.keys());
       
   167     variables = variablesSet.toList();
       
   168 
       
   169     // Set Variables reverse mapping
       
   170     // We also need to be able to find the index for a given variable, to do that
       
   171     // we store in each variable its index.
       
   172     for (int i = 0; i < variables.size(); ++i) {
       
   173         // The variable "0" goes at the column "1", etc...
       
   174         variables[i]->index = i + 1;
       
   175     }
       
   176 
       
   177     // Normalize Constraints
       
   178     // In this step, we prepare the constraints in two ways:
       
   179     // Firstly, we modify all constraints of type "LessOrEqual" or "MoreOrEqual"
       
   180     // by the adding slack or surplus variables and making them "Equal" constraints.
       
   181     // Secondly, we need every single constraint to have a direct, easy feasible
       
   182     // solution. Constraints that have slack variables are already easy to solve,
       
   183     // to all the others we add artificial variables.
       
   184     //
       
   185     // At the end we modify the constraints as follows:
       
   186     //  - LessOrEqual: SLACK variable is added.
       
   187     //  - Equal: ARTIFICIAL variable is added.
       
   188     //  - More or Equal: ARTIFICIAL and SURPLUS variables are added.
       
   189     int variableIndex = variables.size();
       
   190     QList <QSimplexVariable *> artificialList;
       
   191 
       
   192     for (int i = 0; i < constraints.size(); ++i) {
       
   193         QSimplexVariable *slack;
       
   194         QSimplexVariable *surplus;
       
   195         QSimplexVariable *artificial;
       
   196 
       
   197         Q_ASSERT(constraints[i]->helper.first == 0);
       
   198         Q_ASSERT(constraints[i]->artificial == 0);
       
   199 
       
   200         switch(constraints[i]->ratio) {
       
   201         case QSimplexConstraint::LessOrEqual:
       
   202             slack = new QSimplexVariable;
       
   203             slack->index = ++variableIndex;
       
   204             constraints[i]->helper.first = slack;
       
   205             constraints[i]->helper.second = 1.0;
       
   206             break;
       
   207         case QSimplexConstraint::MoreOrEqual:
       
   208             surplus = new QSimplexVariable;
       
   209             surplus->index = ++variableIndex;
       
   210             constraints[i]->helper.first = surplus;
       
   211             constraints[i]->helper.second = -1.0;
       
   212             // fall through
       
   213         case QSimplexConstraint::Equal:
       
   214             artificial = new QSimplexVariable;
       
   215             constraints[i]->artificial = artificial;
       
   216             artificialList += constraints[i]->artificial;
       
   217             break;
       
   218         }
       
   219     }
       
   220 
       
   221     // All original, slack and surplus have already had its index set
       
   222     // at this point. We now set the index of the artificial variables
       
   223     // as to ensure they are at the end of the variable list and therefore
       
   224     // can be easily removed at the end of this method.
       
   225     firstArtificial = variableIndex + 1;
       
   226     for (int i = 0; i < artificialList.size(); ++i)
       
   227         artificialList[i]->index = ++variableIndex;
       
   228     artificialList.clear();
       
   229 
       
   230     /////////////////////////////
       
   231     // Fill the Simplex matrix //
       
   232     /////////////////////////////
       
   233 
       
   234     // One for each variable plus the Basic and BFS columns (first and last)
       
   235     columns = variableIndex + 2;
       
   236     // One for each constraint plus the objective function
       
   237     rows = constraints.size() + 1;
       
   238 
       
   239     matrix = (qreal *)malloc(sizeof(qreal) * columns * rows);
       
   240     if (!matrix) {
       
   241         qWarning() << "QSimplex: Unable to allocate memory!";
       
   242         return false;
       
   243     }
       
   244     for (int i = columns * rows - 1; i >= 0; --i)
       
   245         matrix[i] = 0.0;
       
   246 
       
   247     // Fill Matrix
       
   248     for (int i = 1; i <= constraints.size(); ++i) {
       
   249         QSimplexConstraint *c = constraints[i - 1];
       
   250 
       
   251         if (c->artificial) {
       
   252             // Will use artificial basic variable
       
   253             setValueAt(i, 0, c->artificial->index);
       
   254             setValueAt(i, c->artificial->index, 1.0);
       
   255 
       
   256             if (c->helper.second != 0.0) {
       
   257                 // Surplus variable
       
   258                 setValueAt(i, c->helper.first->index, c->helper.second);
       
   259             }
       
   260         } else {
       
   261             // Slack is used as the basic variable
       
   262             Q_ASSERT(c->helper.second == 1.0);
       
   263             setValueAt(i, 0, c->helper.first->index);
       
   264             setValueAt(i, c->helper.first->index, 1.0);
       
   265         }
       
   266 
       
   267         QHash<QSimplexVariable *, qreal>::const_iterator iter;
       
   268         for (iter = c->variables.constBegin();
       
   269              iter != c->variables.constEnd();
       
   270              ++iter) {
       
   271             setValueAt(i, iter.key()->index, iter.value());
       
   272         }
       
   273 
       
   274         setValueAt(i, columns - 1, c->constant);
       
   275     }
       
   276 
       
   277     // Set objective for the first-phase Simplex.
       
   278     // Z = -1 * sum_of_artificial_vars
       
   279     for (int j = firstArtificial; j < columns - 1; ++j)
       
   280         setValueAt(0, j, 1.0);
       
   281 
       
   282     // Maximize our objective (artificial vars go to zero)
       
   283     solveMaxHelper();
       
   284 
       
   285     // If there is a solution where the sum of all artificial
       
   286     // variables is zero, then all of them can be removed and yet
       
   287     // we will have a feasible (but not optimal) solution for the
       
   288     // original problem.
       
   289     // Otherwise, we clean up our structures and report there is
       
   290     // no feasible solution.
       
   291     if ((valueAt(0, columns - 1) != 0.0) && (qAbs(valueAt(0, columns - 1)) > 0.00001)) {
       
   292         qWarning() << "QSimplex: No feasible solution!";
       
   293         clearDataStructures();
       
   294         return false;
       
   295     }
       
   296 
       
   297     // Remove artificial variables. We already have a feasible
       
   298     // solution for the first problem, thus we don't need them
       
   299     // anymore.
       
   300     clearColumns(firstArtificial, columns - 2);
       
   301 
       
   302     return true;
       
   303 }
       
   304 
       
   305 /*!
       
   306   \internal
       
   307 
       
   308   Run simplex on the current matrix with the current objective.
       
   309 
       
   310   This is the iterative method. The matrix lines are combined
       
   311   as to modify the variable values towards the best solution possible.
       
   312   The method returns when the matrix is in the optimal state.
       
   313 */
       
   314 void QSimplex::solveMaxHelper()
       
   315 {
       
   316     reducedRowEchelon();
       
   317     while (iterate()) ;
       
   318 }
       
   319 
       
   320 /*!
       
   321   \internal
       
   322 */
       
   323 void QSimplex::setObjective(QSimplexConstraint *newObjective)
       
   324 {
       
   325     objective = newObjective;
       
   326 }
       
   327 
       
   328 /*!
       
   329   \internal
       
   330 */
       
   331 void QSimplex::clearRow(int rowIndex)
       
   332 {
       
   333     qreal *item = matrix + rowIndex * columns;
       
   334     for (int i = 0; i < columns; ++i)
       
   335         item[i] = 0.0;
       
   336 }
       
   337 
       
   338 /*!
       
   339   \internal
       
   340 */
       
   341 void QSimplex::clearColumns(int first, int last)
       
   342 {
       
   343     for (int i = 0; i < rows; ++i) {
       
   344         qreal *row = matrix + i * columns;
       
   345         for (int j = first; j <= last; ++j)
       
   346             row[j] = 0.0;
       
   347     }
       
   348 }
       
   349 
       
   350 /*!
       
   351   \internal
       
   352 */
       
   353 void QSimplex::dumpMatrix()
       
   354 {
       
   355     qDebug("---- Simplex Matrix ----\n");
       
   356 
       
   357     QString str(QLatin1String("       "));
       
   358     for (int j = 0; j < columns; ++j)
       
   359         str += QString::fromAscii("  <%1 >").arg(j, 2);
       
   360     qDebug("%s", qPrintable(str));
       
   361     for (int i = 0; i < rows; ++i) {
       
   362         str = QString::fromAscii("Row %1:").arg(i, 2);
       
   363 
       
   364         qreal *row = matrix + i * columns;
       
   365         for (int j = 0; j < columns; ++j)
       
   366             str += QString::fromAscii("%1").arg(row[j], 7, 'f', 2);
       
   367         qDebug("%s", qPrintable(str));
       
   368     }
       
   369     qDebug("------------------------\n");
       
   370 }
       
   371 
       
   372 /*!
       
   373   \internal
       
   374 */
       
   375 void QSimplex::combineRows(int toIndex, int fromIndex, qreal factor)
       
   376 {
       
   377     if (!factor)
       
   378         return;
       
   379 
       
   380     qreal *from = matrix + fromIndex * columns;
       
   381     qreal *to = matrix + toIndex * columns;
       
   382 
       
   383     for (int j = 1; j < columns; ++j) {
       
   384         qreal value = from[j];
       
   385 
       
   386         // skip to[j] = to[j] + factor*0.0
       
   387         if (value == 0.0)
       
   388             continue;
       
   389 
       
   390         to[j] += factor * value;
       
   391 
       
   392         // ### Avoid Numerical errors
       
   393         if (qAbs(to[j]) < 0.0000000001)
       
   394             to[j] = 0.0;
       
   395     }
       
   396 }
       
   397 
       
   398 /*!
       
   399   \internal
       
   400 */
       
   401 int QSimplex::findPivotColumn()
       
   402 {
       
   403     qreal min = 0;
       
   404     int minIndex = -1;
       
   405 
       
   406     for (int j = 0; j < columns-1; ++j) {
       
   407         if (valueAt(0, j) < min) {
       
   408             min = valueAt(0, j);
       
   409             minIndex = j;
       
   410         }
       
   411     }
       
   412 
       
   413     return minIndex;
       
   414 }
       
   415 
       
   416 /*!
       
   417   \internal
       
   418 
       
   419   For a given pivot column, find the pivot row. That is, the row with the
       
   420   minimum associated "quotient" where:
       
   421 
       
   422   - quotient is the division of the value in the last column by the value
       
   423     in the pivot column.
       
   424   - rows with value less or equal to zero are ignored
       
   425   - if two rows have the same quotient, lines are chosen based on the
       
   426     highest variable index (value in the first column)
       
   427 
       
   428   The last condition avoids a bug where artificial variables would be
       
   429   left behind for the second-phase simplex, and with 'good'
       
   430   constraints would be removed before it, what would lead to incorrect
       
   431   results.
       
   432 */
       
   433 int QSimplex::pivotRowForColumn(int column)
       
   434 {
       
   435     qreal min = qreal(999999999999.0); // ###
       
   436     int minIndex = -1;
       
   437 
       
   438     for (int i = 1; i < rows; ++i) {
       
   439         qreal divisor = valueAt(i, column);
       
   440         if (divisor <= 0)
       
   441             continue;
       
   442 
       
   443         qreal quotient = valueAt(i, columns - 1) / divisor;
       
   444         if (quotient < min) {
       
   445             min = quotient;
       
   446             minIndex = i;
       
   447         } else if ((quotient == min) && (valueAt(i, 0) > valueAt(minIndex, 0))) {
       
   448             minIndex = i;
       
   449         }
       
   450     }
       
   451 
       
   452     return minIndex;
       
   453 }
       
   454 
       
   455 /*!
       
   456   \internal
       
   457 */
       
   458 void QSimplex::reducedRowEchelon()
       
   459 {
       
   460     for (int i = 1; i < rows; ++i) {
       
   461         int factorInObjectiveRow = valueAt(i, 0);
       
   462         combineRows(0, i, -1 * valueAt(0, factorInObjectiveRow));
       
   463     }
       
   464 }
       
   465 
       
   466 /*!
       
   467   \internal
       
   468 
       
   469   Does one iteration towards a better solution for the problem.
       
   470   See 'solveMaxHelper'.
       
   471 */
       
   472 bool QSimplex::iterate()
       
   473 {
       
   474     // Find Pivot column
       
   475     int pivotColumn = findPivotColumn();
       
   476     if (pivotColumn == -1)
       
   477         return false;
       
   478 
       
   479     // Find Pivot row for column
       
   480     int pivotRow = pivotRowForColumn(pivotColumn);
       
   481     if (pivotRow == -1) {
       
   482         qWarning() << "QSimplex: Unbounded problem!";
       
   483         return false;
       
   484     }
       
   485 
       
   486     // Normalize Pivot Row
       
   487     qreal pivot = valueAt(pivotRow, pivotColumn);
       
   488     if (pivot != 1.0)
       
   489         combineRows(pivotRow, pivotRow, (1.0 - pivot) / pivot);
       
   490 
       
   491     // Update other rows
       
   492     for (int row=0; row < rows; ++row) {
       
   493         if (row == pivotRow)
       
   494             continue;
       
   495 
       
   496         combineRows(row, pivotRow, -1 * valueAt(row, pivotColumn));
       
   497     }
       
   498 
       
   499     // Update first column
       
   500     setValueAt(pivotRow, 0, pivotColumn);
       
   501 
       
   502     //    dumpMatrix();
       
   503     //    qDebug("------------ end of iteration --------------\n");
       
   504     return true;
       
   505 }
       
   506 
       
   507 /*!
       
   508   \internal
       
   509 
       
   510   Both solveMin and solveMax are interfaces to this method.
       
   511 
       
   512   The enum solverFactor admits 2 values: Minimum (-1) and Maximum (+1).
       
   513 
       
   514   This method sets the original objective and runs the second phase
       
   515   Simplex to obtain the optimal solution for the problem. As the internal
       
   516   simplex solver is only able to _maximize_ objectives, we handle the
       
   517   minimization case by inverting the original objective and then
       
   518   maximizing it.
       
   519 */
       
   520 qreal QSimplex::solver(solverFactor factor)
       
   521 {
       
   522     // Remove old objective
       
   523     clearRow(0);
       
   524 
       
   525     // Set new objective in the first row of the simplex matrix
       
   526     qreal resultOffset = 0;
       
   527     QHash<QSimplexVariable *, qreal>::const_iterator iter;
       
   528     for (iter = objective->variables.constBegin();
       
   529          iter != objective->variables.constEnd();
       
   530          ++iter) {
       
   531 
       
   532         // Check if the variable was removed in the simplification process.
       
   533         // If so, we save its offset to the objective function and skip adding
       
   534         // it to the matrix.
       
   535         if (iter.key()->index == -1) {
       
   536             resultOffset += iter.value() * iter.key()->result;
       
   537             continue;
       
   538         }
       
   539 
       
   540         setValueAt(0, iter.key()->index, -1 * factor * iter.value());
       
   541     }
       
   542 
       
   543     solveMaxHelper();
       
   544     collectResults();
       
   545 
       
   546 #ifdef QT_DEBUG
       
   547     for (int i = 0; i < constraints.size(); ++i) {
       
   548         Q_ASSERT(constraints[i]->isSatisfied());
       
   549     }
       
   550 #endif
       
   551 
       
   552     // Return the value calculated by the simplex plus the value of the
       
   553     // fixed variables.
       
   554     return (factor * valueAt(0, columns - 1)) + resultOffset;
       
   555 }
       
   556 
       
   557 /*!
       
   558   \internal
       
   559   Minimize the original objective.
       
   560 */
       
   561 qreal QSimplex::solveMin()
       
   562 {
       
   563     return solver(Minimum);
       
   564 }
       
   565 
       
   566 /*!
       
   567   \internal
       
   568   Maximize the original objective.
       
   569 */
       
   570 qreal QSimplex::solveMax()
       
   571 {
       
   572     return solver(Maximum);
       
   573 }
       
   574 
       
   575 /*!
       
   576   \internal
       
   577 
       
   578   Reads results from the simplified matrix and saves them in the
       
   579   "result" member of each QSimplexVariable.
       
   580 */
       
   581 void QSimplex::collectResults()
       
   582 {
       
   583     // All variables are zero unless overridden below.
       
   584 
       
   585     // ### Is this really needed? Is there any chance that an
       
   586     // important variable remains as non-basic at the end of simplex?
       
   587     for (int i = 0; i < variables.size(); ++i)
       
   588         variables[i]->result = 0;
       
   589 
       
   590     // Basic variables
       
   591     // Update the variable indicated in the first column with the value
       
   592     // in the last column.
       
   593     for (int i = 1; i < rows; ++i) {
       
   594         int index = valueAt(i, 0) - 1;
       
   595         if (index < variables.size())
       
   596             variables[index]->result = valueAt(i, columns - 1);
       
   597     }
       
   598 }
       
   599 
       
   600 /*!
       
   601   \internal
       
   602 
       
   603   Looks for single-valued variables and remove them from the constraints list.
       
   604 */
       
   605 bool QSimplex::simplifyConstraints(QList<QSimplexConstraint *> *constraints)
       
   606 {
       
   607     QHash<QSimplexVariable *, qreal> results;   // List of single-valued variables
       
   608     bool modified = true;                       // Any chance more optimization exists?
       
   609 
       
   610     while (modified) {
       
   611         modified = false;
       
   612 
       
   613         // For all constraints
       
   614         QList<QSimplexConstraint *>::iterator iter = constraints->begin();
       
   615         while (iter != constraints->end()) {
       
   616             QSimplexConstraint *c = *iter;
       
   617             if ((c->ratio == QSimplexConstraint::Equal) && (c->variables.count() == 1)) {
       
   618                 // Check whether this is a constraint of type Var == K
       
   619                 // If so, save its value to "results".
       
   620                 QSimplexVariable *variable = c->variables.constBegin().key();
       
   621                 qreal result = c->constant / c->variables.value(variable);
       
   622 
       
   623                 results.insert(variable, result);
       
   624                 variable->result = result;
       
   625                 variable->index = -1;
       
   626                 modified = true;
       
   627 
       
   628             }
       
   629 
       
   630             // Replace known values among their variables
       
   631             QHash<QSimplexVariable *, qreal>::const_iterator r;
       
   632             for (r = results.constBegin(); r != results.constEnd(); ++r) {
       
   633                 if (c->variables.contains(r.key())) {
       
   634                     c->constant -= r.value() * c->variables.take(r.key());
       
   635                     modified = true;
       
   636                 }
       
   637             }
       
   638 
       
   639             // Keep it normalized
       
   640             if (c->constant < 0)
       
   641                 c->invert();
       
   642 
       
   643             if (c->variables.isEmpty()) {
       
   644                 // If constraint became empty due to substitution, delete it.
       
   645                 if (c->isSatisfied() == false)
       
   646                     // We must ensure that the constraint soon to be deleted would not
       
   647                     // make the problem unfeasible if left behind. If that's the case,
       
   648                     // we return false so the simplex solver can properly report that.
       
   649                     return false;
       
   650 
       
   651                 delete c;
       
   652                 iter = constraints->erase(iter);
       
   653             } else {
       
   654                 ++iter;
       
   655             }
       
   656         }
       
   657     }
       
   658 
       
   659     return true;
       
   660 }
       
   661 
       
   662 void QSimplexConstraint::invert()
       
   663 {
       
   664     constant = -constant;
       
   665     ratio = Ratio(2 - ratio);
       
   666 
       
   667     QHash<QSimplexVariable *, qreal>::iterator iter;
       
   668     for (iter = variables.begin(); iter != variables.end(); ++iter) {
       
   669         iter.value() = -iter.value();
       
   670     }
       
   671 }
       
   672 
       
   673 QT_END_NAMESPACE