#! /usr/bin/env perl

my $VERSION; 
BEGIN {

    $VERSION = "1.0";

    $ROOT = "XXXREPLACEXXX";
    $ROOT = "/afs/csail.mit.edu/u/c/carreras/local/phreco";

}
use lib "$ROOT/src";

use strict;
use PHRECO::phraseset;

use Getopt::Long;
use strict;

my $script = "clause-eval";
my $help = <<"End_of_help;";
clause-eval
  Options : 

    -g    Global results, i.e. skip SE evaluation


End_of_help;


########################################
# Options Processing
#

my (%opts);
GetOptions(\%opts, "se", 
            "l=s", "b", "h:i", "g:i", "p:i"
	   ) or die $help;


my $briefoutput = $opts{b}; 
my $label = exists($opts{l}) ? $opts{l} : undef; 
my $header = exists($opts{h}) ? $opts{h} : 1; 

my $fGold = exists($opts{g}) ? $opts{g} : 0; 
my $fPred = exists($opts{p}) ? $opts{p} : 1; 
my $fOscore = 2; 
my $fCscore = 3; 


my $evalSE = exists($opts{se}) ? 1 : 0;



my (@Oct, @Cct);
my $nw = 0;
my $ns = 0;
my $P = 0;  # number of candidate phrases produced by the Start-End filter
my (%cleval, %UBeval); 

my $s = read_sentence(\*STDIN);
while ($s) {
    
    my (@predO,@predC); 

    ### Word Decisions
    
    if ($evalSE) {

	@predO = map { ( $_->[$fOscore] > 0 ) ? 1 : 0 } @{$s};
	@predC = map { ( $_->[$fCscore] > 0 ) ? 1 : 0 } @{$s};

	my $nopens = 0; # number of Open Words in the sentence
	my $w; 
	my $i = 0; 
	foreach $w (@{$s}) {

#	print "word $i: ", join(" ", @{$w}), "\n";
	
	    ## Open eval
	    my $goldO = ( $w->[$fGold] =~ /\(/ ) ? 1 : 0; 
	    $Oct[$goldO][$predO[$i]]++;
	    
	    if ($predO[$i]) {
		$nopens++;
	    }

	    ## Close eval
	    my $goldC = ( $w->[$fGold] =~ /\)/ ) ? 1 : 0; 
	    $Cct[$goldC][$predC[$i]]++;
	    
	    if ($predC[$i]) {
		$P += $nopens;
	    }

	    $i++;
	}

    }

    $nw += scalar(@{$s}); 

    ### Phrase Decisions

    my $goldS = PHRECO::phrase_set->new(); 
    $goldS->load_OC_tagging( map { $_->[$fGold] } @{$s} ); 

    my $predS = PHRECO::phrase_set->new(); 
    $predS->load_OC_tagging( map { $_->[$fPred] } @{$s} ); 
#    print "Pred Split : ", $predS->to_string, "\n";

    my %e = $goldS->evaluation($predS); 
    foreach ( keys %e ) {
	$cleval{$_} += $e{$_};
    }


    if ($evalSE) {
	## Phrase Recognition Upper Bound, wrt predicted word decisions
	my $ph; 
	foreach $ph ( $goldS->phrases ) {
	    my $b = $ph->begin_wid;
	    my $e = $ph->end_wid;
	    if ($predO[$b] and $predC[$e]) {
		$UBeval{ok}++;
	    }
	    else {
		$UBeval{ms}++;
	    }
	}
    }

    $ns++;
    $s = read_sentence(\*STDIN);

}

### Print Statistics

my @hformat = (); 
my @hfields = (); 
my @format = (); 
my @fields = (); 


## Global Counts

if ($briefoutput) {
    if (defined($label)) {
	push @hformat, "%6s";
	push @format,  "%6s";
	push @hfields, "#label";
	push @fields,  $label; 
    }

    push @hformat, "%6s", "%6s";
    push @format,  "%6s", "%6s";
    push @hfields, "#sent.", "#words";
    push @fields,  $ns, $nw; 
}
else {
    my $nph = $UBeval{ok}+$UBeval{ms};
    print "$ns sentences processed containing $nw words and $nph phrases.\n";
    printf "%9s %6s %6s %6s %6s %8s %8s %8s %8s\n", "", 
    "y->y", "y->n", "n->y", "n->n", "acc", "prec.", "recall", "f1";
}


my ($acc, $r, $p, $f);

