COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/work/athos/lp/lp_base.h @ 1294:2dec219d9ca2

Last change on this file since 1294:2dec219d9ca2 was 1294:2dec219d9ca2, checked in by Alpar Juttner, 19 years ago

Documentation of abstract functions is in lp_solver_skeleton.h

File size: 21.4 KB
Line 
1/* -*- C++ -*-
2 * src/lemon/lp_base.h - Part of LEMON, a generic C++ optimization library
3 *
4 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
5 * (Egervary Combinatorial Optimization Research Group, EGRES).
6 *
7 * Permission to use, modify and distribute this software is granted
8 * provided that this copyright notice appears in all copies. For
9 * precise terms see the accompanying LICENSE file.
10 *
11 * This software is provided "AS IS" with no warranty of any kind,
12 * express or implied, and with no claim as to its suitability for any
13 * purpose.
14 *
15 */
16
17#ifndef LEMON_LP_BASE_H
18#define LEMON_LP_BASE_H
19
20#include<vector>
21#include<map>
22#include<limits>
23#include<math.h>
24
25#include<lemon/utility.h>
26#include<lemon/error.h>
27#include<lemon/invalid.h>
28
29//#include"lin_expr.h"
30
31///\file
32///\brief The interface of the LP solver interface.
33namespace lemon {
34 
35  ///Internal data structure to convert floating id's to fix one's
36   
37  ///\todo This might be implemented to be also usable in other places.
38  class _FixId
39  {
40    std::vector<int> index;
41    std::vector<int> cross;
42    int first_free;
43  public:
44    _FixId() : first_free(-1) {};
45    ///Convert a floating id to a fix one
46
47    ///\param n is a floating id
48    ///\return the corresponding fix id
49    int fixId(int n) {return cross[n];}
50    ///Convert a fix id to a floating one
51
52    ///\param n is a fix id
53    ///\return the corresponding floating id
54    int floatingId(int n) { return index[n];}
55    ///Add a new floating id.
56
57    ///\param n is a floating id
58    ///\return the fix id of the new value
59    ///\todo Multiple additions should also be handled.
60    int insert(int n)
61    {
62      if(n>=int(cross.size())) {
63        cross.resize(n+1);
64        if(first_free==-1) {
65          cross[n]=index.size();
66          index.push_back(n);
67        }
68        else {
69          cross[n]=first_free;
70          int next=index[first_free];
71          index[first_free]=n;
72          first_free=next;
73        }
74        return cross[n];
75      }
76      ///\todo Create an own exception type.
77      else throw LogicError(); //floatingId-s must form a continuous range;
78    }
79    ///Remove a fix id.
80
81    ///\param n is a fix id
82    ///
83    void erase(int n)
84    {
85      int fl=index[n];
86      index[n]=first_free;
87      first_free=n;
88      for(int i=fl+1;i<int(cross.size());++i) {
89        cross[i-1]=cross[i];
90        index[cross[i]]--;
91      }
92      cross.pop_back();
93    }
94    ///An upper bound on the largest fix id.
95
96    ///\todo Do we need this?
97    ///
98    std::size_t maxFixId() { return cross.size()-1; }
99 
100  };
101   
102  ///Common base class for LP solvers
103  class LpSolverBase {
104   
105  public:
106
107    ///\e
108    enum SolutionStatus {
109      ///\e
110      SOLVED = 0,
111      ///\e
112      UNSOLVED = 1
113    };
114     
115    ///\e
116    enum SolutionType {
117      ///\e
118      UNDEFINED = 0,
119      ///\e
120      INFEASIBLE = 1,
121      ///\e
122      FEASIBLE = 2,
123      ///\e
124      OPTIMAL = 3
125    };
126     
127    ///The floating point type used by the solver
128    typedef double Value;
129    ///The infinity constant
130    static const Value INF;
131    ///The not a number constant
132    static const Value NaN;
133   
134    ///Refer to a column of the LP.
135
136    ///This type is used to refer to a column of the LP.
137    ///
138    ///Its value remains valid and correct even after the addition or erase of
139    ///other columns.
140    ///
141    ///\todo Document what can one do with a Col (INVALID, comparing,
142    ///it is similar to Node/Edge)
143    class Col {
144    protected:
145      int id;
146      friend class LpSolverBase;
147    public:
148      typedef Value ExprValue;
149      typedef True LpSolverCol;
150      Col() {}
151      Col(const Invalid&) : id(-1) {}
152      bool operator<(Col c) const  {return id<c.id;}
153      bool operator==(Col c) const  {return id==c.id;}
154      bool operator!=(Col c) const  {return id==c.id;}
155    };
156
157    ///Refer to a row of the LP.
158
159    ///This type is used to refer to a row of the LP.
160    ///
161    ///Its value remains valid and correct even after the addition or erase of
162    ///other rows.
163    ///
164    ///\todo Document what can one do with a Row (INVALID, comparing,
165    ///it is similar to Node/Edge)
166    class Row {
167    protected:
168      int id;
169      friend class LpSolverBase;
170    public:
171      typedef Value ExprValue;
172      typedef True LpSolverRow;
173      Row() {}
174      Row(const Invalid&) : id(-1) {}
175      typedef True LpSolverRow;
176      bool operator<(Row c) const  {return id<c.id;}
177      bool operator==(Row c) const  {return id==c.id;}
178      bool operator!=(Row c) const  {return id==c.id;}
179   };
180   
181    ///Linear expression of variables and a constant component
182   
183    ///This data structure strores a linear expression of the variables
184    ///(\ref Col "Col"s) and also has a constant component.
185    ///
186    ///There are several ways to access and modify the contents of this
187    ///container.
188    ///- Its it fully compatible with \c std::map<Col,double>, so for expamle
189    ///if \c e is an Expr and \c v and \c w are of type \ref Col then you can
190    ///read and modify the coefficients like
191    ///these.
192    ///\code
193    ///e[v]=5;
194    ///e[v]+=12;
195    ///e.erase(v);
196    ///\endcode
197    ///or you can also iterate through its elements.
198    ///\code
199    ///double s=0;
200    ///for(LpSolverBase::Expr::iterator i=e.begin();i!=e.end();++i)
201    ///  s+=i->second;
202    ///\endcode
203    ///(This code computes the sum of all coefficients).
204    ///- Numbers (<tt>double</tt>'s)
205    ///and variables (\ref Col "Col"s) directly convert to an
206    ///\ref Expr and the usual linear operations are defined so 
207    ///\code
208    ///v+w
209    ///2*v-3.12*(v-w/2)+2
210    ///v*2.1+(3*v+(v*12+w+6)*3)/2
211    ///\endcode
212    ///are valid expressions. The usual assignment operations are also defined.
213    ///\code
214    ///e=v+w;
215    ///e+=2*v-3.12*(v-w/2)+2;
216    ///e*=3.4;
217    ///e/=5;
218    ///\endcode
219    ///- The constant member can be set and read by \ref constComp()
220    ///\code
221    ///e.constComp()=12;
222    ///double c=e.constComp();
223    ///\endcode
224    ///
225    ///\note that \ref clear() not only sets all coefficients to 0 but also
226    ///clears the constant components.
227    class Expr : public std::map<Col,Value>
228    {
229    public:
230      typedef LpSolverBase::Col Key;
231      typedef LpSolverBase::Value Value;
232     
233    protected:
234      typedef std::map<Col,Value> Base;
235     
236      Value const_comp;
237  public:
238      typedef True IsLinExpression;
239      ///\e
240      Expr() : Base(), const_comp(0) { }
241      ///\e
242      Expr(const Key &v) : const_comp(0) {
243        Base::insert(std::make_pair(v, 1));
244      }
245      ///\e
246      Expr(const Value &v) : const_comp(v) {}
247      ///\e
248      void set(const Key &v,const Value &c) {
249        Base::insert(std::make_pair(v, c));
250      }
251      ///\e
252      Value &constComp() { return const_comp; }
253      ///\e
254      const Value &constComp() const { return const_comp; }
255     
256      ///Removes the components with zero coefficient.
257      void simplify() {
258        for (Base::iterator i=Base::begin(); i!=Base::end();) {
259          Base::iterator j=i;
260          ++j;
261          if ((*i).second==0) Base::erase(i);
262          j=i;
263        }
264      }
265
266      ///Sets all coefficients and the constant component to 0.
267      void clear() {
268        Base::clear();
269        const_comp=0;
270      }
271
272      ///\e
273      Expr &operator+=(const Expr &e) {
274        for (Base::const_iterator j=e.begin(); j!=e.end(); ++j)
275          (*this)[j->first]+=j->second;
276        ///\todo it might be speeded up using "hints"
277        const_comp+=e.const_comp;
278        return *this;
279      }
280      ///\e
281      Expr &operator-=(const Expr &e) {
282        for (Base::const_iterator j=e.begin(); j!=e.end(); ++j)
283          (*this)[j->first]-=j->second;
284        const_comp-=e.const_comp;
285        return *this;
286      }
287      ///\e
288      Expr &operator*=(const Value &c) {
289        for (Base::iterator j=Base::begin(); j!=Base::end(); ++j)
290          j->second*=c;
291        const_comp*=c;
292        return *this;
293      }
294      ///\e
295      Expr &operator/=(const Value &c) {
296        for (Base::iterator j=Base::begin(); j!=Base::end(); ++j)
297          j->second/=c;
298        const_comp/=c;
299        return *this;
300      }
301    };
302   
303    ///Linear constraint
304    //typedef LinConstr<Expr> Constr;
305    class Constr
306    {
307    public:
308      typedef LpSolverBase::Expr Expr;
309      typedef Expr::Key Key;
310      typedef Expr::Value Value;
311     
312      static const Value INF;
313      static const Value NaN;
314      //     static const Value INF=0;
315      //     static const Value NaN=1;
316     
317    protected:
318      Expr _expr;
319      Value _lb,_ub;
320    public:
321      ///\e
322      Constr() : _expr(), _lb(NaN), _ub(NaN) {}
323      ///\e
324      Constr(Value lb,const Expr &e,Value ub) :
325        _expr(e), _lb(lb), _ub(ub) {}
326      ///\e
327      Constr(const Expr &e,Value ub) :
328        _expr(e), _lb(NaN), _ub(ub) {}
329      ///\e
330      Constr(Value lb,const Expr &e) :
331        _expr(e), _lb(lb), _ub(NaN) {}
332      ///\e
333      Constr(const Expr &e) :
334        _expr(e), _lb(NaN), _ub(NaN) {}
335      ///\e
336      void clear()
337      {
338        _expr.clear();
339        _lb=_ub=NaN;
340      }
341      ///\e
342      Expr &expr() { return _expr; }
343      ///\e
344      const Expr &expr() const { return _expr; }
345      ///\e
346      Value &lowerBound() { return _lb; }
347      ///\e
348      const Value &lowerBound() const { return _lb; }
349      ///\e
350      Value &upperBound() { return _ub; }
351      ///\e
352      const Value &upperBound() const { return _ub; }
353      ///\e
354      bool lowerBounded() const { return std::isfinite(_lb); }
355      ///\e
356      bool upperBounded() const { return std::isfinite(_ub); }
357    };
358   
359
360  protected:
361    _FixId rows;
362    _FixId cols;
363
364    virtual int _addCol() = 0;
365    virtual int _addRow() = 0;
366    virtual void _setRowCoeffs(int i,
367                               int length,
368                               int  const * indices,
369                               Value  const * values ) = 0;
370    virtual void _setColCoeffs(int i,
371                               int length,
372                               int  const * indices,
373                               Value  const * values ) = 0;
374    virtual void _setColLowerBound(int i, Value value) = 0;
375    virtual void _setColUpperBound(int i, Value value) = 0;
376    virtual void _setRowLowerBound(int i, Value value) = 0;
377    virtual void _setRowUpperBound(int i, Value value) = 0;
378    virtual void _setObjCoeff(int i, Value obj_coef) = 0;
379    virtual SolutionStatus _solve() = 0;
380    virtual Value _getPrimal(int i) = 0;
381    virtual SolutionType _getPrimalType() = 0;
382
383
384    void clearObj() {}
385  public:
386
387
388    ///\e
389    virtual ~LpSolverBase() {}
390
391    ///\name Build up and modify of the LP
392
393    ///@{
394
395    ///Add a new empty column (i.e a new variable) to the LP
396    Col addCol() { Col c; c.id=cols.insert(_addCol()); return c;}
397
398    ///\brief Adds several new columns
399    ///(i.e a variables) at once
400    ///
401    ///This magic function takes a container as its argument
402    ///and fills its elements
403    ///with new columns (i.e. variables)
404    ///\param t can be
405    ///- a standard STL compatible iterable container with
406    ///\ref Col as its \c values_type
407    ///like
408    ///\code
409    ///std::vector<LpSolverBase::Col>
410    ///std::list<LpSolverBase::Col>
411    ///\endcode
412    ///- a standard STL compatible iterable container with
413    ///\ref Col as its \c mapped_type
414    ///like
415    ///\code
416    ///std::map<AnyType,LpSolverBase::Col>
417    ///\endcode
418    ///- an iterable lemon \ref concept::WriteMap "write map" like
419    ///\code
420    ///ListGraph::NodeMap<LpSolverBase::Col>
421    ///ListGraph::EdgeMap<LpSolverBase::Col>
422    ///\endcode
423    ///\return The number of the created column.
424    ///\bug Iterable nodemap hasn't been implemented yet.
425#ifdef DOXYGEN
426    template<class T>
427    int addColSet(T &t) { return 0;}
428#else
429    template<class T>
430    typename enable_if<typename T::value_type::LpSolverCol,int>::type
431    addColSet(T &t,dummy<0> = 0) {
432      int s=0;
433      for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addCol();s++;}
434      return s;
435    }
436    template<class T>
437    typename enable_if<typename T::value_type::second_type::LpSolverCol,
438                       int>::type
439    addColSet(T &t,dummy<1> = 1) {
440      int s=0;
441      for(typename T::iterator i=t.begin();i!=t.end();++i) {
442        i->second=addCol();
443        s++;
444      }
445      return s;
446    }
447    template<class T>
448    typename enable_if<typename T::ValueSet::value_type::LpSolverCol,
449                       int>::type
450    addColSet(T &t,dummy<2> = 2) {
451      ///\bug <tt>return addColSet(t.valueSet());</tt> should also work.
452      int s=0;
453      for(typename T::ValueSet::iterator i=t.valueSet().begin();
454          i!=t.valueSet().end();
455          ++i)
456        {
457          *i=addCol();
458          s++;
459        }
460      return s;
461    }
462#endif
463
464    ///Add a new empty row (i.e a new constaint) to the LP
465
466    ///This function adds a new empty row (i.e a new constaint) to the LP.
467    ///\return The created row
468    Row addRow() { Row r; r.id=rows.insert(_addRow()); return r;}
469
470    ///Set a row (i.e a constaint) of the LP
471
472    ///\param r is the row to be modified
473    ///\param l is lower bound (-\ref INF means no bound)
474    ///\param e is a linear expression (see \ref Expr)
475    ///\param u is the upper bound (\ref INF means no bound)
476    ///\bug This is a temportary function. The interface will change to
477    ///a better one.
478    void setRow(Row r, Value l,const Expr &e, Value u) {
479      std::vector<int> indices;
480      std::vector<Value> values;
481      indices.push_back(0);
482      values.push_back(0);
483      for(Expr::const_iterator i=e.begin(); i!=e.end(); ++i)
484        if((*i).second!=0) { ///\bug EPSILON would be necessary here!!!
485          indices.push_back(cols.floatingId((*i).first.id));
486          values.push_back((*i).second);
487        }
488      _setRowCoeffs(rows.floatingId(r.id),indices.size()-1,
489                    &indices[0],&values[0]);
490      _setRowLowerBound(rows.floatingId(r.id),l-e.constComp());
491      _setRowUpperBound(rows.floatingId(r.id),u-e.constComp());
492    }
493
494    ///Set a row (i.e a constaint) of the LP
495
496    ///\param r is the row to be modified
497    ///\param c is a linear expression (see \ref Constr)
498    void setRow(Row r, const Constr &c) {
499      setRow(r,
500             c.lowerBounded()?c.lowerBound():-INF,
501             c.expr(),
502             c.upperBounded()?c.upperBound():INF);
503    }
504
505    ///Add a new row (i.e a new constaint) to the LP
506
507    ///\param l is the lower bound (-\ref INF means no bound)
508    ///\param e is a linear expression (see \ref Expr)
509    ///\param u is the upper bound (\ref INF means no bound)
510    ///\return The created row.
511    ///\bug This is a temportary function. The interface will change to
512    ///a better one.
513    Row addRow(Value l,const Expr &e, Value u) {
514      Row r=addRow();
515      setRow(r,l,e,u);
516      return r;
517    }
518
519    ///Add a new row (i.e a new constaint) to the LP
520
521    ///\param c is a linear expression (see \ref Constr)
522    ///\return The created row.
523    Row addRow(const Constr &c) {
524      Row r=addRow();
525      setRow(r,c);
526      return r;
527    }
528
529    /// Set the lower bound of a column (i.e a variable)
530
531    /// The upper bound of a variable (column) has to be given by an
532    /// extended number of type Value, i.e. a finite number of type
533    /// Value or -\ref INF.
534    void colLowerBound(Col c, Value value) {
535      _setColLowerBound(cols.floatingId(c.id),value);
536    }
537    /// Set the upper bound of a column (i.e a variable)
538
539    /// The upper bound of a variable (column) has to be given by an
540    /// extended number of type Value, i.e. a finite number of type
541    /// Value or \ref INF.
542    void colUpperBound(Col c, Value value) {
543      _setColUpperBound(cols.floatingId(c.id),value);
544    };
545    /// Set the lower and the upper bounds of a column (i.e a variable)
546
547    /// The lower and the upper bounds of
548    /// a variable (column) have to be given by an
549    /// extended number of type Value, i.e. a finite number of type
550    /// Value, -\ref INF or \ref INF.
551    void colBounds(Col c, Value lower, Value upper) {
552      _setColLowerBound(cols.floatingId(c.id),lower);
553      _setColUpperBound(cols.floatingId(c.id),upper);
554    }
555   
556    /// Set the lower bound of a row (i.e a constraint)
557
558    /// The lower bound of a linear expression (row) has to be given by an
559    /// extended number of type Value, i.e. a finite number of type
560    /// Value or -\ref INF.
561    void rowLowerBound(Row r, Value value) {
562      _setRowLowerBound(rows.floatingId(r.id),value);
563    };
564    /// Set the upper bound of a row (i.e a constraint)
565
566    /// The upper bound of a linear expression (row) has to be given by an
567    /// extended number of type Value, i.e. a finite number of type
568    /// Value or \ref INF.
569    void rowUpperBound(Row r, Value value) {
570      _setRowUpperBound(rows.floatingId(r.id),value);
571    };
572    /// Set the lower and the upper bounds of a row (i.e a variable)
573
574    /// The lower and the upper bounds of
575    /// a constraint (row) have to be given by an
576    /// extended number of type Value, i.e. a finite number of type
577    /// Value, -\ref INF or \ref INF.
578    void rowBounds(Row c, Value lower, Value upper) {
579      _setRowLowerBound(rows.floatingId(c.id),lower);
580      _setRowUpperBound(rows.floatingId(c.id),upper);
581    }
582   
583    ///Set an element of the objective function
584    void objCoeff(Col c, Value v) {_setObjCoeff(cols.floatingId(c.id),v); };
585    ///Set the objective function
586   
587    ///\param e is a linear expression of type \ref Expr.
588    ///\todo What to do with the constant component?
589    void setObj(Expr e) {
590      clearObj();
591      for (Expr::iterator i=e.begin(); i!=e.end(); ++i)
592        objCoeff((*i).first,(*i).second);
593    }
594
595    ///@}
596
597
598    ///\name Solve the LP
599
600    ///@{
601
602    ///\e
603    SolutionStatus solve() { return _solve(); }
604   
605    ///@}
606   
607    ///\name Obtain the solution
608
609    ///@{
610
611    ///\e
612    SolutionType primalType() {
613      return _getPrimalType();
614    }
615
616    ///\e
617    Value primal(Col c) { return _getPrimal(cols.floatingId(c.id)); }
618
619    ///@}
620   
621  }; 
622
623  ///\e
624 
625  ///\relates LpSolverBase::Expr
626  ///
627  inline LpSolverBase::Expr operator+(const LpSolverBase::Expr &a,
628                                      const LpSolverBase::Expr &b)
629  {
630    LpSolverBase::Expr tmp(a);
631    tmp+=b; ///\todo Don't STL have some special 'merge' algorithm?
632    return tmp;
633  }
634  ///\e
635 
636  ///\relates LpSolverBase::Expr
637  ///
638  inline LpSolverBase::Expr operator-(const LpSolverBase::Expr &a,
639                                      const LpSolverBase::Expr &b)
640  {
641    LpSolverBase::Expr tmp(a);
642    tmp-=b; ///\todo Don't STL have some special 'merge' algorithm?
643    return tmp;
644  }
645  ///\e
646 
647  ///\relates LpSolverBase::Expr
648  ///
649  inline LpSolverBase::Expr operator*(const LpSolverBase::Expr &a,
650                                      const LpSolverBase::Value &b)
651  {
652    LpSolverBase::Expr tmp(a);
653    tmp*=b; ///\todo Don't STL have some special 'merge' algorithm?
654    return tmp;
655  }
656 
657  ///\e
658 
659  ///\relates LpSolverBase::Expr
660  ///
661  inline LpSolverBase::Expr operator*(const LpSolverBase::Value &a,
662                                      const LpSolverBase::Expr &b)
663  {
664    LpSolverBase::Expr tmp(b);
665    tmp*=a; ///\todo Don't STL have some special 'merge' algorithm?
666    return tmp;
667  }
668  ///\e
669 
670  ///\relates LpSolverBase::Expr
671  ///
672  inline LpSolverBase::Expr operator/(const LpSolverBase::Expr &a,
673                                      const LpSolverBase::Value &b)
674  {
675    LpSolverBase::Expr tmp(a);
676    tmp/=b; ///\todo Don't STL have some special 'merge' algorithm?
677    return tmp;
678  }
679 
680  ///\e
681 
682  ///\relates LpSolverBase::Constr
683  ///
684  inline LpSolverBase::Constr operator<=(const LpSolverBase::Expr &e,
685                                         const LpSolverBase::Expr &f)
686  {
687    return LpSolverBase::Constr(-LpSolverBase::INF,e-f,0);
688  }
689
690  ///\e
691 
692  ///\relates LpSolverBase::Constr
693  ///
694  inline LpSolverBase::Constr operator<=(const LpSolverBase::Value &e,
695                                         const LpSolverBase::Expr &f)
696  {
697    return LpSolverBase::Constr(e,f);
698  }
699
700  ///\e
701 
702  ///\relates LpSolverBase::Constr
703  ///
704  inline LpSolverBase::Constr operator<=(const LpSolverBase::Expr &e,
705                                         const LpSolverBase::Value &f)
706  {
707    return LpSolverBase::Constr(e,f);
708  }
709
710  ///\e
711 
712  ///\relates LpSolverBase::Constr
713  ///
714  inline LpSolverBase::Constr operator>=(const LpSolverBase::Expr &e,
715                                         const LpSolverBase::Expr &f)
716  {
717    return LpSolverBase::Constr(-LpSolverBase::INF,f-e,0);
718  }
719
720
721  ///\e
722 
723  ///\relates LpSolverBase::Constr
724  ///
725  inline LpSolverBase::Constr operator>=(const LpSolverBase::Value &e,
726                                         const LpSolverBase::Expr &f)
727  {
728    return LpSolverBase::Constr(f,e);
729  }
730
731
732  ///\e
733 
734  ///\relates LpSolverBase::Constr
735  ///
736  inline LpSolverBase::Constr operator>=(const LpSolverBase::Expr &e,
737                                         const LpSolverBase::Value &f)
738  {
739    return LpSolverBase::Constr(f,e);
740  }
741
742  ///\e
743 
744  ///\relates LpSolverBase::Constr
745  ///
746  inline LpSolverBase::Constr operator==(const LpSolverBase::Expr &e,
747                                         const LpSolverBase::Expr &f)
748  {
749    return LpSolverBase::Constr(0,e-f,0);
750  }
751
752  ///\e
753 
754  ///\relates LpSolverBase::Constr
755  ///
756  inline LpSolverBase::Constr operator<=(const LpSolverBase::Value &n,
757                                         const LpSolverBase::Constr&c)
758  {
759    LpSolverBase::Constr tmp(c);
760    ///\todo Create an own exception type.
761    if(!isnan(tmp.lowerBound())) throw LogicError();
762    else tmp.lowerBound()=n;
763    return tmp;
764  }
765  ///\e
766 
767  ///\relates LpSolverBase::Constr
768  ///
769  inline LpSolverBase::Constr operator<=(const LpSolverBase::Constr& c,
770                                         const LpSolverBase::Value &n)
771  {
772    LpSolverBase::Constr tmp(c);
773    ///\todo Create an own exception type.
774    if(!isnan(tmp.upperBound())) throw LogicError();
775    else tmp.upperBound()=n;
776    return tmp;
777  }
778
779  ///\e
780 
781  ///\relates LpSolverBase::Constr
782  ///
783  inline LpSolverBase::Constr operator>=(const LpSolverBase::Value &n,
784                                         const LpSolverBase::Constr&c)
785  {
786    LpSolverBase::Constr tmp(c);
787    ///\todo Create an own exception type.
788    if(!isnan(tmp.upperBound())) throw LogicError();
789    else tmp.upperBound()=n;
790    return tmp;
791  }
792  ///\e
793 
794  ///\relates LpSolverBase::Constr
795  ///
796  inline LpSolverBase::Constr operator>=(const LpSolverBase::Constr& c,
797                                         const LpSolverBase::Value &n)
798  {
799    LpSolverBase::Constr tmp(c);
800    ///\todo Create an own exception type.
801    if(!isnan(tmp.lowerBound())) throw LogicError();
802    else tmp.lowerBound()=n;
803    return tmp;
804  }
805
806
807} //namespace lemon
808
809#endif //LEMON_LP_BASE_H
Note: See TracBrowser for help on using the repository browser.