#! /usr/bin/perl 
# XcuteN  [-T] [-S] [-r] <.ccf[tc] file> [<count>]
#  "runs" and plots a component's output behavior.
#
#  Default is output behavior; -T for run time; -S for state.
#  <count> defaults to 150 points to be sampled; -r means use random sequences
#    to override counts in .ccf.
#
#  For .ccft, plot only subdomain plateaux.
#  For .ccf, plot actual component, and if .ccft is valid, also subdomain plateaux.
#  For .ccfc, plot only approximation, using vector sum of states for that dimension;
#   write .datt files with all input-state tuples (and output tuples for state choice).

use samplings;

$plotOpt = "O"; #default is to plot output
$randOpt = 0; #default sampling is systematic
$highwater = -1; #last "-" arg
for ($opt=0; defined($ARGV[$opt]); $opt++) {
  if ($ARGV[$opt] eq "-T") {
    $plotOpt = "T";
    $highwater = $opt;
  } elsif ($ARGV[$opt] eq "-S") {
    $plotOpt = "S";
    $highwater = $opt;
  } elsif ($ARGV[$opt] eq "-r") {
    $randOpt = 1;
    $highwater = $opt;
  }
}
die "A .ccf[tc] file must be given" unless (defined($ARGV[$highwater+1]));
$ccf = $ARGV[$highwater+1];
die "given file ",$ccf," not found" unless (-e $ccf);
@sep = split(/\./,$ccf);
$ext = $sep[scalar(@sep)-1];
$samplecount = 150;
if (defined($ARGV[$highwater+2])) {
  $samplecount = $ARGV[$highwater+2];
}
$meastg = "";
if ($ext eq "ccf") { # .ccf file, execute code
#TBD random-sequence option not implemented, nor use of count option
#  If .ccft exists, use its counts to select subdomains?
  open(CCF, $ccf);
  chop($name = <CCF>);
  @sep = split(/\./,$name); 
  $sf = $sep[0].".state";
  unless (-x $name) {die "No code file to measure";}
  #find the extremes of the input domain
  $line = <CCF>;
  @vals = split(" ",$line);
  $leftin = $vals[0];
  while ($line ne "\n") {
    @vals = split(" ",$line);
    $line = <CCF>;
  }
  $rightin = $vals[1];
  #find the extremes of the state domain
  $line = <CCF>;
  @vals = split(" ",$line);
  $leftst = $vals[0];
  while ($line) {
    @vals = split(" ",$line);
    $line = <CCF>;
  }
  $rightst = $vals[1];
  $countin = 40;
  $countst = 20;
  #debug
  #print "input: [$leftin, $rightin) state: [$leftst, $rightst) \n";

  #collect the lists of inputs/states to use
  &samplings::init($leftin,$rightin,$countin);
  $numin = 0;
  while (($input = &samplings::next) ne ".") {
    $Ins[$numin++] = $input;
  }
  &samplings::init($leftst,$rightst,$countst);
  $numst = 0;
  while (($input = &samplings::next) ne ".") {
    $Sts[$numst++] = $input;
  }
  open(M,">meas.plt");
  open(MR,">runmeas.plt");  
  open(MS,">statemeas.plt");  
  $sed = "sed 's/^/out:  /'";  # command to reproduce stdin to stdout with a leading "out:  "
  for ($i=0; $i<$numst; $i++) { #loop over states
    for ($j=0; $j<$numin; $j++) { #loop over inputs
      open(STS,">$sf");
      print STS $Sts[$i];
      close(STS);
      $cmd = "(echo ".$Ins[$j]." | ".$name." | ".$sed.") 2>&1|" ;
      open(PM, $cmd);
      $rmeas = 0;
      while ($line = <PM>) {  #not eof, all output from this system on this input
        # results all come out together, but stdout is preceeded by "out:  "
        @outstrm = split(' ',$line);
        #debug
        #print "$line \n";
        if ($outstrm[0] =~ /out:/) {
          $meas = $outstrm[1];
        }
        else {
          $rmeas += $outstrm[0];
        }
      }
      close(PM);
      print M "$Ins[$j] $Sts[$i] $meas \n";
      print MR "$Ins[$j] $Sts[$i] $rmeas \n";
      open(STS,"<$sf");
      $smeas = <STS>;
      close(STS);
      print MS "$Ins[$j] $Sts[$i] $smeas \n";
    }
    print M "\n"; 
    print MR "\n"; 
    print MS "\n"; 
  } #end loop over states
  close(M); 
  close(MR); 
  close(MS);

  close(CCF);
  $meastg = "\"meas.plt\" with lines";
} #end of executing code case

