/*HIS++*/
/************************************************************************/
/*                      CEB.C MODULE                                    */
/************************************************************************/
/*  gilles.bannay@free.fr, Annecy, France.
 *
 * ENVIRONMENT:
 *
 *  MS VisualC++ (Dos32) compiler
 *
 *  GCC compiler (Linux):
 *       gcc -march=i686 -O2 -fomit-frame-pointer -oceb ceb.c
 *
 *
 * DESCRIPTION:
 *
 *  Solves a 'Countdown' or 'Compte Est Bon' problem.
 *  The target must be fitted arithmetically with the
 *  argument list and the operators +, -, *, / (and optionally exponant)
 *  See Help() function below for all options.
 *
 * HISTORY:                
 *
 *  V 1.00  (GBY)   11-Mar-1998 Mod: creation
 *  V 1.01  (GBY)   02-Mai-1998 Add: Linux portage
 *  V 1.10  (GBY)   03-Mai-1998 Fix: display issue when lines<5
 *  V 1.20  (GBY)   05-Mai-1998 Opt: rewrite EssaiOp() for speed
 *                              Add: BorlandC 4.5 portage
 *                              Add: verbose in multi-line format (-v option)
 *  V 1.30  (GBY)   01-Sep-2000 Opt: add some tests in EssaiOp()
 *                              Opt: don't explore 2*2 after 2+2
 *  V 1.31  (GBY)   01-Sep-2000 Add: excluding mode ('-x[P]' option)
 *  V 1.40  (GBY)   02-Sep-2000 Mod: rewrite code
 *  V 1.41  (GBY)   02-Sep-2000 Opt: using SWAP
 *  V 1.42  (GBY)   06-Sep-2000 Add: variable arguments number ('-a[N]' option)
 *  V 1.43  (GBY)   07-Sep-2000 Add: diagnostic mode ('-d' option)
 *  V 1.44  (GBY)   08-Sep-2000 Add: using mode ('-u[N]' option)
 *                              Fix: special case for -u0 et -u1
 *                              Add: optimize mode ('-o' option)
 *  V 1.45  (GBY)   15-Sep-2000 Add: mapping mode for statistics
 *  V 1.50  (GBY)   23-Jan-2001 Mod: 16 bits compiler portage
 *                              Mod: max arguments number = 64.
 *  V 1.51  (GBY)   23-May-2006 Add: operators selection (-s[+*-/] option)
 *  V 1.52  (GBY)   01-Mar-2007 Add: exponant operator selection (-s[+*-/e] option)
 *  V 1.53  (GBY)   16-Mar-2007 Add: verbose in one-line format (-v1 option)
 *                              Add: test overflow.
 *  V 1.54  (GBY)   18-Mar-2007 Add: associativity
 *  V 1.60  (GBY)   19-Mar-2007 Fix: -s option (- without + or / without *)
 *  V 1.61  (GBY)   09-Avr-2011 Add: -g option global
 *  V 1.62  (GBY)   11-Avr-2011 Fix: bugfix end variable init
 *  V 1.63  (GBY)   30-Avr-2011 Add: -w option (with)
 *  V 1.64  (GBY)   01-May-2011 Mod: merge 1.62 & 1.63 version for performance
 *                              Fix: Operation with 0^0=1 is allowed.
 *  V 1.65  (GBY)   14-Sep-2012 Add: -f option (fractionnal)
 *  V 1.66  (GBY)   29-Sep-2012 Opt: power_frac() uses nthroot() in place of exp & log
 *  V 1.67  (GBY)   22-Oct-2012 Opt: Elag tree with 'first' parameter 
 */
/*HIS--*/

#define VERSION     "V 1.67"

/* Comment or uncomment the supported language*/
#define ENGLISH
//#define FRENCH

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#include <time.h>

static int Help(void)
{
#ifdef ENGLISH
  printf("\nCEB a1 a2 a3 a4 a5 a6 [target] [options]               "VERSION
         "\n"
         "\n  Solves  a  'Countdown'  or  a  'Compte Est Bon'  problem."
         "\n  The  target  must be fitted  arithmetically  with the six"
         "\n  arguments 'a1'..'a6' and the operators +, -, *, /, ^."
         "\n"
         "\n  a1..a6    six numerical positive arguments."
         "\n  [target]  target number to fit."
         "\n            When 'target' is not present CEB returns a"
         "\n            statistics for the targets from 0 to 999."
         "\n  [options] Permits to define some default parameters:       "
         "\n  -aN       set the number of arguments to N   (default is 6)"
         "\n  -bP       set the begin limit for statistics (default is 0)"
         "\n  -d        prints debug information                         "
         "\n  -eP       set the end limit for statistics (default is 999)"
         "\n  -f        fractionnal numbers allowed                      "
         "\n  -g        global mode                                      "
         "\n  -o        optimizes the number of arguments used           "
         "\n  -s[+*-/e] set the allowed operators list  (default is +*-/)"
         "\n  -uP       using P arguments or less          (default is N)"
         "\n  -v        displays the solution        (multi-lines format)"
         "\n  -v1       displays the solution           (one-line format)"
         "\n  -wP       with P arguments or more           (default is 1)"
         "\n  -xP       search up to Pth unfit target        (no default)"
         "\nAuthor:                                 gilles.bannay@free.fr\n");
#else
#ifdef FRENCH
  printf("\nCEB a1 a2 a3 a4 a5 a6 [cible] [options]                "VERSION
         "\n"
         "\n  Permet de resoudre  un probleme  du type  'Compte Est Bon'."
         "\n  La cible  doit  etre  atteinte  arithmetiquement  avec  les"
         "\n  six  nombres  'a1'..'a6'  et  les operateurs  +, *, -, /, ^"
         "\n"
         "\n  a1..a6    Six arguments numeriques positifs."
         "\n  [cible]   Nombre positif a atteindre."
         "\n            Si 'cible' n'est pas precisee,  retourne pour les"
         "\n            cibles de 0 a 999  une statistique des solutions."
         "\n  [options] Permet de modifier  certaines valeurs par defaut:"
         "\n  -aN       fixe a N le nombre d'arguments     (6 par defaut)"
         "\n  -bP       fixe a P la borne min pour stat    (0 par defaut)"
         "\n  -d        mode debug                                       "
         "\n  -eP       fixe a P la borne max pour stat  (999 par defaut)"
         "\n  -f        nombres fractionnaires autorises                 "
         "\n  -g        mode global                                      "
         "\n  -o        recherche avec nombre d'arguments minimum        "
         "\n  -s[+*-/e] liste des operateurs autorises  (+*-/ par defaut)"
         "\n  -uP       avec au plus P arguments utilises  (N par defaut)"
         "\n  -v        affiche la solution             (en multi-lignes)"
         "\n  -v1       affiche la solution                (en une ligne)"
         "\n  -wP       avec au moins P arguments utilises (1 par defaut)"
         "\n  -xP       recherche jusqu'au Pieme recalcitrant."
         "\nAuteur:                                 gilles.bannay@free.fr\n");
#endif
#endif
  return 0;
}

