//---------------------------------------------------------------------------
#include <stdlib.h>
//---------------------------------------------------------------------------
#include "main.h"
#include "conf.h"
#include "boom.h"
#include "tboolfnct.h"
#include "tpfnct.h"
#include "implcheck.h"
#include "bufferstruct.h"
#include "ie.h"
//---------------------------------------------------------------------------
TBoolFnct * RandomSeqSearchIE( TBoolFnct * sfn, int ovr, int IC_memory, int IC_type, TermTree * imp_test, TermTree * offtree, TermTree * primes_ie, TGauge gauge )
{
  int i, i2, j;
  char tmp;
  TPfnct * ff, * ff1, * pff, * ff2;
  TBoolFnct * fn;

#if (trck&2)
  tf = fopen( "track.txt", "a" );
  fprintf( tf, "SeqSearchExpansion\n" );
#endif
  gauge.NewGauge( "IE - Sequential search", sfn->terms, 1 );
  fn = sfn->parent->CreateChildFnct();
  ff = sfn->fnct;
  pff = 0;
  j = 0;
  while ( ff != 0 )
  {
    if ( ff->dvar == ovr )
    {
      ff2 = fn->last;
      ff1 = fn->AddTermToEnd( ff->iv, sfn->parent->fnct->ov, ff->dim );
      ff1->prime = 1;
      ff1->origin = 1;
#if (trck&2)
      fprintf( tf, "  From:   %s\n", ff->iv );
#endif
      i = random( fn->inpvars );
      i2 = i;
      do
      {
        tmp = ff1->iv[i];
        if ( tmp != '-' )
        {
          ff1->iv[i] = '-';
          if ( ImplCheck( fn->parent, ff1, ovr, IC_memory, IC_type, imp_test, offtree ) == 0 )
            ff1->iv[i] = tmp;
          else
            ff1->dim++;
        }
        i++;
        i %= fn->inpvars;
      }
      while ( i != i2 );
#if (trck&2)
      fprintf( tf, "  To:     %s\n", ff1->iv );
#endif
      if ( primes_ie->AddToTreeHistory( ff1 ) == 1 )
        fn->DeleteTerm( ff1, ff2 );
      ff = sfn->DeleteTerm( ff, pff );
    }
    else
    {
      pff = ff;
      ff = ff->next;
    }
    if ( gauge.GaugeStep( j++, 0 ) == 2 ) break;
  }
#if (trck&2)
  fclose( tf );
#endif
  gauge.CloseGauge();
  if ( ff != 0 ) return 0;
  return fn;
}
//---------------------------------------------------------------------------
TBoolFnct * DistribMultiIE( TBoolFnct * hist, int ovr, int IC_memory, int IC_type, TermTree * imp_test, TermTree * offtree, TermTree * primes_ie, TGauge gauge )
{
  int i, i2, i3, j;
  char tmp;
  TPfnct * ff, * ff1, * pff, * ff3;
  TBoolFnct * fn;
  int secnd;

#if (trck&2)
  tf = fopen( "track.txt", "a" );
  fprintf( tf, "Distributed Multiple Sequential Search\n" );
#endif
  gauge.NewGauge( "IE - Distributed Multiple Sequential Search", hist->terms, 1 );
  fn = hist->parent->CreateChildFnct();
  ff = hist->fnct;
  pff = 0;
  j = 0;
  while ( ff != 0 )
  {
    if ( ff->dvar == ovr )
    {
      i = random( fn->inpvars );
      i2 = i;
      i3 = -1;
#if (trck&2)
      fprintf( tf, "  Chck:   %s %s\n", ff->iv, ff->ov );
#endif
      while ( ( ff->ov[i] != '0' || ff->iv[i] == '-' ) && i != i3 )
      {
        i3 = i2;
        i++;
        i %= fn->inpvars;
      }
      if ( i != i3 )
      {
        ff3 = fn->last;
        ff1 = fn->AddTermToEnd( ff->iv, hist->parent->fnct->ov, ff->dim );
        ff1->prime = 1;
        ff1->origin = 1;
#if (trck&2)
        fprintf( tf, "  From:   %s\n", ff1->iv );
#endif
        secnd = 0;
        do
        {
          tmp = ff1->iv[i];
          if ( tmp != '-' )
          {
            ff1->iv[i] = '-';
            if ( ImplCheck( hist->parent, ff1, ovr, IC_memory, IC_type, imp_test, offtree ) == 0 )
            {
              ff1->iv[i] = tmp;
              if ( secnd == 0 ) ff->ov[i] = '1';
            }
            else
            {
              ff1->dim++;
              if ( secnd == 0 ) ff->ov[i] = '2';
              secnd = 1;
            }
          }
          i++;
          i %= fn->inpvars;
        }
        while ( i != i2 );
#if (trck&2)
        fprintf( tf, "  To:     %s\n", ff1->iv );
#endif
        if ( primes_ie->AddToTreeHistory( ff1 ) == 1 ) fn->DeleteTerm( ff1, ff3 );
        pff = ff;
        ff = ff->next;
      }
      else
        ff = hist->DeleteTerm( ff, pff );
    }
    else
    {
      pff = ff;
      ff = ff->next;
    }
    if ( gauge.GaugeStep( j++, 0 ) == 2 ) break;
  }
#if (trck&2)
  fclose( tf );
#endif
  gauge.CloseGauge();
  if ( ff != 0 ) return 0;
  return fn;
}
//---------------------------------------------------------------------------
TBoolFnct * DistribExhIE( TBoolFnct * hist, int ovr, int IC_memory, int IC_type, TermTree * imp_test, TermTree * offtree, TermTree * primes_ie, TGauge gauge )
{
  int i, i2, i3, j;
  char tmp;
  TPfnct * ff, * ff1, * pff, * ff3 = 0, * ff4;
  TBoolFnct * fn;
  int secnd;

#if (trck & 2)
  tf = fopen( "track.txt", "a" );
  fprintf( tf, "ExhaustiveDistributedExpansion\n" );
#endif
  gauge.NewGauge( "IE - Distributed Exhaustive Implicant Expansion", hist->terms, 1 );
  fn = hist->parent->CreateChildFnct();
  ff = hist->fnct;
  pff = 0;
  j = 0;
  while ( ff != 0 )
  {
    if ( ff->dvar == ovr )
    {
      i = random( fn->inpvars );
      i2 = i;
      i3 = -1;
      while ( ( ff->ov[i] != '0' || ff->iv[i] == '-' ) && i != i3 )
      {
        i3 = i2;
        i++;
        i %= fn->inpvars;
      }
      if ( i != i3 )
      {
        ff4 = fn->last;
        ff1 = fn->AddTermToEnd( ff->iv, hist->parent->fnct->ov, ff->dim );
        ff1->prime = 1;
        ff1->origin = 1;
#if (trck & 2)
        fprintf( tf, "  From:   %s %s\n", ff->iv, ff->ov );
#endif
        i2 = i;
        secnd = 0;
        do
        {
          tmp = ff1->iv[i];
          if ( tmp != '-' )
          {
            ff1->iv[i] = '-';
            if ( ImplCheck( fn->parent, ff1, ovr, IC_memory, IC_type, imp_test, offtree ) == 0 )
            {
              ff1->iv[i] = tmp;
              if ( secnd == 0 ) ff->ov[i] = '1';
              if ( secnd == 1 ) ff3->ov[i] = '1';
            }
            else
            {
              ff1->dim++;
              if ( secnd == 1 )
              {
                ff3->ov[i] = '2';
                secnd = 2;
              }
              if ( secnd == 0 )
              {
                ff->ov[i] = '2';
                ff3 = hist->AddTermToBeginning( ff1->iv, ff->ov, ff1->dim );
                hist->fnct->dvar = ovr;
                if ( pff == 0 ) pff = ff3;
                secnd = 1;
              }
            }
          }
          i++;
          i %= fn->inpvars;
        }
        while ( i != i2 );
#if (trck & 2)
        fprintf( tf, "  To:     %s %s\n", ff1->iv, ff->ov );
#endif
        if ( primes_ie->AddToTreeHistory( ff1 ) == 1 ) fn->DeleteTerm( ff1, ff4 );
        pff = ff;
        ff = ff->next;
      }
      else
        ff = hist->DeleteTerm( ff, pff );
    }
    else
    {
      pff = ff;
      ff = ff->next;
    }
    if ( gauge.GaugeStep( j++, 0 ) == 2 ) break;
  }
#if (trck & 2)
  fclose( tf );
#endif
  gauge.CloseGauge();
  if ( ff != 0 ) return 0;
  return fn;
}
//---------------------------------------------------------------------------
TBoolFnct * MultiIE( TBoolFnct * sfn, int ovr, int IC_memory, int IC_type, TermTree * imp_test, TermTree * offtree, TermTree * primes_ie, TGauge gauge )
{
  int i, i2, i4, j;
  char tmp;
  TPfnct * ff, * ff1, * ff4, * pff;
  TBoolFnct * fn;
  int frst, frst2;

  gauge.NewGauge( "IE - Multiple Sequential Search", sfn->terms, 1 );
  fn = sfn->parent->CreateChildFnct();
  ff = sfn->fnct;
  pff = 0;
  j = 0;
  while ( ff != 0 )
  {
    if ( ff->dvar == ovr )
    {
      frst2 = 1;
      i2 = 0; //pocatek
      do
      {
        i4 = -1;
        i = i2;
        while ( i < fn->inpvars && ff->iv[i] == '-' ) i++;
        if ( i < fn->inpvars )
        {
          ff4 = fn->last;
          ff1 = fn->AddTermToEnd( ff->iv, sfn->parent->fnct->ov, ff->dim );
          ff1->prime = 1;
          ff1->origin = 1;
          frst = 1;
          do
          {
            tmp = ff1->iv[i];
            if ( tmp != '-' )
            {
              ff1->iv[i] = '-';
              if ( ImplCheck( fn->parent, ff1, ovr, IC_memory, IC_type, imp_test, offtree ) == 0 )
              {
                ff1->iv[i] = tmp;
              }
              else
              {
                ff1->dim++;
                if ( frst == 1 && i >= i2 ) i4 = i;
                frst = 0;
                frst2 = 0;
              }
            }
            i++;
            i %= fn->inpvars;
          }
          while ( i != i2 );
          if ( ( frst == 1 && frst2 == 0 ) || ( primes_ie->AddToTreeHistory( ff1 ) == 1 ) )
            fn->DeleteTerm( ff1, ff4 );
        }
        i2 = i4 + 1;
      }
      while ( i4 != -1 );
      ff = sfn->DeleteTerm( ff, pff );
    }
    else
    {
      pff = ff;
      ff = ff->next;
    }
    if ( gauge.GaugeStep( j++, 0 ) == 2 ) break;
  }
  gauge.CloseGauge();
  if ( ff != 0 ) return 0;
  return fn;
}
//---------------------------------------------------------------------------
TBoolFnct * ExhIE( TBoolFnct * sfn, int ovr, int IC_memory, int IC_type, TermTree * imp_test, TermTree * offtree, TermTree * primes_ie, TGauge gauge )
{
  int i, i2, i4;
  char tmp;
  TPfnct * ff, * ff1, * ff3 = 0, * ff4, * ff5, * pff;
  TBoolFnct * fn;
  int secnd;

#if (trck&2)
  tf = fopen( "track.txt", "a" );
  fprintf( tf, "ExhaustiveExpansion\n" );
#endif
  gauge.NewGauge( "IE - Exhaustive Expansion", 0, 1 );
  fn = sfn->parent->CreateChildFnct();
  ff = sfn->fnct;
  pff = 0;
  while ( ff != 0 )
  {
    if ( ff->dvar == ovr )
    {
      i2 = 0;
      do
      {
        i4 = -1;
        i = i2;
        while ( ( ff->iv[i] == '-' || ff->ov[i] != '0' ) && i < fn->inpvars ) i++;
        if ( i < fn->inpvars )
        {
          ff5 = fn->last;
          ff1 = fn->AddTermToEnd( ff->iv, sfn->parent->fnct->ov, ff->dim );
          ff1->prime = 1;
          ff1->origin = 1;
          secnd = 0;
          do
          {
            tmp = ff1->iv[i];
            if ( tmp != '-' )
            {
              ff1->iv[i] = '-';
              if ( ImplCheck( fn->parent, ff1, ovr, IC_memory, IC_type, imp_test, offtree ) == 0 )
              {
                ff1->iv[i] = tmp;
                if ( secnd == 0 ) ff->ov[i] = '1';
                if ( secnd == 1 ) ff3->ov[i] = '1';
              }
              else
              {
                ff1->dim++;
                if ( secnd == 1 )
                {
                  ff3->ov[i] = '2';
                  secnd = 2;
                };
                if ( secnd == 0 )
                {
                  if ( i >= i2 ) i4 = i;
                  ff4 = sfn->last;
                  ff->ov[i] = '2';
                  ff3 = sfn->AddTermToEnd( ff1->iv, ff->ov, ff1->dim );
                  ff3->dvar = ovr;
                  secnd = 1;
                }
              }
            }
            i++;
            i %= fn->inpvars;
          }
          while ( i != i2 );
          if ( secnd == 1 ) sfn->DeleteTerm( ff3, ff4 );
          if ( primes_ie->AddToTreeHistory( ff1 ) == 1 ) fn->DeleteTerm( ff1, ff5 );
        }
        i2 = i4 + 1;
      }
      while ( i4 != -1 );
      ff = sfn->DeleteTerm( ff, pff );
    }
    else
    {
      pff = ff;
      ff = ff->next;
    }
    if ( gauge.GaugeStep( 0, 0 ) == 2 ) break;
  }
#if (trck&2)
  fclose( tf );
#endif
  gauge.CloseGauge();
  if ( ff != 0 ) return 0;
  return fn;
}
//---------------------------------------------------------------------------

