// -*- c++ -*-

// Use a DIMACS max flow file as stdin.
// max_flow_demo < dimacs_max_flow_file

#include <iostream>
#include <fstream>

#include <lemon/smart_graph.h>
#include <lemon/list_graph.h>
#include <lemon/dimacs.h>
#include <lemon/time_measure.h>
#include <lemon/preflow.h>
#include <augmenting_flow.h>
#include <graph_concept.h>

using namespace lemon;

int main(int, char **) {

  typedef ListGraph MutableGraph;
  typedef SmartGraph Graph;
  typedef Graph::Node Node;
  typedef Graph::EdgeIt EdgeIt;

  Graph g;

  Node s, t;
  Graph::EdgeMap<int> cap(g);
  //readDimacsMaxFlow(std::cin, g, s, t, cap);
  readDimacs(std::cin, g, cap, s, t);
  Timer ts;
  Graph::EdgeMap<int> flow(g); //0 flow
  Preflow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
    max_flow_test(g, s, t, cap, flow);
  AugmentingFlow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> > 
    augmenting_flow_test(g, s, t, cap, flow);
  
  Graph::NodeMap<bool> cut(g);

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

    for(Graph::EdgeIt e(g); e!=INVALID; ++e) {
      if (cut[g.source(e)] && !cut[g.target(e)] && !flow[e]==cap[e]) 
	std::cout << "Slackness does not hold!" << std::endl;
      if (!cut[g.source(e)] && cut[g.target(e)] && flow[e]>0) 
	std::cout << "Slackness does not hold!" << std::endl;
    }
  }

  {
    std::cout << "preflow ..." << std::endl;
    for(Graph::EdgeIt e(g); e!=INVALID; ++e) flow.set(e, 0);
    ts.reset();
    max_flow_test.run(Preflow<Graph, int, Graph::EdgeMap<int>, Graph::EdgeMap<int> >::GEN_FLOW);
    std::cout << "elapsed time: " << ts << std::endl;
    std::cout << "flow value: "<< max_flow_test.flowValue() << std::endl;

    for(Graph::EdgeIt e(g); e!=INVALID; ++e) {
      if (cut[g.source(e)] && !cut[g.target(e)] && !flow[e]==cap[e]) 
	std::cout << "Slackness does not hold!" << std::endl;
      if (!cut[g.source(e)] && cut[g.target(e)] && flow[e]>0) 
	std::cout << "Slackness does not hold!" << std::endl;
    }
  }

//   {
//     std::cout << "wrapped preflow ..." << std::endl;
//     FOR_EACH_LOC(Graph::EdgeIt, e, g) flow.set(e, 0);
//     ts.reset();
//     pre_flow_res.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(Graph::EdgeIt e(g); e!=INVALID; ++e) flow.set(e, 0);
    ts.reset();
    int i=0;
    while (augmenting_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: "<< augmenting_flow_test.flowValue() << std::endl;

    for(Graph::EdgeIt e(g); e!=INVALID; ++e) {
      if (cut[g.source(e)] && !cut[g.target(e)] && !flow[e]==cap[e]) 
	std::cout << "Slackness does not hold!" << std::endl;
      if (!cut[g.source(e)] && cut[g.target(e)] && flow[e]>0) 
	std::cout << "Slackness does not hold!" << std::endl;
    }
  }

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

    for(Graph::EdgeIt e(g); e!=INVALID; ++e) {
      if (cut[g.source(e)] && !cut[g.target(e)] && !flow[e]==cap[e]) 
	std::cout << "Slackness does not hold!" << std::endl;
      if (!cut[g.source(e)] && cut[g.target(e)] && flow[e]>0) 
	std::cout << "Slackness does not hold!" << std::endl;
    }
  }

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

    for(Graph::EdgeIt e(g); e!=INVALID; ++e) {
      if (cut[g.source(e)] && !cut[g.target(e)] && !flow[e]==cap[e]) 
	std::cout << "Slackness does not hold!" << std::endl;
      if (!cut[g.source(e)] && cut[g.target(e)] && flow[e]>0) 
	std::cout << "Slackness does not hold!" << std::endl;
    }
  }

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

    for(Graph::EdgeIt e(g); e!=INVALID; ++e) {
      if (cut[g.source(e)] && !cut[g.target(e)] && !flow[e]==cap[e]) 
	std::cout << "Slackness does not hold!" << std::endl;
      if (!cut[g.source(e)] && cut[g.target(e)] && flow[e]>0) 
	std::cout << "Slackness does not hold!" << std::endl;
    }
  }

  return 0;
}
