//---------------------------------------------------------------------------
#include <stdlib.h>
//---------------------------------------------------------------------------
#include "main.h"
#include "conf.h"
#include "boom.h"
#include "tboolfnct.h"
#include "tpfnct.h"
#include "ir.h"
//---------------------------------------------------------------------------
void MoReduce( TBoolFnct * fn, TGauge gauge, int IR_mutations )
{
  int i, j, k, l;
  TPfnct * ff, * ff1;
  TPfnct * cff;
  int * * rests;
  int * * * nrflg;
  int flg;
  int max, mprom, mpol, mcnt;
  int aff, sw;

  gauge.NewGauge( "IR", 0, 1 );
  rests = new( int * [2] );
  for ( l = 0; l < 2; l++ ) rests[l] = new( int[fn->inpvars] );
  nrflg = new( int * * [2] );
  for ( l = 0; l < 2; l++ )
  {
    nrflg[l] = new( int * [fn->inpvars] );
    for ( j = 0; j < fn->inpvars; j++ ) nrflg[l] [j] = new( int[fn->outvars] );
  }
  ff = fn->fnct;
  while ( ff != 0 )
  {
    if ( ff->dim != 0 )
    {
      for ( l = 0; l < 2; l++ )
        for ( i = 0; i < fn->inpvars; i++ ) rests[l] [i] = 0;
      for ( l = 0; l < 2; l++ )
        for ( j = 0; j < fn->inpvars; j++ )
          for ( i = 0; i < fn->outvars; i++ ) nrflg[l] [j] [i] = 0;
      aff = 0;
      for ( j = 0; j < fn->outvars; j++ )
        if ( ff->ov[j] == '0' )
        {
          cff = fn->parent->offset[j];
          while ( cff != 0 )
          {
            flg = 0;
            for ( k = 0; k < fn->inpvars; k++ )
            {
              if ( ff->iv[k] != cff->iv[k] && ff->iv[k] != '-' && cff->iv[k] != '-' )
              {
                flg = 1;
                break;
              }
            }
            if ( flg == 0 )
            { // there is an intersection
              for ( i = 0; i < fn->inpvars; i++ )
                if ( ff->iv[i] == '-' )
                {
                  if ( cff->iv[i] == '1' )
                  {
                    rests[0] [i] ++;
                    nrflg[1] [i] [j] = 1;
                    aff = 1;
                  }
                  else if ( cff->iv[i] == '0' )
                  {
                    rests[1] [i] ++;
                    nrflg[0] [i] [j] = 1;
                    aff = 1;
                  }
                  else
                  {
                    nrflg[1] [i] [j] = 1;
                    nrflg[0] [i] [j] = 1;
                  }
                }
            }
            cff = cff->next;
          }
        }
      if ( aff == 1 )
      {
        if ( random( 100 ) < IR_mutations )
        {
          mprom = random( fn->inpvars );
          mpol = random( 2 );
          sw = 0;
          while ( rests[mpol] [mprom] == 0 )
          {
            mprom++;
            if ( mprom == fn->inpvars )
            {
              mprom = 0;
              if ( sw == 0 ) sw = 1;
              else
                mpol = 1 - mpol;
            }
          }
          mcnt = 1;
        }
        else
        {
          max = 0;
          mcnt = 0;
          for ( l = 0; l < 2; l++ )
            for ( i = 0; i < fn->inpvars; i++ )
            {
              if ( rests[l] [i] == max && max != 0 ) mcnt++;
              if ( rests[l] [i] > max && rests[l] [i] != 0 )
              {
                max = rests[l] [i];
                mpol = l;
                mprom = i;
                mcnt = 1;
              }
            }
          if ( mcnt > 1 )
          {
            j = random( mcnt );
            flg = 0;
            for ( l = 0; l < 2; l++ )
            {
              for ( i = 0; i < fn->inpvars; i++ )
                if ( rests[l] [i] == max )
                {
                  if ( j == 0 )
                  {
                    flg = 1;
                    break;
                  }
                  j--;
                }
              if ( flg == 1 ) break;
            }
            mpol = l;
            mprom = i;
          }
        }
        if ( mcnt != 0 )
        {
          ff1 = fn->AddTermToEnd( ff->iv, ff->ov, ff->dim );
          ff1->prime = 0;
          ff1->origin = 1;
          ff1->iv[mprom] = mpol + '0';
          ff1->dim--;
          for ( j = 0; j < fn->outvars; j++ )
            if ( ff1->ov[j] == '0' && nrflg[mpol] [mprom] [j] == 0 ) ff1->ov[j] = '1';
        }
      }
    }
    ff = ff->next;
    if ( gauge.GaugeStep( 0, 0 ) == 2 ) break;
  }
  for ( l = 0; l < 2; l++ ) delete[] rests[l];
  delete[] rests;
  for ( l = 0; l < 2; l++ )
  {
    for ( j = 0; j < fn->inpvars; j++ ) delete[] nrflg[l] [j];
    delete[] nrflg[l];
  }
  delete[] nrflg;
  gauge.CloseGauge();
}
//---------------------------------------------------------------------------
