#! /usr/bin/perl

# makeParilLoopsRationalBigIntMpi-02.pl - ST - 2005-09-07

# COMMAND LINE SYNTAX:
# makePerlLoopsRationalBigFloat-02.pl inputDataFileName wVectorFileName

# NOTE(S):
# There is no such thing as makeParilLoopsRationalBigIntMpi-01.pl, we start
# directly at version 02 to keep in sync with the makeParilLoopsRationalBigInt
# serials.
#
# Changes from makeParilLoopsRationalBigInt-02.pl
# We use MPI to run PIP in parallel for the min and the max search.
# Also includes some minor tweaks and more extended comments.
#
# Changes from makePariLoopsRationalBigInt.pl
# We do not compute the min and max for the last variable with PIP since we
# already have it from previous calculations. Saves a lot of time.
#
# Changes from makePerlLoopsRationalBigInt.pl
# Output was changed to code the gp utility (from the PARI suite) instead of Perl.
# Values are computed much faster.
#
# Changes from makePerlLoopsRational.pl
# In this version, all parameter arithmetics are revamped in BigFloat or in
# BigInt.
#
##############################################################################
# PROGRAM DECLARATIONS
##############################################################################

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

# 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
# Load the MPI module and initialize it immediatly, making sur you
# do not forget to do so, before loading any other module.
use Parallel::MPI qw(:all);
MPI_Init();
#
use MpiUtils qw(:BASIC);
# 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 $maxPrefix               = "max";
my $minPrefix               = "min";
my $pipInputDataPrefix      = "./pipData/forPip-";
my $pipOutputDataPrefix     = "./pipData/fromPip-";
my $pipUtility              = "pipMP";
my $pipParams               = "-z";
my $integerMode             = 0;
# For PARI
my $loopPreamble            = "zzzz=0;\n";
my $varDeclPrefix           = "";
my $varNamePrefix           = '';
my $initialIndentation      = "";
my $loopEpilog              = '' . "\n";
my $minSub                  = "";
my $maxSub                  = "";
# For MPI ("semi- constants")
my $mpiRank                 = MPI_Comm_rank(MPI_COMM_WORLD);
my $mpiSize                 = MPI_Comm_size(MPI_COMM_WORLD);
my $mpiTag                  = 1137; # A "true" constant.
my $masterThread            = 0;
my $minSearchThread         = 1;
my $maxSearchThread         = 2;
my $MAX_STRING_LENGTH       = 500000;
##############################################################################
# PROGRAM VARIABLE DECLARATIONS
##############################################################################
my $inputDataFileName       = "";
my $wVectorFileName         = "";
my $pipMinInputFileName     = "";
my $pipMaxInputFileName     = "";
my $pipOutputFileName       = "";
my $numVars                 = 0;
my $line                    = "";
my $isFirstLine             = 1;
my $numLines                = 0;
my $numColumns              = 0;
my @values                  = ();
my @coeffLines              = ();
my $currentCoeffLine        = 0;
my $currentDataLineNum      = 0;
my @wVector                 = ();
my $minExpression           = "";
my $maxExpression           = "";
my @minExpressions          = ();
my @maxExpressions          = ();
my @minExpressionsBigArith = ();
my @maxExpressionsBigArith = ();
my $currentInputFileName    = "";
my $loopCode                = "";
my $indentation             = "";
my $currentVarIndex         = "";
my @context                 = (); # Each element is a reference to an array of 
                                  # parameters. Used for min PIP searches.
my @contextBp               = (); # Idem but for max PIP searches
my @recvContext             = ();
my @sendContext             = ();
##############################################################################
# TEST ENVIRONMENT AND CONFIGURATION VARIABLES
##############################################################################

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

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

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

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

&usage();

