[Lemon-commits] Peter Kovacs: Greatly extend LP section

Lemon HG hg at lemon.cs.elte.hu
Mon Mar 1 09:39:06 CET 2010


details:   http://lemon.cs.elte.hu/hg/lemon-tutorial/rev/edb7d5759e0d
changeset: 55:edb7d5759e0d
user:      Peter Kovacs <kpeter [at] inf.elte.hu>
date:      Mon Mar 01 02:27:36 2010 +0100
description:
	Greatly extend LP section

diffstat:

 lp.dox  |  215 ++++++++++++++++++++++++++++++++++++++++-------------
 toc.txt |    3 +
 2 files changed, 163 insertions(+), 55 deletions(-)

diffs (253 lines):

diff --git a/lp.dox b/lp.dox
--- a/lp.dox
+++ b/lp.dox
@@ -44,76 +44,181 @@
 However, additional wrapper classes for new solvers can also be implemented
 quite easily.
 
-In this section, we will show two examples. The first one shows how simple
-it is to formalize and solve an LP problem in LEMON, while the second one
-shows how LEMON facilitates solving network optimization problems using LP
-solvers.
+[SEC]sec_lp_basics[SEC] Basic LP Features
+
+The following example demonstrates how simple it is to formalize and solve
+an LP problem in LEMON. You can find the whole program in \ref lp_demo.cc.
+
+\dontinclude lp_demo.cc
+\skip Create
+\until }
+\until }
+
+\ref LpBase::Col "Lp::Col" type represents the columns, i.e. the (primal)
+variables of the LP problem. The numerical operators can be used to form
+expressions from columns, which are required for specifying rows
+(constraints) and the objective function. Due to the suitable operator
+overloads, a problem can be described in C++ conveniently, directly as it is
+expressed in mathematics.
+After specifying all the parameters of the problem, we can solve it using
+the \ref LpSolver::solve() "solve()" function. The status of the solution
+(namely OPTIMAL, UNBOUNDED, INFEASIBLE etc.) can be obtained using
+\ref LpSolver::primalType() "primalType()" and the results can be
+obtained using \ref LpSolver::primal() "primal()".
+
+The above problem has an optimal solution. If you execute this example,
+it will print out the following results.
 
 \code
-  Lp lp;
-
-  Lp::Col x1 = lp.addCol();
-  Lp::Col x2 = lp.addCol();
-
-  lp.addRow(0 <= x1 + x2 <= 100);
-  lp.addRow(2 * x1 <= x2 + 32);
-
-  lp.colLowerBound(x1, 0);
-  lp.colUpperBound(x2, 100);
-
-  lp.max();
-  lp.obj(10 * x1 + 6 * x2);
-  lp.solve();
-
-  std::cout << "Objective function value: " << lp.primal() << std::endl;
-  std::cout << "x1 = " << lp.primal(x1) << std::endl;
-  std::cout << "x2 = " << lp.primal(x2) << std::endl;
+  Objective function value: 67.5
+  x1 = 7.5
+  x2 = 10
 \endcode
 
-\ref LpBase::Col "Lp::Col" type represents the variables in the LP problems,
-while \ref LpBase::Row "Lp::Row" represents the constraints. The numerical
-operators can be used to form expressions from columns and dual
-expressions from rows. Due to the suitable operator overloads,
-a problem can be described in C++ conveniently, directly as it is
-expressed in mathematics.
-
-The following example solves a maximum flow problem with linear
-programming. Several other graph optimization problems can also be
-expressed as linear programs and this interface helps to solve them easily
-(though usually not so efficiently as by a direct combinatorial method).
+However, if you, for example, removed the lines that specify the rows,
+you would obtain an LP problem, for which the objective function value
+is unbounded over the feasible solutions. Thus the program would print
+out this line.
 
 \code
-  Lp lp;
-  ListDigraph::ArcMap<Lp::Col> f(g);
-  lp.addColSet(f);
+  Optimal solution found.
+\endcode
 
