/* check-representation.cpp -- Check whether a vector is generated by given generators
	       
   Copyright 2007 Matthias Koeppe

   This file is part of LattE.
   
   LattE is free software; you can redistribute it and/or modify it
   under the terms of the version 2 of the GNU General Public License
   as published by the Free Software Foundation.

   LattE 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.

   You should have received a copy of the GNU General Public License
   along with LattE; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/

#include <cstdlib>
#include <cassert>
#include <climits>
#include <cstring>
#include <string>
#include <iostream>
#include <fstream>

#include <cplex.h>

#include "ReductionTest.h"

using namespace std;

int verbose = false;

ReductionTest *reduction_test = NULL;
ReductionTestFactory reduction_test_factory;

static void usage()
{
  cerr << "usage: check-representation [OPTIONS] VECTORS" << endl;
  cerr << "Options are: " << endl
       << "  --no-header                              Read an input file without a dimensions header" << endl;
  reduction_test_factory.show_options(cerr);
}

void
open_matrix_file(const string &filename, ifstream &file,
		 int &num, int &dim)
{
  file.open(filename.c_str());
  if (!file.good()) {
    cerr << "Failed to open " << filename << endl;
    exit(1);
  }
  file >> num >> dim;
  if (!file.good()) {
    cerr << "Parse error reading file " << filename << endl;
    exit(1);
  }
}

int main(int argc, char **argv)
{
  if (argc < 2) {
    usage();
    exit(1);
  }
  // Set default.
  reduction_test_factory.type = ReductionTestFactory::ReductionWithCPLEX;
  
  bool vectors_file_no_header = false;
  {
    int i;
    for (i = 1; i<argc-1; i++) {
      if (reduction_test_factory.parse_option(argv[i])) {}
      else if (strcmp(argv[i], "--no-header") == 0) {
	vectors_file_no_header = true;
      }
      else if (strcmp(argv[i], "--verbose") == 0) {
	reduction_test_factory.verbose = true;
      }
      else {
	cerr << "Unknown option: " << argv[i] << endl;
	exit(1);
      }
    }
  }
  reduction_test = reduction_test_factory.CreateReductionTest();

  int dim_generators = reduction_test->GetDimension();
  
  string vectors_filename(argv[argc - 1]);
  int num_vectors, dim_vectors;
  ifstream vectors_file;
  if (vectors_file_no_header) {
    vectors_file.open(vectors_filename.c_str());
    if (!vectors_file.good()) {
      cerr << "Failed to open file " << vectors_filename << endl;
      exit(1);
    }
    if (dim_generators < 0) {
      cerr << "Sorry, I do not know the dimension of the vectors." << endl;
      exit(1);
    }
    dim_vectors = dim_generators;
    num_vectors = INT_MAX;
  }
  else {
    open_matrix_file(vectors_filename, vectors_file, num_vectors, dim_vectors);
    if (dim_generators >= 0) {
      assert(dim_vectors == dim_generators);
    }
  }

  cerr << "Checking that all vectors are generated over the nonnegative reals, and the nonnegative integers." << endl;
  vector<int> v(dim_vectors);
  int i;
  for (i = 0; i<num_vectors; i++) {
    if (i % 1000 == 0) {
      cerr << i << "/" << num_vectors << " done. " << endl;
    }
    if (verbose)
    	cerr << "Checking vector: ";
    int j;
    for (j = 0; j<dim_vectors; j++) {
      vectors_file >> v[j];
      if (verbose)
    	  cerr << v[j] << " ";
    }

    if (vectors_file_no_header && vectors_file.eof()) {
    	cerr << "After reading " << i << " vectors, end of file." << endl;
      exit(0);
    }
    if (!vectors_file.good()) {
    	cerr << "After reading " << i << " vectors, parse error reading vectors file" << endl;
      exit(1);
    }
    if (verbose)
    	cerr << endl;

    if (!reduction_test->IsReducible(v)) {
    	cerr << "Irreducible: ";
      for (j = 0; j<dim_vectors; j++)
    	  cerr << v[j] << " ";
      cerr << endl;
    }
  }
  delete reduction_test;
}
