/*
 * This file is part of PARAM.
 *
 * PARAM 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 3 of the License, or
 * (at your option) any later version.
 *
 * PARAM 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 PARAM.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2009-2010 Ernst Moritz Hahn (emh@cs.uni-sb.de)
 */

#include "BoundedIterator.h"

/**
 * TODOs:
 * - use priority queue to reduce in an order such that overall number of
 *   transitions stays small
 */

#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <boost/graph/strong_components.hpp>
#include "SparseMC.h"

using namespace std;
using namespace boost;
using namespace Rational;

namespace parametric {  
  void BoundedIterator::setGraph(Graph *graph__) {
    graph = graph__;
  }
  
  void BoundedIterator::setInitStates(StateSet &initStates__) {
    initStates = &initStates__;
  }
  
  
  void BoundedIterator::setTargetStates(StateSet &targetStates__) {
    targetStates = &targetStates__;
  }
  
  void BoundedIterator::setTimeBound(double bound) {
    timeBound = (unsigned) bound;
  }
  
  void BoundedIterator::multiply
  (StateMap &probs, StateMap &probsPrimed) {
    pair<vertex_iterator, vertex_iterator> vp;
    for (vp = vertices(*graph); vp.first != vp.second; ++vp.first) {
      vertex_descriptor source(*vp.first);
      pair<out_edge_iterator, out_edge_iterator> it;
      if (targetStates->end() != targetStates->find(source)) {
	probsPrimed[source] = 1;
      } else {
	probsPrimed[source] = 0;
	for (it = out_edges(source, *graph); it.first != it.second; ++it.first) {
	  edge_descriptor edge(*it.first);
	  vertex_descriptor targetState(target(edge, *graph));
	  probsPrimed[source] += (*graph)[edge].getValue() * probs[targetState];
	}
      }
    }
  }

  void BoundedIterator::iterate(std::vector<RationalFunction> &result) {
    StateMap probs;
    StateMap probsPrimed;
    pair<vertex_iterator, vertex_iterator> vp;
    for (vp = vertices(*graph); vp.first != vp.second; ++vp.first) {
      vertex_descriptor v(*vp.first);
      probs[v] = (targetStates->end() != targetStates->find(v)) ? 1 : 0;
      probsPrimed[v] = 0;
    }

    for (unsigned time(0); time < timeBound; time++) {
      multiply(probs, probsPrimed);
      probs.swap(probsPrimed);
    }

    for (vp = vertices(*graph); vp.first != vp.second; ++vp.first) {
      vertex_descriptor v(*vp.first);
      if (initStates->find(v) != initStates->end()) {
        result.push_back(probs[v]);
      }
    }
  }
}
