#!/usr/bin/perl

# test.pl -w weightfile [-n | -p] -i infile [-o outfile]
#
# Classifies the data in INFILE using the weights in WEIGHTFILE and
# writes the binary labels to OUTFILE (or STDOUT). If one of -n or
# -p is specified to indicate that the points are all negative or
# all positive, also reports on the error.
#
# This program implements the same algorithm, and should do the same 
# thing, as the GNU Octave/Matlab program "test.m" included with Perform.
#
# Perform (Perceptron Classifier in Inform) v1.0
# Nick Montfort  http://nickm.com  2004-06-24

use strict;
use warnings;
use Getopt::Std;
use vars qw/ $opt_n $opt_p $opt_w $opt_u $opt_i $opt_o /;

getopts("w:npi:o:");
my @w; my $poscount = 0; my @labels;
if(($opt_n and $opt_p) or (!$opt_w) or (!$opt_i) or $opt_u)
  { die ("Usage: $0 -w weightfile [-n | -p] -i infile [-o outfile]\n"); }
open WEIGHT, "<$opt_w" or die("<!> Can't open $opt_w for reading.");

# Load the weight vector and bias from their file.
my $wline = "#";
while ($wline =~ /^#/) { $wline = <WEIGHT>; }
my $bias = "#";
while ($bias =~ /^#/) { $bias = <WEIGHT>; }
chomp($bias);
$bias =~ s/ //;
close WEIGHT;
for(split(/ /, $wline)) { if(/^-?\d/) { push(@w,$_); } }

# Load the data points from their file.
print "Loading instances from $opt_i ... ";
open IN, "<$opt_i" or die("<!> Can't open $opt_i for reading.");
my @testdata = <IN>;
close IN;
print "got all ".scalar(@testdata)." of them.\n";

# Open output file if requested.
if ($opt_o)
  { open OUT, ">$opt_o" or die("<!> Can't open $opt_o for writing."); }

# For each data point, sum up the weight vector * data.
# If it is greater than zero, label it positive; otherwise, negative.
my $i = 0;
for (@testdata)
  {
  my $j = 0;
  my $sum = $bias;
  for(split(/ /))
    { if(/^-?\d/) { $sum += ($_ * $w[$j]); $j++; } }
  if($sum > 0) { $poscount++; $labels[$i] = 1; }
  else { $labels[$i] = 0; }
  $i++;
  }

# Notify about misclassifications.
if($opt_n)
  { print "(-) data provided: $poscount of $i points misclassified.\n"; }
if($opt_p)
  { print "(+) data provided: ". ($i-$poscount) ." of $i points misclassified.\n"; }

# Output labels.
if ($opt_o) { print OUT "@labels "; print OUT "\n"; close OUT; }
else { print "\n"; print "@labels "; print "\n"; }

__END__