#define kFalse      (0==1)
#define kTrue       (1==1)
#define NOT(exp)    (!(exp))
#define NONE        ((unsigned int)(-1))
#define MAX_OP      ((unsigned int)(-2))
#define kMaxLength  64          /* max arguments number*/

#ifdef ENGLISH
#define PARA_INC    "Error: parameter after '-%c' is incorrect.\n"
#define PARA_OPT    "Error: option '%s' is incorrect.\n"
#define PARA_NUL    "Error: null denominator.\n"
#define PARA_TOO    "Error: too much numerical arguments.\n"
#define BEST_MSG    "best = ("
#define VERS_MSG    "Version "VERSION" ('ceb -h' for help)\n"
#define SOLV_MSG1   "Solved (with %u args) !\n"
#define SOLV_MSG2   "Solved !\n"
#define SOLV_MSG3   "unfit ="
#define SOLV_MSG4   "\n%u%s unfit = %u.\n"
#define SOLV_MSG5   "\nSuccess = %.2f%%, %u unfit in %u-%u.\n"
#define TIME_MEA    "Mean time per target = %.4f sec.\n"
#define TIME_TOT    "Time = %.4f sec.\n\n"
#else
#ifdef FRENCH
#define PARA_INC    "Erreur: parametre apres '-%c' incorrect.\n"
#define PARA_OPT    "Erreur: option '%s' incorrecte.\n"
#define PARA_NUL    "Erreur: denominateur nul.\n"
#define PARA_TOO    "Erreur: trop d'arguments numeriques.\n"
#define BEST_MSG    "meilleur = ("
#define VERS_MSG    "Version "VERSION" ('ceb -h' pour l'aide)\n"
#define SOLV_MSG1   "Possible (avec %u args) !\n"
#define SOLV_MSG2   "Possible !\n"
#define SOLV_MSG3   "recalcitrant ="
#define SOLV_MSG4   "\n%u%s recalcitrant = %u.\n"
#define SOLV_MSG5   "\nSucces = %.2f%%, %u recalcitrants dans %u-%u.\n"
#define TIME_MEA    "Temps moyen par cible = %.4f sec.\n"
#define TIME_TOT    "Temps = %.4f sec.\n\n"
#endif
#endif

static unsigned int length;     /* tabl length*/
static unsigned int begin;      /* inf for statistics*/
static unsigned int end;        /* sup for statistique*/
static unsigned int uLevel;     /* using #arg */
static unsigned int wLevel;     /* with #arg */
static unsigned int debugLevel; /* deep for debug '-d'*/
static   signed int diag;       /* diag parameter*/
static unsigned int help;       /* help request*/
static unsigned int optimize;   /* optimize request*/
static unsigned int verbose;    /* display type*/
static unsigned int debug;      /* debug request*/
static unsigned int global;     /* global request*/
static unsigned int special;    /* special indicator*/
static unsigned char *map;      /* mapping for statistics*/
static unsigned int beg_map;    /* min for mapping*/
static unsigned int end_map;    /* max for mapping*/
static unsigned int level;      /* deep*/
static unsigned int ligne;      /* line number*/
static unsigned int ligned;     /* debug lines number*/
static unsigned int cible;      /* target request*/
static unsigned int cible_Den;  /* target denominator request*/
static   signed int alloper;    /* allowed operators list*/
static unsigned int fract;      /* fractionnal request*/

typedef enum flag_s {
  _ARG_=0,
  _RES_,
  _ADD_,
  _SUB_,
  _MUL_,
  _DIV_,
  _EXPE,
  _EXPF,
  _FLAG_NBR
} flag_t;

typedef struct ceb_s {
  unsigned int Op;              /* operator (numerator)*/
  unsigned int Den;             /* denominator*/
#if _DEBUG
  flag_t Flag;                  /* true enum*/
  unsigned char Next;
  unsigned char Nbr;
#else
  unsigned char Flag;           /* one byte enum*/
  unsigned char Reserv;
  unsigned char Next;
  unsigned char Nbr;
#endif
} ceb_t;

static ceb_t tabl[kMaxLength+1]; /* arguments list*/

struct {
  ceb_t left;
  ceb_t right;
  ceb_t val;
} result[kMaxLength];           /* for display only*/



#define ______ (0)
#define A_____ (1)
#define _M____ (2)
#define __S___ (4)
#define A_S___ (5)
#define ___D__ (8)
#define _M_D__ (10)
#define A_SD__ (13)
#define AMSD__ (15)
#define ____E_ (16)
#define A_S_E_ (21)
#define _M_DE_ (26)
#define A_SDE_ (29)
#define _MSDE_ (30)
#define AMSDE_ (31)
#define _____F (32)
#define A_S__F (37)
#define ___D_F (40)
#define A_SD_F (45)
#define AMSD_F (47)
#define ____EF (48)
#define _M__EF (50)
#define __S_EF (52)
#define A_S_EF (53)
#define _M_DEF (58)
#define _MSDEF (62)
#define AMSDEF (63)

/**/
/* Convert flag enum to character
 **/
static char Oper(unsigned char flag)
{
  char oper;

  switch (flag) {
  case _ADD_: 
    oper = '+'; break;
  case _SUB_: 
    oper = '-'; break;
  case _MUL_: 
    oper = '*'; break;
  case _DIV_: 
    oper = '/'; break;
  case _EXPE: 
  case _EXPF: 
    oper = '^'; break;
  default:    
    oper = ' '; break;
  }
  return oper;
}

/**/
/* String construction for fractionnal number
 **/
#define NBR_LEN (11+1+11) /* numerator/denominator*/
static char* PrintFrac(ceb_t *frac)
{
  char *string = (char *)malloc(NBR_LEN+1);

  if (frac->Den==1)
    sprintf(string,"%u",frac->Op);
  else
    sprintf(string,"%u/%u",frac->Op,frac->Den);
  return string;
}

/**/
/* Set 'found target' indicator in map
 **/
#define SETMAP(i)                             \
  if (((i)>=beg_map)&&((i)<=end_map)) {       \
    map[(i)-beg_map] = 1;                     \
  }

/**/
/* Debug tracing mode & Map tracing mode
 **/
static void SpecialCase(ceb_t *pi, unsigned int lev)
{
  unsigned int i;

  if (debug)
  {
    if (cible_Den==1)
      printf("%u:\t%u (%u)", ++ligned, cible, lev);
    else
      printf("%u:\t%u/%u (%u)", ++ligned, cible, cible_Den, lev);
    for (i=0;i<debugLevel-lev;i++) printf("   ");
    for (i=tabl->Next;i!=0;i=tabl[i].Next) {
      if (tabl[i].Den==1)
      {
        printf(" %4u%c", tabl[i].Op, Oper((unsigned char)tabl[i].Flag));
      }
      else
      {
        printf(" %4u/%u%c", tabl[i].Op, tabl[i].Den, Oper((unsigned char)tabl[i].Flag));
      }
    }
    putchar('\n');
  }
  if ((pi->Den==1) && (pi->Nbr>=wLevel) && map) SETMAP(pi->Op); /* Mode mapping: set indicator*/
}