#
# Reading and scanning the data file, only necessary for the "master thread"
#
if ($mpiRank == 0)
{
  # Specific variables
  my $message;
  # 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";
    MPI_Abort(MPI_COMM_WORLD, $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);
        MPI_Abort(MPI_COMM_WORLD, $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);
      MPI_Abort(MPI_COMM_WORLD, $EX_DATAERR);
    }
    # Check if the line has not too 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);
      MPI_Abort(MPI_COMM_WORLD, $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);
    MPI_Abort(MPI_COMM_WORLD, $EX_DATAERR);
  }
  close(DF);
  $numVars = @{$coeffLines[0]} -1 ; # coeffLines also hold a constant
  #
  # End loading and quick and dirty data check.
  #
  # Load the W vector, if present.
  if ($wVectorFileName ne "")
  {
    if (! open(WF, "<$wVectorFileName"))
    {
      print STDERR "\n\nCan't open file $wVectorFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_NOINPUT);
    }
    $isFirstLine = 1;
    $currentDataLineNum = 0;
    while($line = <WF>)
    {
      # 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 elements
      if ($isFirstLine)
      {
        $isFirstLine = 0;
        # There must be a number of elements and it can't be null.
        if (! defined($values[0]) || $values[0] == 0 )
        {
          print STDERR "\n\nMissing or invalid W vector description! ";
          print STDERR "Aborting program!\n\n";
          close(WF);
          MPI_Abort(MPI_COMM_WORLD, $EX_DATAERR);
        }
        $numColumns   = $values[0];
        if ($numColumns !=  $numVars)
        {
          print STDERR "\n\nThe number of variables ($numVars) and  ";
          print STDERR "the number of elements of the W ($numColumns) vector do ";
          print STDERR "not match! ";
          print STDERR "Aborting the program!\n\n";
          close(WF);
          MPI_Abort(MPI_COMM_WORLD, $EX_DATAERR);
        }
        $currentDataLineNum++;
        next;
      } # End isFirstLine
      # Check if the line has enough parameters
      if (! defined($values[$numColumns - 1]))
      {
        print STDERR "\n\nMissing data in W vector! ";
        print STDERR "Aborting program!\n\n";
        close(WF);
        MPI_Abort(MPI_COMM_WORLD, $EX_DATAERR);
      }
      # Check if the line has not to much parameters
      if (defined($values[$numColumns]))
      {
        print STDERR "\n\nToo many data in W vector! ";
        print STDERR "Aborting program!\n\n";
        close(WF);
        MPI_Abort(MPI_COMM_WORLD, $EX_DATAERR);
      }
      $currentDataLineNum++;
      # Store the parameters.
      if ($currentDataLineNum = 2)
      {
        @wVector = @values;
        last;
      }
      if ($debug) { print $line; }
    } # End while
    close(WF);
  } # End if ($wVectorFileName ne "")
  #
  # Send the number of vars to the search threads
  #
  MPI_Send(\$numVars, 
            1, 
            MPI_INT, 
            $minSearchThread, 
            $mpiTag, 
            MPI_COMM_WORLD);
  MPI_Send(\$numVars, 
            1, 
            MPI_INT, 
            $maxSearchThread, 
            $mpiTag, 
            MPI_COMM_WORLD);
  # -compute the data for PIP;
  # -get the min and max expressions;
  # -update the context.
  # We only want to run PIP for n-1 first variables hence $numColumns - 2.
  for (my $i = 0; $i < $numVars - 1 ; $i++)
  {
    # Initialize the variables before a new round.
    @recvContext        = ();
    # Compute the file names and data for PIP searches
    $pipMinInputFileName = &computeFileName($pipInputDataPrefix,
                                            "txt",
                                            $i,
                                            $inputFileNameIndexSize,
                                            $minPrefix);
    $pipMaxInputFileName = &computeFileName($pipInputDataPrefix,
                                            "txt",
                                            $i,
                                            $inputFileNameIndexSize,
                                            $maxPrefix);
    # For min PIP search.
    &createOutputFile($pipMinInputFileName);
    &generatePipInputForMin(\@coeffLines, \@context, $i, $numLines, $numVars + 1);
    # For max PIP search.
    &createOutputFile($pipMaxInputFileName);
    &generatePipInputForMax(\@coeffLines, \@contextBp, $i, $numLines, $numVars + 1);
    # Enlarge the contexts for the next step (add one column).
    &contextEnlarge(\@context);
    &contextEnlarge(\@contextBp);
    #
    # Set a barrier here in order to force the search threads
    # to wait until the files are ready
    #
    MPI_Barrier(MPI_COMM_WORLD);
    #
    # 
    #
    # print STDERR &contextAsText(\@context);
    # print STDERR "\n";
    # print STDERR &contextAsText(\@contextBp);
    # print STDERR "\n";
    # print STDERR "Min done for $i!\n";
    #
    # Min search stuff.  
    #
    # Receive the min expression
    MPI_Recv(\$minExpressions[$i], 
              $MAX_STRING_LENGTH, 
              MPI_CHAR, 
              $minSearchThread, 
              $mpiTag,
              MPI_COMM_WORLD);
    #
    # Max search stuff.  
    # Receive the max expression
    MPI_Recv(\$maxExpressions[$i], 
              $MAX_STRING_LENGTH, 
              MPI_CHAR, 
              $maxSearchThread, 
              $mpiTag,
              MPI_COMM_WORLD);
    # Update the contexts (for min and max searches).
    # Get the extras lines for the context.
    # Max context for min search.
    &recvStringsMatrix(\@recvContext, $MAX_STRING_LENGTH, $minSearchThread, $mpiTag);
    for (my $i = 0 ; $i < @recvContext ; $i++)
    {
      if (! &isInContext(\@context, $recvContext[$i]))
      {
        push(@context, $recvContext[$i]);
      }
    }
    @recvContext = ();
    &recvStringsMatrix(\@recvContext, $MAX_STRING_LENGTH, $minSearchThread, $mpiTag);
    for (my $i = 0 ; $i < @recvContext ; $i++)
    {
      if (! &isInContext(\@contextBp, $recvContext[$i]))
      {
        push(@contextBp, $recvContext[$i]);
      }
    }
    @recvContext = ();
    &recvStringsMatrix(\@recvContext, $MAX_STRING_LENGTH, $maxSearchThread, $mpiTag);
    for (my $i = 0 ; $i < @recvContext ; $i++)
    {
      if (! &isInContext(\@context, $recvContext[$i]))
      {
        push(@context, $recvContext[$i]);
      }
    }
    @recvContext = ();
    &recvStringsMatrix(\@recvContext, $MAX_STRING_LENGTH, $maxSearchThread, $mpiTag);
    for (my $i = 0 ; $i < @recvContext ; $i++)
    {
      if (! &isInContext(\@contextBp, $recvContext[$i]))
      {
        push(@contextBp, $recvContext[$i]);
      }
    }
    @recvContext = ();
    #
  #  print STDERR "**$i**\n";
  #  print STDERR &contextAsText(\@context);
  #  print STDERR "\n";
  #  print STDERR &contextAsText(\@contextBp);
  #  print STDERR "\n";
  #  print STDERR "Max done for $i!\n";
    #MPI_Abort(MPI_COMM_WORLD,1);
    #
  } # End for $i
  # Generate the PARI/GP code.
  #$numVars = @minExpressions * 1 + 1;
  $loopCode .= $loopPreamble;
  # No variable declarations needed for GP/PARI.
  $loopCode .= "wwww=[";
  for (my $i = 0 ; $i < $numVars ; $i++)
  {
    if ($wVectorFileName ne "")
    {
      $loopCode .= $wVector[$i];
    }
    else
    {
      $loopCode .= '0';
    }
    if ($i < $numVars - 1)
    {
      $loopCode .=  ", ";
    }
  }
  $loopCode .= "];";
  for (my $i = 0 ; $i < $numVars  ; $i++)
  {
    if($i < ($numVars - 1))
    {
      $loopCode .= $indentation . $varNamePrefix .
                   &computeVariableName($i) .
                   $minPrefix . " = ceil(" . $minExpressions[$i] . "); ";
      $loopCode .= $indentation . $varNamePrefix .
                   &computeVariableName($i) .
                   $maxPrefix . " = floor(" . $maxExpressions[$i] . "); ";
      $loopCode .= $indentation . "for (" . $varNamePrefix . 
                   &computeVariableName($i). " = " .
                   $varNamePrefix . &computeVariableName($i) . $minPrefix .
                   ' , ' . $varNamePrefix . &computeVariableName($i) . $maxPrefix .
                   ' , ';
      $indentation .= "  ";
    }
    else # $i == ($numVars - 1)
    {
      $loopCode .= $indentation . &computeLastVarMinMaxPari(\@coeffLines, 
                                                              $maxPrefix,
                                                              $minPrefix,
                                                              $varDeclPrefix,
                                                              $varNamePrefix);
      $loopCode .= 'for (' . $varNamePrefix .
                    &computeVariableName($i) . ' = ' .
                    $varNamePrefix . &computeVariableName($i) . $minPrefix .
                    ' , ' . $varNamePrefix . &computeVariableName($i) . $maxPrefix .
                    ' , ';
      $loopCode .= $indentation . 'print("A[",' . 'zzzz,' . '"]:=["' . ',';
      for (my $j = 0 ; $j <= $i ; $j++)
      {
        $loopCode .= $varNamePrefix . &computeVariableName($j);
        $loopCode .= " + wwww[" . ($j + 1) . "]";
        if ($i != $j)
        {
          $loopCode .= ',",",';
        }
        else
        {
          $loopCode .= ',"]:");zzzz++)';
        }
      }
    }
  } # End for
  for (my $i = $numVars - 1 ; $i > 0 ; $i--)
  {
    $loopCode .= ")";
  }
  # Append min and max functions code.
  $loopCode .= $minSub . $maxSub;
  print $loopCode;
  print "\n";
  #print STDERR "It's over!\n";
} # End $mpiRank == $masterThread