if ($evalSE) {

## Open Statistics

$acc = 100 * ($Oct[1][1] + $Oct[0][0]) / $nw;
#$r = 100* $Oct[1][1] / ($Oct[1][1] + $Oct[1][0]);
#$p = ($Oct[1][1] + $Oct[0][1]) ? 100 * $Oct[1][1] / ($Oct[1][1] + $Oct[0][1]) : 0;
#$f = ($p + $r) ? 2*$p*$r / ($p + $r) : 0;

($p, $r, $f) = precision_recall_f1($Oct[1][1], $Oct[1][0], $Oct[0][1]); 

if ($briefoutput) {
    push @hformat, "| %6s", "%6s", "%6s", "%6s";
    push @hfields, "Oacc.", "Oprec.", "Orec.", "Of1";
    push @format,  "| %6.2f", "%6.2f", "%6.2f", "%6.2f";
    push @fields,   $acc, $p, $r, $f;
}
else {
    printf "%9s %6s %6s %6s %6s %8.4f %8.4f %8.4f %8.4f\n", "Open:",
    $Oct[1][1], $Oct[1][0], $Oct[0][1], $Oct[0][0], $acc, $p, $r, $f;
}


## Close Statistics

$acc = 100 * ($Cct[1][1] + $Cct[0][0]) / $nw;
#$r = 100 * $Cct[1][1] / ($Cct[1][1] + $Cct[1][0]);
#$p = ($Cct[1][1] + $Cct[0][1]) ? 100 * $Cct[1][1] / ($Cct[1][1] + $Cct[0][1]) : 0;
#$f = ($p + $r) ? 2*$p*$r / ($p + $r) : 0;

($p, $r, $f) = precision_recall_f1($Cct[1][1], $Cct[1][0], $Cct[0][1]); 

if ($briefoutput) {
    push @hformat, "| %6s", "%6s", "%6s", "%6s";
    push @hfields, "Cacc.", "Cprec.", "Crec.", "Cf1";
    push @format,  "| %6.2f", "%6.2f", "%6.2f", "%6.2f";
    push @fields,  $acc, $p, $r, $f;
}
else {
    printf "%9s %6s %6s %6s %6s %8.4f %8.4f %8.4f %8.4f\n", "Close:",
    $Cct[1][1], $Cct[1][0], $Cct[0][1], $Cct[0][0], $acc, $p, $r, $f;
}

## Clause Recognition Upper Bound Statistics 

($p, $r, $f) = precision_recall_f1($UBeval{ok}, $UBeval{ms}, 0); 

if ($briefoutput) {
    push @hformat, "| %6s", "%6s", "%6s", "%6s", "%6s";
    push @hfields, "P", "Uy->y", "Uy->n", "Urec.", "Uf1";
    push @format,  "| %6s", "%6s", "%6s", "%6.2f", "%6.2f";
    push @fields,  $P, $UBeval{ok}, $UBeval{ms}, $r, $f;
}
else {
    printf "%9s %6s %6s %6s %6s %8.4f %8.4f %8.4f %8.4f\n", "Upper:",
    $UBeval{ok}, $UBeval{ms}, 0, -1, -1, $p, $r, $f;
}

}


## Clause Recognition Statistics

($p, $r, $f) = precision_recall_f1($cleval{ok}, $cleval{ms}, $cleval{op}); 

if ($briefoutput) {
    push @hformat, "| %6s", "%6s", "%6s", "%6s", "%6s", "%6s";
    push @format,  "| %6s", "%6s", "%6s", "%6.2f", "%6.2f", "%6.2f";
    push @hfields, "Sy->y", "Sy->n", "Sn->y", "Sprec.", "Srec.", "Sf1";
    push @fields,  $cleval{ok}, $cleval{ms}, $cleval{op}, $p, $r, $f;
}
else {
    printf "%9s %6s %6s %6s %6s %8.4f %8.4f %8.4f %8.4f\n", "Clauses:",
    $cleval{ok}, $cleval{ms}, $cleval{op}, -1, -1, $p, $r, $f;
}





## global header

if ($briefoutput) {
    printf(join(" ",@hformat)."\n", @hfields) if $header; 
    printf(join(" ",@format)."\n", @fields); 
}

### End of Main Program




sub read_sentence {
    my $in = shift; 

    my @W; 
    my @w = split(" ", <$in>); 
    while (@w) {
	push @W, [ @w ]; 
	@w = split(" ", <$in>); 
    }
    if (@W) {
	return \@W; 
    }
    else {
	return undef; 
    }
}


sub precision_recall_f1 {
    my ($yestoyes, $yestono, $notoyes) = @_;

    my $p = ( $yestoyes + $notoyes ) ? ( 100 *  $yestoyes / ($yestoyes + $notoyes)) : 0; 
    my $r = ( $yestoyes + $yestono ) ? ( 100 * $yestoyes / ($yestoyes + $yestono)) : 0; 
    my $f1 = ( $p + $r ) ? 2*$p*$r / ($p + $r) : 0;
					 
    return ($p, $r, $f1); 
}





