/* Copyright (c) 1997-2010
   Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Darmstadt, Germany)
   http://www.polymake.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.
--------------------------------------------------------------------------------
   $Project: polymake $$Id: check_inc.cc 9991 2010-12-12 23:36:28Z gawrilow $
*/

#include "polymake/client.h"
#include "polymake/Rational.h"
#include "polymake/Matrix.h"
#include <sstream>

namespace polymake { namespace polytope {

bool check_inc(const Matrix<Rational>& P, const Matrix<Rational>& H, const char* sign_arg, bool verbose)
{
   bool ok=true,
     minus=false, equal=false, plus=false;  // what is allowed
   int n_minus=0, n_equal=0, n_plus=0;         // number of point/hyperplane pairs

   // analyze sign argument
   char c;
   for (int i=0; (c = sign_arg[i]); ++i) {
      switch (c) {
      case '-' : minus = true; break;
      case '0' : equal = true; break;
      case '+' : plus  = true; break;
      default :
         std::ostringstream err_msg;
         err_msg << "check_inc: unrecognized sign argument " << sign_arg;
         throw std::runtime_error(err_msg.str());
      }
   }

   // read the points and hyperplanes
   // matrices of points and hyperplanes, rsp.

   if (!P.rows() || !H.rows())   // nothing to do
      return true;
   if (P.cols() != H.cols()) {
      std::ostringstream err_msg;
      err_msg << "check_inc: the matrices must match in dimension";
      throw std::runtime_error(err_msg.str());
   }

   // check all pairs
   Rational scp;
   for (int i=0; i<P.rows(); ++i) {
      for (int j=0; j<H.rows(); ++j) {
         scp = P[i] * H[j];
         int s=sign(scp);
         if (s<0) {
            n_minus++;
            if (!minus) {
               if (verbose)
                  cout << "<" << i << "," << j << ">   ( "
                       << P[i] << " ) * [ " << H[j] << " ] == " << scp << endl;
               ok=false;
            }
         } else if (s==0) {
            n_equal++;
            if (!equal) {
               if (verbose)
                  cout << "<" << i << "," << j << ">   ( "
                       << P[i] << " ) * [ " << H[j] << " ] == " << scp << endl;
               ok=false;
            }
         } else {
            n_plus++;
            if (!plus) {
               if (verbose)
                  cout << "<" << i << "," << j << ">   ( "
                       << P[i] << " ) * [ " << H[j] << " ] == " << scp << endl;
               ok=false;
            }
         }
      }
   }

   // print statistics if data not plausible
   if (!ok && verbose)
      cout << "#points==" << P.rows() << ", #hyperplanes==" << H.rows()
           << ", -:" << n_minus << ", 0:" << n_equal
           << ", +:" << n_plus << ", total:" << P.rows()*H.rows() << endl;
   return ok;
}

UserFunction4perl("# @category Consistency check"
                  "# Check coordinate data. For each pair of vectors from two given matrices"
                  "# their inner product must satisfy the given relation."
                  "# @param Matrix points"
                  "# @param Matrix hyperplanes"
                  "# @param String sign composed of one or two characters from [-+0], representing the"
                  "#  allowed domain of the vector inner products."
                  "# @param Bool verbose print all products violating the required relation",
                  &check_inc,"check_inc(Matrix Matrix $; $=0)");
} }

// Local Variables:
// mode:C++
// c-basic-offset:3
// indent-tabs-mode:nil
// End:
