summaryrefslogtreecommitdiffstats
path: root/src/gui/graphicsview/qsimplex_p.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/graphicsview/qsimplex_p.cpp')
-rw-r--r--src/gui/graphicsview/qsimplex_p.cpp673
1 files changed, 0 insertions, 673 deletions
diff --git a/src/gui/graphicsview/qsimplex_p.cpp b/src/gui/graphicsview/qsimplex_p.cpp
deleted file mode 100644
index d2d9646b90..0000000000
--- a/src/gui/graphicsview/qsimplex_p.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsimplex_p.h"
-
-#include <QtCore/qset.h>
-#include <QtCore/qdebug.h>
-
-#include <stdlib.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \internal
- \class QSimplex
-
- The QSimplex class is a Linear Programming problem solver based on the two-phase
- simplex method.
-
- It takes a set of QSimplexConstraints as its restrictive constraints and an
- additional QSimplexConstraint as its objective function. Then methods to maximize
- and minimize the problem solution are provided.
-
- The two-phase simplex method is based on the following steps:
- First phase:
- 1.a) Modify the original, complex, and possibly not feasible problem, into a new,
- easy to solve problem.
- 1.b) Set as the objective of the new problem, a feasible solution for the original
- complex problem.
- 1.c) Run simplex to optimize the modified problem and check whether a solution for
- the original problem exists.
-
- Second phase:
- 2.a) Go back to the original problem with the feasibl (but not optimal) solution
- found in the first phase.
- 2.b) Set the original objective.
- 3.c) Run simplex to optimize the original problem towards its optimal solution.
-*/
-
-/*!
- \internal
-*/
-QSimplex::QSimplex() : objective(0), rows(0), columns(0), firstArtificial(0), matrix(0)
-{
-}
-
-/*!
- \internal
-*/
-QSimplex::~QSimplex()
-{
- clearDataStructures();
-}
-
-/*!
- \internal
-*/
-void QSimplex::clearDataStructures()
-{
- if (matrix == 0)
- return;
-
- // Matrix
- rows = 0;
- columns = 0;
- firstArtificial = 0;
- free(matrix);
- matrix = 0;
-
- // Constraints
- for (int i = 0; i < constraints.size(); ++i) {
- delete constraints[i]->helper.first;
- delete constraints[i]->artificial;
- delete constraints[i];
- }
- constraints.clear();
-
- // Other
- variables.clear();
- objective = 0;
-}
-
-/*!
- \internal
- Sets the new constraints in the simplex solver and returns whether the problem
- is feasible.
-
- This method sets the new constraints, normalizes them, creates the simplex matrix
- and runs the first simplex phase.
-*/
-bool QSimplex::setConstraints(const QList<QSimplexConstraint *> newConstraints)
-{
- ////////////////////////////
- // Reset to initial state //
- ////////////////////////////
- clearDataStructures();
-
- if (newConstraints.isEmpty())
- return true; // we are ok with no constraints
-
- // Make deep copy of constraints. We need this copy because we may change
- // them in the simplification method.
- for (int i = 0; i < newConstraints.size(); ++i) {
- QSimplexConstraint *c = new QSimplexConstraint;
- c->constant = newConstraints[i]->constant;
- c->ratio = newConstraints[i]->ratio;
- c->variables = newConstraints[i]->variables;
- constraints << c;
- }
-
- // Remove constraints of type Var == K and replace them for their value.
- if (!simplifyConstraints(&constraints)) {
- qWarning() << "QSimplex: No feasible solution!";
- clearDataStructures();
- return false;
- }
-
- ///////////////////////////////////////
- // Prepare variables and constraints //
- ///////////////////////////////////////
-
- // Set Variables direct mapping.
- // "variables" is a list that provides a stable, indexed list of all variables
- // used in this problem.
- QSet<QSimplexVariable *> variablesSet;
- for (int i = 0; i < constraints.size(); ++i)
- variablesSet += \
- QSet<QSimplexVariable *>::fromList(constraints[i]->variables.keys());
- variables = variablesSet.toList();
-
- // Set Variables reverse mapping
- // We also need to be able to find the index for a given variable, to do that
- // we store in each variable its index.
- for (int i = 0; i < variables.size(); ++i) {
- // The variable "0" goes at the column "1", etc...
- variables[i]->index = i + 1;
- }
-
- // Normalize Constraints
- // In this step, we prepare the constraints in two ways:
- // Firstly, we modify all constraints of type "LessOrEqual" or "MoreOrEqual"
- // by the adding slack or surplus variables and making them "Equal" constraints.
- // Secondly, we need every single constraint to have a direct, easy feasible
- // solution. Constraints that have slack variables are already easy to solve,
- // to all the others we add artificial variables.
- //
- // At the end we modify the constraints as follows:
- // - LessOrEqual: SLACK variable is added.
- // - Equal: ARTIFICIAL variable is added.
- // - More or Equal: ARTIFICIAL and SURPLUS variables are added.
- int variableIndex = variables.size();
- QList <QSimplexVariable *> artificialList;
-
- for (int i = 0; i < constraints.size(); ++i) {
- QSimplexVariable *slack;
- QSimplexVariable *surplus;
- QSimplexVariable *artificial;
-
- Q_ASSERT(constraints[i]->helper.first == 0);
- Q_ASSERT(constraints[i]->artificial == 0);
-
- switch(constraints[i]->ratio) {
- case QSimplexConstraint::LessOrEqual:
- slack = new QSimplexVariable;
- slack->index = ++variableIndex;
- constraints[i]->helper.first = slack;
- constraints[i]->helper.second = 1.0;
- break;
- case QSimplexConstraint::MoreOrEqual:
- surplus = new QSimplexVariable;
- surplus->index = ++variableIndex;
- constraints[i]->helper.first = surplus;
- constraints[i]->helper.second = -1.0;
- // fall through
- case QSimplexConstraint::Equal:
- artificial = new QSimplexVariable;
- constraints[i]->artificial = artificial;
- artificialList += constraints[i]->artificial;
- break;
- }
- }
-
- // All original, slack and surplus have already had its index set
- // at this point. We now set the index of the artificial variables
- // as to ensure they are at the end of the variable list and therefore
- // can be easily removed at the end of this method.
- firstArtificial = variableIndex + 1;
- for (int i = 0; i < artificialList.size(); ++i)
- artificialList[i]->index = ++variableIndex;
- artificialList.clear();
-
- /////////////////////////////
- // Fill the Simplex matrix //
- /////////////////////////////
-
- // One for each variable plus the Basic and BFS columns (first and last)
- columns = variableIndex + 2;
- // One for each constraint plus the objective function
- rows = constraints.size() + 1;
-
- matrix = (qreal *)malloc(sizeof(qreal) * columns * rows);
- if (!matrix) {
- qWarning() << "QSimplex: Unable to allocate memory!";
- return false;
- }
- for (int i = columns * rows - 1; i >= 0; --i)
- matrix[i] = 0.0;
-
- // Fill Matrix
- for (int i = 1; i <= constraints.size(); ++i) {
- QSimplexConstraint *c = constraints[i - 1];
-
- if (c->artificial) {
- // Will use artificial basic variable
- setValueAt(i, 0, c->artificial->index);
- setValueAt(i, c->artificial->index, 1.0);
-
- if (c->helper.second != 0.0) {
- // Surplus variable
- setValueAt(i, c->helper.first->index, c->helper.second);
- }
- } else {
- // Slack is used as the basic variable
- Q_ASSERT(c->helper.second == 1.0);
- setValueAt(i, 0, c->helper.first->index);
- setValueAt(i, c->helper.first->index, 1.0);
- }
-
- QHash<QSimplexVariable *, qreal>::const_iterator iter;
- for (iter = c->variables.constBegin();
- iter != c->variables.constEnd();
- ++iter) {
- setValueAt(i, iter.key()->index, iter.value());
- }
-
- setValueAt(i, columns - 1, c->constant);
- }
-
- // Set objective for the first-phase Simplex.
- // Z = -1 * sum_of_artificial_vars
- for (int j = firstArtificial; j < columns - 1; ++j)
- setValueAt(0, j, 1.0);
-
- // Maximize our objective (artificial vars go to zero)
- solveMaxHelper();
-
- // If there is a solution where the sum of all artificial
- // variables is zero, then all of them can be removed and yet
- // we will have a feasible (but not optimal) solution for the
- // original problem.
- // Otherwise, we clean up our structures and report there is
- // no feasible solution.
- if ((valueAt(0, columns - 1) != 0.0) && (qAbs(valueAt(0, columns - 1)) > 0.00001)) {
- qWarning() << "QSimplex: No feasible solution!";
- clearDataStructures();
- return false;
- }
-
- // Remove artificial variables. We already have a feasible
- // solution for the first problem, thus we don't need them
- // anymore.
- clearColumns(firstArtificial, columns - 2);
-
- return true;
-}
-
-/*!
- \internal
-
- Run simplex on the current matrix with the current objective.
-
- This is the iterative method. The matrix lines are combined
- as to modify the variable values towards the best solution possible.
- The method returns when the matrix is in the optimal state.
-*/
-void QSimplex::solveMaxHelper()
-{
- reducedRowEchelon();
- while (iterate()) ;
-}
-
-/*!
- \internal
-*/
-void QSimplex::setObjective(QSimplexConstraint *newObjective)
-{
- objective = newObjective;
-}
-
-/*!
- \internal
-*/
-void QSimplex::clearRow(int rowIndex)
-{
- qreal *item = matrix + rowIndex * columns;
- for (int i = 0; i < columns; ++i)
- item[i] = 0.0;
-}
-
-/*!
- \internal
-*/
-void QSimplex::clearColumns(int first, int last)
-{
- for (int i = 0; i < rows; ++i) {
- qreal *row = matrix + i * columns;
- for (int j = first; j <= last; ++j)
- row[j] = 0.0;
- }
-}
-
-/*!
- \internal
-*/
-void QSimplex::dumpMatrix()
-{
- qDebug("---- Simplex Matrix ----\n");
-
- QString str(QLatin1String(" "));
- for (int j = 0; j < columns; ++j)
- str += QString::fromAscii(" <%1 >").arg(j, 2);
- qDebug("%s", qPrintable(str));
- for (int i = 0; i < rows; ++i) {
- str = QString::fromAscii("Row %1:").arg(i, 2);
-
- qreal *row = matrix + i * columns;
- for (int j = 0; j < columns; ++j)
- str += QString::fromAscii("%1").arg(row[j], 7, 'f', 2);
- qDebug("%s", qPrintable(str));
- }
- qDebug("------------------------\n");
-}
-
-/*!
- \internal
-*/
-void QSimplex::combineRows(int toIndex, int fromIndex, qreal factor)
-{
- if (!factor)
- return;
-
- qreal *from = matrix + fromIndex * columns;
- qreal *to = matrix + toIndex * columns;
-
- for (int j = 1; j < columns; ++j) {
- qreal value = from[j];
-
- // skip to[j] = to[j] + factor*0.0
- if (value == 0.0)
- continue;
-
- to[j] += factor * value;
-
- // ### Avoid Numerical errors
- if (qAbs(to[j]) < 0.0000000001)
- to[j] = 0.0;
- }
-}
-
-/*!
- \internal
-*/
-int QSimplex::findPivotColumn()
-{
- qreal min = 0;
- int minIndex = -1;
-
- for (int j = 0; j < columns-1; ++j) {
- if (valueAt(0, j) < min) {
- min = valueAt(0, j);
- minIndex = j;
- }
- }
-
- return minIndex;
-}
-
-/*!
- \internal
-
- For a given pivot column, find the pivot row. That is, the row with the
- minimum associated "quotient" where:
-
- - quotient is the division of the value in the last column by the value
- in the pivot column.
- - rows with value less or equal to zero are ignored
- - if two rows have the same quotient, lines are chosen based on the
- highest variable index (value in the first column)
-
- The last condition avoids a bug where artificial variables would be
- left behind for the second-phase simplex, and with 'good'
- constraints would be removed before it, what would lead to incorrect
- results.
-*/
-int QSimplex::pivotRowForColumn(int column)
-{
- qreal min = qreal(999999999999.0); // ###
- int minIndex = -1;
-
- for (int i = 1; i < rows; ++i) {
- qreal divisor = valueAt(i, column);
- if (divisor <= 0)
- continue;
-
- qreal quotient = valueAt(i, columns - 1) / divisor;
- if (quotient < min) {
- min = quotient;
- minIndex = i;
- } else if ((quotient == min) && (valueAt(i, 0) > valueAt(minIndex, 0))) {
- minIndex = i;
- }
- }
-
- return minIndex;
-}
-
-/*!
- \internal
-*/
-void QSimplex::reducedRowEchelon()
-{
- for (int i = 1; i < rows; ++i) {
- int factorInObjectiveRow = valueAt(i, 0);
- combineRows(0, i, -1 * valueAt(0, factorInObjectiveRow));
- }
-}
-
-/*!
- \internal
-
- Does one iteration towards a better solution for the problem.
- See 'solveMaxHelper'.
-*/
-bool QSimplex::iterate()
-{
- // Find Pivot column
- int pivotColumn = findPivotColumn();
- if (pivotColumn == -1)
- return false;
-
- // Find Pivot row for column
- int pivotRow = pivotRowForColumn(pivotColumn);
- if (pivotRow == -1) {
- qWarning() << "QSimplex: Unbounded problem!";
- return false;
- }
-
- // Normalize Pivot Row
- qreal pivot = valueAt(pivotRow, pivotColumn);
- if (pivot != 1.0)
- combineRows(pivotRow, pivotRow, (1.0 - pivot) / pivot);
-
- // Update other rows
- for (int row=0; row < rows; ++row) {
- if (row == pivotRow)
- continue;
-
- combineRows(row, pivotRow, -1 * valueAt(row, pivotColumn));
- }
-
- // Update first column
- setValueAt(pivotRow, 0, pivotColumn);
-
- // dumpMatrix();
- // qDebug("------------ end of iteration --------------\n");
- return true;
-}
-
-/*!
- \internal
-
- Both solveMin and solveMax are interfaces to this method.
-
- The enum solverFactor admits 2 values: Minimum (-1) and Maximum (+1).
-
- This method sets the original objective and runs the second phase
- Simplex to obtain the optimal solution for the problem. As the internal
- simplex solver is only able to _maximize_ objectives, we handle the
- minimization case by inverting the original objective and then
- maximizing it.
-*/
-qreal QSimplex::solver(solverFactor factor)
-{
- // Remove old objective
- clearRow(0);
-
- // Set new objective in the first row of the simplex matrix
- qreal resultOffset = 0;
- QHash<QSimplexVariable *, qreal>::const_iterator iter;
- for (iter = objective->variables.constBegin();
- iter != objective->variables.constEnd();
- ++iter) {
-
- // Check if the variable was removed in the simplification process.
- // If so, we save its offset to the objective function and skip adding
- // it to the matrix.
- if (iter.key()->index == -1) {
- resultOffset += iter.value() * iter.key()->result;
- continue;
- }
-
- setValueAt(0, iter.key()->index, -1 * factor * iter.value());
- }
-
- solveMaxHelper();
- collectResults();
-
-#ifdef QT_DEBUG
- for (int i = 0; i < constraints.size(); ++i) {
- Q_ASSERT(constraints[i]->isSatisfied());
- }
-#endif
-
- // Return the value calculated by the simplex plus the value of the
- // fixed variables.
- return (factor * valueAt(0, columns - 1)) + resultOffset;
-}
-
-/*!
- \internal
- Minimize the original objective.
-*/
-qreal QSimplex::solveMin()
-{
- return solver(Minimum);
-}
-
-/*!
- \internal
- Maximize the original objective.
-*/
-qreal QSimplex::solveMax()
-{
- return solver(Maximum);
-}
-
-/*!
- \internal
-
- Reads results from the simplified matrix and saves them in the
- "result" member of each QSimplexVariable.
-*/
-void QSimplex::collectResults()
-{
- // All variables are zero unless overridden below.
-
- // ### Is this really needed? Is there any chance that an
- // important variable remains as non-basic at the end of simplex?
- for (int i = 0; i < variables.size(); ++i)
- variables[i]->result = 0;
-
- // Basic variables
- // Update the variable indicated in the first column with the value
- // in the last column.
- for (int i = 1; i < rows; ++i) {
- int index = valueAt(i, 0) - 1;
- if (index < variables.size())
- variables[index]->result = valueAt(i, columns - 1);
- }
-}
-
-/*!
- \internal
-
- Looks for single-valued variables and remove them from the constraints list.
-*/
-bool QSimplex::simplifyConstraints(QList<QSimplexConstraint *> *constraints)
-{
- QHash<QSimplexVariable *, qreal> results; // List of single-valued variables
- bool modified = true; // Any chance more optimization exists?
-
- while (modified) {
- modified = false;
-
- // For all constraints
- QList<QSimplexConstraint *>::iterator iter = constraints->begin();
- while (iter != constraints->end()) {
- QSimplexConstraint *c = *iter;
- if ((c->ratio == QSimplexConstraint::Equal) && (c->variables.count() == 1)) {
- // Check whether this is a constraint of type Var == K
- // If so, save its value to "results".
- QSimplexVariable *variable = c->variables.constBegin().key();
- qreal result = c->constant / c->variables.value(variable);
-
- results.insert(variable, result);
- variable->result = result;
- variable->index = -1;
- modified = true;
-
- }
-
- // Replace known values among their variables
- QHash<QSimplexVariable *, qreal>::const_iterator r;
- for (r = results.constBegin(); r != results.constEnd(); ++r) {
- if (c->variables.contains(r.key())) {
- c->constant -= r.value() * c->variables.take(r.key());
- modified = true;
- }
- }
-
- // Keep it normalized
- if (c->constant < 0)
- c->invert();
-
- if (c->variables.isEmpty()) {
- // If constraint became empty due to substitution, delete it.
- if (c->isSatisfied() == false)
- // We must ensure that the constraint soon to be deleted would not
- // make the problem unfeasible if left behind. If that's the case,
- // we return false so the simplex solver can properly report that.
- return false;
-
- delete c;
- iter = constraints->erase(iter);
- } else {
- ++iter;
- }
- }
- }
-
- return true;
-}
-
-void QSimplexConstraint::invert()
-{
- constant = -constant;
- ratio = Ratio(2 - ratio);
-
- QHash<QSimplexVariable *, qreal>::iterator iter;
- for (iter = variables.begin(); iter != variables.end(); ++iter) {
- iter.value() = -iter.value();
- }
-}
-
-QT_END_NAMESPACE