if ($mpiRank == $minSearchThread)
{
  # print STDERR "Min search\n";
  #
  # Receive the number of variables
  # 
  MPI_Recv(\$numVars, 1, MPI_INT, $masterThread, $mpiTag, MPI_COMM_WORLD);
  #
  # Process the data files
  #
  for (my $i = 0; $i < $numVars - 1 ; $i++)
  {
    # Initialize the variables before a new round.
    @context            = ();
    @contextBp          = ();
    # Compute the file names and data for PIP searches
    $pipMinInputFileName = &computeFileName($pipInputDataPrefix,
                                            "txt",
                                            $i,
                                            $inputFileNameIndexSize,
                                            $minPrefix);
    # All files are created by the "master thread"
    # We set a barrier here to let it the time to write them
    MPI_Barrier(MPI_COMM_WORLD);
    # Min search stuff.
    $pipOutputFileName = &computeFileName($pipOutputDataPrefix,
                                          "txt",
                                          $i,
                                          $inputFileNameIndexSize,
                                          $minPrefix);
    # Run the PIP min search
    print STDERR &computeVariableName($i), "-min\n";
    if (system("$pipUtility $pipParams $pipMinInputFileName > $pipOutputFileName"))
    {
      print STDERR "\n\nPIP execution failed for file $pipMinInputFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
    }
    # Compute the min expression for the $i 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";
      MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
    }
    # Go ahead with the computation
    $minExpression = &computeMinExpression($varDeclPrefix, 
                                            $varNamePrefix,
                                            $i);
    if ($minExpression eq "")
    {
      print STDERR "\n\nMin expression for variable $i is Empty! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
    }
    # Send the minExpression
    $minExpression .= ""; # This seemingly frivolous statement is here 
                          # to patching a weired bug: for some unknown
                          # reason, if the expression is only one 
                          # character long, it is not correctly 
                          # transmitted by MPI before the string
                          # is manipulated somehow.
    MPI_Send(\$minExpression, 
              length($minExpression),
              MPI_CHAR,
              $masterThread,
              $mpiTag,
              MPI_COMM_WORLD);
    # Update the contexts (for min and max searches).
    # Compute the extras lines for the context.
    # Min context for min search.
    if (! open(INPUT, "<$pipOutputFileName"))
    {
      print STDERR "\n\nCan't open file $pipOutputFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_NOINPUT);
    }
    # Go ahead with the computation
    &computeMinContextLines(\@context, $i, 0);
    # Min contex for max search.
    # Check and open file.
    if (! open(INPUT, "<$pipOutputFileName"))
    {
      print STDERR "\n\nCan't open file $pipOutputFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_NOINPUT);
    }
    # Go ahead with the computation
    &computeMinContextLines(\@contextBp, $i, 1);
    #
    # Send the contexts to the master thread
    #
    &sendStringsMatrix(\@context, " ", $masterThread, $mpiTag);
    &sendStringsMatrix(\@contextBp, " ", $masterThread, $mpiTag);
    #
  #  print STDERR &contextAsText(\@context);
  #  print STDERR "\n";
  #  print STDERR &contextAsText(\@contextBp);
  #  print STDERR "\n";
  #  print STDERR "Min done for $i!\n";
  } # End for $i
} # End $mpiRank == $minSearchThread

