#! /usr/bin/perl -w
#infeas <file>
# processes a theory.ccfc <file> to adjust counts to zero
# if a state is (approximately) infeasible.  Algorithm
# is to begin with the initialized state, and follow to
# other accessable states.  Those not reached can be marked
# infeasible.
# Output file from xxx.ccfc is xxx-feas.ccfc

#code could be moved into CalcI or SYNI to work on the
#range3 array produced there.

unless (defined($ARGV[0]) && -e $ARGV[0]) {die "Given file $ARGV[0] missing";}
open (C, "< $ARGV[0]");
$feas = (split('\.',$ARGV[0]))[0];
open (D, "> $feas-feas.ccfc"); #corrected output file
$line1 = <C>;
print D $line1;
@head = split(" ",$line1);
$nstates = $head[1];
$inputcount = $head[2];
for ($i=0;$i<$nstates;$i++) {
  $statecount[$i] = $head[3+$i];
}
@initialstate = @{head}[3+$i..3+$i+$nstates-1];
#print that
#print "header: $nstates states--(@statecount); initial (@initialstate); $inputcount inputs \n"; #debug

#store input subdomains
for ($i=0; $i<$inputcount; $i++) {
  $line = <C>;
  print D $line;
  @sub = split(' ',$line);
  $inputsubsLB[$i] = $sub[0];
  $inputsubsUB[$i] = $sub[1];
  
}

#store state subdomains
$rangecount = $inputcount;
for ($i=0; $i<$nstates; $i++) {
  $rangecount *= $statecount[$i];
  for ($j=0; $j<$statecount[$i]; $j++) {
    $line = <C>;
    print D $line;
    @sub = split(' ',$line);
    $statesubsLB[$i][$j] = $sub[0];
    $statesubsUB[$i][$j] = $sub[1];
  }
}
#theory file positioned at start of measurement data

for ($i=0; $i<$rangecount; $i++) {
  $range[$i] = <C>;
  $feas[$i] = 0;  #correct count
}
#print "last meas: $range[$i-1]"; #debug
close C;
#output file has everything down to the data, still open
##################################
sub lookupstate {
  #params:  state value, index into states (0..$nstates)
  my($val) = $_[0];
  my($si) = $_[1];
  my($k);
  for ($k=0; $k<$statecount[$si]; $k++) {
    if ($val >= $statesubsLB[$si][$k] && $val < $statesubsUB[$si][$k]) {
      return $k;
    }
  }
  #no such subdomain
  warn "State $si value $val not in any subdomain";
  return -1;
}
##############################
sub whereis { #return state index in range array
  #params:  state(list)
  my(@state) = @_;
  my($nstates, $i, $offset, $spacer);
  $nstates = scalar(@state);
  $offset = 0;
  for ($i=0; $i<$nstates; $i++) { #lookup each state element
    $elem = $state[$i];
    $substate = lookupstate($elem,$i);
    if ($i==0) {
      $spacer = $inputcount;
    } else {
      $spacer *= $statecount[$i-1];
    }
    $offset += $spacer*$substate;
  }
#print "found state (@state) at range[$offset]\n";  #debug
  return $offset;
}
#########################
sub printitall { # debug particulars for this (params) index and states into range
  my($idx,$s) = @_;
  if ($nstates != 1) { #don't try multiple states
    return;
  }
  my($in,$ns);
  #decode index
  @line = split(' ',$range[$idx]);
  $out = $line[1];
  $ns = $line[3];
  $ssub = int($idx/$inputcount);
  $L2 = $statesubsLB[0][$ssub];
  $R2 = $statesubsUB[0][$ssub];
  $isub = $idx - $ssub*$inputcount;
  $L1 = $inputsubsLB[$isub];
  $R1 = $inputsubsUB[$isub];
  if ($feas[$idx]) {
    print "went to $idx again\n";
  } else {
    print "found state $s index $idx; [$L1,$R1)x[$L2,$R2); found output $out & state $ns\n";
  }
}
################
sub trace { #recursive routine to follow a state through
  #params:  state(list)
  my(@state) = @_;
  my($inline, $index, @rangeline, $count, @newstate); #remember it's recursive
  $index = whereis(@state); # subscript in range array for this state
  if ($feas[$index]) { #been here before
    return;
  }
  for ($inline=0; $inline<$inputcount; $inline++) { #try all input lines of this state
#printitall($index,@state); #debug 
    $feas[$index] = 1;  #mark that it is feasible
    @rangeline = split(' ',$range[$index]);
    $count = $rangeline[0];
    if ($count != 0) {
      @newstate = @{rangeline}[3..3+$nstates-1];
      trace(@newstate);
    }
    $index++;
  }
#print "Finished state (@state)\n";  #debug
}
##############################

trace(@initialstate); 

#all should now be marked
$changed = 0;
$werealready = 0;
$whichstate = 0;
for ($i=0; $i<$rangecount; $i+=$inputcount) { #copy corrected data in input blocks
  for ($k=0; $k<$inputcount; $k++) { #for all the inputs in the block
    if ($feas[$i]) { # used
      $line = $range[$i+$k];  #original line
    } else {
      @rangeline = split(' ',$range[$i+$k]);
      if ($rangeline[0]) {
        $changed++;
        #print "state subdomain [", $statesubsLB[0][$whichstate], "," ,$statesubsUB[0][$whichstate],") traced as infeasible\n"; #debug
      } else {
        $werealready++;
      }
      $rangeline[0] = 0;
      $line = join(' ',@rangeline)."\n";
    }
  print D $line;
  }
  $whichstate++;
}
print $changed+$werealready," subdomains, (", ($changed+$werealready)/$inputcount, " states) were infeasible\n";
print "$changed were altered\n";
close D;
