/*******************************************************************/
/*      File: process.C                                            */
/*    Author: Helmut Schmid                                        */
/*   Purpose: selection of the most probable parse                 */
/*   Created: Tue Dec 10 10:57:14 2002                             */
/*  Modified: Thu Jan 15 14:10:34 2009 (schmid)                    */
/* Copyright: Institut fuer maschinelle Sprachverarbeitung         */
/*            Universitaet Stuttgart                               */
/*******************************************************************/

#include <iostream>
using std::cerr;

#include "parser.h"

static bool VitProb=false;
static bool Finished;

static bool UseScores;


/*******************************************************************/
/*                                                                 */
/*  edge_func                                                      */
/*                                                                 */
/*******************************************************************/

static void edge_func( Edge &edge )

{
  Prob p = 1.0;
  Edge::iterator end = edge.end();
  for( Edge::iterator it=edge.begin(); it!=end; ++it ) {
    Node node=*it;
    p *= node.prob();
  }
  if (UseScores) {
    double score=edge.score();
    if (score != 1.0)
      p *= score;
  }
  edge.prob() = p;
}


/*******************************************************************/
/*                                                                 */
/*  ana_func                                                       */
/*                                                                 */
/*******************************************************************/

static void ana_func( Edge &edge )

{
  edge.prob() *= edge.rule_prob();
}


/*******************************************************************/
/*                                                                 */
/*  node_func                                                      */
/*                                                                 */
/*******************************************************************/

static void node_func( Node node )

{
  Prob p = 0.0;
  Node::iterator end = node.end();
  for( Node::iterator it=node.begin(); it!=end; ++it ) {
    Edge edge=*it;
    if (VitProb) {
      if (p <= edge.prob())
	p = edge.prob();
    }
    else // Inside algorithm
      p += edge.prob();
  }

  if (node.prob() < p * 0.999999999999) {
    node.prob() = p;
    Finished = false;
  }
}


/*******************************************************************/
/*                                                                 */
/*  Parser::viterbi                                                */
/*                                                                 */
/*******************************************************************/

void Parser::viterbi( bool use_scores )

{
  UseScores = use_scores;
  VitProb = true;

  if (NodeProb.size() > 0) {
    vector<Prob>().swap(NodeProb); // clear and free the memory
    vector<Prob>().swap(EdgeProb); // clear and free the memory
  }
  NodeProb.resize(parse.number_of_nodes(), (Prob)0.0);
  EdgeProb.resize(parse.number_of_edges(), (Prob)0.0);

  apply(NULL, node_func, NULL, edge_func, NULL, ana_func);
}


/*******************************************************************/
/*                                                                 */
/*  Parser::inside                                                 */
/*                                                                 */
/*******************************************************************/

void Parser::inside( bool use_scores )

{
  UseScores = use_scores;
  VitProb = false;

  if (NodeProb.size() > 0) {
    vector<Prob>().swap(NodeProb); // clear and free the memory
    vector<Prob>().swap(EdgeProb); // clear and free the memory
  }
  NodeProb.resize(parse.number_of_nodes(), (Prob)0.0);
  EdgeProb.resize(parse.number_of_edges(), (Prob)0.0);

  int n=0;
  do {         // multiple passes required in order to approximate 
    n++;       // the Inside probabilities in cyclic grammars 
    Finished = true;
    apply(NULL, node_func, NULL, edge_func, NULL, ana_func);
  } while (!Finished);

  if (verbose)
    cerr << "\n" << n << " iterations to compute inside probabilities\n";
}
