#! /usr/bin/perl

# computeBoundsForMkloops-01.pl - ST - 2006-03-22

# COMMAND LINE SYNTAX:
# computeBoundsForMkloops-01.pl inputDataFileName
#
# NOTE(S):
# Derived from addBoundsToMkloops.pl.
#
# It will run PIP to compute the bounds of each coefficient and create a new.
# file to hold the bounds.
#
##############################################################################
# PROGRAM DECLARATIONS
##############################################################################

BEGIN
{
  # Modify @INC here if necessary
  my $scriptDirName = `dirname $0`;
  chomp($scriptDirName);
  unshift(@INC,$scriptDirName);
  unshift(@INC, '../utils');
};

# core modules
use strict; # must be first to force strict in all others
use Carp;
use Getopt::Long;
use POSIX;
use Math::BigInt;
use Math::BigRat;
use Math::BigFloat;

# custom modules
# Uncomment if you want to use standard exit error codes.
# the stdExitErrors.pm file must be available around.
use stdExitErrors;

##############################################################################
# PROGRAM CONSTANT DECLARATIONS
##############################################################################
my $debug = 0;
my $inputFileNameExtension  = "txt";
my $inputFileNameIndexSize  = 3;
my $numBoundsPerVar         = 2;
my $maxPrefix               = "max";
my $minPrefix               = "min";
my $pipInputDataPrefix      = "forPip-";
my $pipOutputDataPrefix     = "fromPip-";
my $searchTag               = "search-";
my $findTag                 = "find-";
my $augmentedTag            = "-bounds";
my $pipUtility              = "pipMP";
my $pipParams               = "-z";
my $integerMode             = 0;
my $varNamePrefix           = '';
my $varDeclPrefix           = '';
##############################################################################
# PROGRAM VARIABLE DECLARATIONS
##############################################################################
my $inputDataFileName       = "";
my @splittedFileName        = ();
my $outputDataFileName      = "";
my $pipMinInputFileName     = "";
my $pipMaxInputFileName     = "";
my $pipOutputFileName       = "";
my $numVars                 = 0;
my $line                    = "";
my $isFirstLine             = 1;
my $numLines                = 0;
my $numColumns              = 0;
my $numVars                 = 0;
my @values                  = ();
my @coeffLines              = ();
my $currentCoeffLine        = 0;
my $currentDataLineNum      = 0;
my @minExpressionsBigArith  = ();
my @maxExpressionsBigArith  = ();
my @mins                    = ();
my @maxs                    = ();
my $maxBigInt               = 0;
my $minBigInt               = 0;
my $currentInputFileName    = "";
my $searchedVarIndex        = "";
my $currentVarIndex         = "";
my @context                 = ();
my @contextBp               = ();
##############################################################################
# TEST ENVIRONMENT AND CONFIGURATION VARIABLES
##############################################################################

##############################################################################
# INITIALIZE DEBUG FILE
##############################################################################

##############################################################################
# INITIALIZE LOG FILE
##############################################################################

##############################################################################
# GET COMMAND LINE ARGUMENTS
##############################################################################

##############################################################################
# PROGRAM MAIN
##############################################################################

&usage();

