/* Copyright (c) 1997-2004
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
   http://www.math.tu-berlin.de/polymake,  mailto:polymake@math.tu-berlin.de

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version: http://www.gnu.org/licenses/gpl.txt.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
*/

#ident "$Project: polymake $$Id: poly2lp.cc,v 1.12 2006/01/16 14:01:33 gawrilow Exp $"

#include <SparseMatrix.h>
#include <SparseVector.h>
#include <Poly.h>

namespace polymake { namespace polytope {

namespace {

template <typename Traits, typename _Vector>
std::basic_ostream<char, Traits>&
print_row (std::basic_ostream<char, Traits>& os, const GenericVector<_Vector>& v, const char* relop=0) {
   typename Entire<_Vector>::const_iterator e=entire(v);
   typename _Vector::element_type free_term=0;
   if (e.index()==0) {
      free_term=*e;  ++e;
   }
   while (!e.at_end()) {
      os << ' ' << std::setiosflags(std::ios::showpos) << *e << std::resetiosflags(std::ios::showpos) << " x" << e.index();
      ++e;
   }
   if (relop) {
      os << ' ' << relop << ' ' << -free_term;
   } else if (free_term) {
      os << ' ' << std::setiosflags(std::ios::showpos) << free_term << std::resetiosflags(std::ios::showpos);
   }
   os << '\n';
   return os;
}

}

template <typename Traits>
void poly2lp(Poly& p, std::basic_ostream<char, Traits>& os)
{
   const SparseMatrix<double> IE=p.give("INEQUALITIES | FACETS"),
                              EQ=p.lookup("EQUATIONS | AFFINE_HULL");
   const SparseVector<double> LO=p.give("LINEAR_OBJECTIVE");

   const int n_variables=IE.cols();

   os << std::setprecision(16)
      << "MINIMIZE\n"
      << "  obj:";
   print_row(os, LO);

   os << "Subject To\n";
   for (Entire< Rows< SparseMatrix<double> > >::const_iterator ie=entire(rows(IE)); !ie.at_end(); ++ie) {
      os << "  ie" << ie.index() << ':';      // cplex enumerates from 1, ...
      print_row(os, *ie, ">=");
   }

   for (Entire< Rows< SparseMatrix<double> > >::const_iterator eq=entire(rows(EQ)); !eq.at_end(); ++eq) {
      os << "  eq" << eq.index() << ':';      // cplex enumerates from 1, ...
      print_row(os, *eq, "=");
   }

   os << "BOUNDS\n";
   for (int i=1; i<n_variables; ++i)
      os << "  x" << i << " free\n"; 

   os << "END\n";
}

} }

using namespace polymake;

/** @file poly2lp
 *
 *  Convert a polymake description of a polyhedron to LP format (as used by CPLEX and other linear problem solvers)
 *  and write it to standard output.
 *
 *  @synopsis poly2lp <file>
 *
 *  @index utilities
 */

int main(int argc, const char *argv[]) {
   if (argc != 2) {
      cerr << "usage: " << argv[0] << " <file> " << endl;
      return 1;
   }
   try {
      Poly p(argv[1],ios::in);
      polytope::poly2lp(p, std::cout);
   }
   catch (const std::exception& e) {
      cerr << e.what() << endl;
      return 1;
   }
   return 0;
}
