Qt 4.8
qsimplex_p.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
50 
84 QSimplex::QSimplex() : objective(0), rows(0), columns(0), firstArtificial(0), matrix(0)
85 {
86 }
87 
92 {
94 }
95 
100 {
101  if (matrix == 0)
102  return;
103 
104  // Matrix
105  rows = 0;
106  columns = 0;
107  firstArtificial = 0;
108  free(matrix);
109  matrix = 0;
110 
111  // Constraints
112  for (int i = 0; i < constraints.size(); ++i) {
113  delete constraints[i]->helper.first;
114  delete constraints[i]->artificial;
115  delete constraints[i];
116  }
117  constraints.clear();
118 
119  // Other
120  variables.clear();
121  objective = 0;
122 }
123 
136 {
138  // Reset to initial state //
141 
142  if (newConstraints.isEmpty())
143  return true; // we are ok with no constraints
144 
145  // Make deep copy of constraints. We need this copy because we may change
146  // them in the simplification method.
147  for (int i = 0; i < newConstraints.size(); ++i) {
149  c->constant = newConstraints[i]->constant;
150  c->ratio = newConstraints[i]->ratio;
151  c->variables = newConstraints[i]->variables;
152  constraints << c;
153  }
154 
155  // Remove constraints of type Var == K and replace them for their value.
157  qWarning() << "QSimplex: No feasible solution!";
159  return false;
160  }
161 
163  // Prepare variables and constraints //
165 
166  // Set Variables direct mapping.
167  // "variables" is a list that provides a stable, indexed list of all variables
168  // used in this problem.
169  QSet<QSimplexVariable *> variablesSet;
170  for (int i = 0; i < constraints.size(); ++i)
171  variablesSet += \
173  variables = variablesSet.toList();
174 
175  // Set Variables reverse mapping
176  // We also need to be able to find the index for a given variable, to do that
177  // we store in each variable its index.
178  for (int i = 0; i < variables.size(); ++i) {
179  // The variable "0" goes at the column "1", etc...
180  variables[i]->index = i + 1;
181  }
182 
183  // Normalize Constraints
184  // In this step, we prepare the constraints in two ways:
185  // Firstly, we modify all constraints of type "LessOrEqual" or "MoreOrEqual"
186  // by the adding slack or surplus variables and making them "Equal" constraints.
187  // Secondly, we need every single constraint to have a direct, easy feasible
188  // solution. Constraints that have slack variables are already easy to solve,
189  // to all the others we add artificial variables.
190  //
191  // At the end we modify the constraints as follows:
192  // - LessOrEqual: SLACK variable is added.
193  // - Equal: ARTIFICIAL variable is added.
194  // - More or Equal: ARTIFICIAL and SURPLUS variables are added.
195  int variableIndex = variables.size();
196  QList <QSimplexVariable *> artificialList;
197 
198  for (int i = 0; i < constraints.size(); ++i) {
199  QSimplexVariable *slack;
200  QSimplexVariable *surplus;
201  QSimplexVariable *artificial;
202 
203  Q_ASSERT(constraints[i]->helper.first == 0);
204  Q_ASSERT(constraints[i]->artificial == 0);
205 
206  switch(constraints[i]->ratio) {
208  slack = new QSimplexVariable;
209  slack->index = ++variableIndex;
210  constraints[i]->helper.first = slack;
211  constraints[i]->helper.second = 1.0;
212  break;
214  surplus = new QSimplexVariable;
215  surplus->index = ++variableIndex;
216  constraints[i]->helper.first = surplus;
217  constraints[i]->helper.second = -1.0;
218  // fall through
220  artificial = new QSimplexVariable;
221  constraints[i]->artificial = artificial;
222  artificialList += constraints[i]->artificial;
223  break;
224  }
225  }
226 
227  // All original, slack and surplus have already had its index set
228  // at this point. We now set the index of the artificial variables
229  // as to ensure they are at the end of the variable list and therefore
230  // can be easily removed at the end of this method.
231  firstArtificial = variableIndex + 1;
232  for (int i = 0; i < artificialList.size(); ++i)
233  artificialList[i]->index = ++variableIndex;
234  artificialList.clear();
235 
237  // Fill the Simplex matrix //
239 
240  // One for each variable plus the Basic and BFS columns (first and last)
241  columns = variableIndex + 2;
242  // One for each constraint plus the objective function
243  rows = constraints.size() + 1;
244 
245  matrix = (qreal *)malloc(sizeof(qreal) * columns * rows);
246  if (!matrix) {
247  qWarning() << "QSimplex: Unable to allocate memory!";
248  return false;
249  }
250  for (int i = columns * rows - 1; i >= 0; --i)
251  matrix[i] = 0.0;
252 
253  // Fill Matrix
254  for (int i = 1; i <= constraints.size(); ++i) {
255  QSimplexConstraint *c = constraints[i - 1];
256 
257  if (c->artificial) {
258  // Will use artificial basic variable
259  setValueAt(i, 0, c->artificial->index);
260  setValueAt(i, c->artificial->index, 1.0);
261 
262  if (c->helper.second != 0.0) {
263  // Surplus variable
265  }
266  } else {
267  // Slack is used as the basic variable
268  Q_ASSERT(c->helper.second == 1.0);
269  setValueAt(i, 0, c->helper.first->index);
270  setValueAt(i, c->helper.first->index, 1.0);
271  }
272 
274  for (iter = c->variables.constBegin();
275  iter != c->variables.constEnd();
276  ++iter) {
277  setValueAt(i, iter.key()->index, iter.value());
278  }
279 
280  setValueAt(i, columns - 1, c->constant);
281  }
282 
283  // Set objective for the first-phase Simplex.
284  // Z = -1 * sum_of_artificial_vars
285  for (int j = firstArtificial; j < columns - 1; ++j)
286  setValueAt(0, j, 1.0);
287 
288  // Maximize our objective (artificial vars go to zero)
289  solveMaxHelper();
290 
291  // If there is a solution where the sum of all artificial
292  // variables is zero, then all of them can be removed and yet
293  // we will have a feasible (but not optimal) solution for the
294  // original problem.
295  // Otherwise, we clean up our structures and report there is
296  // no feasible solution.
297  if ((valueAt(0, columns - 1) != 0.0) && (qAbs(valueAt(0, columns - 1)) > 0.00001)) {
298  qWarning() << "QSimplex: No feasible solution!";
300  return false;
301  }
302 
303  // Remove artificial variables. We already have a feasible
304  // solution for the first problem, thus we don't need them
305  // anymore.
306  clearColumns(firstArtificial, columns - 2);
307 
308  return true;
309 }
310 
324 {
326  while (iterate()) ;
327 }
328 
333 {
334  objective = newObjective;
335 }
336 
340 void QSimplex::clearRow(int rowIndex)
341 {
342  qreal *item = matrix + rowIndex * columns;
343  for (int i = 0; i < columns; ++i)
344  item[i] = 0.0;
345 }
346 
350 void QSimplex::clearColumns(int first, int last)
351 {
352  for (int i = 0; i < rows; ++i) {
353  qreal *row = matrix + i * columns;
354  for (int j = first; j <= last; ++j)
355  row[j] = 0.0;
356  }
357 }
358 
363 {
364  qDebug("---- Simplex Matrix ----\n");
365 
366  QString str(QLatin1String(" "));
367  for (int j = 0; j < columns; ++j)
368  str += QString::fromAscii(" <%1 >").arg(j, 2);
369  qDebug("%s", qPrintable(str));
370  for (int i = 0; i < rows; ++i) {
371  str = QString::fromAscii("Row %1:").arg(i, 2);
372 
373  qreal *row = matrix + i * columns;
374  for (int j = 0; j < columns; ++j)
375  str += QString::fromAscii("%1").arg(row[j], 7, 'f', 2);
376  qDebug("%s", qPrintable(str));
377  }
378  qDebug("------------------------\n");
379 }
380 
384 void QSimplex::combineRows(int toIndex, int fromIndex, qreal factor)
385 {
386  if (!factor)
387  return;
388 
389  qreal *from = matrix + fromIndex * columns;
390  qreal *to = matrix + toIndex * columns;
391 
392  for (int j = 1; j < columns; ++j) {
393  qreal value = from[j];
394 
395  // skip to[j] = to[j] + factor*0.0
396  if (value == 0.0)
397  continue;
398 
399  to[j] += factor * value;
400 
401  // ### Avoid Numerical errors
402  if (qAbs(to[j]) < 0.0000000001)
403  to[j] = 0.0;
404  }
405 }
406 
411 {
412  qreal min = 0;
413  int minIndex = -1;
414 
415  for (int j = 0; j < columns-1; ++j) {
416  if (valueAt(0, j) < min) {
417  min = valueAt(0, j);
418  minIndex = j;
419  }
420  }
421 
422  return minIndex;
423 }
424 
446 {
447  qreal min = qreal(999999999999.0); // ###
448  int minIndex = -1;
449 
450  for (int i = 1; i < rows; ++i) {
451  qreal divisor = valueAt(i, column);
452  if (divisor <= 0)
453  continue;
454 
455  qreal quotient = valueAt(i, columns - 1) / divisor;
456  if (quotient < min) {
457  min = quotient;
458  minIndex = i;
459  } else if ((quotient == min) && (valueAt(i, 0) > valueAt(minIndex, 0))) {
460  minIndex = i;
461  }
462  }
463 
464  return minIndex;
465 }
466 
471 {
472  for (int i = 1; i < rows; ++i) {
473  int factorInObjectiveRow = valueAt(i, 0);
474  combineRows(0, i, -1 * valueAt(0, factorInObjectiveRow));
475  }
476 }
477 
488 {
489  // Find Pivot column
490  int pivotColumn = findPivotColumn();
491  if (pivotColumn == -1)
492  return false;
493 
494  // Find Pivot row for column
495  int pivotRow = pivotRowForColumn(pivotColumn);
496  if (pivotRow == -1) {
497  qWarning() << "QSimplex: Unbounded problem!";
498  return false;
499  }
500 
501  // Normalize Pivot Row
502  qreal pivot = valueAt(pivotRow, pivotColumn);
503  if (pivot != 1.0)
504  combineRows(pivotRow, pivotRow, (qreal(1.0) - pivot) / pivot);
505 
506  // Update other rows
507  for (int row=0; row < rows; ++row) {
508  if (row == pivotRow)
509  continue;
510 
511  combineRows(row, pivotRow, -1 * valueAt(row, pivotColumn));
512  }
513 
514  // Update first column
515  setValueAt(pivotRow, 0, pivotColumn);
516 
517  // dumpMatrix();
518  // qDebug("------------ end of iteration --------------\n");
519  return true;
520 }
521 
539 {
540  // Remove old objective
541  clearRow(0);
542 
543  // Set new objective in the first row of the simplex matrix
544  qreal resultOffset = 0;
546  for (iter = objective->variables.constBegin();
547  iter != objective->variables.constEnd();
548  ++iter) {
549 
550  // Check if the variable was removed in the simplification process.
551  // If so, we save its offset to the objective function and skip adding
552  // it to the matrix.
553  if (iter.key()->index == -1) {
554  resultOffset += iter.value() * iter.key()->result;
555  continue;
556  }
557 
558  setValueAt(0, iter.key()->index, -1 * factor * iter.value());
559  }
560 
561  solveMaxHelper();
562  collectResults();
563 
564 #ifdef QT_DEBUG
565  for (int i = 0; i < constraints.size(); ++i) {
566  Q_ASSERT(constraints[i]->isSatisfied());
567  }
568 #endif
569 
570  // Return the value calculated by the simplex plus the value of the
571  // fixed variables.
572  return (factor * valueAt(0, columns - 1)) + resultOffset;
573 }
574 
583 {
584  return solver(Minimum);
585 }
586 
595 {
596  return solver(Maximum);
597 }
598 
609 {
610  // All variables are zero unless overridden below.
611 
612  // ### Is this really needed? Is there any chance that an
613  // important variable remains as non-basic at the end of simplex?
614  for (int i = 0; i < variables.size(); ++i)
615  variables[i]->result = 0;
616 
617  // Basic variables
618  // Update the variable indicated in the first column with the value
619  // in the last column.
620  for (int i = 1; i < rows; ++i) {
621  int index = valueAt(i, 0) - 1;
622  if (index < variables.size())
623  variables[index]->result = valueAt(i, columns - 1);
624  }
625 }
626 
636 {
637  QHash<QSimplexVariable *, qreal> results; // List of single-valued variables
638  bool modified = true; // Any chance more optimization exists?
639 
640  while (modified) {
641  modified = false;
642 
643  // For all constraints
644  QList<QSimplexConstraint *>::iterator iter = constraints->begin();
645  while (iter != constraints->end()) {
646  QSimplexConstraint *c = *iter;
647  if ((c->ratio == QSimplexConstraint::Equal) && (c->variables.count() == 1)) {
648  // Check whether this is a constraint of type Var == K
649  // If so, save its value to "results".
650  QSimplexVariable *variable = c->variables.constBegin().key();
651  qreal result = c->constant / c->variables.value(variable);
652 
653  results.insert(variable, result);
654  variable->result = result;
655  variable->index = -1;
656  modified = true;
657 
658  }
659 
660  // Replace known values among their variables
662  for (r = results.constBegin(); r != results.constEnd(); ++r) {
663  if (c->variables.contains(r.key())) {
664  c->constant -= r.value() * c->variables.take(r.key());
665  modified = true;
666  }
667  }
668 
669  // Keep it normalized
670  if (c->constant < 0)
671  c->invert();
672 
673  if (c->variables.isEmpty()) {
674  // If constraint became empty due to substitution, delete it.
675  if (c->isSatisfied() == false)
676  // We must ensure that the constraint soon to be deleted would not
677  // make the problem unfeasible if left behind. If that's the case,
678  // we return false so the simplex solver can properly report that.
679  return false;
680 
681  delete c;
682  iter = constraints->erase(iter);
683  } else {
684  ++iter;
685  }
686  }
687  }
688 
689  return true;
690 }
691 
693 {
694  constant = -constant;
695  ratio = Ratio(2 - ratio);
696 
698  for (iter = variables.begin(); iter != variables.end(); ++iter) {
699  iter.value() = -iter.value();
700  }
701 }
702 
void solveMaxHelper()
Run simplex on the current matrix with the current objective.
Definition: qsimplex_p.cpp:323
int findPivotColumn()
Definition: qsimplex_p.cpp:410
double qreal
Definition: qglobal.h:1193
unsigned char c[8]
Definition: qnumeric_p.h:62
bool setConstraints(const QList< QSimplexConstraint *> constraints)
Sets the new constraints in the simplex solver and returns whether the problem is feasible...
Definition: qsimplex_p.cpp:135
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
static QString fromAscii(const char *, int size=-1)
Returns a QString initialized with the first size characters from the string str. ...
Definition: qstring.cpp:4276
void clearDataStructures()
Definition: qsimplex_p.cpp:99
QPair< QSimplexVariable *, qreal > helper
Definition: qsimplex_p.h:95
qreal solveMax()
Maximize the original objective.
Definition: qsimplex_p.cpp:594
int firstArtificial
Definition: qsimplex_p.h:191
T1 first
Definition: qpair.h:65
T2 second
Definition: qpair.h:66
iterator begin()
Returns an STL-style iterator pointing to the first item in the list.
Definition: qlist.h:267
QSimplexVariable * artificial
Definition: qsimplex_p.h:96
QList< QSimplexConstraint * > constraints
Definition: qsimplex_p.h:185
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QString class provides a Unicode character string.
Definition: qstring.h:83
T take(const Key &key)
Removes the item with the key from the hash and returns the value associated with it...
Definition: qhash.h:807
The QHash class is a template class that provides a hash-table-based dictionary.
Definition: qdatastream.h:66
Q_DECL_CONSTEXPR T qAbs(const T &t)
Definition: qglobal.h:1201
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
QSimplexConstraint * objective
Definition: qsimplex_p.h:187
QHash< QSimplexVariable *, qreal > variables
Definition: qsimplex_p.h:91
bool contains(const Key &key) const
Returns true if the hash contains an item with the key; otherwise returns false.
Definition: qhash.h:872
static double ratio(Bigint *a, Bigint *b)
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
void dumpMatrix()
Definition: qsimplex_p.cpp:362
bool isEmpty() const
Returns true if the list contains no items; otherwise returns false.
Definition: qlist.h:152
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
Q_CORE_EXPORT void qDebug(const char *,...)
int columns
Definition: qsimplex_p.h:190
void collectResults()
Reads results from the simplified matrix and saves them in the "result" member of each QSimplexVariab...
Definition: qsimplex_p.cpp:608
void setObjective(QSimplexConstraint *objective)
Definition: qsimplex_p.cpp:332
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QList< T > toList() const
Definition: qset.h:296
iterator end()
Returns an STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:270
void reducedRowEchelon()
Definition: qsimplex_p.cpp:470
qreal valueAt(int row, int column)
Definition: qsimplex_p.h:196
bool isEmpty() const
Returns true if the hash contains no items; otherwise returns false.
Definition: qhash.h:297
Q_CORE_EXPORT void qWarning(const char *,...)
bool iterate()
Does one iteration towards a better solution for the problem.
Definition: qsimplex_p.cpp:487
virtual ~QSimplex()
Definition: qsimplex_p.cpp:91
void clear()
Removes all items from the list.
Definition: qlist.h:764
qreal solver(solverFactor factor)
Both solveMin and solveMax are interfaces to this method.
Definition: qsimplex_p.cpp:538
int pivotRowForColumn(int column)
For a given pivot column, find the pivot row.
Definition: qsimplex_p.cpp:445
The QList::iterator class provides an STL-style non-const iterator for QList and QQueue.
Definition: qlist.h:181
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the hash.
Definition: qhash.h:466
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the hash...
Definition: qhash.h:469
bool simplifyConstraints(QList< QSimplexConstraint *> *constraints)
Looks for single-valued variables and remove them from the constraints list.
Definition: qsimplex_p.cpp:635
void clearRow(int rowIndex)
Definition: qsimplex_p.cpp:340
iterator erase(iterator pos)
Removes the item associated with the iterator pos from the list, and returns an iterator to the next ...
Definition: qlist.h:464
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
int rows
Definition: qsimplex_p.h:189
const Key key(const T &value) const
Returns the first key mapped to value.
Definition: qhash.h:674
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
QList< QSimplexVariable * > variables
Definition: qsimplex_p.h:186
void setValueAt(int row, int column, qreal value)
Definition: qsimplex_p.h:201
quint16 index
void clearColumns(int first, int last)
Definition: qsimplex_p.cpp:350
int count(const Key &key) const
Returns the number of items associated with the key.
Definition: qhash.h:719
qreal * matrix
Definition: qsimplex_p.h:193
#define qPrintable(string)
Definition: qglobal.h:1750
qreal solveMin()
Minimize the original objective.
Definition: qsimplex_p.cpp:582
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
void combineRows(int toIndex, int fromIndex, qreal factor)
Definition: qsimplex_p.cpp:384