TBoolFnct * ImplExpand( TBoolFnct * fnct, int ovr, int IE_type, int IC_memory, int IC_type, TermTree * imp_test, TermTree * offtree, TermTree * primes_ie, TGauge gauge )
{
  TBoolFnct * minf1;

  switch ( IE_type )
  {
    case 0:
      minf1 = RandomSeqSearchIE( fnct, ovr, IC_memory, IC_type, imp_test, offtree, primes_ie, gauge );
    break;
    case 1:
      minf1 = DistribMultiIE( fnct, ovr, IC_memory, IC_type, imp_test, offtree, primes_ie, gauge );
    break;
    case 2:
      minf1 = DistribExhIE( fnct, ovr, IC_memory, IC_type, imp_test, offtree, primes_ie, gauge );
    break;
    case 3:
      minf1 = MultiIE( fnct, ovr, IC_memory, IC_type, imp_test, offtree, primes_ie, gauge );
    break;
    case 4:
      minf1 = ExhIE( fnct, ovr, IC_memory, IC_type, imp_test, offtree, primes_ie, gauge );
    break;
  }
  return minf1;
}
//---------------------------------------------------------------------------

int SparseInput( TBoolFnct * fn, int IC_memory, int IC_type, TermTree ** imp_test, TermTree ** offtree, TGauge gauge )
/*
    Removes unnecessary literals from the function.
    The output plane has to be specified.
    Returns the total number of removed literals.
    Greedy. Starts from a random input position.
*/
{
    int i, i1, ov, j;
    TPfnct * ff;
    char tmp;
    int rem;

    rem = 0;
    ff = fn->fnct;
    while ( ff != NULL ) {
        i = random( fn->inpvars );
        i1 = i;
        do {
            if ( ff->iv[i] != '-' ) {
               tmp = ff->iv[i];
               ff->iv[i] = '-';
               for ( ov = 0; ov < fn->outvars; ov++ )
                    if ( ff->ov[ov] == '1' ) {
                       if ( ImplCheck( fn->parent, ff, ov, IC_memory, IC_type, imp_test[ov], offtree[ov] ) == 0 ) {
                            ff->iv[i] = tmp;
                            break;
                       }
                    }
               if ( ov == fn->outvars ) {
                    rem++;
                    for ( j = 0; j < fn->outvars; j++ )
                        if ( ff->ov[j] == '-' && ImplCheck( fn->parent, ff, j, IC_memory, IC_type, imp_test[j], offtree[j] ) == 0 )
                            ff->ov[j] = '0';
                    ff->dim++;
               }
            }
            i++;
            i %= fn->inpvars;
        } while ( i != i1 );
        ff = ff->next;
    }
    return rem;
}