/**/
/* Debug tracing mode & Map tracing mode
 **/
static void SpecialCase_elag(unsigned int op, unsigned int lev)
{
  unsigned int i;

  if (debug)
  {
    printf("%u:\t%u (%u)", ++ligned, cible, lev);
    for (i=0;i<debugLevel-lev;i++) printf("   ");
    for (i=tabl->Next;i!=0;i=tabl[i].Next) {
      printf(" %4u%c", tabl[i].Op, Oper((unsigned char)tabl[i].Flag));
    }
    putchar('\n');
  }
  if (map) SETMAP(op);  /* Mode mapping: set indicator*/
}

/**/
/* String construction for verbose mode
 **/
static char* PrintResult(unsigned int i)
{
  char *string;
  char *str_left  = (result[i].left.Next)  ? PrintResult(result[i].left.Next)  : NULL;
  char *str_right = (result[i].right.Next) ? PrintResult(result[i].right.Next) : NULL;

  if (verbose==1) {
    if (str_left==NULL)  {
      str_left = PrintFrac(&result[i].left);
    }
    if (str_right==NULL) {
      str_right = PrintFrac(&result[i].right);
    }
    string = (char *)malloc(strlen(str_left)+strlen(str_right)+5+3+NBR_LEN+1);
    sprintf(string,"(%s %c %s)",str_left,Oper((unsigned char)result[i].val.Flag),str_right);
    if (i==0) {
      char *str_cible = PrintFrac(&result[0].val);
      strcat(string," = ");
      strcat(string,str_cible);
      free(str_cible);
    }
  }
  else {
    char *str_op1;
    char *str_op2;
    char *str_res;
    string = (char *)malloc(strlen(str_left ? str_left : "")+strlen(str_right ? str_right : "")+3*NBR_LEN+7+1);
    str_op1 = PrintFrac(&result[i].left);
    str_op2 = PrintFrac(&result[i].right);
    str_res = PrintFrac(&result[i].val);
    sprintf(string,"%s%s%s %c %s = %s\n",str_left ? str_left : "",str_right ? str_right : "",
      str_op1,Oper((unsigned char)result[i].val.Flag),str_op2,str_res);
    free(str_op1);
    free(str_op2);
    free(str_res);
  }
  if (str_left) free(str_left);
  if (str_right) free(str_right);

  return string;
}

/**/
/* Normalizes the fraction
 **/
static void norm_frac(ceb_t *frac)
{
  unsigned int oper;
  unsigned int pgcd;
  unsigned int temp;

  if (frac->Op==0) {
    frac->Den = 1;
    return;
  }
  oper = frac->Op;
  pgcd = frac->Den;
  while ((temp=(oper % pgcd))!=0) {
    oper = pgcd;
    pgcd = temp;
  }
  frac->Op /= pgcd;
  frac->Den /= pgcd;
}

/**/
/* Record the stack state in result table
 **/
static unsigned int PrintStackNext(ceb_t *tab, ceb_t *pi, ceb_t *pj, unsigned int lev)
{
  unsigned int i;

  if (special) SpecialCase(tab,lev);
  if (verbose) {      /* display indicator */
    if ((tab->Flag==_EXPE) || (((tab->Flag==_SUB_)||(tab->Flag==_DIV_)) && (pi->Op*pj->Den>pj->Op*pi->Den))) {
      result[ligne].left = *pi;
      result[ligne].right = *pj;
    }
    else {
      result[ligne].left = *pj;
      result[ligne].right = *pi;
    }
    if ((fract) && (tab->Flag==_DIV_))  // correction needed
    {
      ceb_t temp;
      temp.Op = pi->Op*pj->Den;
      temp.Den = pi->Den*pj->Op;
      norm_frac(&temp);
      if ((tab->Op==temp.Op) && (tab->Den==temp.Den))
      {
        result[ligne].left = *pi;
        result[ligne].right = *pj;
      }
      else if ((tab->Op==temp.Den) && (tab->Den==temp.Op))
      {
        result[ligne].left = *pj;
        result[ligne].right = *pi;
      }
      else
      {
        printf("ERROR\n");
      }
    }

    result[ligne].val = *tab;
    result[ligne].left.Next = 0;
    result[ligne].right.Next = 0;
    result[ligne].val.Next = 0;
    for (i=0;i<ligne;i++) {
      if ((result[i].left.Op==result[ligne].val.Op) &&
          (result[i].left.Den==result[ligne].val.Den) &&
          (result[i].left.Next==0)) {
        result[i].left.Next = ligne; 
        break;
      }
      if ((result[i].right.Op==result[ligne].val.Op) &&
          (result[i].right.Den==result[ligne].val.Den) &&
          (result[i].right.Next==0)) {
        result[i].right.Next = ligne; 
        break;
      }
    }
    ligne++;
    if (lev==level-1) {
      char *mess = PrintResult(0);
      printf(mess);
      free(mess);
    }
  }
  *tab = *pj;
  return kTrue;
}

/**/
/* Calculate op^n with op>=0, n>=0
 * return NONE when overflow error
 **/
static unsigned int power(unsigned int op, unsigned int n)
{
  unsigned int temp;

  if (op<=1) return (op==1) || (n==0);
  if (n>=32) return NONE;

  temp = (n & 1) ? op : 1;
  while (n>>=1) {
    if (op > 0xFFFF) return NONE;
    op *= op;
    if (n & 1) {
      if (temp > (MAX_OP/op)) return NONE;
      temp *= op;
    }
  }
  return temp;
}

/**/
/* Calculate [op^(1/n)] with op>1, n>1
 **/
static unsigned int nthroot(unsigned int op, unsigned int n)
{
  unsigned int iter = 0;
  unsigned int temp = op-1;
  
  if (n>=32) return 1;

  if (temp & 0xFFFF0000) temp>>=16, iter+=16;
  if (temp & 0x0000FF00) temp>>=8, iter+=8;
  if (temp & 0x000000F0) temp>>=4, iter+=4;
  if (temp & 0x0000000C) temp>>=2, iter+=2;
  if (temp & 0x00000002) iter++;
  /* Newton's method first value */
  temp = 1UL << (iter/n+1);
  
  /* Newton's method iteration */
  while ((iter=op/power(temp,n-1))<temp) {
    temp = (temp*(n-1)+iter)/n;
  }
  return temp;
}

/**/
/* Calculate fop^fe with fop>=0, fe>=0 for fractionnal number
 * return NONE when overflow error
 **/