if ($mpiRank == $maxSearchThread)
{
  # print STDERR "Max search\n";
  #
  # Receive the number of variables
  # 
  MPI_Recv(\$numVars, 1, MPI_INT, $masterThread, $mpiTag, MPI_COMM_WORLD);
  for (my $i = 0; $i < $numVars - 1 ; $i++)
  {
    # Initialize the variables before a new round.
    @context            = ();
    @contextBp          = ();
    # Compute the file names and data for PIP searches
    $pipMaxInputFileName = &computeFileName($pipInputDataPrefix,
                                            "txt",
                                            $i,
                                            $inputFileNameIndexSize,
                                            $maxPrefix);
    # All files are created by the "master thread"
    # We set a barrier here to let it the time to write them
    MPI_Barrier(MPI_COMM_WORLD);
    #
    # Max search stuff.  
    #
    $pipOutputFileName = &computeFileName($pipOutputDataPrefix,
                                          "txt",
                                          $i,
                                          $inputFileNameIndexSize,
                                          $maxPrefix);
    # Run the PIP max search
    print STDERR &computeVariableName($i), "-max\n";
    if (system("$pipUtility $pipParams $pipMaxInputFileName > $pipOutputFileName"))
    {
      print STDERR "\n\nPIP execution failed for file $pipMaxInputFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
    }
    # Compute the max expression for the $i 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";
      MPI_Abort(MPI_COMM_WORLD, $EX_NOINPUT);
    }
    # Go ahead with the computation
    $maxExpression = &computeMaxExpression($varNamePrefix,$i);
    if ($maxExpression eq "")
    {
      print STDERR "\n\nMax expression for variable $i is Empty! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
    }
    #print STDERR "Compute Max Expression for $i done:! \n";
    #
    # Send the maxExpression
    $maxExpression .= ""; # This seemingly frivolous statement is here 
                          # to patching a weired bug: for some unknown
                          # reason, if the expression is only one 
                          # character long, it is not correctly 
                          # transmitted by MPI before the string
                          # is manipulated somehow.
    MPI_Send(\$maxExpression, 
              length($maxExpression),
              MPI_CHAR,
              $masterThread,
              $mpiTag,
              MPI_COMM_WORLD);
    # Update the contexts (for min and max searches).
    # Compute the extras lines for the context.
    # Max context for min search.
    # Check and open file.
    if (! open(INPUT, "<$pipOutputFileName"))
    {
      print STDERR "\n\nCan't open file $pipOutputFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_NOINPUT);
    }
    # Go ahead with the computation
    &computeMaxContextLines(\@context, $i, 0);
    #print STDERR "Compute Max Context (min search) for $i done:! \n";
    # Context for max search.
    # Check and open file.
    if (! open(INPUT, "<$pipOutputFileName"))
    {
      print STDERR "\n\nCan't open file $pipOutputFileName! Aborting program!\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_NOINPUT);
    }
    # Go ahead with the computation
    &computeMaxContextLines(\@contextBp, $i, 1);
    #
    # Send the contexts to the master thread
    #
    &sendStringsMatrix(\@context, " ", $masterThread, $mpiTag);
    &sendStringsMatrix(\@contextBp, " ", $masterThread, $mpiTag);
    #
  #  print STDERR "**$i**\n";
  #  print STDERR &contextAsText(\@context);
  #  print STDERR "\n";
  #  print STDERR &contextAsText(\@contextBp);
  #  print STDERR "\n";
  #  print STDERR "Max done for $i!\n";
    #MPI_Abort(MPI_COMM_WORLD, 1);
    #
  } # End for $i
} # End $mpiRank == $maxSearchThread
MPI_Finalize(); # End of all threads