-  // Capacity constraints
-  for (ListDigraph::ArcIt a(g); a != INVALID; ++a) {
-    lp.colLowerBound(f[a], 0);
-    lp.colUpperBound(f[a], capacity[a]);
+If you would like to build linear expressions or constraints in more steps,
+then you can use the classes \ref LpBase::Expr "Lp::Expr" and
+\ref LpBase::Constr "Lp::Constr". For example, this line
+\code
+  lp.addRow(x1 - 5 <= x2);
+\endcode
+can also be written as
+\code
+  Lp::Expr e1, e2;
+  e1 = x1;
+  e1 -= 5;
+  e2 = x2;
+  Lp::Constr c = e1 <= e2;
+  lp.addRow(c);
+\endcode
+
+These classes make it easy to build more complex expressions and constraints,
+e.g. using loops. For example, we can sum all the variables (columns) in an
+expression using the \ref LpBase::ColIt "Lp::ColIt" iterator, which can be
+used the same as node and arc iterators for graphs.
+
+\code
+  Lp::Expr sum;
+  for (Lp::ColIt col(lp); col != INVALID; ++col) {
+    sum += col;
   }
+\endcode
 
-  // Flow conservation constraints
-  for (ListDigraph::NodeIt n(g); n != INVALID; ++n) {
-    if (n == src || n == trg) continue;
-    Lp::Expr e;
-    for (ListDigraph::OutArcIt a(g,n); a != INVALID; ++a) e += f[a];
-    for (ListDigraph::InArcIt a(g,n); a != INVALID; ++a) e -= f[a];
-    lp.addRow(e == 0);
+After solving the problem, you can query the value of any primal expression,
+not just the individual columns and the objective function.
+
+\todo Check this example after closing ticket #326.
+
+\code
+  std::cout << lp.primal(sum) << std::endl;
+\endcode
+
+Of course, working with the dual problem is also supported by the LP
+interface. \ref LpBase::Row "Lp::Row" represents the rows, i.e. the dual
+variables of the LP problem.
+
+\code
+  Lp::Row r = lp.addRow(x2 >= 3);
+\endcode
+
+The dual solutions of an LP problem can be obtained using the functions
+\ref LpSolver::dualType() "dualType()" and \ref LpSolver::dual "dual()"
+(after solving the problem).
+
+\code
+  std::cout << lp.dual(r) << std::endl;
+\endcode
+
+\ref LpBase::DualExpr "Lp::DualExpr" can be used to build dual expressions
+from rows and \ref LpBase::RowIt "Lp::RowIt" can be used to list the rows.
+
+\code
+  Lp::DualExpr dual_sum;
+  for (Lp::RowIt row(lp); row != INVALID; ++row) {
+    dual_sum += row;
   }
+\endcode
 
-  // Objective function
-  Lp::Expr o;
-  for (ListDigraph::OutArcIt a(g,src); a != INVALID; ++a) o += f[a];
-  for (ListDigraph::InArcIt a(g,src); a != INVALID; ++a) o -= f[a];
+The LP solver interface provides several other features, which are
+documented in the classes \ref LpBase and \ref LpSolver.
+For detailed documentation, see these classes in the reference manual.
 
-  lp.max();
-  lp.obj(o);
-  lp.solve();
+If you would like to use a specific solver instead of the default one,
+you can use \ref GlpkLp, \ref ClpLp, \ref CplexLp etc. instead of
+the class \ref Lp.
 
-  std::cout << "Max flow value: " << lp.primal() << std::endl;
+
+[SEC]sec_lp_mip[SEC] Mixed Integer Programming
+
+LEMON also provides a similar high-level interface for mixed integer
+programming (MIP) solvers. The default MIP solver can be used through
+the class \ref Mip, while the concrete solvers are implemented in the
+classes \ref GlpkMip, \ref CbcMip, \ref CplexMip etc.
+
+The following example demonstrates the usage of the MIP solver interface.
+The whole program can be found in \ref mip_demo.cc.
+
+\dontinclude mip_demo.cc
+\skip Create
+\until }
+\until }
+
+\todo Check this demo file after closing ticket #326.
+E.g. could we write <tt>mip.sol()</tt> instead of <tt>mip.solValue()</tt>?
+Or could we write <tt>primalValue()</tt> for \c Lp in \c lp_demo.cc?
+
+In this program, the same problem is built as in the above example,
+with the exception that the variable \c x1 is specified to be
+\c INTEGER valued. \c x2 is set to \c REAL, which is the default option.
+
+\code
+  // Set the type of the columns
+  mip.colType(x1, Mip::INTEGER);
+  mip.colType(x2, Mip::REAL);
 \endcode
 
+Because of this integrality requirement, the results will be different
+from the LP solution.
+
+\code
+  Objective function value: 67
+  x1 = 8
+  x2 = 9
+\endcode
+
+The documnetation of the MIP solver interface can be found in the
+reference manual at the class \ref MipSolver. The common parts of the
+LP and MIP interfaces are docmented in their common ancestor class
+\ref LpBase.
+
+
+[SEC]sec_lp_optimization[SEC] Solving Complex Optimization Problems
+
+The LP and MIP solvers are powerful tools for solving various complex
+optimization problems, as well.
+The following example solves a maximum flow problem with linear
+programming, see the whole program in \re lp_maxflow_demo.cc.
+Several other graph optimization problems can also be expressed as
+linear programs and the interface provided in LEMON facilitates solving
+them easily (though usually not so efficiently as by a direct
+combinatorial method, if one exists). 
+
+\dontinclude lp_maxflow_demo.cc
+\skip DIGRAPH_TYPEDEFS
+\until solve()
+
+\note This problem can be solved much more efficiently using common
+combinatorial optimization methods, such as the \ref Preflow
+"preflow push-relabel algorithm".
+
 [TRAILER]
 */
 }
diff --git a/toc.txt b/toc.txt
--- a/toc.txt
+++ b/toc.txt
@@ -33,6 +33,9 @@
 ** sec_subgraphs
 ** sec_other_adaptors
 * sec_lp
+** sec_lp_basics
+** sec_lp_mip
+** sec_lp_optimization
 * sec_lgf
 * sec_tools
 ** sec_aux_structures



More information about the Lemon-commits mailing list