if ($ext eq "ccfc") {
  open(CCFC, "<$ccf");
  $line = <CCFC>;
  @lane = split(" ",$line); # theory number-of-states number-input-subdomains numbers-state-subdomains
  die "bad .ccfc file format in $ccf" unless ($lane[0] eq "theory");
  $NumStates = $lane[1];
  $NumInSubd = $lane[2];
  for ($i=0; $i<$NumStates; $i++) {
    $NumStSubd[$i] = $lane[3+$i];
  }
  open(C,">pred.plt");
  $meastg = "";
  $pred = "\"pred.plt\" with points";
  while ($line = <CCFC>) {
    @lane = split(" ",$line); # subdomain count out run s1 s2 ... sN
    $datai = 2*($NumStates+1);
    if ($lane[$datai]) { #data count > 0
      print C ($lane[0]+$lane[1])/2; #input
      $vec = 0;
      for ($i=0; $i<$NumStates; $i++) {
        $vec += (($lane[2*$i + 2] + $lane[2*$i+3])/2)**2;
      }
      $vec = sqrt($vec);
      print C " $vec";
      print C " $lane[$datai+1]\n"; #output
    }
  }
  close(C);
} else { # ccft case, may fall in from ccf case
  $isccft = 0;  #assume no .ccft file
  $pred = "";
  if ($ext eq "ccft") {
    $ccftFile = $ccf;
    $ccf = substr($ccf,0,-1); #remove "t"
    die "no configuration file $ccf exists" unless (-e $ccf);
    $isccft = 1;
  } elsif ($ext eq "ccf") {
    $ccftFile = $ccf."t";
  }
  if (-e $ccftFile) {
    $isccft = 1;
  } else {
    warn "no approximation file (.ccft) exists for the configuration file $ccf";
  }
  open(CCF, "<$ccf");
  $name = <CCF>; #discard code name
  open(B,">subd.plt"); #subdomains
  $numin = 0;
  $numst = 0;
  $inputProc = 1;  #doing input subdomains first
  L:
  while ($line = <CCF>) { #read and store boundaries, plot theory.
    @subd = split(" ",$line);
    if ($inputProc) {
      if ($line eq "\n") {
        $inputProc = 0;
        next L;
      }
      $LBi[$numin] = $subd[0];
      $UBi[$numin++] = $subd[1];
    } else { #state subs now, go to EOF
      $LBs[$numst] = $subd[0];
      $UBs[$numst++] = $subd[1];
    }
  }
  close(CCF);
  $base = 0; #height of subdomain plane
  for ($i=0; $i<$numst; $i++) { #plot subdomains as a low plane
    for ($j=0; $j<$numin; $j++) {
      print B "$LBi[$j] $LBs[$i] $base\n";
    }
    print B "$UBi[$numin-1] $LBs[$i] $base\n";
    print B "\n";
  }
  for ($j=0; $j<$numin; $j++) {
    print B "$LBi[$j] $UBs[$numst-1] $base\n";
  }
  print B "$UBi[$numin-1] $UBs[$numst-1] $base\n";
  close(B);

  if ($isccft) { # Theory file exists 
    open(C,">pred.plt"); #calculation values
    open(CR,">runpred.plt"); #calc runtimes
    open(CS,">statepred.plt"); #calc runtimes
    $WtdVerr = 0;
    $WtdRerr = 0;
    open(CCFT, "<$ccftFile");
    $name = <CCFT>; #discard control/name line
    $stride = 7; #line contents:  num out run state outerr runerr staterr

#TBD Run time and state need to be fixed as output is...

    for ($lno = 0; $lno<$numst; $lno++) {
      $line = <CCFT>;
      die "ccft file ended prematurely" unless($line);
      @subd = split(" ",$line);
      for ($k=0;$k<$numin;$k++) {
        if ($subd[$stride*$k] > 0) {
          $val = $subd[$stride*$k+1];
          $run = $subd[$stride*$k+2];
          $state = $subd[$stride*$k+3];
          print C "$LBi[$k] $LBs[$lno] $val\n";
          print C "$LBi[$k] $UBs[$lno] $val\n";
          print C "$UBi[$k] $UBs[$lno] $val\n";
          print C "$UBi[$k] $LBs[$lno] $val\n";
          print C "$LBi[$k] $LBs[$lno] $val\n";
          print C "\n";
        }
      }
      $klast = -1;
      for ($k=0;$k<$numin;$k++) {
        if ($subd[$stride*$k] > 0) {
          $val = $subd[$stride*$k+1];
          $run = $subd[$stride*$k+2];
          $state = $subd[$stride*$k+3];
          if ($kLast>=0 && $k != $kLast+1) { #previous plateau not drawn
            print C "\n";
          }
          print C "$LBi[$k] $LBs[$lno] $val\n";
          print C "$UBi[$k] $LBs[$lno] $val\n";
          $kLast = $k;
          print CR "$LBi[$k] $LBs[$lno] $run\n";
          print CR "$UBi[$k] $LBs[$lno] $run\n";
          print CS "$LBi[$k] $LBs[$lno] $state\n";
          print CS "$UBi[$k] $LBs[$lno] $state\n";
          $verr = 100*$subd[$stride*$k+4];
          $rerr = 100*$subd[$stride*$k+5];
          $serr = 100*$subd[$stride*$k+6];  
        }
      }
      #space for grid lines  
      print C "\n";
      print CR "\n";
      print CS "\n";
      $kLast = -1;
      for ($k=0;$k<$numin;$k++) {
        if ($subd[$stride*$k] > 0) {
          $val = $subd[$stride*$k+1];
          $run = $subd[$stride*$k+2];
          $state = $subd[$stride*$k+3];
          if ($kLast>=0 && $k != $kLast+1) { #previous plateau not drawn
            print C "\n";
          }
          print C "$LBi[$k] $UBs[$lno] $val\n";
          print C "$UBi[$k] $UBs[$lno] $val\n";
          $kLast = $k;
          print CR "$LBi[$k] $UBs[$lno] $run\n";
          print CR "$UBi[$k] $UBs[$lno] $run\n";
          print CS "$LBi[$k] $UBs[$lno] $state\n";
          print CS "$UBi[$k] $UBs[$lno] $state\n";
        }
      }
      print C "\n";
      print CR "\n";
      print CS "\n";
      unless(1) { #not yet
      $WtdVerr += $verr*($UB[$k] - $LB[$k]);
      $WtdRerr += $rerr*($UB[$k] - $LB[$k]); 
      printf "[%.1f, %.1f):	%3.2f%%  %3.2f%% %%3.2f%%\n",$LB[$k], $UB[$k], $verr, $rerr, $serr;
      }  
      } #end loop over states (lines in file)
      print STDERR "Too many lines in .ccft file\n" if ($line = <CCFT>);
      unless(1) { #not yet
      $WtdVerr /= $UB[$k-1] - $LB[0];
      $WtdRerr /= $UB[$k-1] - $LB[0];
      printf "Weighted errors: %3.1f%%   %3.1f%%\n", $WtdVerr, $WtdRerr;
      }  
      close(C);
      close(CR);
      close(CS);
      $pred = "\"pred.plt\" with lines";
      if ($ext eq "ccf") {
        $pred .= ",";
      }
    } #end isccft
  } #end ccft case

open(PF,">complot");
print PF "set terminal X11\n";
print PF qq(set xlabel "Input Space"\n);
print PF qq(set ylabel "State Space"\n);
print PF qq(set zlabel "Outputs"\n);
print PF qq(set nokey\n);
print PF qq(set xtics nomirror\n);
print PF qq(set ytics nomirror\n);
print PF qq(set hidden3d\n);
print PF qq(set ticslevel .05\n);
print PF qq(splot "subd.plt" with lines, $pred $meastg \n) if ($plotOpt eq "O");
print PF qq(splot "subd.plt" with lines, "runmeas.plt" with lines, "runpred.plt" with lines\n) if ($plotOpt eq "T");
print PF qq(splot "subd.plt" with lines, "statemeas.plt" with lines, "statepred.plt" with lines\n) if ($plotOpt eq "S");
print PF qq(pause -1 \n);
close(PF);  

system("gnuplot complot");
