/* 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: face_lattice.cc,v 1.19 2004/06/22 16:23:09 gawrilow Exp $"

#include <Poly.h>
#include <IncidenceMatrix.h>
#include <FacetList.h>
#include <argv_options.h>

namespace polymake { namespace polytope {

namespace {

template <typename IMatrix>
FacetList faces_below(const FacetList& F, const GenericIncidenceMatrix<IMatrix>& VIF)
{
   FacetList F_below(F.cols());
   for (typename Entire<FacetList>::const_iterator face=entire(F); !face.at_end(); ++face) {
      // intersecting k-faces with facets
      for (typename Entire< Rows<IMatrix> >::const_iterator facet=entire(rows(VIF)); !facet.at_end(); ++facet) {
	 Set<int> face_below=(*face) * (*facet);
	 if (face_below.size() &&
	     face_below.size() < face->size() )  // only real subsets of the k-face are canditates for faces below
	    F_below.replaceMax(face_below);
      }
   }
   return F_below;
}

template <typename Layer> inline
void print_layer(pm::ostream_wrapper<>& os, const Layer& L)
{
   os << "{";
   for (typename Entire<Layer>::const_iterator l=entire(L); ;) {
      os << *l;
      if ((++l).at_end()) break;
      os << ' ';
   }
   os << "}\n";
}

template <typename IMatrix, typename Enum>
void print_lattice(pm::ostream_wrapper<>& os, const GenericIncidenceMatrix<IMatrix>& VIF, Enum dim)
{
   FacetList F(VIF.cols(), entire(rows(VIF)));
   do {
      os << "[ " << *dim << " : " << F.size() << " ]\n";
      print_layer(os, lex_ordered(F));
      os << endl;
      F=faces_below(F,VIF);
      ++dim;
   } while (!F.empty());
}

} // end unnamed namespace

void print_face_lattice(pm::ostream_wrapper<>& os, Poly& p, bool primal)
{
   const IncidenceMatrix<> VIF=p.give("VERTICES_IN_FACETS");
   if (primal) {
      os << "FACE_LATTICE\n\n";
      print_lattice(os, VIF, sequence(0,0).rbegin());
   } else {
      os << "DUAL_FACE_LATTICE\n\n";
      print_lattice(os, T(VIF), sequence(0,0).begin());
   }
}

} }

using namespace polymake;

/** @file face_lattice
 *
 *  Write the face lattice of the polytope or its dual to stdout.
 *
 *  $mode$ may be -primal or -dual
 *
 *  @synopsis face_lattice <file> <mode>
 *
 *  @reading  VERTICES_IN_FACETS
 */

int main(int argc, const char *argv[]) {
   argv_option options[]={ { "-primal" }, { "-dual" } };
   enum { primal, dual };
   if (argc != 3 ||
       !extract_options(argc,argv,1,options) ||
       argc != 2) {
      cerr << "usage: " << argv[0]  << " <file> { -primal | -dual }" << endl;
      return 1;
   }

   try {
      Poly p(argv[1], ios::in);
      polytope::print_face_lattice(cout, p, options[primal]);
   }
   catch (const std::exception& e) {
     cerr << e.what() << endl;
     return 1;
   }
   return 0;
}
