solverimpl.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) 2013-2017, Nucleic Development Team.
  3. |
  4. | Distributed under the terms of the Modified BSD License.
  5. |
  6. | The full license is in the file COPYING.txt, distributed with this software.
  7. |----------------------------------------------------------------------------*/
  8. #pragma once
  9. #include <algorithm>
  10. #include <limits>
  11. #include <memory>
  12. #include <vector>
  13. #include "constraint.h"
  14. #include "errors.h"
  15. #include "expression.h"
  16. #include "maptype.h"
  17. #include "row.h"
  18. #include "symbol.h"
  19. #include "term.h"
  20. #include "util.h"
  21. #include "variable.h"
  22. namespace kiwi
  23. {
  24. namespace impl
  25. {
  26. class SolverImpl
  27. {
  28. friend class DebugHelper;
  29. struct Tag
  30. {
  31. Symbol marker;
  32. Symbol other;
  33. };
  34. struct EditInfo
  35. {
  36. Tag tag;
  37. Constraint constraint;
  38. double constant;
  39. };
  40. typedef MapType<Variable, Symbol>::Type VarMap;
  41. typedef MapType<Symbol, Row*>::Type RowMap;
  42. typedef MapType<Constraint, Tag>::Type CnMap;
  43. typedef MapType<Variable, EditInfo>::Type EditMap;
  44. struct DualOptimizeGuard
  45. {
  46. DualOptimizeGuard( SolverImpl& impl ) : m_impl( impl ) {}
  47. ~DualOptimizeGuard() { m_impl.dualOptimize(); }
  48. SolverImpl& m_impl;
  49. };
  50. public:
  51. SolverImpl() : m_objective( new Row() ), m_id_tick( 1 ) {}
  52. ~SolverImpl() { clearRows(); }
  53. /* Add a constraint to the solver.
  54. Throws
  55. ------
  56. DuplicateConstraint
  57. The given constraint has already been added to the solver.
  58. UnsatisfiableConstraint
  59. The given constraint is required and cannot be satisfied.
  60. */
  61. void addConstraint( const Constraint& constraint )
  62. {
  63. if( m_cns.find( constraint ) != m_cns.end() )
  64. throw DuplicateConstraint( constraint );
  65. // Creating a row causes symbols to be reserved for the variables
  66. // in the constraint. If this method exits with an exception,
  67. // then its possible those variables will linger in the var map.
  68. // Since its likely that those variables will be used in other
  69. // constraints and since exceptional conditions are uncommon,
  70. // i'm not too worried about aggressive cleanup of the var map.
  71. Tag tag;
  72. std::auto_ptr<Row> rowptr( createRow( constraint, tag ) );
  73. Symbol subject( chooseSubject( *rowptr, tag ) );
  74. // If chooseSubject could not find a valid entering symbol, one
  75. // last option is available if the entire row is composed of
  76. // dummy variables. If the constant of the row is zero, then
  77. // this represents redundant constraints and the new dummy
  78. // marker can enter the basis. If the constant is non-zero,
  79. // then it represents an unsatisfiable constraint.
  80. if( subject.type() == Symbol::Invalid && allDummies( *rowptr ) )
  81. {
  82. if( !nearZero( rowptr->constant() ) )
  83. throw UnsatisfiableConstraint( constraint );
  84. else
  85. subject = tag.marker;
  86. }
  87. // If an entering symbol still isn't found, then the row must
  88. // be added using an artificial variable. If that fails, then
  89. // the row represents an unsatisfiable constraint.
  90. if( subject.type() == Symbol::Invalid )
  91. {
  92. if( !addWithArtificialVariable( *rowptr ) )
  93. throw UnsatisfiableConstraint( constraint );
  94. }
  95. else
  96. {
  97. rowptr->solveFor( subject );
  98. substitute( subject, *rowptr );
  99. m_rows[ subject ] = rowptr.release();
  100. }
  101. m_cns[ constraint ] = tag;
  102. // Optimizing after each constraint is added performs less
  103. // aggregate work due to a smaller average system size. It
  104. // also ensures the solver remains in a consistent state.
  105. optimize( *m_objective );
  106. }
  107. /* Remove a constraint from the solver.
  108. Throws
  109. ------
  110. UnknownConstraint
  111. The given constraint has not been added to the solver.
  112. */
  113. void removeConstraint( const Constraint& constraint )
  114. {
  115. CnMap::iterator cn_it = m_cns.find( constraint );
  116. if( cn_it == m_cns.end() )
  117. throw UnknownConstraint( constraint );
  118. Tag tag( cn_it->second );
  119. m_cns.erase( cn_it );
  120. // Remove the error effects from the objective function
  121. // *before* pivoting, or substitutions into the objective
  122. // will lead to incorrect solver results.
  123. removeConstraintEffects( constraint, tag );
  124. // If the marker is basic, simply drop the row. Otherwise,
  125. // pivot the marker into the basis and then drop the row.
  126. RowMap::iterator row_it = m_rows.find( tag.marker );
  127. if( row_it != m_rows.end() )
  128. {
  129. std::auto_ptr<Row> rowptr( row_it->second );
  130. m_rows.erase( row_it );
  131. }
  132. else
  133. {
  134. row_it = getMarkerLeavingRow( tag.marker );
  135. if( row_it == m_rows.end() )
  136. throw InternalSolverError( "failed to find leaving row" );
  137. Symbol leaving( row_it->first );
  138. std::auto_ptr<Row> rowptr( row_it->second );
  139. m_rows.erase( row_it );
  140. rowptr->solveFor( leaving, tag.marker );
  141. substitute( tag.marker, *rowptr );
  142. }
  143. // Optimizing after each constraint is removed ensures that the
  144. // solver remains consistent. It makes the solver api easier to
  145. // use at a small tradeoff for speed.
  146. optimize( *m_objective );
  147. }
  148. /* Test whether a constraint has been added to the solver.
  149. */
  150. bool hasConstraint( const Constraint& constraint ) const
  151. {
  152. return m_cns.find( constraint ) != m_cns.end();
  153. }
  154. /* Add an edit variable to the solver.
  155. This method should be called before the `suggestValue` method is
  156. used to supply a suggested value for the given edit variable.
  157. Throws
  158. ------
  159. DuplicateEditVariable
  160. The given edit variable has already been added to the solver.
  161. BadRequiredStrength
  162. The given strength is >= required.
  163. */
  164. void addEditVariable( const Variable& variable, double strength )
  165. {
  166. if( m_edits.find( variable ) != m_edits.end() )
  167. throw DuplicateEditVariable( variable );
  168. strength = strength::clip( strength );
  169. if( strength == strength::required )
  170. throw BadRequiredStrength();
  171. Constraint cn( Expression( variable ), OP_EQ, strength );
  172. addConstraint( cn );
  173. EditInfo info;
  174. info.tag = m_cns[ cn ];
  175. info.constraint = cn;
  176. info.constant = 0.0;
  177. m_edits[ variable ] = info;
  178. }
  179. /* Remove an edit variable from the solver.
  180. Throws
  181. ------
  182. UnknownEditVariable
  183. The given edit variable has not been added to the solver.
  184. */
  185. void removeEditVariable( const Variable& variable )
  186. {
  187. EditMap::iterator it = m_edits.find( variable );
  188. if( it == m_edits.end() )
  189. throw UnknownEditVariable( variable );
  190. removeConstraint( it->second.constraint );
  191. m_edits.erase( it );
  192. }
  193. /* Test whether an edit variable has been added to the solver.
  194. */
  195. bool hasEditVariable( const Variable& variable ) const
  196. {
  197. return m_edits.find( variable ) != m_edits.end();
  198. }
  199. /* Suggest a value for the given edit variable.
  200. This method should be used after an edit variable as been added to
  201. the solver in order to suggest the value for that variable.
  202. Throws
  203. ------
  204. UnknownEditVariable
  205. The given edit variable has not been added to the solver.
  206. */
  207. void suggestValue( const Variable& variable, double value )
  208. {
  209. EditMap::iterator it = m_edits.find( variable );
  210. if( it == m_edits.end() )
  211. throw UnknownEditVariable( variable );
  212. DualOptimizeGuard guard( *this );
  213. EditInfo& info = it->second;
  214. double delta = value - info.constant;
  215. info.constant = value;
  216. // Check first if the positive error variable is basic.
  217. RowMap::iterator row_it = m_rows.find( info.tag.marker );
  218. if( row_it != m_rows.end() )
  219. {
  220. if( row_it->second->add( -delta ) < 0.0 )
  221. m_infeasible_rows.push_back( row_it->first );
  222. return;
  223. }
  224. // Check next if the negative error variable is basic.
  225. row_it = m_rows.find( info.tag.other );
  226. if( row_it != m_rows.end() )
  227. {
  228. if( row_it->second->add( delta ) < 0.0 )
  229. m_infeasible_rows.push_back( row_it->first );
  230. return;
  231. }
  232. // Otherwise update each row where the error variables exist.
  233. RowMap::iterator end = m_rows.end();
  234. for( row_it = m_rows.begin(); row_it != end; ++row_it )
  235. {
  236. double coeff = row_it->second->coefficientFor( info.tag.marker );
  237. if( coeff != 0.0 &&
  238. row_it->second->add( delta * coeff ) < 0.0 &&
  239. row_it->first.type() != Symbol::External )
  240. m_infeasible_rows.push_back( row_it->first );
  241. }
  242. }
  243. /* Update the values of the external solver variables.
  244. */
  245. void updateVariables()
  246. {
  247. typedef RowMap::iterator row_iter_t;
  248. typedef VarMap::iterator var_iter_t;
  249. row_iter_t row_end = m_rows.end();
  250. var_iter_t var_end = m_vars.end();
  251. for( var_iter_t var_it = m_vars.begin(); var_it != var_end; ++var_it )
  252. {
  253. Variable& var( const_cast<Variable&>( var_it->first ) );
  254. row_iter_t row_it = m_rows.find( var_it->second );
  255. if( row_it == row_end )
  256. var.setValue( 0.0 );
  257. else
  258. var.setValue( row_it->second->constant() );
  259. }
  260. }
  261. /* Reset the solver to the empty starting condition.
  262. This method resets the internal solver state to the empty starting
  263. condition, as if no constraints or edit variables have been added.
  264. This can be faster than deleting the solver and creating a new one
  265. when the entire system must change, since it can avoid unecessary
  266. heap (de)allocations.
  267. */
  268. void reset()
  269. {
  270. clearRows();
  271. m_cns.clear();
  272. m_vars.clear();
  273. m_edits.clear();
  274. m_infeasible_rows.clear();
  275. m_objective.reset( new Row() );
  276. m_artificial.reset();
  277. m_id_tick = 1;
  278. }
  279. private:
  280. SolverImpl( const SolverImpl& );
  281. SolverImpl& operator=( const SolverImpl& );
  282. struct RowDeleter
  283. {
  284. template<typename T>
  285. void operator()( T& pair ) { delete pair.second; }
  286. };
  287. void clearRows()
  288. {
  289. std::for_each( m_rows.begin(), m_rows.end(), RowDeleter() );
  290. m_rows.clear();
  291. }
  292. /* Get the symbol for the given variable.
  293. If a symbol does not exist for the variable, one will be created.
  294. */
  295. Symbol getVarSymbol( const Variable& variable )
  296. {
  297. VarMap::iterator it = m_vars.find( variable );
  298. if( it != m_vars.end() )
  299. return it->second;
  300. Symbol symbol( Symbol::External, m_id_tick++ );
  301. m_vars[ variable ] = symbol;
  302. return symbol;
  303. }
  304. /* Create a new Row object for the given constraint.
  305. The terms in the constraint will be converted to cells in the row.
  306. Any term in the constraint with a coefficient of zero is ignored.
  307. This method uses the `getVarSymbol` method to get the symbol for
  308. the variables added to the row. If the symbol for a given cell
  309. variable is basic, the cell variable will be substituted with the
  310. basic row.
  311. The necessary slack and error variables will be added to the row.
  312. If the constant for the row is negative, the sign for the row
  313. will be inverted so the constant becomes positive.
  314. The tag will be updated with the marker and error symbols to use
  315. for tracking the movement of the constraint in the tableau.
  316. */
  317. Row* createRow( const Constraint& constraint, Tag& tag )
  318. {
  319. typedef std::vector<Term>::const_iterator iter_t;
  320. const Expression& expr( constraint.expression() );
  321. Row* row = new Row( expr.constant() );
  322. // Substitute the current basic variables into the row.
  323. iter_t end = expr.terms().end();
  324. for( iter_t it = expr.terms().begin(); it != end; ++it )
  325. {
  326. if( !nearZero( it->coefficient() ) )
  327. {
  328. Symbol symbol( getVarSymbol( it->variable() ) );
  329. RowMap::const_iterator row_it = m_rows.find( symbol );
  330. if( row_it != m_rows.end() )
  331. row->insert( *row_it->second, it->coefficient() );
  332. else
  333. row->insert( symbol, it->coefficient() );
  334. }
  335. }
  336. // Add the necessary slack, error, and dummy variables.
  337. switch( constraint.op() )
  338. {
  339. case OP_LE:
  340. case OP_GE:
  341. {
  342. double coeff = constraint.op() == OP_LE ? 1.0 : -1.0;
  343. Symbol slack( Symbol::Slack, m_id_tick++ );
  344. tag.marker = slack;
  345. row->insert( slack, coeff );
  346. if( constraint.strength() < strength::required )
  347. {
  348. Symbol error( Symbol::Error, m_id_tick++ );
  349. tag.other = error;
  350. row->insert( error, -coeff );
  351. m_objective->insert( error, constraint.strength() );
  352. }
  353. break;
  354. }
  355. case OP_EQ:
  356. {
  357. if( constraint.strength() < strength::required )
  358. {
  359. Symbol errplus( Symbol::Error, m_id_tick++ );
  360. Symbol errminus( Symbol::Error, m_id_tick++ );
  361. tag.marker = errplus;
  362. tag.other = errminus;
  363. row->insert( errplus, -1.0 ); // v = eplus - eminus
  364. row->insert( errminus, 1.0 ); // v - eplus + eminus = 0
  365. m_objective->insert( errplus, constraint.strength() );
  366. m_objective->insert( errminus, constraint.strength() );
  367. }
  368. else
  369. {
  370. Symbol dummy( Symbol::Dummy, m_id_tick++ );
  371. tag.marker = dummy;
  372. row->insert( dummy );
  373. }
  374. break;
  375. }
  376. }
  377. // Ensure the row as a positive constant.
  378. if( row->constant() < 0.0 )
  379. row->reverseSign();
  380. return row;
  381. }
  382. /* Choose the subject for solving for the row.
  383. This method will choose the best subject for using as the solve
  384. target for the row. An invalid symbol will be returned if there
  385. is no valid target.
  386. The symbols are chosen according to the following precedence:
  387. 1) The first symbol representing an external variable.
  388. 2) A negative slack or error tag variable.
  389. If a subject cannot be found, an invalid symbol will be returned.
  390. */
  391. Symbol chooseSubject( const Row& row, const Tag& tag )
  392. {
  393. typedef Row::CellMap::const_iterator iter_t;
  394. iter_t end = row.cells().end();
  395. for( iter_t it = row.cells().begin(); it != end; ++it )
  396. {
  397. if( it->first.type() == Symbol::External )
  398. return it->first;
  399. }
  400. if( tag.marker.type() == Symbol::Slack || tag.marker.type() == Symbol::Error )
  401. {
  402. if( row.coefficientFor( tag.marker ) < 0.0 )
  403. return tag.marker;
  404. }
  405. if( tag.other.type() == Symbol::Slack || tag.other.type() == Symbol::Error )
  406. {
  407. if( row.coefficientFor( tag.other ) < 0.0 )
  408. return tag.other;
  409. }
  410. return Symbol();
  411. }
  412. /* Add the row to the tableau using an artificial variable.
  413. This will return false if the constraint cannot be satisfied.
  414. */
  415. bool addWithArtificialVariable( const Row& row )
  416. {
  417. // Create and add the artificial variable to the tableau
  418. Symbol art( Symbol::Slack, m_id_tick++ );
  419. m_rows[ art ] = new Row( row );
  420. m_artificial.reset( new Row( row ) );
  421. // Optimize the artificial objective. This is successful
  422. // only if the artificial objective is optimized to zero.
  423. optimize( *m_artificial );
  424. bool success = nearZero( m_artificial->constant() );
  425. m_artificial.reset();
  426. // If the artificial variable is not basic, pivot the row so that
  427. // it becomes basic. If the row is constant, exit early.
  428. RowMap::iterator it = m_rows.find( art );
  429. if( it != m_rows.end() )
  430. {
  431. std::auto_ptr<Row> rowptr( it->second );
  432. m_rows.erase( it );
  433. if( rowptr->cells().empty() )
  434. return success;
  435. Symbol entering( anyPivotableSymbol( *rowptr ) );
  436. if( entering.type() == Symbol::Invalid )
  437. return false; // unsatisfiable (will this ever happen?)
  438. rowptr->solveFor( art, entering );
  439. substitute( entering, *rowptr );
  440. m_rows[ entering ] = rowptr.release();
  441. }
  442. // Remove the artificial variable from the tableau.
  443. RowMap::iterator end = m_rows.end();
  444. for( it = m_rows.begin(); it != end; ++it )
  445. it->second->remove( art );
  446. m_objective->remove( art );
  447. return success;
  448. }
  449. /* Substitute the parametric symbol with the given row.
  450. This method will substitute all instances of the parametric symbol
  451. in the tableau and the objective function with the given row.
  452. */
  453. void substitute( const Symbol& symbol, const Row& row )
  454. {
  455. typedef RowMap::iterator iter_t;
  456. iter_t end = m_rows.end();
  457. for( iter_t it = m_rows.begin(); it != end; ++it )
  458. {
  459. it->second->substitute( symbol, row );
  460. if( it->first.type() != Symbol::External &&
  461. it->second->constant() < 0.0 )
  462. m_infeasible_rows.push_back( it->first );
  463. }
  464. m_objective->substitute( symbol, row );
  465. if( m_artificial.get() )
  466. m_artificial->substitute( symbol, row );
  467. }
  468. /* Optimize the system for the given objective function.
  469. This method performs iterations of Phase 2 of the simplex method
  470. until the objective function reaches a minimum.
  471. Throws
  472. ------
  473. InternalSolverError
  474. The value of the objective function is unbounded.
  475. */
  476. void optimize( const Row& objective )
  477. {
  478. while( true )
  479. {
  480. Symbol entering( getEnteringSymbol( objective ) );
  481. if( entering.type() == Symbol::Invalid )
  482. return;
  483. RowMap::iterator it = getLeavingRow( entering );
  484. if( it == m_rows.end() )
  485. throw InternalSolverError( "The objective is unbounded." );
  486. // pivot the entering symbol into the basis
  487. Symbol leaving( it->first );
  488. Row* row = it->second;
  489. m_rows.erase( it );
  490. row->solveFor( leaving, entering );
  491. substitute( entering, *row );
  492. m_rows[ entering ] = row;
  493. }
  494. }
  495. /* Optimize the system using the dual of the simplex method.
  496. The current state of the system should be such that the objective
  497. function is optimal, but not feasible. This method will perform
  498. an iteration of the dual simplex method to make the solution both
  499. optimal and feasible.
  500. Throws
  501. ------
  502. InternalSolverError
  503. The system cannot be dual optimized.
  504. */
  505. void dualOptimize()
  506. {
  507. while( !m_infeasible_rows.empty() )
  508. {
  509. Symbol leaving( m_infeasible_rows.back() );
  510. m_infeasible_rows.pop_back();
  511. RowMap::iterator it = m_rows.find( leaving );
  512. if( it != m_rows.end() && !nearZero( it->second->constant() ) &&
  513. it->second->constant() < 0.0 )
  514. {
  515. Symbol entering( getDualEnteringSymbol( *it->second ) );
  516. if( entering.type() == Symbol::Invalid )
  517. throw InternalSolverError( "Dual optimize failed." );
  518. // pivot the entering symbol into the basis
  519. Row* row = it->second;
  520. m_rows.erase( it );
  521. row->solveFor( leaving, entering );
  522. substitute( entering, *row );
  523. m_rows[ entering ] = row;
  524. }
  525. }
  526. }
  527. /* Compute the entering variable for a pivot operation.
  528. This method will return first symbol in the objective function which
  529. is non-dummy and has a coefficient less than zero. If no symbol meets
  530. the criteria, it means the objective function is at a minimum, and an
  531. invalid symbol is returned.
  532. */
  533. Symbol getEnteringSymbol( const Row& objective )
  534. {
  535. typedef Row::CellMap::const_iterator iter_t;
  536. iter_t end = objective.cells().end();
  537. for( iter_t it = objective.cells().begin(); it != end; ++it )
  538. {
  539. if( it->first.type() != Symbol::Dummy && it->second < 0.0 )
  540. return it->first;
  541. }
  542. return Symbol();
  543. }
  544. /* Compute the entering symbol for the dual optimize operation.
  545. This method will return the symbol in the row which has a positive
  546. coefficient and yields the minimum ratio for its respective symbol
  547. in the objective function. The provided row *must* be infeasible.
  548. If no symbol is found which meats the criteria, an invalid symbol
  549. is returned.
  550. */
  551. Symbol getDualEnteringSymbol( const Row& row )
  552. {
  553. typedef Row::CellMap::const_iterator iter_t;
  554. Symbol entering;
  555. double ratio = std::numeric_limits<double>::max();
  556. iter_t end = row.cells().end();
  557. for( iter_t it = row.cells().begin(); it != end; ++it )
  558. {
  559. if( it->second > 0.0 && it->first.type() != Symbol::Dummy )
  560. {
  561. double coeff = m_objective->coefficientFor( it->first );
  562. double r = coeff / it->second;
  563. if( r < ratio )
  564. {
  565. ratio = r;
  566. entering = it->first;
  567. }
  568. }
  569. }
  570. return entering;
  571. }
  572. /* Get the first Slack or Error symbol in the row.
  573. If no such symbol is present, and Invalid symbol will be returned.
  574. */
  575. Symbol anyPivotableSymbol( const Row& row )
  576. {
  577. typedef Row::CellMap::const_iterator iter_t;
  578. iter_t end = row.cells().end();
  579. for( iter_t it = row.cells().begin(); it != end; ++it )
  580. {
  581. const Symbol& sym( it->first );
  582. if( sym.type() == Symbol::Slack || sym.type() == Symbol::Error )
  583. return sym;
  584. }
  585. return Symbol();
  586. }
  587. /* Compute the row which holds the exit symbol for a pivot.
  588. This method will return an iterator to the row in the row map
  589. which holds the exit symbol. If no appropriate exit symbol is
  590. found, the end() iterator will be returned. This indicates that
  591. the objective function is unbounded.
  592. */
  593. RowMap::iterator getLeavingRow( const Symbol& entering )
  594. {
  595. typedef RowMap::iterator iter_t;
  596. double ratio = std::numeric_limits<double>::max();
  597. iter_t end = m_rows.end();
  598. iter_t found = m_rows.end();
  599. for( iter_t it = m_rows.begin(); it != end; ++it )
  600. {
  601. if( it->first.type() != Symbol::External )
  602. {
  603. double temp = it->second->coefficientFor( entering );
  604. if( temp < 0.0 )
  605. {
  606. double temp_ratio = -it->second->constant() / temp;
  607. if( temp_ratio < ratio )
  608. {
  609. ratio = temp_ratio;
  610. found = it;
  611. }
  612. }
  613. }
  614. }
  615. return found;
  616. }
  617. /* Compute the leaving row for a marker variable.
  618. This method will return an iterator to the row in the row map
  619. which holds the given marker variable. The row will be chosen
  620. according to the following precedence:
  621. 1) The row with a restricted basic varible and a negative coefficient
  622. for the marker with the smallest ratio of -constant / coefficient.
  623. 2) The row with a restricted basic variable and the smallest ratio
  624. of constant / coefficient.
  625. 3) The last unrestricted row which contains the marker.
  626. If the marker does not exist in any row, the row map end() iterator
  627. will be returned. This indicates an internal solver error since
  628. the marker *should* exist somewhere in the tableau.
  629. */
  630. RowMap::iterator getMarkerLeavingRow( const Symbol& marker )
  631. {
  632. const double dmax = std::numeric_limits<double>::max();
  633. typedef RowMap::iterator iter_t;
  634. double r1 = dmax;
  635. double r2 = dmax;
  636. iter_t end = m_rows.end();
  637. iter_t first = end;
  638. iter_t second = end;
  639. iter_t third = end;
  640. for( iter_t it = m_rows.begin(); it != end; ++it )
  641. {
  642. double c = it->second->coefficientFor( marker );
  643. if( c == 0.0 )
  644. continue;
  645. if( it->first.type() == Symbol::External )
  646. {
  647. third = it;
  648. }
  649. else if( c < 0.0 )
  650. {
  651. double r = -it->second->constant() / c;
  652. if( r < r1 )
  653. {
  654. r1 = r;
  655. first = it;
  656. }
  657. }
  658. else
  659. {
  660. double r = it->second->constant() / c;
  661. if( r < r2 )
  662. {
  663. r2 = r;
  664. second = it;
  665. }
  666. }
  667. }
  668. if( first != end )
  669. return first;
  670. if( second != end )
  671. return second;
  672. return third;
  673. }
  674. /* Remove the effects of a constraint on the objective function.
  675. */
  676. void removeConstraintEffects( const Constraint& cn, const Tag& tag )
  677. {
  678. if( tag.marker.type() == Symbol::Error )
  679. removeMarkerEffects( tag.marker, cn.strength() );
  680. if( tag.other.type() == Symbol::Error )
  681. removeMarkerEffects( tag.other, cn.strength() );
  682. }
  683. /* Remove the effects of an error marker on the objective function.
  684. */
  685. void removeMarkerEffects( const Symbol& marker, double strength )
  686. {
  687. RowMap::iterator row_it = m_rows.find( marker );
  688. if( row_it != m_rows.end() )
  689. m_objective->insert( *row_it->second, -strength );
  690. else
  691. m_objective->insert( marker, -strength );
  692. }
  693. /* Test whether a row is composed of all dummy variables.
  694. */
  695. bool allDummies( const Row& row )
  696. {
  697. typedef Row::CellMap::const_iterator iter_t;
  698. iter_t end = row.cells().end();
  699. for( iter_t it = row.cells().begin(); it != end; ++it )
  700. {
  701. if( it->first.type() != Symbol::Dummy )
  702. return false;
  703. }
  704. return true;
  705. }
  706. CnMap m_cns;
  707. RowMap m_rows;
  708. VarMap m_vars;
  709. EditMap m_edits;
  710. std::vector<Symbol> m_infeasible_rows;
  711. std::auto_ptr<Row> m_objective;
  712. std::auto_ptr<Row> m_artificial;
  713. Symbol::Id m_id_tick;
  714. };
  715. } // namespace impl
  716. } // namespace kiwi