static void power_frac(ceb_t *res, ceb_t *fop, ceb_t *fe)
{
  if (fop->Op==0) {
    res->Op = (fe->Op==0);
    res->Den = 1;
    return;
  }
  if (fe->Den==1) {
    res->Op = fop->Op;
    res->Den = fop->Den;
  } else {
    if (fop->Op==1) {
      res->Op = 1;
    } else {
      res->Op = nthroot(fop->Op,fe->Den);
      if (fop->Op!=power(res->Op,fe->Den)) {
        res->Op = NONE;
        return;
      }
    }
    if (fop->Den==1) {
      res->Den = 1;
    } else {
      res->Den = nthroot(fop->Den,fe->Den);
      if (fop->Den!=power(res->Den,fe->Den)) {
        res->Op = NONE;
        return;
      }
    }
  }
  res->Op = power(res->Op,fe->Op);
  if (res->Op==NONE) {
    return;
  }
  res->Den = power(res->Den,fe->Op);
  if (res->Den==NONE) {
    res->Op = NONE;
    return;
  }
  return;
}

/**/
/* Combines pi[0] argument with tab[0] argument with result in tab[0]
 * according to the flag list operators
 * return kTrue when found
 **/
static unsigned int EssaiOp_frac(unsigned int flag, ceb_t *pi, ceb_t *tab, unsigned int lev, unsigned int first)
{
  unsigned int explore_frac(unsigned int lev, unsigned int first);
  unsigned int op0;
  unsigned int op1;
  ceb_t sav = *tab;

  op1 = sav.Op;
  op0 = pi->Op;

  tab->Nbr += pi->Nbr;

  if (flag & A_____)
  {
    if ((op1<=(MAX_OP/2/pi->Den)) && (sav.Den<=(MAX_OP/pi->Den)) && (op0<=(MAX_OP/2/sav.Den))) //not overflow
    {
      tab->Op = op1*pi->Den+op0*sav.Den;
      tab->Den = sav.Den*pi->Den;
      norm_frac(tab);
      tab->Flag = _ADD_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & _M____)
  {
    if (((op0==0) || (op1<=(MAX_OP/op0))) && (sav.Den<=(MAX_OP/pi->Den))) //not overflow
    {
      tab->Op = op1*op0;
      tab->Den = sav.Den*pi->Den;
      norm_frac(tab);
      tab->Flag = _MUL_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ____EF)
  {
    if ((flag & _____F)) { //op1^op0
     if ((op0==op1) && (sav.Den==pi->Den)) flag &=~(____E_); //suppress next tries for op^op
     power_frac(tab,&sav,pi);
     if (tab->Op!=NONE) {
      tab->Flag = _EXPF;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
     }
    }

    if ((flag & ____E_)) { //op0^op1
     power_frac(tab,pi,&sav);
     if (tab->Op!=NONE) {
      tab->Flag = _EXPE;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
     }
    }
  }

  if (flag & __S___)
  {
    if ((op1<=(MAX_OP/pi->Den)) && (sav.Den<=(MAX_OP/pi->Den) && (op0<=(MAX_OP/sav.Den)))) //not overflow
    {
      tab->Op = abs(op1*pi->Den-op0*sav.Den);
      tab->Den = sav.Den*pi->Den;
      norm_frac(tab);
      tab->Flag = _SUB_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ___D__)
  {
    if ((op1<=(MAX_OP/pi->Den)) && (op0<=(MAX_OP/sav.Den))) //not overflow
    {
      if (op0!=0) {
        tab->Op = op1*pi->Den;
        tab->Den = op0*sav.Den;
        norm_frac(tab);
        tab->Flag = _DIV_;
        if (special) SpecialCase(tab,lev);
        if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      }
      if (op1!=0) {
        tab->Op = op0*sav.Den;
        tab->Den = op1*pi->Den;
        norm_frac(tab);
        tab->Flag = _DIV_;
        if (special) SpecialCase(tab,lev);
        if (tab->Op==cible) if (tab->Den==cible_Den) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_frac(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      }
    }
  }
  *tab = sav;

  return kFalse;
}

/**/
/* Combines pi[0] argument with tab[0] argument with result in tab[0]
 * according to the flag list operators
 * return kTrue when found
 **/
static unsigned int EssaiOp_frac_elag(unsigned int flag, ceb_t *pi, ceb_t *tab, unsigned int lev, unsigned int first)
{
  unsigned int explore_frac_elag(unsigned int lev, unsigned int first);
  unsigned int op0;
  unsigned int op1;
  ceb_t sav = *tab;

  op1 = sav.Op;
  op0 = pi->Op;

  if (flag & A_____)
  {
    tab->Op = op1*pi->Den+op0*sav.Den;
    if ((op1<=(MAX_OP/2/pi->Den)) && (sav.Den<=(MAX_OP/pi->Den)) && (op0<=(MAX_OP/2/sav.Den))) //not overflow
    {
      tab->Den = sav.Den*pi->Den;
      norm_frac(tab);
      tab->Flag = _ADD_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & _M____)
  {
    if (((op0==0) || (op1<=(MAX_OP/op0))) && (sav.Den<=(MAX_OP/pi->Den))) //not overflow
    {
      tab->Op = op1*op0;
      tab->Den = sav.Den*pi->Den;
      norm_frac(tab);
      tab->Flag = _MUL_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ____EF)
  {
    if ((flag & _____F)) { //op1^op0
     power_frac(tab,&sav,pi);
     if (tab->Op!=NONE) {
      tab->Flag = _EXPF;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      //suppress next tries for op^op 2^4 4^2
      if (((op0==op1) && (sav.Den==pi->Den)) || ((tab->Op==16) && (tab->Den==1))) flag &=~(____E_);
     }
    }

    if ((flag & ____E_)) { //op0^op1
     power_frac(tab,pi,&sav);
     if (tab->Op!=NONE) {
      tab->Flag = _EXPE;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
     }
    }
  }

  if (flag & __S___)
  {
    if ((op1<=(MAX_OP/pi->Den)) && (sav.Den<=(MAX_OP/pi->Den) && (op0<=(MAX_OP/sav.Den)))) //not overflow
    {
      tab->Op = abs(op1*pi->Den-op0*sav.Den);
      tab->Den = sav.Den*pi->Den;
      norm_frac(tab);
      if (((tab->Op!=sav.Op) || (tab->Den!=sav.Den)) && ((tab->Op!=pi->Op) || (tab->Den!=pi->Den))) { /* suppress case 2a-a=a*/
        tab->Flag = _SUB_;
        if (special) SpecialCase(tab,lev);
        if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      }
    }
  }

  if (flag & ___D__)
  {
    if ((op1<=(MAX_OP/pi->Den)) && (op0<=(MAX_OP/sav.Den))) //not overflow
    {
      if ((op0>1) || (pi->Den!=1)) {
        tab->Op = op1*pi->Den;
        tab->Den = op0*sav.Den;
        norm_frac(tab);
        tab->Flag = _DIV_;
        if (special) SpecialCase(tab,lev);
        if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      }
      if ((op1>1) || (sav.Den!=1)) {
        tab->Op = op0*sav.Den;
        tab->Den = op1*pi->Den;
        norm_frac(tab);
        tab->Flag = _DIV_;
        if (special) SpecialCase(tab,lev);
        if (tab->Op==cible) if (tab->Den==cible_Den) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_frac_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      }
    }
  }
  *tab = sav;

  return kFalse;
}

/**/
/* Combines pi[0] argument with tab[0] argument with result in tab[0]
 * according to the flag list operators
 * return kTrue when found
 **/
static unsigned int EssaiOp(unsigned int flag, ceb_t *pi, ceb_t *tab, unsigned int lev, unsigned int first)
{
  unsigned int explore(unsigned int lev, unsigned int first);
  unsigned int op0;
  unsigned int op1;
  unsigned int tmp;
  ceb_t sav = *tab;

  op1 = sav.Op;
  op0 = pi->Op;

  tab->Nbr += pi->Nbr;

  if (flag & A_____)
  {
    if ((op1 < (~op0))) //not overflow
    {
      tab->Op = op1+op0;
      tab->Flag = _ADD_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & _M____)
  {
    if ((op0==0) || (op1 <= (MAX_OP/op0))) //not overflow
    {
      tab->Op = op1*op0;
      tab->Flag = _MUL_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ____EF)
  {
    if ((flag & _____F)) { //op1^op0
     if (op0==op1) flag &=~(____E_); //suppress next tries for op^op
     tmp = power(op1,op0);
     if (tmp!=NONE) {
      tab->Op = tmp;
      tab->Flag = _EXPF;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
     }
    }

    if ((flag & ____E_)) { //op0^op1
     tmp = power(op0,op1);
     if (tmp!=NONE) {
      tab->Op = tmp;
      tab->Flag = _EXPE;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
     }
    }
  }

  if (op0 > op1) {
    op1 = op0;
    op0 = sav.Op;
  }

  if (flag & __S___)
  {
    {
      tab->Op = op1-op0;
      tab->Flag = _SUB_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ___D__)
  {
    if ((op0) && ((op1 % op0)==0)) /* suppress case divide error*/
    {
      tab->Op = op1/op0;
      tab->Flag = _DIV_;
      if (special) SpecialCase(tab,lev);
      if (tab->Op==cible) if (tab->Nbr>=wLevel) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }
  *tab = sav;

  return kFalse;
}

/**/
/* Combines pi[0] argument with tab[0] argument with result in tab[0] with elag
 * according to the flag list operators
 * return kTrue when found
 **/
static unsigned int EssaiOp_elag(unsigned flag, ceb_t *pi, ceb_t *tab, unsigned int lev, unsigned int first)
{
  unsigned int explore_elag(unsigned int lev, unsigned int first);
  unsigned int op0;
  unsigned int op1;
  unsigned int tmp;
  ceb_t sav = *tab;

  op1 = sav.Op;
  op0 = pi->Op;

  if (flag & A_____)
  {
    if ((op1 < (~op0)))
    {
      tab->Op = op1+op0;
      tab->Flag = _ADD_;
      if (special) SpecialCase_elag(tab->Op,lev);
      if (tab->Op==cible) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & _M____)
  {
    if ((op0!=0) && (op1 <= (MAX_OP/op0)))
    {
      tab->Op = op1*op0;                                                   /* a*1=a et 2*2=4*/
      tab->Flag = _MUL_;
      if (special) SpecialCase_elag(tab->Op,lev);
      if (tab->Op==cible) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (explore_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ____EF)
  {
    if ((flag & _____F)) { //op1^op0
      tmp = power(op1,op0);
      if (tmp!=NONE) {
        tab->Op = tmp;
        tab->Flag = _EXPF;
        if (special) SpecialCase_elag(tab->Op,lev);
        if (tab->Op==cible) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
        //suppress next tries for op^op 2^4 4^2
        if ((op0==op1) || (tab->Op==16)) flag &=~(____E_);
      }
    }

    if ((flag & ____E_)) { //op0^op1
      tmp = power(op0,op1);
      if (tmp!=NONE) {
        tab->Op = tmp;
        tab->Flag = _EXPE;
        if (special) SpecialCase_elag(tab->Op,lev);
        if (tab->Op==cible) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
      }
    }
  }

  if (op0 > op1) {
    op1 = op0;
    op0 = sav.Op;
  }

  if (flag & __S___)
  {
    if (op1-op0!=op0)
    {               /* suppress case 2a-a=a*/
      tab->Op = op1-op0;
      tab->Flag = _SUB_;
      if (special) SpecialCase_elag(tab->Op,lev);
      if (tab->Op==cible) return PrintStackNext(tab,pi,&sav,lev);
      if (lev>=2) if (tab->Op!=0) if (explore_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  if (flag & ___D__)
  {
    if ( (op0>1) &&                     /* suppress case a/1=a*/
      ((op1 % op0)==0) &&               /* suppress case divide error*/
      (op1/op0!=op0)                    /* suppress case a^2/a=a*/
      ) {
        tab->Op = op1/op0;
        tab->Flag = _DIV_;
        if (special) SpecialCase_elag(tab->Op,lev);
        if (tab->Op==cible) return PrintStackNext(tab,pi,&sav,lev);
        if (lev>=2) if (explore_elag(lev,first)) return PrintStackNext(tab,pi,&sav,lev);
    }
  }

  *tab = sav;

  return kFalse;
}

static unsigned int hMatrix[] = {
  /*     pj  ARG   ______  ADD    SUB    MUL    DIV    EXPE   EXPF  */
  /*pi */
  /*ARG*/   AMSDEF,______,_MSDEF,_M_DEF,A_SD_F,A_S_EF,AMSDE_,AMSDEF,
  /*RES*/   ______,______,______,______,______,______,______,______,
  /*ADD*/   AMSDEF,______,_MSDEF,_M_DEF,A_SD_F,A_S_EF,AMSDE_,AMSDE_,
  /*SUB*/   _M_DEF,______,_M_DEF,_M_DEF,___D_F,____EF,_M_DE_,_M_DEF,
  /*MUL*/   AMSDE_,______,_MSDE_,_M_DE_,A_SD__,A_S_E_,AMSD__,AMSD__,
  /*DIV*/   A_S_EF,______,__S_EF,____EF,A_S__F,A_S_EF,A_SDE_,A_SDE_,
  /*EXPE*/  AMSDEF,______,_MSDEF,_M_DEF,A_SD_F,A_S_EF,AMSD__,AMSD__,
  /*EXPF*/  AMSDEF,______,_MSDEF,_M_DEF,A_SD_F,A_S_EF,AMSD__,AMSD__,
};

/**/
/* Select two arguments in the list and explore it
 **/
unsigned int explore_frac(unsigned int lev, unsigned int first)
{
  unsigned int i;
  unsigned int j;
  unsigned int tmp_i;
  unsigned int tmp_j;
  unsigned int flag;

  for (i=0;tabl[tabl[i].Next].Next;i=tabl[i].Next) {
    tmp_i = tabl[i].Next;
    tabl[i].Next = tabl[tmp_i].Next;
    for (j=i;tabl[j].Next;j=tabl[j].Next) {
      tmp_j = tabl[j].Next;
      if (tmp_j<first) continue;
      flag = hMatrix[tabl[tmp_i].Flag*_FLAG_NBR+tabl[tmp_j].Flag];
      if (flag) {
        if (EssaiOp_frac(flag,&tabl[tmp_i],&tabl[tmp_j],lev-1,tmp_j)) {
          tabl[tmp_i].Next = tabl[i].Next;
          tabl[i].Next = tmp_i;
          return kTrue;
        }
      }
    }
    tabl[tmp_i].Next = tabl[i].Next;
    tabl[i].Next = tmp_i;
  }

  return kFalse;
}

/**/
/* Select two arguments in the list and explore it (with elag)
 **/
unsigned int explore_frac_elag(unsigned int lev, unsigned int first)
{
  unsigned int i;
  unsigned int j;
  unsigned int k;
  unsigned int tmp_i;
  unsigned int tmp_j;
  unsigned int flag;

  for (i=0;tabl[tabl[i].Next].Next;i=tabl[i].Next) {
    tmp_i = tabl[i].Next;
    for (k=tabl->Next;k!=tmp_i;k=tabl[k].Next) 
      if ((tabl[k].Op==tabl[tmp_i].Op) && (tabl[k].Den==tabl[tmp_i].Den)) goto next_i;
    tabl[i].Next = tabl[tmp_i].Next;
    for (j=i;tabl[j].Next;j=tabl[j].Next) {
      tmp_j = tabl[j].Next;
      if (tmp_j<first) continue;
      flag = hMatrix[tabl[tmp_i].Flag*_FLAG_NBR+tabl[tmp_j].Flag];
      if (((tabl[tmp_i].Op<=1) && (tabl[tmp_i].Den==1)) || ((tabl[tmp_j].Op<=1) && (tabl[tmp_j].Den==1))) {
        if (((tabl[tmp_i].Op==1) && (tabl[tmp_i].Den==1)) || ((tabl[tmp_j].Op==1) && (tabl[tmp_j].Den==1)))
          flag &=~(_M__EF); //&=~(_M_DEF);
        else
          flag &=~(AMSD__);
      }
      else if ((tabl[tmp_i].Op==2) && (tabl[tmp_i].Den==1) && (tabl[tmp_j].Op==2) && (tabl[tmp_j].Den==1)) {
        if (flag & A_____) flag &=~(_M__EF);
        else if (flag & _M____) flag &=~(____EF);
      }
      if (flag) {
        for (k=tabl->Next;k!=tmp_j;k=tabl[k].Next) 
          if ((tabl[k].Op==tabl[tmp_j].Op) && (tabl[k].Den==tabl[tmp_j].Den)) goto next_j;
        if (EssaiOp_frac_elag(flag,&tabl[tmp_i],&tabl[tmp_j],lev-1,tmp_j)) {
          tabl[tmp_i].Next = tabl[i].Next;
          tabl[i].Next = tmp_i;
          return kTrue;
        }
      }
next_j:;
    }
    tabl[tmp_i].Next = tabl[i].Next;
    tabl[i].Next = tmp_i;
next_i:;
  }

  return kFalse;
}

/**/
/* Select two arguments in the list and explore it
 **/
unsigned int explore(unsigned int lev, unsigned int first)
{
  unsigned int i;
  unsigned int j;
  unsigned int tmp_i;
  unsigned int tmp_j;
  unsigned int flag;

  for (i=0;tabl[tabl[i].Next].Next;i=tabl[i].Next) {
    tmp_i = tabl[i].Next;
    tabl[i].Next = tabl[tmp_i].Next;
    for (j=i;tabl[j].Next;j=tabl[j].Next) {
      tmp_j = tabl[j].Next;
      if (tmp_j<first) continue;
      flag = hMatrix[tabl[tmp_i].Flag*_FLAG_NBR+tabl[tmp_j].Flag];
      if (flag) {
        if (EssaiOp(flag,&tabl[tmp_i],&tabl[tmp_j],lev-1,tmp_j)) {
          tabl[tmp_i].Next = tabl[i].Next;
          tabl[i].Next = tmp_i;
          return kTrue;
        }
      }
    }
    tabl[tmp_i].Next = tabl[i].Next;
    tabl[i].Next = tmp_i;
  }

  return kFalse;
}

/**/
/* Select two arguments in the list and explore it (with elag)
 **/
unsigned int explore_elag(unsigned int lev, unsigned int first)
{
  unsigned int i;
  unsigned int j;
  unsigned int k;
  unsigned int tmp_i;
  unsigned int tmp_j;
  unsigned int flag;

  for (i=0;tabl[tabl[i].Next].Next;i=tabl[i].Next) {
    tmp_i = tabl[i].Next;
    for (k=tabl->Next;k!=tmp_i;k=tabl[k].Next) 
      if ((tabl[k].Op==tabl[tmp_i].Op)) goto next_i;
    tabl[i].Next = tabl[tmp_i].Next;
    for (j=i;tabl[j].Next;j=tabl[j].Next) {
      tmp_j = tabl[j].Next;
      if (tmp_j<first) continue;
      flag = hMatrix[tabl[tmp_i].Flag*_FLAG_NBR+tabl[tmp_j].Flag];
      if ((tabl[tmp_i].Op<=1) || (tabl[tmp_j].Op<=1)) {
        if ((tabl[tmp_i].Op==1) || (tabl[tmp_j].Op==1))
          flag &=~(_M_DEF);
        else
          flag &=~(AMSD__);
      }
      else if ((tabl[tmp_i].Op==2) && (tabl[tmp_j].Op==2)) {
        if (flag & A_____) flag &=~(_M__EF);
        else if (flag & _M____) flag &=~(____EF);
      }
      if (flag) {
        for (k=tabl->Next;k!=tmp_j;k=tabl[k].Next) 
          if ((tabl[k].Op==tabl[tmp_j].Op)) goto next_j;
        if (EssaiOp_elag(flag,&tabl[tmp_i],&tabl[tmp_j],lev-1, tmp_j)) {
          tabl[tmp_i].Next = tabl[i].Next;
          tabl[i].Next = tmp_i;
          return kTrue;
        }
      }
next_j:;
    }
    tabl[tmp_i].Next = tabl[i].Next;
    tabl[i].Next = tmp_i;
next_i:;
  }

  return kFalse;
}

/**/
/* trivial cases
 * return the #arguments used
 **/
static unsigned int Explore(void)
{
  unsigned int i;

  if (uLevel>0) {         /* case '-u1'*/
    for (i=tabl->Next;i!=0;i=tabl[i].Next) {
      if (map && (wLevel==1)) SETMAP(tabl[i].Op);
      if ((wLevel==1) && (cible==tabl[i].Op) && (cible_Den==tabl[i].Den)) {
        ligne = 0;
        ligned = 0;
        debugLevel = level = uLevel;
        if (special) SpecialCase(&tabl[i],level);
        if (verbose) {
          if (cible_Den==1)
          {
            if (verbose==1)
              printf("(%u) = %u", cible, cible);
            else
              printf("%u = %u !\n", cible, cible);
          } else {
            if (verbose==1)
              printf("(%u/%u) = %u/%u", cible, cible_Den, cible, cible_Den);
            else
              printf("%u/%u = %u/%u !\n", cible, cible_Den, cible, cible_Den);
          }
        }
        return 1;
      }
    }
    if (uLevel>1) {       /* general case*/
      for (i=optimize?(wLevel>2?wLevel:2):uLevel;i<=uLevel;i++) {
        ligne = 0;
        ligned = 0;
        debugLevel = level = i;
        if (special) SpecialCase(&tabl[tabl->Next],level);
        if ((tabl[tabl->Next].Next!=0)) {
          if (fract)
          {
            if (wLevel!=1) {
              if (explore_frac(level,0)) return i;
            } else {
              if (explore_frac_elag(level,0)) return i;
            }
          } else {
            if (wLevel!=1) {
              if (explore(level,0)) return i;
            } else {
              if (explore_elag(level,0)) return i;
            }
          }
        }
        if (special) SpecialCase(&tabl[tabl->Next],level);
      }
    }
  }
  return kFalse;          /* case '-u0'*/
}

/**/
/* convert '-s[+*-/e]' option to allowed operators list
 * return NONE when error
 **/
static int signtoi(const char *p)
{
  int result = 0;
  while (*p) {
    switch (*p) {
    case '+':
      result |= A_____;
      break;
    case '*':
      result |= _M____;
      break;
    case '-':
      result |= __S___;
      break;
    case '/':
      result |= ___D__;
      break;
    case 'E':
    case 'e':
      result |= ____EF;
      break;
    default:
      return NONE;
    }
    p++;
  }
  return result;
}

/**/
/* Parses the command line
 **/
static unsigned int parse(int argc, char *argv[])
{
  unsigned int narg;
  char car;
  int  val;
  int  i;

  /*1st pass*/
  for (i=1;i<argc;i++) {
    car = argv[i][0];
    if ((car=='-') || (car=='/')) {
      /* option*/
      car = argv[i][1];
      /* option parameter*/
      if ((car!='\0') && (argv[i][2]!='\0')) {
        if ((argv[i][2]<'0') || (argv[i][2]>'9')) { 
          if (car!='s') {
            /* not a number*/
            printf(PARA_INC,car);
            return 1;
          } else val = signtoi(&argv[i][2]);
        } else val = atoi(&argv[i][2]);
      } else val = NONE;

      switch (car | 0x20) {             /* ignore MAJ/min*/

      case 'a':                         /* -a for #arguments*/
        if (val!=NONE) length = val;    /* #arguments*/
        if (((int)length<=0) || ((int)length>=kMaxLength)) {
          printf(PARA_INC,car);
          return 1;
        }
        uLevel = length;                /* default init*/
        break;

      case 'b':                         /* -b for begin statistics*/
        if (val!=NONE) { 
          begin = val;                  /* set begin statistics*/
          end = (begin/1000)*1000+999;  /* default end statistics*/
        }
        if ((int)begin<0) {
          printf(PARA_INC,car);
          return 1;
        }
        break;

      case 'd':
        debug   = kTrue;                /* -d for debug mode*/
        break;

      case 'e':                         /* -e for end statistics*/
        if (val!=NONE) end = val;
        if ((int)begin>(int)end) {
          printf(PARA_INC,car);
          return 1;
        }
        break;

      case 'f':
        fract = kTrue;                  /* -f for fractionnal request */
        break;
        
      case 'g':
        global = kTrue;                 /* -g for global mode*/
        break;

      case 'h':
        help = kTrue;                   /* -h for help*/
        break;

      case 'o':
        optimize = kTrue;               /* -o for optimize*/
        break;

      case 's':
        if (val==NONE) {
          printf(PARA_INC,car);
          return 1;
        }
        alloper = val;
        break;

      case 'u':                         /* -u for using #argument or less*/
        if (val!=NONE) uLevel = val;
        if (((int)uLevel<=0) || ((int)uLevel>(int)length)) {
          printf(PARA_INC,car);
          return 1;
        }
        break;

      case 'v':
        verbose = val;                  /* verbose mode -v for multi-line, -v1 for one-line*/
        break;

      case 'w':                         /* -w for with #argument or more*/
        if (val!=NONE) wLevel = val;
        if (((int)wLevel<=0) || ((int)wLevel>(int)length)) {
          printf(PARA_INC,car);
          return 1;
        }
        break;

      case 'x':                         /* -x for exclude*/
        if (val!=NONE) {
          diag = val;
        }
        if ((int)diag<=0) {
          printf(PARA_INC,car);
          return 1;
        }
        break;

      default:
        printf(PARA_OPT, argv[i]);
        return 1;
      }
    } else if ((car>='0') && (car<='9')) { /* number in argument list*/
      /*moved in 2nd pass*/
    } else {
      printf(PARA_OPT, argv[i]);
      return 1;
    }
  }

  /*2nd pass*/
  narg = 0;
  tabl[narg].Op = 0;
  tabl[narg].Flag = 0;
  tabl[narg].Next = 1;
  for (i=1;i<argc;i++) {
    car = argv[i][0];
    if ((car>='0') && (car<='9')) {     /* number in argument list*/
      char *p;
      if (narg<length) {
        tabl[narg+1].Op = atoi(argv[i]);
        tabl[narg+1].Flag = _ARG_;
        tabl[narg+1].Next = narg+2;
        tabl[narg+1].Nbr = 1;
        p = strchr(argv[i],'/');
        if (p) {
          tabl[narg+1].Den = atoi(p+1);
          if (tabl[narg+1].Den==0) {
            printf(PARA_NUL);
            return 1;
          }
          norm_frac(&tabl[narg+1]);
          if (tabl[narg+1].Den!=1) fract = kTrue;
        } else {
          tabl[narg+1].Den = 1;
        }        
        if ((tabl[narg+1].Op!=0) || (wLevel!=1) || (alloper&____EF)) narg++;
        else length--;
      } else if (narg==length) {
        cible = atoi(argv[i]);          /* target request */
        p = strchr(argv[i],'/');
        if (p) {
          ceb_t temp;
          cible_Den = atoi(p+1);
          if (cible_Den==0) {
            printf(PARA_NUL);
            return 1;
          }
          temp.Op = cible;
          temp.Den = cible_Den;
          norm_frac(&temp);
          cible = temp.Op;
          cible_Den = temp.Den;
          if (cible_Den!=1) fract = kTrue;
        } else {
          cible_Den = 1;
        }        
      } else {
        printf(PARA_TOO);
        return 1;
      }
    }
  }
  tabl[narg].Next = 0;                  /* end list*/
  return 0;
}

#ifdef _TEST
#define main main_tst
#endif

void ExploreGlobal(void)
{
  ceb_t tablmax[kMaxLength]; /* initial arguments list*/
  ceb_t tablbest[kMaxLength]; /* best arguments list*/
  unsigned int i,j,max,maxmax;

  map=(unsigned char *)calloc(end_map-beg_map+1,sizeof(*map));
  if (map==0) return;

  special = kTrue;                /* special mode*/
  for (i=0;i<=length;i++) tablmax[i] = tabl[i]; /* save */
  for (i=0;i<=length;i++) tablmax[length+1-i].Op = tabl[i].Op; /* reverse order */
  for (i=1;i<=length;i++) tabl[i].Op = 1; /* first try */
  for (i=0;i<=length;i++) tablbest[i] = tabl[i]; /* save the best */
  maxmax = 0;
  while (kTrue) {
    Explore(); /* launch exploration*/
    for (i=0;i<=end_map-beg_map;i++) if NOT(map[i]) break;
    max = i;
    for (i=0;i<=end_map-beg_map;i++) map[i] = 0; /* reset map */
    if ((max>=maxmax) && (max)) {
      if (max>maxmax) {
        for (i=0;i<=length;i++) tablbest[i] = tabl[i]; /* save the best */
      }
      maxmax = max;
      printf("(");
      for (i=length;i>1;i--) printf("%d,",tabl[i].Op);
      printf("%d) : %d\n",tabl[1].Op,beg_map+maxmax-1);
    }
    for (i=1;;i++) {
      tabl[i].Op++;
      for (j=1;j<i;j++) 
        tabl[j].Op = tabl[i].Op;
      if (tabl[i].Op>tablmax[i].Op) {
        if (length==i) goto _end_;
        continue;
      }
      break;
    }
  }
_end_:
  free(map);
  map = 0;
  for (i=0;i<=length;i++) tabl[i] = tablbest[i]; /* restore the best */
  printf(BEST_MSG);
  for (i=length;i>1;i--) printf("%d,",tabl[i].Op);
  printf("%d) : %d\n",tabl[1].Op,beg_map+maxmax-1);
  end = end_map = maxmax+beg_map-1;
  if (end==-1) end = end_map = 0;
}

/**/
/* main()
 **/
int main(int argc, char *argv[])
{
  clock_t start;      /* for statistics*/
  double  temps;      /* for statistics*/
  unsigned int narg,i;
  unsigned int pos = 0;     /* found targets*/
  unsigned int imp = 0;     /* unfit targets*/

  /* Fixe les parameters par defaut*/
  length  = 6;
  begin   = 0;
  end     = 999;
  uLevel  = 6;
  wLevel  = 1;
  diag    = -1;
  help    = kFalse;
  optimize= kFalse;
  verbose = 0;
  debug   = kFalse;
  global  = kFalse;
  cible   = NONE;
  map     = 0;
  alloper = AMSD__;                     /* default operator list is '+*-/' (not e) */
  fract   = kFalse;
  cible_Den = 1;
  
  if (argc==1) {
    printf(VERS_MSG);
    return 0;
  }

  /* parse the command line*/
  if (parse(argc, argv))
    return 1;                           /* error in command line*/

  /* help request*/
  if (help) {
    return Help();
  }

  /* hMatrix correction*/
  if ((alloper & A_S___)==__S___) {
    for (i=0;i<_FLAG_NBR;i++) {
      hMatrix[i*_FLAG_NBR+_SUB_] |= AMSD_F;
      hMatrix[_SUB_*_FLAG_NBR+i] |= AMSD_F;
    }
  }
  if ((alloper & _M_D__)==___D__) {
    for (i=0;i<_FLAG_NBR;i++) {
      hMatrix[i*_FLAG_NBR+_DIV_] |= AMSD_F;
      hMatrix[_DIV_*_FLAG_NBR+i] |= AMSD_F;
    }
  }
  if ((alloper & ____EF)!=______) { //avoid overflow
    hMatrix[_DIV_*_FLAG_NBR+_ARG_] |= _M____; 
    hMatrix[_DIV_*_FLAG_NBR+_ADD_] |= _M____;
    hMatrix[_DIV_*_FLAG_NBR+_SUB_] |= _M____;
    hMatrix[_ARG_*_FLAG_NBR+_DIV_] |= _M____; 
    hMatrix[_ADD_*_FLAG_NBR+_DIV_] |= _M____;
    hMatrix[_SUB_*_FLAG_NBR+_DIV_] |= _M____;
  }
  for (i=0;i<(sizeof(hMatrix)/sizeof(hMatrix[0]));i++)
    hMatrix[i] &= alloper;             /* -s for sign +*-/e */

  start = clock();

  beg_map = begin;
  end_map = end;
  if (global) {
    ExploreGlobal();
  }
  if (cible!=NONE) {                   /* problem with target request*/
    begin = cible;
    end   = cible;
    diag  = 0;
  } 

  if ((diag!=-1) && (diag!=0)) end = NONE; /* no end for '-x'*/

  if ((diag==-1) && NOT(verbose)) {
    if ((map=(unsigned char *)calloc(end_map-beg_map+1,sizeof(*map)))!=0) {
      cible = NONE;                     /* target can't be fit*/
      begin = cible;
      end   = cible;
    }
  }

  special = debug || map;                 /* special mode*/

  for (cible=begin;;cible++) {
    if ((narg=Explore())!=0) {            /* launch exploration*/
      if (verbose==0) {
        if NOT(diag) {
          if (optimize) printf(SOLV_MSG1,narg);
          else printf(SOLV_MSG2);
        }
      }
      pos++;
    }
    else if NOT(map) {
      if (diag && NOT(verbose)) 
        if (cible_Den==1)
          printf(" %u",cible);              /* display unfit targets list*/
        else
          printf(" %u/%u",cible,cible_Den); /* display unfit targets list*/
      else {
        if (cible_Den==1)
          printf("%u impossible !",cible);
        else
          printf("%u/%u impossible !",cible,cible_Den);
        if (verbose!=1) printf("\n");
      }
      if (++imp==(unsigned int)diag) break;
    }
    if (NOT(diag) || verbose) printf("\n");

    if (cible==end)
      break;
  }

  if (map) {
    if (diag && NOT(debug)) printf(SOLV_MSG3);
    pos = 0;
    imp = 0;
    for (i=0;i<=end_map-beg_map;i++) {
      if (map[i]) pos++; 
      else { 
        printf(" %u",beg_map+i);
        imp++; 
      }
    }
    free(map);
  }

  temps = (double)(clock()-start)/(double)CLOCKS_PER_SEC;

  if (diag>0) printf(SOLV_MSG4,imp,imp==1?"st":"th",cible);
  else if (diag) printf(SOLV_MSG5,
    (double)(100.0*pos)/(double)(imp+pos), imp, beg_map, end_map);
  if (diag) printf(TIME_MEA, temps/(double)(imp+pos));
  printf(TIME_TOT, temps);
  return 0; //(diag) ? imp : pos;
}