##############################################################################
# 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.
    MPI_Abort(MPI_COMM_WORLD, $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";
  MPI_Abort(MPI_COMM_WORLD, $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";
    MPI_Abort(MPI_COMM_WORLD, $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";
    MPI_Abort(MPI_COMM_WORLD, $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";
    MPI_Abort(MPI_COMM_WORLD, $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);
    MPI_Abort(MPI_COMM_WORLD, $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).
      $commonDenominator = Math::BigFloat->new('1');
      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";
    MPI_Abort(MPI_COMM_WORLD, $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.
# notes   : Almost purely 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";
    MPI_Abort(MPI_COMM_WORLD, 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();
      $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";
    MPI_Abort(MPI_COMM_WORLD, $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";
    MPI_Abort(MPI_COMM_WORLD, 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";
    MPI_Abort(MPI_COMM_WORLD, $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);
    MPI_Abort(MPI_COMM_WORLD, $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 a 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.
      $commonDenominator = Math::BigFloat->new('1');
      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";
    MPI_Abort(MPI_COMM_WORLD, $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.
#
# notes   : On code generation.
#           This subroutine does not work well to generate Perl expressions
#           because of the limited size of number representation. The
#           &computeMinExpressionBigFloat subroutine yelds a more efficent
#           and correct code.Conversely, the code generated for PARI is
#           abolutely correct.
#
#           How PIP result are exploited.
#           We do not exploit all the subtleties of the PIP results.
#           In particular, we do not take into account the conditional expressions.
#           PIP computes the lexicographical minimum for *all* the variables, but,
#           at each step, we only consider the possible solutions for the current
#           variable.
#           If the $variableIndex == 0 there is only one result line to take into
#           account. In this particular case, the minimum expression is just a number.
#           In other cases we collect all the possible solutions as subexpressions
#           and combine them into a global max() expression.
#           
#           
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";
    MPI_Abort(MPI_COMM_WORLD, $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;
    if ($variableIndex == 0)
    {
      #
      # For the first variable, there is only one result line and
      # it only holds a single constant.
      #
      $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(); # It's a minimum !
      $lowerBoundExp = $currentParamValue;
      close(INPUT);
      return($lowerBoundExp);
    }
    else # $variableIndex >= 1
    {
      #
      # We are going to use all the solutions for the current variable.
      # and drop the solutions about other variables.
      # From each solution we buid an expression stored as elements
      # of @expArray.
      #
      @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);
  #
  # Whatever the $variableIndex, if no solution was found (i.e. no "#list" string
  # was found) we reach this point with an empty @expArray.
  #
  if (@expArray == 0) 
  {
    my @call_info = caller(0);
    print "\n\n", $call_info[3], " nothing to form an expression with. Aborting program!\n\n";
    MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
  }
  if (@expArray == 1) 
  {
    # It is not clear whether this situation is actually possible. Code is left
    # here "just in case".
    $lowerBoundExp = $expArray[0];
    return($lowerBoundExp);
  } # End if
  #
  # We build the global max() expression from all the sub expressions.
  #
  $lowerBoundExp = "max(" . shift(@expArray) .
                    "," . shift(@expArray) . ")";
  while(@expArray)
  {
    $lowerBoundExp = "max(" . $lowerBoundExp . "," . 
                      shift(@expArray) . ")";
  } # End while
  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";
    MPI_Abort(MPI_COMM_WORLD, 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";
    MPI_Abort(MPI_COMM_WORLD, $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";
    MPI_Abort(MPI_COMM_WORLD, $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 to the input file for PIP or printed out for 
#                 debugging.
#
# 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.
    MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
  }
  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.
    MPI_Abort(MPI_COMM_WORLD, $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";
    MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
  }
  if (! open (OUTPUT, ">$fileName"))
  {
    print STDERR "\n\n Can't create $fileName. Aborting program!\n\n";
    MPI_Abort(MPI_COMM_WORLD, $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 at the beginning of the input
#           file 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, $currentPassNum, $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";
  MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
}
# Open the data set.
print OUTPUT "(\n";
# Comments (Empty)
print OUTPUT "()\n";
# Number of variables.
print OUTPUT $numColumns - $currentPassNum - 1, " ";
# $currentPass number of symbolic parameters
print OUTPUT $currentPassNum + 1, " ";
# $numLines inequalities for variables
print OUTPUT $numLines, " ";
# The number of parameters inequalities is the size of the context.
print OUTPUT (@$refContext * 1), " ";
# 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 current variable which we are looking for a maximum.
  print  OUTPUT ($$lineRef[$currentPassNum]) * -1, " ";
  # Looking for all parameters lexicographical maximum.
  $bigparmCoeff = $$lineRef[$currentPassNum];
  # The remaining "maximized" variables
  for (my $j = $currentPassNum + 1; 
          $j < ($numColumns - 1) ; 
          $j++)
  {
    print OUTPUT ($$lineRef[$j] * -1), " "; 
  $bigparmCoeff += $$lineRef[$j];
  } # End for $j
  # The unchanged constant
  print OUTPUT $$lineRef[$numColumns -1 ], " "; 
  # The unchanged symbolic parameters
  for (my $j = 0 ; $j < $currentPassNum ; $j++)
  {
    print OUTPUT $$lineRef[$j], " ";
  } # End for $j
  # The bigparm coefficient.
  print OUTPUT $bigparmCoeff;
  print OUTPUT "]\n";
} # End for $i
print OUTPUT ")\n";
# Parameter inequalities
print OUTPUT "(\n";
print OUTPUT &contextAsText($refContext);
print OUTPUT ")\n";
# Close the data set.
print OUTPUT ")\n";
close(OUTPUT);
} 
# End sub generatePipInputForMax
##############################################################################
# sub generatePipInputForMin
##############################################################################
# Performed task:
#
# input   :
# output  :
# globals :
#
sub generatePipInputForMin{
my ($refCoeffLines, $refContext, $currentPassNum, $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";
  MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
}
# Open the data set.
print OUTPUT "(\n";
# Comments
print OUTPUT "()\n";
# Number of variables.
print OUTPUT $numColumns - $currentPassNum - 1, " ";
# $currentPass number of symbolic parameters
print OUTPUT $currentPassNum, " ";
# $numLines inequalities for variables
print OUTPUT $numLines, " ";
# The number of parameters inequalities is the size of the context.
print OUTPUT (@$refContext * 1), " ";
# 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 "#[";
  for (my $j = $currentPassNum ; 
          $j < $numColumns ; 
          $j++)
  {
    print OUTPUT $$lineRef[$j], " "; 
  } # End for $j
  for (my $j = 0 ; $j < $currentPassNum ; $j++)
  {
    print OUTPUT $$lineRef[$j]; 
    if ($j < $currentPassNum + 1)
    {
      print OUTPUT " "; 
    }
  } # End for $j
  print OUTPUT "]\n";
} # End for $i
print OUTPUT ")\n";
# Parameter inequalities
print OUTPUT "(\n";
print OUTPUT &contextAsText($refContext);
print OUTPUT ")\n";
# Close the data set.
print OUTPUT ")\n";
close(OUTPUT);
}
# End sub generatePipInputForMin
##############################################################################
# sub hasFractions
##############################################################################
# Performed task:
#
# input   :
# output  :
# globals :
#
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.
    MPI_Abort(MPI_COMM_WORLD, $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:
#
# 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.
# globals :
#
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.
    MPI_Abort(MPI_COMM_WORLD, $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;
      }
      # If, up to this point, all elements match and 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: Sets a an array of fractions (given as strings) to the same 
# denominator and removes the denominator : the result is an array of integers.
# So the input array is made of string and is side effect transformed into
# an array of BigFloat integers.
#
# Fractions are given as 
# fraction    = sign , numerator , '/' , denominator;
# sign        = '-' | '+';
# numerator   = integer;
# denominator = integer;
# integer     = digit , {digit}
#
# input   : a reference on the fraction array (side effect modified).
# output  : the least common denominator.
# globals : none
#
# We collect all the denominators (we assume 1 for integers).
# All but denominator arithmetics are BigFloat.
# We compute the least common denominator with the Math::BigInt::blcm function
# We modify all the fractions (compute and set the numerator only and get rid of
# the denominator: results are BigFloat 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.
    #MPI_Abort(MPI_COMM_WORLD, $EX_SOFTWARE);
    MPI_Abort(MPI_COMM_WORLD, 1);
  }
  my @denominators  = ();
  my @numerators    = ();
  my @fraction      = ();
  my $oneAsBigInt   = Math::BigInt->bone();
  my $lcd           = Math::BigInt->bone();
  my $multiplicator = Math::BigInt->bone();
  # 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, $oneAsBigInt->copy());
    }
    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++)
  {
    if ($denominators[$i]->is_one()) #
    {
      $$refFracArray[$i] = Math::BigFloat->new($numerators[$i]) * $lcd;
    }
    else
    {
      $multiplicator = $lcd / $denominators[$i];
      $$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,others...
#
sub usage
{
  if (! defined($ARGV[0]))
    {
      my $scriptName = `basename $0`;
      chomp($scriptName);
      print STDERR "\n\nUsage: input_data_file_name [w_vector_file_name]";
      print STDERR "\n\n\tinput_data_file_name: name of the file holding the coefficients";
      print STDERR "\tw_vector_file_name: name of the file holding the W vector";
      print STDERR "\n\n";
      MPI_Abort(MPI_COMM_WORLD, $EX_USAGE);
    }
  else
    {
      $inputDataFileName  = $ARGV[0];
      if (defined $ARGV[1])
      {
        $wVectorFileName    = $ARGV[1];
      }
    }
} # End usage



__END__

