// -*- c++ -*-
#include <iostream>
#include <fstream>
#include <string>

#include <list_graph.h>
#include <smart_graph.h>
#include <dimacs.h>
#include <edmonds_karp.h>
#include <preflow.h>
#include <time_measure.h>
#include <for_each_macros.h>

using namespace hugo;

// Use a DIMACS max flow file as stdin.
// read_dimacs_demo dimacs_max_flow_file

int main(int, char** argv) {

  std::string in=argv[1];
  typedef ListGraph MutableGraph;

  {
    typedef ListGraph Graph;
    typedef Graph::Node Node;
    typedef Graph::EdgeIt EdgeIt;

    Graph G;
    Node s, t;
    Graph::EdgeMap<int> cap(G);
    std::ifstream ins(in.c_str());
    readDimacsMaxFlow(ins, G, s, t, cap);

    Timer ts;
    Graph::EdgeMap<int> flow(G); //0 flow
    Preflow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
      pre_flow_test(G, s, t, cap, flow, true);
    MaxFlow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
      max_flow_test(G, s, t, cap, flow);

    std::cout << "ListGraph ..." << std::endl;

    {
      std::cout << "preflow ..." << std::endl;
      ts.reset();
      pre_flow_test.run();
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "flow value: "<< pre_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "physical blocking flow augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnBlockingFlow<MutableGraph>()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "faster physical blocking flow augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnBlockingFlow1<MutableGraph>()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "on-the-fly blocking flow augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnBlockingFlow2()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "on-the-fly shortest path augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnShortestPath()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }
  }


  {
    typedef SmartGraph Graph;
    typedef Graph::Node Node;
    typedef Graph::EdgeIt EdgeIt;

    Graph G;
    Node s, t;
    Graph::EdgeMap<int> cap(G);
    std::ifstream ins(in.c_str());
    readDimacsMaxFlow(ins, G, s, t, cap);

    Timer ts;
    Graph::EdgeMap<int> flow(G); //0 flow
    Preflow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
      pre_flow_test(G, s, t, cap, flow, true);
    MaxFlow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
      max_flow_test(G, s, t, cap, flow);

    std::cout << "SmatrGraph ..." << std::endl;

    {
      std::cout << "preflow ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      pre_flow_test.run();
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "flow value: "<< pre_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "physical blocking flow augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnBlockingFlow<MutableGraph>()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "faster physical blocking flow augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnBlockingFlow1<MutableGraph>()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "on-the-fly blocking flow augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnBlockingFlow2()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }

    {
      std::cout << "on-the-fly shortest path augmentation ..." << std::endl;
      FOR_EACH_LOC(Graph::EdgeIt, e, G) flow.set(e, 0);
      ts.reset();
      int i=0;
      while (max_flow_test.augmentOnShortestPath()) { ++i; }
      std::cout << "elapsed time: " << ts << std::endl;
      std::cout << "number of augmentation phases: " << i << std::endl; 
      std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;
    }
  }




  return 0;
}