# Load the data and make a quick an dirty check of the data file.
if (! open(DF, "<$inputDataFileName"))
{
  print STDERR "\n\nCan't open file $inputDataFileName! Aborting program!\n\n";
  exit($EX_NOINPUT);
}
while($line = <DF>)
{
  # Get rid of comments.
  if ($line =~ /s*#/) { next; }
  # Collapse multiple consecutive spaces into a single space.
  $line =~ s/(\s)+/ /g;
  # Getting rid of empty (or "space only") lines
  if ($line =~ /^\s*$/) { next; }
  # We assume now that the line holds some usefull payload.
  # Get the line elements (they are separated by single spaces).
  @values = split(' ', $line);
  # The first line must hold the number of lines and the number of columns.
  if ($isFirstLine)
  {
    $isFirstLine = 0;
    # There must be a number of lines and a number of columns and none can be
    # null.
    if (! defined($values[1]) || $values[1] == 0 
        || ! defined($values[0]) || $values[0] == 0 )
    {
      print STDERR "\n\nMissing or invalid array description! Aborting program!\n\n";
      close(DF);
      exit($EX_DATAERR);
    }
    $numLines   = $values[0];
    $numColumns = $values[1];
    next;
  } # End isFirstLine
  # Check if the line has enough parameters
  if (! defined($values[$numColumns - 1]))
  {
    print STDERR "\n\nMissing data in values array at line $currentDataLineNum! ";
    print STDERR "Aborting program!\n\n";
    close(DF);
    exit($EX_DATAERR);
  }
  # Check if the line has not to much parameters
  if (defined($values[$numColumns]))
  {
    print STDERR "\n\nToo many data in values array at line $currentDataLineNum! ";
    print STDERR "Aborting program!\n\n";
    close(DF);
    exit($EX_DATAERR);
  }
  # Store the parameters.
  push(@coeffLines, []);
  for (my $i = 0 ; $i < @values ; $i++)
  {
    push(@{$coeffLines[@coeffLines - 1]}, Math::BigFloat->new($values[$i]));
  }
  $currentDataLineNum++;
  if ($debug) { print $line; }
} # End while
if ($currentDataLineNum != $numLines)
{
  print STDERR "\nNum lines announced: $numLines\n";
  print STDERR "\nNum lines found:     $currentDataLineNum\n";
  print STDERR "\n\nInvalid data in values array! Aborting program!\n\n";
  close(DF);
  exit($EX_DATAERR);
}
close(DF);
#
# End loading and quick and dirty data check.
#
# Remember the last element of the parameters is a constant, hence:
$numVars = $numColumns - 1;
# For each variable (i.e. coefficient):
# -compute the data for PIP;
# -get the min and max expressions;
# -compute the bounds;
for (my $i = 0 ; $i < $numVars ; $i++)
{
  # Compute the file names and data for PIP searches
  $pipMinInputFileName = $pipInputDataPrefix . $searchTag . $minPrefix . ".txt";
  $pipMaxInputFileName = $pipInputDataPrefix . $searchTag . $maxPrefix . ".txt";
  # For min PIP search.
  &createOutputFile($pipMinInputFileName);
  &generatePipInputForMin(\@coeffLines, 
                          \@context, 
                          $i, 
                          $numLines, 
                          $numColumns);
  # For max PIP search.
  &createOutputFile($pipMaxInputFileName);
  &generatePipInputForMax(\@coeffLines, 
                          \@contextBp, 
                          $i, 
                          $numLines, 
                          $numColumns);
  # Min search stuff.
  $pipOutputFileName = $pipOutputDataPrefix . $findTag . $minPrefix . ".txt";
  # Run the PIP min search
  if (system("$pipUtility $pipParams $pipMinInputFileName > $pipOutputFileName"))
  {
    print STDERR "\n\nPIP execution failed for file $pipMinInputFileName! Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  # Compute the min expression for the first variable
  # Check and open the PIP output file 
  #print STDERR "$ i : $currentInputFileName\n";
  if (! open(INPUT, "<$pipOutputFileName"))
  {
    print STDERR "\n\nCan't open file $pipOutputFileName! Aborting program!\n\n";
    exit($EX_NOINPUT);
  }
  $minExpressionsBigArith[0] = &computeMinExpressionBigFloat($varDeclPrefix, 
                                                              $varNamePrefix,
                                                              0);
  if ($minExpressionsBigArith[0] eq "")
  {
    print STDERR "\n\nMin expression for variable $searchedVarIndex is Empty!";
    print STDERR "Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
#
  # Max search stuff.  
  #
  $pipOutputFileName = $pipOutputDataPrefix . $findTag . $maxPrefix . ".txt";
  # Run the PIP max search
  if (system("$pipUtility $pipParams $pipMaxInputFileName > $pipOutputFileName"))
  {
    print STDERR "\n\nPIP execution failed for file $pipMaxInputFileName! Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  # Compute the max expression for the first variable (index==0)
  # Check and open the PIP output file 
  #print STDERR "$ i : $currentInputFileName\n";
  if (! open(INPUT, "<$pipOutputFileName"))
  {
    print STDERR "\n\nCan't open file $pipOutputFileName! Aborting program!\n\n";
    exit($EX_NOINPUT);
  }
  # Go ahead with the computation
  $maxExpressionsBigArith[0] = &computeMaxExpressionBigFloat($varNamePrefix, 0);
    if ($maxExpressionsBigArith[0] eq "")
    {
      print STDERR "\n\nMax expression for variable $searchedVarIndex is Empty! ";
      print STDERR "Aborting program!\n\n";
      exit($EX_SOFTWARE);
    }
  push (@maxs, eval($maxExpressionsBigArith[0]));
  push (@mins, eval($minExpressionsBigArith[0]));
} # End for $i
@splittedFileName = split(/\./, $inputDataFileName);
if (@splittedFileName >= 2)
{
  for(my $i = 0 ; $i < @splittedFileName - 1 ; $i ++)
  { if ($i != 0)
    {
      $outputDataFileName .= '.';
    }
    $outputDataFileName .= $splittedFileName[$i]
  }
  $outputDataFileName .= $augmentedTag;
  $outputDataFileName .= '.' . $splittedFileName[@splittedFileName - 1];
}
else
{
  $outputDataFileName = $inputDataFileName . $augmentedTag;
}
#
# Check and print the bounds
#
#print STDERR "$outputDataFileName\n";
if (! open(NDF, ">$outputDataFileName"))
{
  print STDERR "\n\nCan't open file $outputDataFileName! Aborting program!\n\n";
  exit($EX_NOINPUT);
}
print NDF "$numVars $numBoundsPerVar\n";
for (my $i = 0 ; $i < $numVars ; $i++)
{
  $minBigInt = Math::BigInt->new($mins[$i]);
  if ($minBigInt->is_nan())
  {
    print STDERR "\n\nFor variable ", &computeVariableName($i);
    print STDERR " this minimum ($mins[$i]) is an invalid integer. ";
    print STDERR "Aborting the program!\n\n";
    exit($EX_DATAERR);
  }
  $maxBigInt = Math::BigInt->new($maxs[$i]);
  if ($maxBigInt->is_nan())
  {
    print STDERR "\n\nFor variable ", &computeVariableName($i);
    print STDERR " this maximum ($maxs[$i]) is an invalid integer. ";
    print STDERR "Aborting the program!\n\n";
    exit($EX_DATAERR);
  }
  if ($minBigInt > $maxBigInt)
  {
    print STDERR "\n\nIncorrect bound:  for variable ", &computeVariableName($i);
    print STDERR " the minimum ($minBigInt) is bigger than ";
    print STDERR "the maximum ($maxBigInt). Aborting the program!\n\n";
    exit($EX_DATAERR);
  }
  print NDF "$maxs[$i] ";
  print NDF "$mins[$i]\n";
} # End for $i
exit($EX_OK); # exit main program

##############################################################################
# PROGRAM SUBS
##############################################################################
#
##############################################################################
# sub mySub
##############################################################################
# Performed task:
#
# input   :
# output  :
# globals :
#
sub mySub {
  my ($someParameter) = @_;
  if (! defined($someParameter))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    # Uncomment this line and remove the next one if using stdExitErrors.
    exit($EX_SOFTWARE);
  }
} # End mySub
##############################################################################
# sub $retv = _privateSubName($argv)
##############################################################################

sub _privateSubName
{
	my $argv = shift();
	my $retv = undef;
	return($retv);
};
#
##############################################################################
# sub computeFileName
##############################################################################
# Performed task: Compute a file names for different program steps.
#
# input   : $fileNamePrefix, $fileNameExtension, $fileIndex (0..n), 
#           $fileNumSize (of the variable part), $maxMinPrefix (sort
#           files for max or min operations)
# output  : a string holding a file name
# globals : none
#
# A simple concatenation of string fragments. The only sophisticated job
# is done by the computeVariableName() procedure.
#
sub computeFileName {
my ($fileNamePrefix, 
    $fileNameExtension, 
    $fileIndex, 
    $fileNumSize,
    $maxMinPrefix) = @_;
if (! defined($maxPrefix))
{
  my @call_info = caller(0);
  print STDERR $call_info[3], " missing parameter. Aborting program!\n";
  exit($EX_SOFTWARE);
}
  my $fileNameSuffix = "";
  $fileNameSuffix = &computeVariableName($fileIndex);
return($fileNamePrefix . 
        $fileNameSuffix .
        "-$maxMinPrefix" . 
        "." . 
        $fileNameExtension);
}
# End computeFileName
##############################################################################
# sub computeLastVarMinMaxPari
##############################################################################
# Performed task: compute the min and max expressions for the last variable (a
# coefficient in fact). These expressions are designed for the gp utility (from
# the PARI suite).
# They are directly available from the initial data whithout having to use PIP
# (and waste a lot of time) to compute them.
#
# input   : $refCoeffLines: a reference on the coefficient lines matrix created
#           with the input file ;
#           $maxPrefix: a string holding the prefix used for upper bound variables.
#           $minPrefix: a string holding the prefix used for lower bound variables.
#           $varDeclPrefix: a string holding the variable declaration prefix (language
#                           dependent, e.g. "my " for Perl under strict).
#           $varNamePrefix: a string holding the prefix used for scalar variables
#                           (language dependent, e.g. "$" for Perl).
# output  : a string holding the min and max expressions.
# globals : none
#
# notes   : 
#
#
sub computeLastVarMinMaxPari {
  my ($refCoeffLines, $maxPrefix, $minPrefix, $varDeclPrefix, $varNamePrefix) = @_;
  if (! defined($varNamePrefix))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  #
  # Some local variables.
  #
  my $lineCont          = 0;
  my $lastLineIndex     = @{$$refCoeffLines[0]} - 1;
  my $lastVarIndex      = $lastLineIndex - 1;
  my $lastVarAsBigInt;
  my $refCurrentLine    = 0;
  my $currentCoeff;
  my @maxExpressions    = ();
  my @minExpressions    = ();
  my $currentExpression = "";
  my $minExpression     = "";
  my $maxExpression     = "";
  # Main computing loop.
  for (my $i = 0 ; $i < @$refCoeffLines ; $i++)
  {
    $refCurrentLine = $$refCoeffLines[$i];
    $lastVarAsBigInt = Math::BigInt->new($$refCurrentLine[$lastVarIndex]);
    $currentExpression = "";
    if (! $lastVarAsBigInt->is_zero())
    {
      for (my $j = 0 ; $j <= $lastLineIndex ; $j++)
      {
        if ($j != $lastVarIndex)
        {
          $currentCoeff =
            Math::BigRat->new("$$refCurrentLine[$j]/" . $lastVarAsBigInt->bstr());
            $currentCoeff->bneg(); 
          if ($j != $lastLineIndex)
          {
            $currentExpression .= $currentCoeff->bstr() . "*";
            $currentExpression .= &computeVariableName($j) . " + ";
          }
          else # $j == $lastLineIndex, constant and last term.
          {
            $currentExpression .= $currentCoeff->bstr();
          }
        }
      } # End for $j
      #print STDERR $currentExpression;
      #print STDERR "\n";
      if ($lastVarAsBigInt->is_pos())
      {
        push(@minExpressions, $currentExpression); 
      }
      else #($lastVarAsBigInt->is_neg())
      {
        push(@maxExpressions, $currentExpression); 
      }
    } # End if 
  } # End for $i
  if (@minExpressions == 0)
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], ": nothing to form an expression with. Aborting the program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (@minExpressions == 1)
  {
    $minExpression = shift(@minExpressions);
  }
  else
  {
    $minExpression = 'max(' . shift(@minExpressions) . ',' . 
                      shift(@minExpressions) . ')';
    while(@minExpressions)
    {
      $minExpression = 'max(' . $minExpression . ',' . shift(@minExpressions) . ')';
    }
  }
  $minExpression = 'ceil(' . $minExpression . ')';
  #
  if (@maxExpressions == 0)
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], ": nothing to form an expression with. Aborting the program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (@maxExpressions == 1)
  {
    $maxExpression = shift(@maxExpressions);
  }
  else # @maxExpressions >= 2
  {
    $maxExpression = 'min(' . shift(@maxExpressions) . ',' . 
                      shift(@maxExpressions) . ')';
    while(@maxExpressions)
    {
      $maxExpression = 'min(' . $maxExpression . ','. shift(@maxExpressions) . ')';
    }
  }
  $maxExpression = 'floor(' . $maxExpression . ')';
  #print STDERR ($varDeclPrefix . $varNamePrefix . &computeVariableName($lastVarIndex) .
  #        $minPrefix . '=' . $minExpression . ';' .
  #        $varDeclPrefix . $varNamePrefix . &computeVariableName($lastVarIndex) . 
  #        $maxPrefix . '=' . $maxExpression . ';'  ), "\n";
  return($varDeclPrefix . $varNamePrefix . &computeVariableName($lastVarIndex) . 
          $minPrefix . '=' . $minExpression . ";" .
          $varDeclPrefix . $varNamePrefix . &computeVariableName($lastVarIndex) . 
          $maxPrefix . '=' . $maxExpression . ';'  );
} # End computeLastVarMinMaxPari
##############################################################################
# sub computeMaxContextLines
##############################################################################
# Performed task: computes the max context lines
#
# input   : $refContext -> a reference on the context
#           $variableIndex -> the index of the variable we deal with
#           $forMax -> are we computing a context for a max bound (an
#           extra 0 at bigparm index is needed in the context).
# output  : a string holding the context (can be multiline) in suitable form
#           for PIP.
# globals : none
#
# internals :
# We parse the line of the output of PIP looking for lines that hold
# the "list #" pattern.
# If $variableIndex == 0, we are only interested in the first line. We've made
# it a special case as it is very straightforward.
# If $variableIndex != 0, we build an array of context lines each corresponding
# to a line in the result set.
# We return a string and we add the new lines to the context.
#
# The computation of the string embeds a control step to make sure at least
# one result line was found. If this computation were removed, the control 
# step should be taken elsewhere.
#
sub computeMaxContextLines {
  my ($refContext,$variableIndex, $forMax) = @_;
  if (! defined($forMax))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], ": missing parameter. Aborting program!\n\n";
    close(INPUT);
    exit($EX_SOFTWARE);
  }
  my $contextLines        = "";
  my @paramArray          = ();
  my $currentParamValue   = Math::BigFloat->new();
  my $refContextLineArray = 0;
  my @contextLinesArray   = ();
  my $currentContextIndex = 0;
  my $numerator           = Math::BigFloat->new();
  my $denominator         = Math::BigFloat->new();
  my @fraction            = ();
  my $commonDenominator   = Math::BigFloat->new("1");
  while($line = <INPUT>)
  {
    # We look for line including the "list #" pattern.
    # and we strip the "[" and the "]".
    if (! ($line =~ s/.*list #\[//)) { next; }
    $line =~ s/\]//;
    # Clean-up spaces.
    chomp $line;
    $line =~ s/(^\s*)||(\s*$)//g;
    $line =~ s/(\s)+/ /g;
    #print STDERR $line, "\n";
    #print STDERR "$variableIndex\n";
    @paramArray = split(" ",$line);
    $refContextLineArray = [];
    if ($variableIndex == 0)
    {
      #print STDERR "\n\nCoucou\n\n";
      if ($forMax)
      {
        $contextLines = "#[-1 0";
        push(@$refContextLineArray, Math::BigFloat->new("-1"));
        push(@$refContextLineArray, Math::BigFloat->new("0"));
      }
      else
      {
        $contextLines = "#[-1";
        push(@$refContextLineArray, Math::BigFloat->new("-1"));
      }
      # Flip the sign before computing the floor: when computing for (and from)
      # a max the return value is the opposite of the actual value.
      $denominator->bone();
      @fraction = split('/',$paramArray[1]);
      $numerator    = Math::BigFloat->new($fraction[0]);
        if (defined($fraction[1]))
        {
          $denominator  = Math::BigFloat->new($fraction[1]);
        }
      $currentParamValue = $numerator / $denominator;
      $currentParamValue->bneg();
      $currentParamValue->bfloor();
      #$currentParamValue = floor(eval("-1 * $paramArray[1]"));
      $contextLines .= " " . $currentParamValue;
      $contextLines .= "]\n";
      push(@$refContextLineArray, $currentParamValue);
      close INPUT;
      if ( ! &isInContext($refContext, $refContextLineArray))
      {
        push(@$refContext, $refContextLineArray);
      }
      return($contextLines);
    }
    else # $variableIndex == 0
    {
      #print STDERR "Variable index : $variableIndex\n";
      #for (my $j =  0 ; $j < @paramArray ; $j++)
      #{
      #  print STDERR "$paramArray[$j] ";
      #}
      #print STDERR "\n";
      # If the result has rational parameters a special step must be taken:
      # parameters a set to the same denominator and the latter is removed
      # (the context is a set of inequations of the form:
      # sum of coefficents >= 0).
      if (&hasFractions(\@paramArray))
      {
        $commonDenominator = &setToAndRidOfCommonDenominator(\@paramArray);
      }
      else
      {
        for (my $i = 0 ; $i < @paramArray ; $i++)
        {
          $paramArray[$i] = Math::BigFloat->new($paramArray[$i]);
        }
      }
      #
      # At this point, all the elements of @paramArray are BigFloats.
      #
      # Flip the sign of all params. PIP gives the minimum value of the
      # parameter. When searching for a maximum, we use the " bigparm trick".
      # In this case, the computed value is the opposite of the wanted one. We
      # must flip the signs to be able to use it to build an inequation 
      # constraint we transform it under the form : 
      # maximum_value - k * parameter >= 0
      #
      for (my $i = 0 ; $i <= $variableIndex  + 1 ; $i++)
      {
        $paramArray[$i]->bneg();
      } # End for $i
      # Move the constant one step up (it's sign is already flipped).
      $paramArray[$variableIndex + 2] = $paramArray[$variableIndex + 1];
      # Set the bigparm stuff.
      if ($forMax)
      {
        $paramArray[$variableIndex + 1] = Math::BigFloat->new("0");
      }
      else
      {
        splice(@paramArray,$variableIndex + 1,1);
      }
      # Insert the coefficient for the current parameter
      # $commonDenominator is always positive. The coefficient for the
      # parameter must be negative.
      $paramArray[$variableIndex] = $commonDenominator->copy();
      $paramArray[$variableIndex]->bneg();
      # Compute the textual form.
      $contextLinesArray[$currentContextIndex] = "#[";
      $contextLinesArray[$currentContextIndex] .= join(" ", @paramArray);
      $contextLinesArray[$currentContextIndex] .= "]\n";
      $currentContextIndex ++;
      for (my $i = 0 ; $i < @paramArray ; $i++)
      {
        push(@$refContextLineArray, $paramArray[$i]);
      }
      # In some cases, the same result appears several times in the result QUAST.
      # We only add it once to the context.
      if ( ! &isInContext($refContext, $refContextLineArray))
      {
        push(@$refContext, $refContextLineArray);
      }
    }
  } # End while
  close(INPUT);
  # Check that, at least, one result was found. The lack of thereof is
  # an evidence that something went wrong.
  if (@contextLinesArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. ";
    print "Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  while(@contextLinesArray)
  {
    $contextLines .=  shift(@contextLinesArray);
  } # End while
  return($contextLines);
} 
# End computeMaxContextLines
##############################################################################
# sub computeMaxExpression
##############################################################################
# Performed task: computes the max expression for a given variable
#
# input   : $varNamePrefix -> string used as prefix in variables names 
#           (e.g. "$" for PERL, nothing for C).
#           $variableIndex: index of the variable used to compute it's name.
# output  : A string holding the conditional (upper bound) for a "for" loop.
# globals : INPUT (handle on the input file). This handle must opended upon
#           subroutine invocation and is closed by the subroutine.
# Almost pure textual work. The only exception is when $variableIndex == 0,
# we then use a numerical value with BigFloat arithmetics.
#
sub computeMaxExpression {
  my ($varNamePrefix, $variableIndex) = @_;
  if (! defined($variableIndex))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    exit(1);
  }
  my $upperBoundExp     = "";
  my @paramArray        = ();
  my $currentParamValue = Math::BigFloat->new();
  my @expArray          = ();
  my $lowerBoundExp     = "";
  my $currentExpIndex   = 0;
  my @fraction          = ();
  my $numerator         = Math::BigFloat->new();
  my $denominator       = Math::BigFloat->new();
  while($line = <INPUT>)
  {
    # Looking for lines holding the "list #[" string and beginning
    # cleanup.
    if (! ($line =~ s/.*list #\[//)) { next; }
    $line =~ s/\]//;
    # Clean-up spaces.
    chomp $line;
    $line =~ s/(^\s*)||(\s*$)//g;
    $line =~ s/(\s)+/ /g;
    #print STDERR $line, "\n";
    if ($variableIndex == 0)
    {
      @paramArray = split(" ", $line);
      $denominator->bone();
      @fraction = split('/',$paramArray[1]);
      $numerator    = Math::BigFloat->new($fraction[0]);
        if (defined($fraction[1]))
        {
          $denominator  = Math::BigFloat->new($fraction[1]);
        }
      $currentParamValue = $numerator / $denominator;
      $currentParamValue->bneg();
      $currentParamValue->bfloor();
      #$currentParamValue = floor(eval("-1 * $paramArray[1]"));
      $upperBoundExp .= $currentParamValue;
      close(INPUT);
      return($upperBoundExp);
    }
    else # $variableIndex != 0
    {
      @paramArray = split(" ", $line);
      # Get rid of bigparm
      splice(@paramArray, $variableIndex, 1);
      for (my $i = 0 ; $i < $variableIndex ; $i++)
      {
        # Switch sign of all other params.
        $paramArray[$i] = "-1 * " . $paramArray[$i] . 
                          " * " . $varNamePrefix .
                          &computeVariableName($i);
      } # End for $i
      # Switch the sign of the constant
      $paramArray[$variableIndex] .= " * -1";
      $expArray[$currentExpIndex] = join(" + ", @paramArray);
      $currentExpIndex ++;
    }
  } # End while
  close(INPUT);
  if (@expArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (@expArray == 1) 
  {
    $upperBoundExp =  $expArray[0];
    return($upperBoundExp);
  }
  $upperBoundExp = "min(" . shift(@expArray) .
                    "," . shift(@expArray) . ")";
  while(@expArray)
  {
    $upperBoundExp = "min(" . $upperBoundExp . "," . 
                      shift(@expArray) . ")";
  } # End while
  #$upperBoundExp = "floor(" . $upperBoundExp . ")";
  return($upperBoundExp);
} 
# End computeMaxExpression
##############################################################################
# sub computeMaxExpressionBigFloat
##############################################################################
# Performed task: computes the max expression for a given variable
#
# input   : $varNamePrefix -> string used as prefix in variables names 
#           (e.g. "$" for PERL, nothing for C).
#           $variableIndex: index of the variable used to compute it's name.
# output  : A string holding the conditional (upper bound) for a "for" loop.
# globals : INPUT (handle on the input file). This handle must opended upon
#           subroutine invocation and is closed by the subroutine.
# Almost pure textual work. The only exception is when $variableIndex == 0,
# we then use a numerical value with BigFloat arithmetics.
#
sub computeMaxExpressionBigFloat {
  my ($varNamePrefix, $variableIndex) = @_;
  if (! defined($variableIndex))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    exit(1);
  }
  my $upperBoundExp     = "";
  my @paramArray        = ();
  my $currentParamValue = Math::BigFloat->new();
  my @expArray          = ();
  my $lowerBoundExp     = "";
  my $currentExpIndex   = 0;
  my @fraction          = ();
  my $numerator         = Math::BigFloat->new();
  my $denominator       = Math::BigFloat->new();
  while($line = <INPUT>)
  {
    # Looking for lines holding the "list #[" string and beginning
    # cleanup.
    if (! ($line =~ s/.*list #\[//)) { next; }
    $line =~ s/\]//;
    # Clean-up spaces.
    chomp $line;
    $line =~ s/(^\s*)||(\s*$)//g;
    $line =~ s/(\s)+/ /g;
    #print STDERR $line, "\n";
    if ($variableIndex == 0)
    {
      @paramArray = split(" ", $line);
      $denominator->bone();
      @fraction = split('/',$paramArray[1]);
      $numerator    = Math::BigFloat->new($fraction[0]);
      if (defined($fraction[1]))
      {
        $denominator  = Math::BigFloat->new($fraction[1]);
      }
      $currentParamValue = $numerator / $denominator;
      $currentParamValue->bneg();
      $currentParamValue->bfloor();
      #$currentParamValue = floor(eval("-1 * $paramArray[1]"));
      $upperBoundExp .= "Math::BigFloat->new('$currentParamValue')";
      close(INPUT);
      return($upperBoundExp);
    }
    else # $variableIndex != 0
    {
      @paramArray = split(" ", $line);
      # Get rid of bigparm
      splice(@paramArray, $variableIndex, 1);
      # Parametric part
      for (my $i = 0 ; $i < $variableIndex ; $i++)
      {
        # Switch signs of all other params.
        @fraction = split('/',$paramArray[$i]);
        $paramArray[$i] = "Math::BigFloat->bone('-') * ";
        $paramArray[$i] .= "Math::BigFloat->new('$fraction[0]')";
        if (defined($fraction[1]))
        {
          $paramArray[$i] .= "/Math::BigFloat->new('$fraction[1]')";
        }
        $paramArray[$i] .= " * " . $varNamePrefix .
                          &computeVariableName($i);
      } # End for $i
      # Constant part
      @fraction = split('/',$paramArray[$variableIndex]);
      # Switch the sign of the constant
      $paramArray[$variableIndex] = "Math::BigFloat->bone('-') * ";
      $paramArray[$variableIndex] .= "Math::BigFloat->new('$fraction[0]')";
      if (defined($fraction[1]))
      {
        $paramArray[$variableIndex] .= "/Math::BigFloat->new('$fraction[1]')";
      }
      $expArray[$currentExpIndex] = join(" + ", @paramArray);
      $currentExpIndex ++;
    }
  } # End while
  close(INPUT);
  if (@expArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (@expArray == 1) 
  {
    $upperBoundExp =  $expArray[0];
    return($upperBoundExp);
  }
  $upperBoundExp = "min(" . shift(@expArray) .
                    "," . shift(@expArray) . ")";
  while(@expArray)
  {
    $upperBoundExp = "min(" . $upperBoundExp . "," . 
                      shift(@expArray) . ")";
  } # End while
  return($upperBoundExp);
} 
# End computeMaxExpressionBigFloat
##############################################################################
# sub computeMinContextLines
##############################################################################
# Performed task: computes the max context lines
#
# input   : $variableIndex -> the index of the variable we deal with
#           $forMax -> are we computing a context for a max bound (an
#           extra 0 at bigparm index is needed in the context).
# output  : a string holding the context (can be multiline).
# globals : the INPUT file handle.
#
# internals :
# We parse the line of the output of PIP looking for lines that hold
# the "list #" pattern.
# If $variableIndex == 0, we are only interested in the first line. We've made
# it a special case as it is very straightforward.
# If $variableIndex != 0, we build an array of context lines each corresponding
# to a line in the result set.
sub computeMinContextLines {
  my ($refContext, $variableIndex, $forMax) = @_;
  if (! defined($forMax))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    close(INPUT);
    exit($EX_SOFTWARE);
  }
  my $line                = "";
  my $contextLine         = "";
  my @paramArray          = ();
  my $currentParamValue   = Math::BigFloat->new();
  my $refContextLineArray = 0;
  my @contextLinesArray   = ();
  my $currentContextIndex = 0;
  my $numerator           = Math::BigFloat->new();
  my $denominator         = Math::BigFloat->new();
  my @fraction            = ();
  my $commonDenominator   = Math::BigFloat->new("1");
  while($line = <INPUT>)
  {
    # We look for line including the "list #" pattern.
    # and we remove the "[" and the "]".
    if (! ($line =~ s/.*list #\[//)) { next; }
    $line =~ s/\]//;
    # Clean-up spaces.
    chomp $line;
    $line =~ s/(^\s*)||(\s*$)//g;
    $line =~ s/(\s)+/ /g;
    #print STDERR $line, "\n";
    #print STDERR "$variableIndex\n";
    @paramArray = split(" ",$line);
    $refContextLineArray = [];
    if ($variableIndex == 0)
    {
      if ($forMax)
      {
        $contextLine = "#[1 0";
        push(@$refContextLineArray, Math::BigFloat->new("1"));
        push(@$refContextLineArray, Math::BigFloat->new("0"));
      }
      else
      {
        $contextLine = "#[1";
        push(@$refContextLineArray, Math::BigFloat->new("1"));
      }
      # Compute the ceil before switching signs for the context.
      $denominator->bone();
      @fraction   = split('/',$paramArray[0]);
      $numerator  = Math::BigFloat->new($fraction[0]);
      if (defined($fraction[1]))
      {
        $denominator  = Math::BigFloat->new($fraction[1]);
      }
      $currentParamValue = $numerator / $denominator;
      $currentParamValue->bceil();
      #$currentParamValue = ceil(eval($paramArray[0]));
      $currentParamValue->bneg();
      #$contextLine .= " " . (eval("-1 * $currentParamValue"));
      $contextLine .= $currentParamValue;
      $contextLine .= "]\n";
      push(@$refContextLineArray,$currentParamValue);
      close INPUT;
      if ( ! &isInContext($refContext, $refContextLineArray))
      {
        push(@$refContext, $refContextLineArray);
      }
      return($contextLine);
    }
    else # $variableIndex != 0
    {
      # As a side effect setToAndRid... changes all the elements of
      # @paramArray into BigFloats.
      if (&hasFractions(\@paramArray))
      {
        $commonDenominator = &setToAndRidOfCommonDenominator(\@paramArray);
      }
      else
      {
        for (my $i = 0 ; $i < @paramArray ; $i++)
        {
          $paramArray[$i] = Math::BigFloat->new($paramArray[$i]);
        }
      }
      #
      # At this point, all the elements of @paramArray are BigFloats.
      # Flip the sign of all params.
      for (my $i = 0 ; $i < $variableIndex  + 1; $i++)
      {
        #print STDERR "$i - ", 1 * @paramArray, " - ", ref($paramArray[$i]), "\n";
        $paramArray[$i]->bneg()
      } # End for $i
      # Move the constant one step up (it's sign is already flipped).
      $paramArray[$variableIndex + 2] = $paramArray[$variableIndex];
      # Set the bigparm stuff.
      if ($forMax)
      {
        $paramArray[$variableIndex + 1] = Math::BigFloat->new("0");
      }
      else
      {
        splice(@paramArray,$variableIndex +1 ,1);
      }
      # Insert the coefficient for the current parameter
      $paramArray[$variableIndex] = $commonDenominator->copy();
      $contextLinesArray[$currentContextIndex] = "#[";
      $contextLinesArray[$currentContextIndex] .= join(" ", @paramArray);
      $contextLinesArray[$currentContextIndex] .= "]\n";
      $currentContextIndex ++;
      for (my $i = 0 ; $i < @paramArray ; $i++)
      {
        push(@$refContextLineArray, $paramArray[$i]);
      }
      if ( ! &isInContext($refContext, $refContextLineArray))
      {
        push(@$refContext, $refContextLineArray);
      }
    }
  } # End while
  close(INPUT);
  if (@contextLinesArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  while(@contextLinesArray)
  {
    $contextLine .=  shift(@contextLinesArray);
  } # End while
  return($contextLine);
} 
# End computeMinContextLines
##############################################################################
# sub computeMinExpression
##############################################################################
# Performed task: computes the minimum expression for a 
# given variable.
#
# input   : $varDeclPrefix, $varNamePrefix, $variableIndex
#           $varDeclPrefix: string to prefix the variable declaration
#           (e.g "my " for PERL or "int " for C.
#           $varNamePrefix: string used as prefix in varaibles names (e.g. "$" 
#           for PERL, none for C).
#           $variableIndex: index of the variable used to compute it's name.
# output  : A string holding the lower bound declaration for a "for" loop.
# globals : INPUT (handle on the input file). This handle must opended upon
#           subroutine invocation and is closed by the subroutine.
#
sub computeMinExpression {
  my ($varDeclPrefix, $varNamePrefix, $variableIndex) = @_;
  if (! defined($variableIndex))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  my @paramArray        = ();
  my @expArray          = ();
  my $currentParamValue = 0;
  my $line              = "";
  my $lowerBoundExp     = "";
  my $currentExpIndex   = 0;
  my $numerator         = Math::BigFloat->new();
  my $denominator       = Math::BigFloat->new();
  my @fraction          = ();
  while($line = <INPUT>)
  {
    # Detect a result line and start cleanup as well.
    if (! ($line =~ s/.*list #\[//)) { next; }
    $line =~ s/\]//;
    # Clean-up white spaces.
    chomp $line;
    $line =~ s/(^\s*)||(\s*$)//g;
    $line =~ s/(\s)+/ /g;
    #print STDERR $line, " $variableIndex \n";
    if ($variableIndex == 0)
    {
      $denominator->bone();
      @fraction = split('/',$line);
      $numerator    = Math::BigFloat->new($fraction[0]);
        if (defined($fraction[1]))
        {
          $denominator  = Math::BigFloat->new($fraction[1]);
        }
      $currentParamValue = $numerator / $denominator;
      $currentParamValue->bceil();
      #$currentParamValue = ceil(eval($line));
      #$lowerBoundExp = $varDeclPrefix .  $varNamePrefix . 'a = ' . $currentParamValue;
      $lowerBoundExp = $currentParamValue;
      close(INPUT);
      return($lowerBoundExp);
    }
    else
    {
      @paramArray = split(" ", $line);
      for (my $i = 0 ; $i < $variableIndex ; $i++)
      {
        $paramArray[$i] = $paramArray[$i] . " * " . 
                          $varNamePrefix .
                          &computeVariableName($i);
      } # End for $i
      $expArray[$currentExpIndex] = join(" + ", @paramArray);
      $currentExpIndex ++;
    }
  } # End while
  close(INPUT);
  if (@expArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (@expArray == 1) 
  {
#    $lowerBoundExp = $varDeclPrefix.
#                      $varNamePrefix . 
#                      &computeVariableName($variableIndex) . 
#                      " = ceil(" . $expArray[0] . ")";
    $lowerBoundExp = $expArray[0];
    return($lowerBoundExp);
  } # End if
  $lowerBoundExp = "max(" . shift(@expArray) .
                    "," . shift(@expArray) . ")";
  while(@expArray)
  {
    $lowerBoundExp = "max(" . $lowerBoundExp . "," . 
                      shift(@expArray) . ")";
  } # End while
  #$lowerBoundExp = $varDeclPrefix.
  #                  $varNamePrefix . 
  #                  &computeVariableName($variableIndex) . 
  #                  " = " . "ceil(" . $lowerBoundExp .")";

  return($lowerBoundExp);
} 
# End computeMinExpression
##############################################################################
# sub computeMinExpressionBigFloat
##############################################################################
# Performed task: computes the minimum expression for a 
# given variable.
#
# input   : $varDeclPrefix, $varNamePrefix, $variableIndex
#           $varDeclPrefix: string to prefix the variable declaration
#           (e.g "my " for PERL or "int " for C.
#           $varNamePrefix: string used as prefix in varaibles names (e.g. "$" 
#           for PERL, none for C).
#           $variableIndex: index of the variable used to compute it's name.
# output  : A string holding the lower bound declaration for a "for" loop.
# globals : INPUT (handle on the input file). This handle must opended upon
#           subroutine invocation and is closed by the subroutine.
#
sub computeMinExpressionBigFloat {
  my ($varDeclPrefix, $varNamePrefix, $variableIndex) = @_;
  if (! defined($variableIndex))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    exit(1);
  }
  my @paramArray        = ();
  my @expArray          = ();
  my $currentParamValue = 0;
  my $line              = "";
  my $lowerBoundExp     = "";
  my $currentExpIndex   = 0;
  my $numerator         = Math::BigFloat->new();
  my $denominator       = Math::BigFloat->new();
  my @fraction          = ();
  while($line = <INPUT>)
  {
    # Detect a result line and start cleanup as well.
    if (! ($line =~ s/.*list #\[//)) { next; }
    $line =~ s/\]//;
    # Clean-up white spaces.
    chomp $line;
    $line =~ s/(^\s*)||(\s*$)//g;
    $line =~ s/(\s)+/ /g;
    #print STDERR $line, " $variableIndex \n";
    if ($variableIndex == 0)
    {
      $denominator->bone();
      @fraction = split('/',$line);
      $numerator    = Math::BigFloat->new($fraction[0]);
        if (defined($fraction[1]))
        {
          $denominator  = Math::BigFloat->new($fraction[1]);
        }
      $currentParamValue = $numerator / $denominator;
      $currentParamValue->bceil();
      #$currentParamValue = ceil(eval($line));
      $lowerBoundExp .= "Math::BigFloat->new('$currentParamValue')";
      close(INPUT);
      return($lowerBoundExp);
    }
    else
    {
      # Parametric part
      @paramArray = split(" ", $line);
      for (my $i = 0 ; $i < $variableIndex ; $i++)
      {
        @fraction = split('/', $paramArray[$i]);
        $paramArray[$i] = "Math::BigFloat->new('$fraction[0]')";
        if (defined($fraction[1]))
        {
          $paramArray[$i] .= "/Math::BigFloat->new('$fraction[1]')"
        }
        $paramArray[$i] .= " * " . $varNamePrefix .
                          &computeVariableName($i);
      } # End for $i
      # Constant part
      @fraction = split('/', $paramArray[$variableIndex]);
      $paramArray[$variableIndex] = "Math::BigFloat->new('$fraction[0]')";
      if (defined($fraction[1]))
      {
        $paramArray[$variableIndex] .= "/Math::BigFloat->new('$fraction[1]')";
      }
      $expArray[$currentExpIndex] = join(" + ", @paramArray);
      $currentExpIndex ++;
    }
  } # End while
  close(INPUT);
  if (@expArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (@expArray == 1) 
  {
    $lowerBoundExp =  $expArray[0];
    return($lowerBoundExp);
  } # End if
  $lowerBoundExp = "max(" . shift(@expArray) .
                    "," . shift(@expArray) . ")";
  while(@expArray)
  {
    $lowerBoundExp = "max(" . $lowerBoundExp . "," . 
                      shift(@expArray) . ")";
  } # End while

  return($lowerBoundExp);
} 
# End computeMinExpressionBigFloat
##############################################################################
# sub computeVariableName
##############################################################################
# Performed task: Compute a variable name (a, b ... z, aa, ab, ... )
#                 from an index (0 -> a, 1 -> b, ..., 27 -> aa...)
#
# input   : index
# output  : a string holding the variable name
# globals : none
#
sub computeVariableName {
  my ($index) = @_;
  if (! defined($index))
  {
    my @call_info = caller(0);
    print STDERR $call_info[3], " missing parameter. Aborting program!\n";
    exit($EX_SOFTWARE);
  }
  my $template      = "\"";
  my $list          = "";
  my $baseAsciiCode = 97;
  my $alphabetSize  = 26;
  my $alphabetOffset = 0;
  my $template =  "\"";
  my $list = "";
  my $quotient = $index;
  my $remainder = $quotient;
  my $variableName = "";
  while (1)
  {
    $remainder = $quotient % $alphabetSize;
    $quotient = int($quotient / $alphabetSize);
    $template .= "C";
    $list     = "," . ($baseAsciiCode + $remainder)  . $list;
    if ($quotient == 0) { last; }
    if ($quotient <= $alphabetSize)
    {
      $template .= "C";
      $list     = "," . ($baseAsciiCode + $quotient - 1) . $list;
      last;
    }
  } # End while

  $template .= "\"";
  $variableName .= "(" . $template . $list . ")";
  return(eval("pack$variableName")); 
}
# End computeVariableName
##############################################################################
# sub contextAsText
##############################################################################
# Performed task: computes the piece of text (holding the context) that will 
#                 be appended into the input file for PIP.
#
# input   : $refContext -> a reference on the context
# output  : a string holding the context lines
# globals : none
#
sub contextAsText 
{
  my ($refContext) = @_;
  if (! defined($refContext))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    # Uncomment this line and remove the next one if using stdExitErrors.
    #exit($EX_SOFTWARE);
    exit(1);
  }
  my $refContextElem = 0;
  my $contextText = "";
  for (my $i = 0 ; $i < @$refContext ; $i++)
  {
    $refContextElem = $$refContext[$i];
    $contextText .= "#[";
    for (my $j = 0 ; $j < @$refContextElem ; $j++)
    {
      $contextText .= "$$refContextElem[$j] ";
    }
    $contextText .= "]\n";
  }
  return($contextText);
} # End contextAsText
##############################################################################
# sub enlargeContext
##############################################################################
# Performed task: Insert a 0 at the end of the parameters list (just before
# the constant value) for the next round of computations.
#
# input   : $refContext (a reference on an array of array references. The
#           arrays hold the coefficient for the parameters and a constant.
#           Each array will form a context line. 
# output  : none (operates only through a side effect on the input parameter).
# globals : none
#
sub contextEnlarge
{
  my ($refContext) = @_;
  if (! defined($refContext))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    # Uncomment this line and remove the next one if using stdExitErrors.
    exit($EX_SOFTWARE);
  }
  my $refContextElem = 0;
  for (my $i = 0 ; $i < @$refContext ; $i++)
  {
    $refContextElem = $$refContext[$i];
    $$refContextElem[@$refContextElem] = $$refContextElem[@$refContextElem - 1];
    $$refContextElem[@$refContextElem - 2] = Math::BigFloat->new("0");
  }
} # End contextEnlarge
##############################################################################
# sub createOutputFile
##############################################################################
# Performed task: Create a file for a PIP input data set.
#
# input   :
# output  :
# globals : OUTPUT file handle
#
sub createOutputFile {
  my($fileName) = @_;
  if (! defined($fileName))
  {
    my @call_info = caller(0);
    print STDERR $call_info[3], " missing parameter. Aborting program!\n\n";
    exit($EX_SOFTWARE);
  }
  if (! open (OUTPUT, ">$fileName"))
  {
    print STDERR "\n\n Can't create $fileName. Aborting program!\n\n";
    exit($EX_CANTCREAT);
  } 
}
# End createOutputFile
##############################################################################
# sub generatePipInputForMax
##############################################################################
# Performed task:
#
# input   : $refCoeffLines -> An reference on an array holding the initial data;
#           $refContext -> reference on the context (array of references on
#           arrays of coefficients;
#           $currentPassNum -> the pass number corresponds to the index of the
#           variable we want to investigate;
#           $numLines and $numColumns are self-evident and refer to initial
#           data size.
# output  : none
# globals : OUTPUT file handle (must be open by the calling program
#           and is closed by the procedure).
#
# We are looking for a global (for all the parameters) lexicographical
# maximum (even if we only use the values for the current one). We use the
# "bigparm trick" for that all the parameters are taken into account when
# we compute the coefficient of the bigparm.
sub generatePipInputForMax {
my ($refCoeffLines, $refContext, $searchedVarIndex, $numLines, $numColumns) = @_;
my $lineRef;
my $bigparmCoeff = 0;
if (! defined($numColumns))
{
  my @call_info = caller(0);
  print STDERR $call_info[3], " missing parameter. Aborting program!\n";
  exit($EX_SOFTWARE);
}
# Open the data set.
print OUTPUT "(\n";
# Comments (Empty)
print OUTPUT "()\n";
# Number of variables.
print OUTPUT $numColumns - 1, " ";
# Number of symbolic parameters (only one).
print OUTPUT "1 ";
# $numLines inequalities for variables
print OUTPUT $numLines, " ";
# The number of parameters inequalities is the size of the context : always 0 in
# this context.
print OUTPUT "0 ";
# Index of the bigparm.
print OUTPUT $numColumns, " ";
# Rational solutions wanted.
print OUTPUT "$integerMode\n";
# Variable inequalities "tableau".
print OUTPUT "(\n";
for (my $i = 0 ; $i < $numLines ; $i++)
{
  $lineRef = $$refCoeffLines[$i];
  print OUTPUT "#[";
  # The variable for which we are looking for a maximum.
  print  OUTPUT ($$lineRef[$searchedVarIndex]) * -1, " ";
  # Looking for all parameters lexicographical maximum.
  $bigparmCoeff = $$lineRef[$searchedVarIndex];
  # The remaining "maximized" variables
  for (my $j = 0 ; 
          $j < ($numColumns - 1) ; 
          $j++)
  {
    if ($j == $searchedVarIndex)
    {
      next;
    }
    print OUTPUT ($$lineRef[$j] * -1), " "; 
  $bigparmCoeff += $$lineRef[$j];
  } # End for $j
  # The unchanged constant
  print OUTPUT $$lineRef[$numColumns -1 ], " "; 
  # The bigparm coefficient.
  print OUTPUT $bigparmCoeff;
  print OUTPUT "]\n";
} # End for $i
print OUTPUT ")\n";
# Parameter inequalities (an empty set)
print OUTPUT "(\n";
print OUTPUT ")\n";
# Close the data set.
print OUTPUT ")\n";
close(OUTPUT);
} 
# End sub generatePipInputForMax
##############################################################################
# sub generatePipInputForMin
##############################################################################
# Performed task:
#
#input:     $refCoeffLines -> An reference on an array holding the initial data;
#           $refContext -> reference on the context (array of references on
#           arrays of coefficients;
#           $currentPassNum -> the pass number corresponds to the index of the
#           variable we want to investigate;
#           $numLines and $numColumns are self-evident and refer to initial
#           data size.
# output  : none, the procedure only writes to a file.
# globals : OUTPUT file handle (must be open by the calling program
#           and is closed by the procedure).
#
sub generatePipInputForMin{
my ($refCoeffLines, $refContext, $searchedVarIndex, $numLines, $numColumns) = @_;
my $lineRef;
my $bigparmCoeff = 0;
if (! defined($numColumns))
{
  my @call_info = caller(0);
  print STDERR $call_info[3], " missing parameter. Aborting program!\n";
  exit($EX_SOFTWARE);
}
# Open the data set.
print OUTPUT "(\n";
# Comments
print OUTPUT "()\n";
# Number of variables.
print OUTPUT $numColumns - 1, " ";
# $currentPass number of symbolic parameters: always zero in this context.
print OUTPUT "0 ";
# $numLines inequalities for variables
print OUTPUT $numLines, " ";
# The number of parameters inequalities is the size of the context: always zero
# int this context.
print OUTPUT "0 ";
# Index of the bigparm (none is used).
print OUTPUT "-1 ";
# Rational solutions wanted.
print OUTPUT "$integerMode\n";
# Variable inequalities tableau.
print OUTPUT "(\n";
for (my $i = 0 ; $i < $numLines ; $i++)
{
  $lineRef = $$refCoeffLines[$i];
  print OUTPUT "#[";
  print OUTPUT $$lineRef[$searchedVarIndex], " "; 
  for (my $j = 0 ; 
          $j < $numColumns ; 
          $j++)
  {
    if ($j != $searchedVarIndex)
    {
      print OUTPUT $$lineRef[$j], " "; 
    }
  } # End for $j
  print OUTPUT "]\n";
} # End for $i
print OUTPUT ")\n";
# Parameter inequalities: nothing to print in this context.
print OUTPUT "(\n";
print OUTPUT ")\n";
# Close the data set.
print OUTPUT ")\n";
close(OUTPUT);
}
# End sub generatePipInputForMin
##############################################################################
# sub hasFractions
##############################################################################
# Performed task: checks whether any of a set of expressions is a fraction.
#         Expression are hel in an array of strings.
#
# input   : $refValuesArray a reference on an array of strings holding
#           (numerical) expressions.
# output  : 0 if no expression is a fraction;
#           1 if any expression is a fraction.
# globals : none
#
# notes   : the presence of a "/" denotes the existance of a fraction. 
sub hasFractions {
  my ($refValuesArray) = @_;
  if (! defined($refValuesArray))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    # Uncomment this line and remove the next one if using stdExitErrors.
    exit($EX_SOFTWARE);
  }
  for (my $i = 0 ; $i < @$refValuesArray ; $i ++)
  {
    if ($$refValuesArray[$i] =~ '/')
    {
      return(1);
    }
  } # End for $i
  return(0);
} # End hasFractions
##############################################################################
# sub isInContext
##############################################################################
# Performed task: check whether a context (an array of strings) is already include
#           in a context array.
#
# input   : $refContext : a reference on a context (array of references on arrays)
#           $refContextLineArray : a reference on an array.
# output  : 0 if the no element of the first argument matches the second
#           argument, 1 otherwise
# globals : none
#
# notes   : We try to find a context that corresponds to the searched context.
#           The match is searched on the contents, not on the references.
#
sub isInContext {
  my ($refContext,$refContextLineArray) = @_;
  if (! defined($refContextLineArray))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    # Uncomment this line and remove the next one if using stdExitErrors.
    exit($EX_SOFTWARE);
  }
  my $refCurrentContextLine = 0;
  for (my $i = 0 ; $i < @$refContext ; $i++)
  {
    $refCurrentContextLine = $$refContext[$i];
    # If sizes do not match, try the next array.
    if ((@$refCurrentContextLine * 1) != (@$refContextLineArray * 1 ))
    {
      next;
    }
    for (my $j = 0 ; $j < @$refCurrentContextLine ; $j++)
    {
      # If an element does not match, try the next array.
      if ($$refCurrentContextLine[$j] != $$refContextLineArray[$j])
      {
        last; # To the end of the current loop.
      }
      # Up to this point, all individual elements of the context match and if 
      # it is the last one, then a match has been found.
      if ($j + 1 == @$refContextLineArray)
      {
        return(1);
      }
    } # End for $j
  } # End for $i
  # No match found.
  return(0);
} # End isInContext
##############################################################################
# sub setToAndRidOfCommonDenominator
##############################################################################
# Performed task: Reduces a an array of fractions to the same denominator and
# eventually removes the denominators : the result is an array of integers.
# All arithmetics are BigFloat.
# Fractions are given as 
# fraction    = sign , numerator , '/' , denominator;
# sign        = '-' | '+';
# numerator   = integer;
# denominator = integer;
# integer     = digit , {digit}
#
# The fraction array is modified as a side effect of the invocation.
#
# input   : a reference on the fraction array
# output  : the least common denominator
# globals : none
#
# We collect all the denominators (we assume 1 for integers).
# We compute the least common denominator with the Math::BigInt::blcm function
# We modify all the fractions (compute and set the numerator only and then get rid 
# of the denominator: results are integer).
sub setToAndRidOfCommonDenominator {
  my ($refFracArray) = @_;
  if (! defined($refFracArray))
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " missing parameter. Aborting program!\n\n";
    # Uncomment this line and remove the next one if using stdExitErrors.
    #exit($EX_SOFTWARE);
    exit(1);
  }
  my @denominators  = ();
  my @numerators    = ();
  my @fraction      = ();
  my $lcd           = Math::BigInt->new("1");
  my $multiplicator = Math::BigInt->new("1");
  # Get all the denominators.
  # For denominators we use BigInt arithmetic to be able to use the
  # blcm function. BigInt and BigFloat mix well in subsequent operations.
  for (my $i = 0 ; $i < @$refFracArray ; $i++)
  {
    @fraction = split("/",$$refFracArray[$i]);
    push(@numerators, $fraction[0]);
    if (! defined($fraction[1]))
    {
      push(@denominators, Math::BigInt->new("1"));
    }
    else
    {
      push(@denominators, Math::BigInt->new($fraction[1]));
    }
  }# End for
  $lcd = Math::BigInt::blcm(@denominators);
  # Set the fractions
  for (my $i = 0 ; $i < @$refFracArray ; $i++)
  {
    @fraction = split("/",$$refFracArray[$i]);
    if (! defined($fraction[1]))
    {
      $$refFracArray[$i] = Math::BigFloat->new($numerators[$i]) * $lcd;
    }
    else
    {
      $multiplicator = $lcd / Math::BigFloat->new($fraction[1]);
      $$refFracArray[$i] = Math::BigFloat->new($numerators[$i]) * $multiplicator;
    }
  }# End for
  return($lcd);
} # End setToAndRidOfCommonDenominator
##############################################################################
# sub usage
##############################################################################
# Performed task: checks the command line parameters
#
# input   : none
# output  : none
# globals : $ARGV, $inputDataFileName.
#
sub usage
{
  if (! defined($ARGV[0]))
    {
      my $scriptName = `basename $0`;
      chomp($scriptName);
      print STDERR "\n\nUsage: $scriptName input_data_file_name";
      print STDERR "\n\n\tinput_data_file_name: name of the file holding the coefficients";
      print STDERR "\n\n";
      exit($EX_USAGE);
    }
  else
    {
      $inputDataFileName = $ARGV[0];
    }
} # End usage



__END__

