Rel.07 NEWS - 3. round
3 * This file is a part of LEMON, a generic C++ optimization library
5 * Copyright (C) 2003-2008
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
19 #ifndef LEMON_LP_UTILS_H
20 #define LEMON_LP_UTILS_H
22 #include <lemon/lp_base.h>
24 #include <lemon/lemon_reader.h>
25 #include <lemon/lemon_writer.h>
35 /// \brief The map for the result of the lp variables.
37 /// The map for the result of the lp variables.
40 typedef LpSolverBase::Col Key;
41 typedef LpSolverBase::Value Value;
43 /// \brief Constructor
46 LpResultMap(const LpSolverBase& _lp) : lp(_lp) {}
47 LpSolverBase::Value operator[](const LpSolverBase::Col col) const {
48 return lp.primal(col);
51 const LpSolverBase& lp;
56 /// \brief Returns an \ref LpResultMap class
58 /// This function just returns an \ref LpResultMap class.
59 /// \relates LpResultMap
60 LpResultMap lpResultMap(const LpSolverBase& lp);
64 /// \brief The map for the name of the lp variables.
66 /// The map for the name of the lp variables.
69 typedef LpSolverBase::Col Key;
70 typedef std::string Value;
72 /// \brief Constructor
75 LpColNameMap(const LpSolverBase& _lp) : lp(_lp) {}
76 std::string operator[](const LpSolverBase::Col col) const {
77 return lp.colName(col);
80 const LpSolverBase& lp;
85 /// \brief Writeable map for the name of the lp variables.
87 /// Writeable map for the name of the lp variables.
88 class LpColNameWriteMap {
90 typedef LpSolverBase::Col Key;
91 typedef std::string Value;
93 /// \brief Constructor
96 LpColNameWriteMap(LpSolverBase& _lp) : lp(_lp) {}
97 std::string operator[](const LpSolverBase::Col col) const {
98 return lp.colName(col);
100 void set(const LpSolverBase::Col col, const std::string& name) {
101 lp.colName(col, name);
107 /// \ingroup lp_utils
109 /// \brief Returns an \ref LpColNameMap class
111 /// This function just returns an \ref LpColNameMap class.
112 /// \relates LpColNameMap
113 LpColNameMap lpColNameMap(const LpSolverBase& lp);
115 LpColNameWriteMap lpColNameMap(LpSolverBase& lp);
117 /// \ingroup lp_utils
119 /// \brief Lp variable item reader for Lemon IO
121 /// This class is an Lp variable item reader for Lemon IO. It makes
122 /// possible to store lp variables in lemon file. The usage of this
123 /// class is very simple:
128 /// Graph::EdgeMap<Lp::Col> var(graph);
130 /// GraphReader<Graph> reader(cin, graph);
131 /// reader.readEdgeMap("lpvar", var, LpColReader(lp));
135 /// If there is already a variable with the same name in the lp then
136 /// it will be used for the return value. If there is no such variable
137 /// then it will be constructed. The file could contain \c '-' as value
138 /// which means that no lp variable associated to the current item and
139 /// in this case INVALID will be returned.
143 /// \brief The value type of reader.
145 /// The value type of reader.
146 typedef LpSolverBase::Col Value;
148 /// \brief Constructor for the reader.
150 /// Constructor for the reader.
151 LpColReader(LpSolverBase& _lp) : lp(_lp) {}
153 /// \brief Reads an lp variable from the given stream.
155 /// Reads an lp variable string from the given stream.
156 void read(std::istream& is, LpSolverBase::Col& col) const {
160 throw DataFormatError("Wrong Lp Column format!");
161 if (varFirstChar(x)) {
165 while (is.get(x) && varChar(x)) {
173 col = lp.colByName(var);
174 if (col == INVALID) {
176 lp.colName(col, var);
178 } else if (x == '-') {
182 std::cerr << x << std::endl;
183 throw DataFormatError("Wrong Lp Column format");
189 static bool varFirstChar(char c) {
190 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
193 static bool varChar(char c) {
194 return (c >= '0' && c <= '9') ||
195 (c >= 'a' && c <= 'z') ||
196 (c >= 'A' && c <= 'Z') ||
197 c == '[' || c == ']';
204 /// \ingroup lp_utils
206 /// \brief Lp variable item writer for Lemon IO
208 /// This class is an Lp variable item writer for Lemon IO. It makes
209 /// possible to store lp variables in lemon file. The usage of this
210 /// class is very simple:
215 /// Graph::EdgeMap<Lp::Col> var(graph);
217 /// GraphWriter<Graph> writer(cin, graph);
218 /// writer.writeEdgeMap("lpvar", var, LpColWriter(lp));
222 /// If there is no name associated to the current item then the name
223 /// will automatically constructed. If the value is INVALID then it
224 /// will write an \c '-' value to the file.
228 /// \brief The value type of writer.
230 /// The value type of writer.
231 typedef LpSolverBase::Col Value;
233 /// \brief Constructor for the writer.
235 /// Constructor for the writer.
236 LpColWriter(const LpSolverBase& _lp) : lp(_lp), num(0) {}
238 /// \brief Writes an lp variable to the given stream.
240 /// Writes an lp variable to the given stream.
241 void write(std::ostream& os, const LpSolverBase::Col& col) const {
242 if (col != INVALID) {
243 std::string name = lp.colName(col);
245 std::ostringstream ls;
248 while (lp.colByName(ls.str()) != INVALID) {
249 ls.str(std::string());
253 const_cast<LpSolverBase&>(lp).colName(col, ls.str());
265 const LpSolverBase& lp;
270 /// \ingroup lp_utils
272 /// \brief Lp section reader for lemon IO
274 /// This section reader provides an easy way to read an Lp problem
275 /// from a file. The lemon lp section format contains three parts.
281 /// 2 * x1 + x3 / 2 <= 7
282 /// x2 + -3 * x3 >= 8
283 /// 3 <= x2 - 2 * x1 <= 8
289 /// min x1 + 2 * x2 - x3
292 /// The first part gives the constraints to the lp. The constraints
293 /// could be equality, lower bound, upper bound or range for an
294 /// expression or equality, less or more for two expressions.
296 /// The second part gives the bounds for the variables. The bounds
297 /// could be the same as for the single expression so equality,
298 /// lower bound, upper bound or range.
300 /// The third part is the objective function, it should start with
301 /// \c min or \c max and then a valid linear expression.
303 /// The reader constructs automatically the variable for a name if
304 /// there is not already a variable with the same name.
306 /// The basic way to read an LP problem is made by the next code:
310 /// LemonReader reader(filename_or_istream);
311 /// LpReader lpreader(reader, lp);
316 /// Of course instead of \c LemonReader you can give a \c
317 /// GraphReader to the LpReader constructor. Also useful that you
318 /// can mix lp problems and graphs in the same file.
319 class LpReader : public LemonReader::SectionReader {
320 typedef LemonReader::SectionReader Parent;
324 /// \brief Constructor.
326 /// Constructor for LpReader. It creates the LpReader and attachs
327 /// it into the given LemonReader. The lp reader will add
328 /// variables, constraints and objective function to the
330 LpReader(LemonReader& _reader, LpSolverBase& _lp,
331 const std::string& _name = std::string())
332 : Parent(_reader), lp(_lp), name(_name) {}
335 /// \brief Destructor.
337 /// Destructor for LpReader.
338 virtual ~LpReader() {}
341 LpReader(const LpReader&);
342 void operator=(const LpReader&);
346 /// \brief Gives back true when the SectionReader can process
347 /// the section with the given header line.
349 /// It gives back true when the header line starts with \c \@lp,
350 /// and the header line's name and the nodeset's name are the same.
351 virtual bool header(const std::string& line) {
352 std::istringstream ls(line);
356 return command == "@lp" && name == id;
362 CONSTRAINTS, BOUNDS, OBJECTIVE
369 std::istream& readConstraint(std::istream& is) {
370 LpSolverBase::Constr c;
372 LpSolverBase::Expr e1, e2;
375 readExpression(is, e1);
377 readRelation(is, op1);
379 readExpression(is, e2);
383 if (e1.size() == 0) {
389 } else if (op1 == GE) {
390 if (e1.size() == 0) {
396 if (e1.size() == 0) {
404 LpSolverBase::Expr e3;
406 readRelation(is, op2);
408 readExpression(is, e3);
409 if (!e1.empty() || !e3.empty()) {
410 throw DataFormatError("Wrong range format");
412 if (op2 != op1 || op1 == EQ) {
413 throw DataFormatError("Wrong range format");
416 c = e1.constComp() <= e2 <= e3.constComp();
418 c = e1.constComp() >= e2 >= e3.constComp();
422 throw DataFormatError("Wrong variable bounds format");
429 std::istream& readObjective(std::istream& is) {
433 if (sense != "min" && sense != "max") {
434 throw DataFormatError("Wrong objective function format");
436 LpSolverBase::Expr expr;
438 readExpression(is, expr);
440 if (sense == "min") {
448 std::istream& readBounds(std::istream& is) {
453 throw DataFormatError("Wrong variable bounds format");
455 if (varFirstChar(x)) {
460 readRelation(is, op1);
464 lp.colLowerBound(c, v);
465 lp.colUpperBound(c, v);
466 } else if (op1 == LE) {
467 lp.colUpperBound(c, v);
469 lp.colLowerBound(c, v);
473 throw DataFormatError("Wrong variable bounds format");
481 readRelation(is, op1);
489 readRelation(is, op2);
493 if (op2 != op1 || op1 == EQ) {
494 throw DataFormatError("Wrong range format");
497 lp.colLowerBound(c, v);
498 lp.colUpperBound(c, w);
500 lp.colLowerBound(c, w);
501 lp.colUpperBound(c, v);
505 throw DataFormatError("Wrong variable bounds format");
509 lp.colLowerBound(c, v);
510 lp.colUpperBound(c, v);
511 } else if (op1 == LE) {
512 lp.colLowerBound(c, v);
514 lp.colUpperBound(c, v);
521 std::istream& readExpression(std::istream& is, LpSolverBase::Expr& e) {
525 readElement(is, c, d);
532 while (is.get(x) && (x == '+' || x == '-')) {
534 readElement(is, c, d);
536 e += (x == '+' ? d : -d) * c;
538 e += (x == '+' ? d : -d);
550 std::istream& readElement(std::istream& is,
551 LpSolverBase::Col& c, double& d) {
555 if (!is.get(x)) throw DataFormatError("Cannot find lp element");
556 if (x == '+' || x == '-') {
558 d *= x == '-' ? -1 : 1;
559 while (is.get(x) && (x == '+' || x == '-')) {
560 d *= x == '-' ? -1 : 1;
563 if (!is) throw DataFormatError("Cannot find lp element");
565 if (numFirstChar(x)) {
570 } else if (varFirstChar(x)) {
576 throw DataFormatError("Invalid expression format");
579 while (is.get(y) && (y == '*' || y == '/')) {
581 if (!is.get(x)) throw DataFormatError("Cannot find lp element");
582 if (x == '+' || x == '-') {
584 d *= x == '-' ? -1 : 1;
585 while (is.get(x) && (x == '+' || x == '-')) {
586 d *= x == '-' ? -1 : 1;
589 if (!is) throw DataFormatError("Cannot find lp element");
591 if (numFirstChar(x)) {
600 } else if (varFirstChar(x)) {
608 throw DataFormatError("Quadratic element in expression");
611 throw DataFormatError("Division by variable");
614 throw DataFormatError("Invalid expression format");
626 std::istream& readCol(std::istream& is, LpSolverBase::Col& c) {
629 while (is.get(x) && varChar(x)) {
637 c = lp.colByName(var);
645 std::istream& readNum(std::istream& is, double& d) {
647 if (!is) throw DataFormatError("Wrong number format");
651 std::istream& readRelation(std::istream& is, Relation& op) {
653 if (!is.get(x) || !(x == '<' || x == '=' || x == '>')) {
654 throw DataFormatError("Wrong relation operator");
656 if (!is.get(y) || y != '=') {
657 throw DataFormatError("Wrong relation operator");
670 static bool relationFirstChar(char c) {
671 return c == '<' || c == '=' || c == '>';
674 static bool varFirstChar(char c) {
675 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
678 static bool numFirstChar(char c) {
679 return (c >= '0' && c <= '9') || c == '.';
682 static bool varChar(char c) {
683 return (c >= '0' && c <= '9') ||
684 (c >= 'a' && c <= 'z') ||
685 (c >= 'A' && c <= 'Z') ||
686 c == '[' || c == ']';
691 /// \brief Reader function of the section.
693 /// It reads the content of the section.
694 virtual void read(std::istream& is) {
696 Part part = CONSTRAINTS;
697 while (getline(is, line)) {
698 std::istringstream ls(line);
701 if (type == "constraints") {
706 throw DataFormatError("Wrong Lp format");
707 } else if (type == "bounds") {
712 throw DataFormatError("Wrong Lp format");
713 } else if (type == "objective") {
718 throw DataFormatError("Wrong Lp format");
736 virtual void missing() {
738 msg << "Lp section not found in file: @lp " << name;
739 throw IoParameterError(msg.message());
750 /// \ingroup lp_utils
752 /// \brief Lp section writer for lemon IO
754 /// This section reader provides an easy way to write an Lp problem
755 /// to a file. The lemon lp section format contains three parts.
761 /// 2 * x1 + x3 / 2 <= 7
762 /// x2 + -3 * x3 >= 8
763 /// 3 <= x2 - 2 * x1 <= 8
769 /// min x1 + 2 * x2 - x3
772 /// The first part gives the constraints to the lp. The constraints
773 /// could be equality, lower bound, upper bound or range for an
774 /// expression or equality, less or more for two expressions.
776 /// The second part gives the bounds for the variables. The bounds
777 /// could be the same as for the single expression so equality,
778 /// lower bound, upper bound or range.
780 /// The third part is the objective function, it should start with
781 /// \c min or \c max and then a valid linear expression.
783 /// If an LP variable does not have name in the writer, then it will
784 /// automatically created in the writer. This make a slight change
785 /// in the \c const variable.
787 /// The basic way to write an LP problem is made by the next code:
791 /// LemonWriter writer(filename_or_ostream);
792 /// LpWriter lpwriter(writer, lp);
797 /// Of course instead of \c LemonWriter you can give a \c
798 /// GraphWriter to the LpWriter constructor. Also useful that you
799 /// can mix lp problems and graphs in the same file.
800 class LpWriter : public LemonWriter::SectionWriter {
801 typedef LemonWriter::SectionWriter Parent;
805 /// \brief Constructor.
807 /// Constructor for LpWriter. It creates the LpWriter and attach
808 /// it into the given LemonWriter.
809 LpWriter(LemonWriter& _writer, const LpSolverBase& _lp,
810 const std::string& _name = std::string())
811 : Parent(_writer), lp(_lp), name(_name) {}
814 /// \brief Destructor.
816 /// Destructor for LpWriter.
817 virtual ~LpWriter() {}
820 LpWriter(const LpWriter&);
821 void operator=(const LpWriter&);
825 /// \brief Gives back true when the SectionWriter can process
826 /// the section with the given header line.
828 /// It gives back the header line of the \c \@lp section.
829 virtual std::string header() {
830 std::ostringstream ls;
831 ls << "@lp " << name;
840 for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
841 std::string name = lp.colName(it);
843 std::ostringstream ls;
846 while (lp.colByName(ls.str()) != INVALID) {
847 ls.str(std::string());
851 const_cast<LpSolverBase&>(lp).colName(it, ls.str());
856 void writeExpression(std::ostream& os, const LpSolverBase::Expr& e) {
858 for (LpSolverBase::Expr::const_iterator jt = e.begin();
859 jt != e.end(); ++jt) {
860 if (jt->second < 0.0) {
862 if (jt->second != -1.0) {
863 os << -jt->second << " * ";
865 } else if (jt->second > 0.0) {
869 if (jt->second != 1.0) {
870 os << jt->second << " * ";
874 os << lp.colName(jt->first) << " ";
876 if (e.constComp() < 0.0) {
877 os << "- " << -e.constComp() << " ";
878 } else if (e.constComp() > 0.0) {
882 os << e.constComp() << " ";
884 if (e.begin() == e.end() && e.constComp() == 0.0) {
891 /// \brief Writer function of the section.
893 /// It writes the content of the section.
894 virtual void write(std::ostream& os) {
897 os << "constraints" << std::endl;
899 for (LpSolverBase::RowIt it(lp); it != INVALID; ++it) {
901 lp.getRowBounds(it, lower, upper);
902 if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF)
906 if (lower != upper) {
907 if (lower != -LpSolverBase::INF) {
908 os << lower << " <= ";
911 writeExpression(os, lp.row(it));
913 if (upper != LpSolverBase::INF) {
914 os << "<= " << upper << " ";
918 writeExpression(os, lp.row(it));
919 os << "== " << upper << " ";
926 os << "bounds" << std::endl;
928 for (LpSolverBase::ColIt it(lp); it != INVALID; ++it) {
929 double lower = lp.colLowerBound(it);
930 double upper = lp.colUpperBound(it);
931 if (lower == -LpSolverBase::INF && upper == LpSolverBase::INF)
935 if (lower != upper) {
936 if (lower != -LpSolverBase::INF) {
937 os << lower << " <= ";
940 os << lp.colName(it) << " ";
942 if (upper != LpSolverBase::INF) {
943 os << "<= " << upper << " ";
946 os << lp.colName(it) << " == " << upper << " ";
951 os << "objective" << std::endl;
958 writeExpression(os, lp.obj());
965 const LpSolverBase& lp;