/**
  @file

  @ingroup nanotrav

  @brief Main program for the nanotrav program.

  @author Fabio Somenzi

  @copyright@parblock
  Copyright (c) 1995-2015, Regents of the University of Colorado

  All rights reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:

  Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

  Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.

  Neither the name of the University of Colorado nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE.
  @endparblock

*/

#include "cuddInt.h"
#include "ntr.h"

/*---------------------------------------------------------------------------*/
/* Constant declarations                                                     */
/*---------------------------------------------------------------------------*/

#define NTR_VERSION "Nanotrav Version #0.13, Release date 2015/7/15"

#define BUFLENGTH 8192

/*---------------------------------------------------------------------------*/
/* Stucture declarations                                                     */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Type declarations                                                         */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Variable declarations                                                     */
/*---------------------------------------------------------------------------*/

static  char    buffer[BUFLENGTH];
#ifdef DD_DEBUG
extern  st_table *checkMinterms (BnetNetwork *net, DdManager *dd, st_table *previous);
#endif

/*---------------------------------------------------------------------------*/
/* Macro declarations                                                        */
/*---------------------------------------------------------------------------*/

/** \cond */

/*---------------------------------------------------------------------------*/
/* Static function prototypes                                                */
/*---------------------------------------------------------------------------*/

static NtrOptions * mainInit ();
static void ntrReadOptions (int argc, char **argv, NtrOptions *option);
static void ntrReadOptionsFile (char *name, char ***argv, int *argc);
static char* readLine (FILE *fp);
static FILE * open_file (char *filename, const char *mode);
static int reorder (BnetNetwork *net, DdManager *dd, NtrOptions *option);
static void freeOption (NtrOptions *option);
static DdManager * startCudd (NtrOptions *option, int nvars);
static int ntrReadTree (DdManager *dd, char *treefile, int nvars);

/** \endcond */


/*---------------------------------------------------------------------------*/
/* Definition of exported functions                                          */
/*---------------------------------------------------------------------------*/

/**
  @brief Main program for ntr.

  @details Performs initialization. Reads command line options and
  network(s). Builds BDDs with reordering, and optionally does
  reachability analysis. Prints stats.

  @sideeffect None

*/
int
main(
  int  argc,
  char ** argv)
{
    NtrOptions	*option;	/* options */
    FILE	*fp1;		/* first network file pointer */
    BnetNetwork	*net1 = NULL;	/* first network */
    FILE	*fp2;		/* second network file pointer */
    BnetNetwork	*net2 = NULL;	/* second network */
    DdManager	*dd;		/* pointer to DD manager */
    int		exitval;	/* return value of Cudd_CheckZeroRef */
    int		ok;		/* overall return value from main() */
    int		result;		/* stores the return value of functions */
    BnetNode	*node;		/* auxiliary pointer to network node */
    int		i;		/* loop index */
    int		j;		/* loop index */
    double	*signatures;	/* array of signatures */
    int		pr;		/* verbosity level */
    int		reencoded;	/* linear transformations attempted */

    /* Initialize. */
#if defined(_WIN32) && defined(_TWO_DIGIT_EXPONENT)
    (void) _set_output_format(_TWO_DIGIT_EXPONENT);
#endif
    option = mainInit();
    ntrReadOptions(argc,argv,option);
    pr = option->verb;
    reencoded = option->reordering == CUDD_REORDER_LINEAR ||
		option->reordering == CUDD_REORDER_LINEAR_CONVERGE ||
		option->autoMethod == CUDD_REORDER_LINEAR ||
		option->autoMethod == CUDD_REORDER_LINEAR_CONVERGE;
    /* Currently traversal requires global BDDs. Override whatever
    ** was specified for locGlob.
    */
    if (option->traverse == TRUE || option->envelope == TRUE ||
	option->scc == TRUE) {
	option->locGlob = BNET_GLOBAL_DD;
    }

    /* Read the first network... */
    fp1 = open_file(option->file1, "r");
    net1 = Bnet_ReadNetwork(fp1,pr);
    (void) fclose(fp1);
    if (net1 == NULL) {
	(void) fprintf(stderr,"Syntax error in %s.\n",option->file1);
	exit(2);
    }
    /* ... and optionally echo it to the standard output. */
    if (pr > 2) {
	Bnet_PrintNetwork(net1);
    }

    /* Read the second network... */
    if (option->verify == TRUE || option->second == TRUE ||
	option->clip > 0.0 || option->dontcares) {
	fp2 = open_file(option->file2, "r");
	net2 = Bnet_ReadNetwork(fp2,pr);
	(void) fclose(fp2);
	if (net2 == NULL) {
	    (void) fprintf(stderr,"Syntax error in %s.\n",option->file2);
	    exit(2);
	}
	/* ... and optionally echo it to the standard output. */
	if (pr > 2) {
	    Bnet_PrintNetwork(net2);
	}
    }

    /* Initialize manager. We start with 0 variables, because
    ** Ntr_buildDDs will create new variables rather than using
    ** whatever already exists.
    */
    dd = startCudd(option,net1->ninputs);
    if (dd == NULL) { exit(2); }

    /* Build the BDDs for the nodes of the first network. */
    result = Ntr_buildDDs(net1,dd,option,NULL);
    if (result == 0) { exit(2); }

    /* Build the BDDs for the nodes of the second network if requested. */
    if (option->verify == TRUE || option->second == TRUE ||
	option->clip > 0.0 || option->dontcares == TRUE) {
	char *nodesave = option->node;
	option->node = NULL;
	result = Ntr_buildDDs(net2,dd,option,net1);
	option->node = nodesave;
	if (result == 0) { exit(2); }
    }

    if (option->noBuild == TRUE) {
	Bnet_FreeNetwork(net1);
	if (option->verify == TRUE || option->second == TRUE ||
	    option->clip > 0.0) {
	    Bnet_FreeNetwork(net2);
	}
	freeOption(option);
	exit(0);
    }
    if (option->locGlob != BNET_LOCAL_DD) {
	/* Print the order before the final reordering. */
	(void) printf("Order before final reordering\n");
	result = Bnet_PrintOrder(net1,dd);
	if (result == 0) exit(2);
    }

    /* Perform final reordering */
    if (option->zddtest == FALSE) {
	result = reorder(net1,dd,option);
	if (result == 0) exit(2);

	/* Print final order. */
	if ((option->reordering != CUDD_REORDER_NONE || option->gaOnOff) &&
	    option->locGlob != BNET_LOCAL_DD) {
	    (void) printf("New order\n");
	    result = Bnet_PrintOrder(net1,dd);
	    if (result == 0) exit(2);
	}

	/* Print the re-encoded inputs. */
	if (pr >= 1 && reencoded == 1) {
	    for (i = 0; i < net1->npis; i++) {
		if (!st_lookup(net1->hash,net1->inputs[i],(void **)&node)) {
		    exit(2);
		}
		(void) fprintf(stdout,"%s ",node->name);
		Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr);
	    }
	    for (i = 0; i < net1->nlatches; i++) {
		if (!st_lookup(net1->hash,net1->latches[i][1],(void **)&node)) {
		    exit(2);
		}
		(void) fprintf(stdout,"%s ",node->name);
		Cudd_PrintDebug(dd,node->dd,Cudd_ReadSize(dd),pr);
	    }
	    if (pr >= 3) {
		result = Cudd_PrintLinear(dd);
		if (result == 0) exit(2);
	    }
	}
    }

    /* Verify (combinational) equivalence. */
    if (option->verify == TRUE) {
	result = Ntr_VerifyEquivalence(dd,net1,net2,option);
	if (result == 0) {
	    (void) printf("Verification abnormally terminated\n");
	    exit(2);
	} else if (result == -1) {
	    (void) printf("Combinational verification failed\n");
	} else {
	    (void) printf("Verification succeeded\n");
	}
    }

    /* Traverse if requested and if the circuit is sequential. */
    result = Ntr_Trav(dd,net1,option);
    if (result == 0) exit(2);

    /* Traverse with trasitive closure. */
    result = Ntr_ClosureTrav(dd,net1,option);
    if (result == 0) exit(2);

    /* Compute outer envelope if requested and if the circuit is sequential. */
    if (option->envelope == TRUE && net1->nlatches > 0) {
	NtrPartTR *T;
	T = Ntr_buildTR(dd,net1,option,option->image);
	result = Ntr_Envelope(dd,T,NULL,option);
        if (result == 0) exit(2);
	Ntr_freeTR(dd,T);
    }

    /* Compute SCCs if requested and if the circuit is sequential. */
    result = Ntr_SCC(dd,net1,option);
    if (result == 0) exit(2);

    /* Test Constrain Decomposition. */
    if (option->partition == TRUE && net1->nlatches > 0) {
	NtrPartTR *T;
	DdNode *product;
	DdNode **decomp;
	int sharingSize;
	T = Ntr_buildTR(dd,net1,option,NTR_IMAGE_MONO);
	decomp = Cudd_bddConstrainDecomp(dd,T->part[0]);
	if (decomp == NULL) exit(2);
	sharingSize = Cudd_SharingSize(decomp, Cudd_ReadSize(dd));
	(void) fprintf(stdout, "Decomposition Size: %d components %d nodes\n",
		       Cudd_ReadSize(dd), sharingSize);
	product = Cudd_ReadOne(dd);
	Cudd_Ref(product);
	for (i = 0; i < Cudd_ReadSize(dd); i++) {
	    DdNode *intermediate = Cudd_bddAnd(dd, product, decomp[i]);
	    if (intermediate == NULL) {
		exit(2);
	    }
	    Cudd_Ref(intermediate);
	    Cudd_IterDerefBdd(dd, product);
	    product = intermediate;
	}
	if (product != T->part[0])
	    exit(2);
	Cudd_IterDerefBdd(dd, product);
	for (i = 0; i < Cudd_ReadSize(dd); i++) {
	    Cudd_IterDerefBdd(dd, decomp[i]);
	}
	FREE(decomp);
	Ntr_freeTR(dd,T);
    }

    /* Test char-to-vect conversion. */
    result = Ntr_TestCharToVect(dd,net1,option);
    if (result == 0) exit(2);

    /* Test extraction of two-literal clauses. */
    result = Ntr_TestTwoLiteralClauses(dd,net1,option);
    if (result == 0) exit(2);

    /* Test BDD minimization functions. */
    result = Ntr_TestMinimization(dd,net1,net2,option);
    if (result == 0) exit(2);

    /* Test density-related functions. */
    result = Ntr_TestDensity(dd,net1,option);
    if (result == 0) exit(2);

    /* Test decomposition functions. */
    result = Ntr_TestDecomp(dd,net1,option);
    if (result == 0) exit(2);

    /* Test cofactor estimation functions. */
    result = Ntr_TestCofactorEstimate(dd,net1,option);
    if (result == 0) exit(2);

    /* Test BDD clipping functions. */
    result = Ntr_TestClipping(dd,net1,net2,option);
    if (result == 0) exit(2);

    /* Test BDD equivalence and containment under DC functions. */
    result = Ntr_TestEquivAndContain(dd,net1,net2,option);
    if (result == 0) exit(2);

    /* Test BDD Cudd_bddClosestCube. */
    result = Ntr_TestClosestCube(dd,net1,option);
    if (result == 0) exit(2);

    /* Test ZDDs if requested. */
    if (option->stateOnly == FALSE && option->zddtest == TRUE) {
	result = Ntr_testZDD(dd,net1,option);
	if (result == 0)
	    (void) fprintf(stdout,"ZDD test failed.\n");
	result = Ntr_testISOP(dd,net1,option);
	if (result == 0)
	    (void) fprintf(stdout,"ISOP test failed.\n");
    }

    /* Compute maximum flow if requested and if the circuit is sequential. */
    if (option->maxflow == TRUE && net1->nlatches > 0) {
	result = Ntr_maxflow(dd,net1,option);
	if (result == 0)
	    (void) fprintf(stdout,"Maxflow computation failed.\n");
    }

    /* Compute shortest paths if requested and if the circuit is sequential. */
    if (option->shortPath != NTR_SHORT_NONE && net1->nlatches > 0) {
	result = Ntr_ShortestPaths(dd,net1,option);
	if (result == 0)
	    (void) fprintf(stdout,"Shortest paths computation failed.\n");
    }

    /* Compute output signatures if so requested. */
    if (option->signatures) {
	(void) printf("Positive cofactor measures\n");
	for (i = 0; i < net1->noutputs; i++) {
	    if (!st_lookup(net1->hash,net1->outputs[i],(void **)&node)) {
		exit(2);
	    }
	    signatures = Cudd_CofMinterm(dd, node->dd);
	    if (signatures) {
		(void) printf("%s:\n", node->name);
		for (j = 0; j < Cudd_ReadSize(dd); j++) {
		    if((j%5 == 0)&&i) (void) printf("\n");
		    (void) printf("%5d: %-#8.4g ", j, signatures[j]);
		}
		(void) printf("\n");
		FREE(signatures);
	    } else {
		(void) printf("Signature computation failed.\n");
	    }
	}
    }

    /* Dump BDDs if so requested. */
    if (option->bdddump && option->second == FALSE &&
	option->density == FALSE && option->decomp == FALSE &&
	option->cofest == FALSE && option->clip < 0.0 &&
	option->scc == FALSE) {
	(void) printf("Dumping BDDs to %s\n", option->dumpfile);
	if (option->node != NULL) {
	    if (!st_lookup(net1->hash,option->node,(void **)&node)) {
		exit(2);
	    }
	    result = Bnet_bddArrayDump(dd,net1,option->dumpfile,&(node->dd),
				       &(node->name),1,option->dumpFmt);
	} else {
	    result = Bnet_bddDump(dd, net1, option->dumpfile,
				  option->dumpFmt, reencoded);
	}
	if (result != 1) {
	    (void) printf("BDD dump failed.\n");
	}
    }

    /* Print stats and clean up. */
    if (pr >= 0) {
	result = Cudd_PrintInfo(dd,stdout);
	if (result != 1) {
	    (void) printf("Cudd_PrintInfo failed.\n");
	}
    }

#if defined(DD_DEBUG) && !defined(DD_NO_DEATH_ROW)
    (void) fprintf(dd->err,"%d empty slots in death row\n",
    cuddTimesInDeathRow(dd,NULL));
#endif
    (void) printf("Final size: %ld\n", Cudd_ReadNodeCount(dd));

    /* Dispose of node BDDs. */
    node = net1->nodes;
    while (node != NULL) {
	if (node->dd != NULL &&
	node->type != BNET_INPUT_NODE &&
	node->type != BNET_PRESENT_STATE_NODE) {
	    Cudd_IterDerefBdd(dd,node->dd);
            node->dd = NULL;
	}
	node = node->next;
    }
    /* Dispose of network. */
    Bnet_FreeNetwork(net1);
    /* Do the same cleanup for the second network if it was created. */
    if (option->verify == TRUE || option->second == TRUE ||
	option->clip > 0.0 || option->dontcares == TRUE) {
        /* Since option->second is TRUE and reading the second network
         * didn't result in a failure, we know net2 is not NULL. */
        assert(net2 != NULL);
	node = net2->nodes;
	while (node != NULL) {
	    if (node->dd != NULL &&
		node->type != BNET_INPUT_NODE &&
		node->type != BNET_PRESENT_STATE_NODE) {
		Cudd_IterDerefBdd(dd,node->dd);
                node->dd = NULL;
	    }
	    node = node->next;
	}
	Bnet_FreeNetwork(net2);
    }

    /* Check reference counts: At this point we should have dereferenced
    ** everything we had, except in the case of re-encoding.
    */
    if (reencoded == CUDD_FALSE) {
        exitval = Cudd_CheckZeroRef(dd);
        ok = exitval != 0;  /* ok == 0 means O.K. */
        if (exitval != 0) {
            (void) fflush(stdout);
            (void) fprintf(stderr,
                           "%d non-zero DD reference counts after dereferencing\n", exitval);
        }
    } else {
        ok = 0;
    }

#ifdef DD_DEBUG
    Cudd_CheckKeys(dd);
#endif

    Cudd_Quit(dd);

    if (pr >= 0) (void) printf("total time = %s\n",
	    util_print_time(util_cpu_time() - option->initialTime));
    freeOption(option);
    if (pr >= 0) util_print_cpu_stats(stdout);

    exit(ok);

} /* end of main */


/*---------------------------------------------------------------------------*/
/* Definition of internal functions                                          */
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* Definition of static functions                                            */
/*---------------------------------------------------------------------------*/


/**
  @brief Allocates the option structure and initializes it.

  @sideeffect none

  @see ntrReadOptions

*/
static NtrOptions *
mainInit(
   )
{
    NtrOptions	*option;

    /* Initialize option structure. */
    option = ALLOC(NtrOptions,1);
    option->initialTime    = util_cpu_time();
    option->verify         = FALSE;
    option->second         = FALSE;
    option->file1          = NULL;
    option->file2          = NULL;
    option->traverse       = FALSE;
    option->depend         = FALSE;
    option->image          = NTR_IMAGE_MONO;
    option->imageClip      = 1.0;
    option->approx         = NTR_UNDER_APPROX;
    option->threshold      = -1;
    option->from	   = NTR_FROM_NEW;
    option->groupnsps      = NTR_GROUP_NONE;
    option->closure        = FALSE;
    option->closureClip    = 1.0;
    option->envelope       = FALSE;
    option->scc            = FALSE;
    option->maxflow        = FALSE;
    option->shortPath      = NTR_SHORT_NONE;
    option->selectiveTrace = FALSE;
    option->zddtest        = FALSE;
    option->printcover     = FALSE;
    option->sinkfile       = NULL;
    option->partition      = FALSE;
    option->char2vect      = FALSE;
    option->density        = FALSE;
    option->quality        = 1.0;
    option->decomp         = FALSE;
    option->cofest         = FALSE;
    option->clip           = -1.0;
    option->dontcares      = FALSE;
    option->closestCube    = FALSE;
    option->clauses        = FALSE;
    option->noBuild        = FALSE;
    option->stateOnly      = FALSE;
    option->node           = NULL;
    option->locGlob        = BNET_GLOBAL_DD;
    option->progress       = FALSE;
    option->cacheSize      = 32768;
    option->maxMemory      = 0;	/* set automatically */
    option->maxMemHard     = 0; /* don't set */
    option->maxLive        = ~0U; /* very large number */
    option->slots          = CUDD_UNIQUE_SLOTS;
    option->ordering       = PI_PS_FROM_FILE;
    option->orderPiPs      = NULL;
    option->reordering     = CUDD_REORDER_NONE;
    option->autoMethod     = CUDD_REORDER_SIFT;
    option->autoDyn        = 0;
    option->treefile       = NULL;
    option->firstReorder   = DD_FIRST_REORDER;
    option->countDead      = FALSE;
    option->maxGrowth      = 20;
    option->groupcheck     = CUDD_GROUP_CHECK7;
    option->arcviolation   = 10;
    option->symmviolation  = 10;
    option->recomb         = DD_DEFAULT_RECOMB;
    option->nodrop         = TRUE;
    option->signatures     = FALSE;
    option->verb           = 0;
    option->gaOnOff        = 0;
    option->populationSize = 0;	/* use default */
    option->numberXovers   = 0;	/* use default */
    option->bdddump	   = FALSE;
    option->dumpFmt	   = 0;	/* dot */
    option->dumpfile	   = NULL;
    option->store          = -1; /* do not store */
    option->storefile      = NULL;
    option->load           = FALSE;
    option->loadfile       = NULL;
    option->seed           = 1;

    return(option);

} /* end of mainInit */


/**
  @brief Reads the command line options.

  @details Scans the command line one argument at a time and performs
  a switch on each arguement it hits.  Some arguemnts also read in the
  following arg from the list (i.e., -f also gets the filename which
  should folow.)  Gives a usage message and exits if any unrecognized
  args are found.

  @sideeffect May initialize the random number generator.

  @see mainInit ntrReadOptionsFile

*/
static void
ntrReadOptions(
  int  argc,
  char ** argv,
  NtrOptions * option)
{
    int	i = 0;

    if (argc < 2) goto usage;

    if (STRING_EQUAL(argv[1],"-f")) {
	ntrReadOptionsFile(argv[2],&argv,&argc);
    }

    for (i = 1; i < argc; i++) {
	if (argv[i][0] != '-' ) {
	    if (option->file1 == NULL) {
		option->file1 = util_strsav(argv[i]);
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-second")) {
	    i++;
	    option->file2 = util_strsav(argv[i]);
	    option->second = TRUE;
	} else if (STRING_EQUAL(argv[i],"-verify")) {
	    i++;
	    option->file2 = util_strsav(argv[i]);
	    option->verify = TRUE;
	} else if (STRING_EQUAL(argv[i],"-trav")) {
	    option->traverse = TRUE;
	} else if (STRING_EQUAL(argv[i],"-depend")) {
	    option->traverse = TRUE;
	    option->depend = TRUE;
	} else if (STRING_EQUAL(argv[i],"-image")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"part")) {
		option->image = NTR_IMAGE_PART;
	    } else if (STRING_EQUAL(argv[i],"clip")) {
		option->image = NTR_IMAGE_CLIP;
	    } else if (STRING_EQUAL(argv[i],"depend")) {
		option->image = NTR_IMAGE_DEPEND;
	    } else if (STRING_EQUAL(argv[i],"mono")) {
		option->image = NTR_IMAGE_MONO;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-depth")) {
	    i++;
	    option->imageClip = (double) atof(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-cdepth")) {
	    i++;
	    option->closureClip = (double) atof(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-approx")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"under")) {
		option->approx = NTR_UNDER_APPROX;
	    } else if (STRING_EQUAL(argv[i],"over")) {
		option->approx = NTR_OVER_APPROX;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-threshold")) {
	    i++;
	    option->threshold = (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-from")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"new")) {
		option->from = NTR_FROM_NEW;
	    } else if (STRING_EQUAL(argv[i],"reached")) {
		option->from = NTR_FROM_REACHED;
	    } else if (STRING_EQUAL(argv[i],"restrict")) {
		option->from = NTR_FROM_RESTRICT;
	    } else if (STRING_EQUAL(argv[i],"compact")) {
		option->from = NTR_FROM_COMPACT;
	    } else if (STRING_EQUAL(argv[i],"squeeze")) {
		option->from = NTR_FROM_SQUEEZE;
	    } else if (STRING_EQUAL(argv[i],"subset")) {
		option->from = NTR_FROM_UNDERAPPROX;
	    } else if (STRING_EQUAL(argv[i],"superset")) {
		option->from = NTR_FROM_OVERAPPROX;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-groupnsps")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"none")) {
		option->groupnsps = NTR_GROUP_NONE;
	    } else if (STRING_EQUAL(argv[i],"default")) {
		option->groupnsps = NTR_GROUP_DEFAULT;
	    } else if (STRING_EQUAL(argv[i],"fixed")) {
		option->groupnsps = NTR_GROUP_FIXED;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-closure")) {
	    option->closure = TRUE;
	} else if (STRING_EQUAL(argv[i],"-envelope")) {
	    option->envelope = TRUE;
	} else if (STRING_EQUAL(argv[i],"-scc")) {
	    option->scc = TRUE;
	} else if (STRING_EQUAL(argv[i],"-maxflow")) {
	    option->maxflow = TRUE;
	} else if (STRING_EQUAL(argv[i],"-shortpaths")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"none")) {
		option->shortPath = NTR_SHORT_NONE;
	    } else if (STRING_EQUAL(argv[i],"bellman")) {
		option->shortPath = NTR_SHORT_BELLMAN;
	    } else if (STRING_EQUAL(argv[i],"floyd")) {
		option->shortPath = NTR_SHORT_FLOYD;
	    } else if (STRING_EQUAL(argv[i],"square")) {
		option->shortPath = NTR_SHORT_SQUARE;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-selective")) {
	    option->selectiveTrace = TRUE;
	} else if (STRING_EQUAL(argv[i],"-zdd")) {
	    option->zddtest = TRUE;
	} else if (STRING_EQUAL(argv[i],"-cover")) {
	    option->zddtest = TRUE;
	    option->printcover = TRUE;
	} else if (STRING_EQUAL(argv[i],"-sink")) {
	    i++;
	    option->maxflow = TRUE;
	    option->sinkfile = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-part")) {
	    option->partition = TRUE;
	} else if (STRING_EQUAL(argv[i],"-char2vect")) {
	    option->char2vect = TRUE;
	} else if (STRING_EQUAL(argv[i],"-density")) {
	    option->density = TRUE;
	} else if (STRING_EQUAL(argv[i],"-quality")) {
	    i++;
	    option->quality = (double) atof(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-decomp")) {
	    option->decomp = TRUE;
	} else if (STRING_EQUAL(argv[i],"-cofest")) {
	    option->cofest = TRUE;
	} else if (STRING_EQUAL(argv[i],"-clip")) {
	    i++;
	    option->clip = (double) atof(argv[i]);
	    i++;
	    option->file2 = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-dctest")) {
	    option->dontcares = TRUE;
	    i++;
	    option->file2 = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-closest")) {
	    option->closestCube = TRUE;
	} else if (STRING_EQUAL(argv[i],"-clauses")) {
	    option->clauses = TRUE;
	} else if (STRING_EQUAL(argv[i],"-nobuild")) {
	    option->noBuild = TRUE;
	    option->reordering = CUDD_REORDER_NONE;
	} else if (STRING_EQUAL(argv[i],"-delta")) {
	    option->stateOnly = TRUE;
	} else if (STRING_EQUAL(argv[i],"-node")) {
	    i++;
	    option->node = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-local")) {
	    option->locGlob = BNET_LOCAL_DD;
	} else if (STRING_EQUAL(argv[i],"-progress")) {
	    option->progress = TRUE;
	} else if (STRING_EQUAL(argv[i],"-cache")) {
	    i++;
	    option->cacheSize = (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-maxmem")) {
	    i++;
	    option->maxMemory = 1048576 * (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-memhard")) {
	    i++;
	    option->maxMemHard = 1048576 * (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-maxlive")) {
	    i++;
	    option->maxLive = (unsigned int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-slots")) {
	    i++;
	    option->slots = (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-ordering")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"dfs")) {
		option->ordering = PI_PS_DFS;
	    } else if (STRING_EQUAL(argv[i],"hw")) {
		option->ordering = PI_PS_FROM_FILE;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-order")) {
	    i++;
	    option->ordering = PI_PS_GIVEN;
	    option->orderPiPs = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-reordering")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"none")) {
		option->reordering = CUDD_REORDER_NONE;
	    } else if (STRING_EQUAL(argv[i],"random")) {
		option->reordering = CUDD_REORDER_RANDOM;
	    } else if (STRING_EQUAL(argv[i],"bernard") ||
		STRING_EQUAL(argv[i],"pivot")) {
		option->reordering = CUDD_REORDER_RANDOM_PIVOT;
	    } else if (STRING_EQUAL(argv[i],"sifting")) {
		option->reordering = CUDD_REORDER_SIFT;
	    } else if (STRING_EQUAL(argv[i],"converge")) {
		option->reordering = CUDD_REORDER_SIFT_CONVERGE;
	    } else if (STRING_EQUAL(argv[i],"symm")) {
		option->reordering = CUDD_REORDER_SYMM_SIFT;
	    } else if (STRING_EQUAL(argv[i],"cosymm")) {
		option->reordering = CUDD_REORDER_SYMM_SIFT_CONV;
	    } else if (STRING_EQUAL(argv[i],"tree") ||
		STRING_EQUAL(argv[i],"group")) {
		option->reordering = CUDD_REORDER_GROUP_SIFT;
	    } else if (STRING_EQUAL(argv[i],"cotree") ||
		STRING_EQUAL(argv[i],"cogroup")) {
		option->reordering = CUDD_REORDER_GROUP_SIFT_CONV;
	    } else if (STRING_EQUAL(argv[i],"win2")) {
		option->reordering = CUDD_REORDER_WINDOW2;
	    } else if (STRING_EQUAL(argv[i],"win3")) {
		option->reordering = CUDD_REORDER_WINDOW3;
	    } else if (STRING_EQUAL(argv[i],"win4")) {
		option->reordering = CUDD_REORDER_WINDOW4;
	    } else if (STRING_EQUAL(argv[i],"win2conv")) {
		option->reordering = CUDD_REORDER_WINDOW2_CONV;
	    } else if (STRING_EQUAL(argv[i],"win3conv")) {
		option->reordering = CUDD_REORDER_WINDOW3_CONV;
	    } else if (STRING_EQUAL(argv[i],"win4conv")) {
		option->reordering = CUDD_REORDER_WINDOW4_CONV;
	    } else if (STRING_EQUAL(argv[i],"annealing")) {
		option->reordering = CUDD_REORDER_ANNEALING;
	    } else if (STRING_EQUAL(argv[i],"genetic")) {
		option->reordering = CUDD_REORDER_GENETIC;
	    } else if (STRING_EQUAL(argv[i],"linear")) {
		option->reordering = CUDD_REORDER_LINEAR;
	    } else if (STRING_EQUAL(argv[i],"linconv")) {
		option->reordering = CUDD_REORDER_LINEAR_CONVERGE;
	    } else if (STRING_EQUAL(argv[i],"exact")) {
		option->reordering = CUDD_REORDER_EXACT;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-autodyn")) {
	    option->autoDyn = 3;
	} else if (STRING_EQUAL(argv[i],"-autodynB")) {
	    option->autoDyn |= 1;
	} else if (STRING_EQUAL(argv[i],"-autodynZ")) {
	    option->autoDyn |= 2;
	} else if (STRING_EQUAL(argv[i],"-automethod")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"none")) {
		option->autoMethod = CUDD_REORDER_NONE;
	    } else if (STRING_EQUAL(argv[i],"random")) {
		option->autoMethod = CUDD_REORDER_RANDOM;
	    } else if (STRING_EQUAL(argv[i],"bernard") ||
		STRING_EQUAL(argv[i],"pivot")) {
		option->autoMethod = CUDD_REORDER_RANDOM_PIVOT;
	    } else if (STRING_EQUAL(argv[i],"sifting")) {
		option->autoMethod = CUDD_REORDER_SIFT;
	    } else if (STRING_EQUAL(argv[i],"converge")) {
		option->autoMethod = CUDD_REORDER_SIFT_CONVERGE;
	    } else if (STRING_EQUAL(argv[i],"symm")) {
		option->autoMethod = CUDD_REORDER_SYMM_SIFT;
	    } else if (STRING_EQUAL(argv[i],"cosymm")) {
		option->autoMethod = CUDD_REORDER_SYMM_SIFT_CONV;
	    } else if (STRING_EQUAL(argv[i],"tree") ||
		STRING_EQUAL(argv[i],"group")) {
		option->autoMethod = CUDD_REORDER_GROUP_SIFT;
	    } else if (STRING_EQUAL(argv[i],"cotree") ||
		STRING_EQUAL(argv[i],"cogroup")) {
		option->autoMethod = CUDD_REORDER_GROUP_SIFT_CONV;
	    } else if (STRING_EQUAL(argv[i],"win2")) {
		option->autoMethod = CUDD_REORDER_WINDOW2;
	    } else if (STRING_EQUAL(argv[i],"win3")) {
		option->autoMethod = CUDD_REORDER_WINDOW3;
	    } else if (STRING_EQUAL(argv[i],"win4")) {
		option->autoMethod = CUDD_REORDER_WINDOW4;
	    } else if (STRING_EQUAL(argv[i],"win2conv")) {
		option->autoMethod = CUDD_REORDER_WINDOW2_CONV;
	    } else if (STRING_EQUAL(argv[i],"win3conv")) {
		option->autoMethod = CUDD_REORDER_WINDOW3_CONV;
	    } else if (STRING_EQUAL(argv[i],"win4conv")) {
		option->autoMethod = CUDD_REORDER_WINDOW4_CONV;
	    } else if (STRING_EQUAL(argv[i],"annealing")) {
		option->autoMethod = CUDD_REORDER_ANNEALING;
	    } else if (STRING_EQUAL(argv[i],"genetic")) {
		option->autoMethod = CUDD_REORDER_GENETIC;
	    } else if (STRING_EQUAL(argv[i],"linear")) {
		option->autoMethod = CUDD_REORDER_LINEAR;
	    } else if (STRING_EQUAL(argv[i],"linconv")) {
		option->autoMethod = CUDD_REORDER_LINEAR_CONVERGE;
	    } else if (STRING_EQUAL(argv[i],"exact")) {
		option->autoMethod = CUDD_REORDER_EXACT;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-tree")) {
	    i++;
	    option->treefile = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-first")) {
	    i++;
	    option->firstReorder = (int)atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-countdead")) {
	    option->countDead = TRUE;
	} else if (STRING_EQUAL(argv[i],"-growth")) {
	    i++;
	    option->maxGrowth = (int)atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-groupcheck")) {
	    i++;
	    if (STRING_EQUAL(argv[i],"check")) {
		option->groupcheck = CUDD_GROUP_CHECK;
	    } else if (STRING_EQUAL(argv[i],"nocheck")) {
		option->groupcheck = CUDD_NO_CHECK;
	    } else if (STRING_EQUAL(argv[i],"check2")) {
		option->groupcheck = CUDD_GROUP_CHECK2;
	    } else if (STRING_EQUAL(argv[i],"check3")) {
		option->groupcheck = CUDD_GROUP_CHECK3;
	    } else if (STRING_EQUAL(argv[i],"check4")) {
		option->groupcheck = CUDD_GROUP_CHECK4;
	    } else if (STRING_EQUAL(argv[i],"check5")) {
		option->groupcheck = CUDD_GROUP_CHECK5;
	    } else if (STRING_EQUAL(argv[i],"check6")) {
		option->groupcheck = CUDD_GROUP_CHECK6;
	    } else if (STRING_EQUAL(argv[i],"check7")) {
		option->groupcheck = CUDD_GROUP_CHECK7;
	    } else if (STRING_EQUAL(argv[i],"check8")) {
		option->groupcheck = CUDD_GROUP_CHECK8;
	    } else if (STRING_EQUAL(argv[i],"check9")) {
		option->groupcheck = CUDD_GROUP_CHECK9;
	    } else {
		goto usage;
	    }
	} else if (STRING_EQUAL(argv[i],"-arcviolation")) {
	    i++;
	    option->arcviolation = (int)atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-symmviolation")) {
	    i++;
	    option->symmviolation = (int)atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-recomb")) {
	    i++;
	    option->recomb = (int)atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-drop")) {
	    option->nodrop = FALSE;
	} else if (STRING_EQUAL(argv[i],"-sign")) {
	    option->signatures = TRUE;
	} else if (STRING_EQUAL(argv[i],"-genetic")) {
	    option->gaOnOff = 1;
	} else if (STRING_EQUAL(argv[i],"-genepop")) {
	    option->gaOnOff = 1;
	    i++;
	    option->populationSize = (int)atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-genexover")) {
	    option->gaOnOff = 1;
	    i++;
	    option->numberXovers = (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-seed")) {
	    i++;
            option->seed = (int32_t) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-dumpfile")) {
	    i++;
	    option->bdddump = TRUE;
	    option->dumpfile = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-dumpblif")) {
	    option->dumpFmt = 1; /* blif */
	} else if (STRING_EQUAL(argv[i],"-dumpdaVinci")) {
	    option->dumpFmt = 2; /* daVinci */
	} else if (STRING_EQUAL(argv[i],"-dumpddcal")) {
	    option->dumpFmt = 3; /* DDcal */
	} else if (STRING_EQUAL(argv[i],"-dumpfact")) {
	    option->dumpFmt = 4; /* factored form */
	} else if (STRING_EQUAL(argv[i],"-dumpmv")) {
	    option->dumpFmt = 5; /* blif-MV */
	} else if (STRING_EQUAL(argv[i],"-store")) {
	    i++;
	    option->store = (int) atoi(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-storefile")) {
	    i++;
	    option->storefile = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-loadfile")) {
	    i++;
	    option->load = 1;
	    option->loadfile = util_strsav(argv[i]);
	} else if (STRING_EQUAL(argv[i],"-p")) {
	    i++;
	    option->verb = (int) atoi(argv[i]);
	} else {
	    goto usage;
	}
    }

    if (option->store >= 0 && option->storefile == NULL) {
	(void) fprintf(stdout,"-storefile mandatory with -store\n");
	exit(-1);
    }

    if (option->verb >= 0) {
	(void) printf("# %s\n", NTR_VERSION);
	/* echo command line and arguments */
	(void) printf("#");
	for (i = 0; i < argc; i++) {
	    (void) printf(" %s", argv[i]);
	}
	(void) printf("\n");
	(void) printf("# CUDD Version ");
	Cudd_PrintVersion(stdout);
	(void) fflush(stdout);
    }

    return;

usage:	/* convenient goto */
    printf("Usage: please read man page\n");
    if (i == 0) {
	(void) fprintf(stdout,"too few arguments\n");
    } else {
	(void) fprintf(stdout,"option: %s is not defined\n",argv[i]);
    }
    exit(-1);

} /* end of ntrReadOptions */


/**
  @brief Reads the program options from a file.

  @details Opens file. Reads the command line from the otpions file
  using the read_line func. Scans the line looking for spaces, each
  space is a searator and demarks a new option.  When a space is
  found, it is changed to a \0 to terminate that string; then the next
  value of slot points to the next non-space character.  There is a
  limit of 1024 options.  Should produce an error (presently doesn't)
  on overrun of options, but this is very unlikely to happen.

  @sideeffect none

*/
static void
ntrReadOptionsFile(
  char * name,
  char *** argv,
  int * argc)
{
    char	**slot;
    char	*line;
    char	c;
    int		index,flag;
    FILE	*fp;

    if ((fp = fopen(name,"r")) == NULL) {
	fprintf(stderr,"Error: can not find cmd file %s\n",name);
	exit(-1);
    }

    slot = ALLOC(char *,1024);
    index = 1;
    line = readLine(fp);
    flag = TRUE;

    do {
	c = *line;
	if ( c == ' ')  {
	    flag = TRUE;
	    *line = '\0';
	} else if ( c != ' ' && flag == TRUE) {
	    flag = FALSE;
	    slot[index] = line;
	    index++;
	}
	line++;
    } while ( *line != '\0');


    *argv = slot;
    *argc = index;

    fclose(fp);

} /* end of ntrReadOptionsFile */


/**
  @brief Reads a line from the option file.

  @sideeffect none

*/
static char*
readLine(
  FILE * fp)
{
    int  c;
    char *pbuffer;

    pbuffer = buffer;

    /* Strip white space from beginning of line. */
    for(;;) {
	c = getc(fp);
	if ( c == EOF) return(NULL);
	if ( c == '\n') {
	    *pbuffer = '\0';
	    return(buffer); /* got a blank line */
	}
	if ( c != ' ') break;
    }
    do {
	if ( c == '\\' ) { /* if we have a continuation character.. */
	    do {	/* scan to end of line */
		c = getc(fp);
		if ( c == '\n' ) break;
	    } while ( c != EOF);
	    if ( c != EOF) {
		*pbuffer = ' ';
		pbuffer++;
	    } else return( buffer);
	    c = getc(fp);
	    continue;
	}
	*pbuffer = (char) c;
	pbuffer++;
	c = getc(fp);
    } while( c != '\n' &&  c != EOF);
    *pbuffer = '\0';
    return(buffer);

} /* end of readLine */


/**
  @brief Opens a file.

  @details Opens a file, or fails with an error message and exits.
  Allows '-' as a synonym for standard input.

  @sideeffect None

*/
static FILE *
open_file(
  char * filename,
  const char * mode)
{
    FILE *fp;

    if (strcmp(filename, "-") == 0) {
	return mode[0] == 'r' ? stdin : stdout;
    } else if ((fp = fopen(filename, mode)) == NULL) {
	perror(filename);
	exit(1);
    }
    return(fp);

} /* end of open_file */


/**
  @brief Explicitly applies reordering to the DDs.

  @return 1 if successful; 0 otherwise.

  @sideeffect None

*/
static int
reorder(
  BnetNetwork * net,
  DdManager * dd,
  NtrOptions * option)
{
#ifdef DD_DEBUG
    st_table	*mintermTable;	/* minterm counts for each output */
#endif
    int result;			/* return value from functions */

    (void) printf("Number of inputs = %d\n",net->ninputs);

    /* Perform the final reordering */
    if (option->reordering != CUDD_REORDER_NONE) {
#ifdef DD_DEBUG
	result = Cudd_DebugCheck(dd);
	if (result != 0) {
	    (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
	    return(0);
	}
	result = Cudd_CheckKeys(dd);
	if (result != 0) {
	    (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
	    return(0);
	}
	mintermTable = checkMinterms(net,dd,NULL);
	if (mintermTable == NULL) exit(2);
#endif

	dd->siftMaxVar = 1000000;
	dd->siftMaxSwap = 1000000000;
	result = Cudd_ReduceHeap(dd,option->reordering,1);
	if (result == 0) return(0);
#ifdef DD_DEBUG
	result = Cudd_DebugCheck(dd);
	if (result != 0) {
	    (void) fprintf(stderr,"Error reported by Cudd_DebugCheck\n");
	    return(0);
	}
	result = Cudd_CheckKeys(dd);
	if (result != 0) {
	    (void) fprintf(stderr,"Error reported by Cudd_CheckKeys\n");
	    return(0);
	}
	mintermTable = checkMinterms(net,dd,mintermTable);
        if (mintermTable != NULL) {
            (void) fprintf(stderr,"Error in checkMinterms\n");
            return(0);
        }
#endif

	/* Print symmetry stats if pertinent */
	if (dd->tree == NULL &&
	    (option->reordering == CUDD_REORDER_SYMM_SIFT ||
	    option->reordering == CUDD_REORDER_SYMM_SIFT_CONV))
	    Cudd_SymmProfile(dd,0,dd->size - 1);
    }

    if (option->gaOnOff) {
	result = Cudd_ReduceHeap(dd,CUDD_REORDER_GENETIC,1);
	if (result == 0) {
	    (void) printf("Something went wrong in cuddGa\n");
	    return(0);
	}
    }

    return(1);

} /* end of reorder */


/**
  @brief Frees the option structure and its appendages.

  @sideeffect None

*/
static void
freeOption(
  NtrOptions * option)
{
    if (option->file1 != NULL) FREE(option->file1);
    if (option->file2 != NULL) FREE(option->file2);
    if (option->orderPiPs != NULL) FREE(option->orderPiPs);
    if (option->treefile != NULL) FREE(option->treefile);
    if (option->sinkfile != NULL) FREE(option->sinkfile);
    if (option->dumpfile != NULL) FREE(option->dumpfile);
    if (option->loadfile != NULL) FREE(option->loadfile);
    if (option->storefile != NULL) FREE(option->storefile);
    if (option->node != NULL) FREE(option->node);
    FREE(option);

} /* end of freeOption */


/**
  @brief Starts the CUDD manager with the desired options.

  @details Starts with 0 variables, because Ntr_buildDDs will create
  new variables rather than using whatever already exists.

  @sideeffect None

*/
static DdManager *
startCudd(
  NtrOptions * option,
  int  nvars)
{
    DdManager *dd;
    int result;

    dd = Cudd_Init(0, 0, option->slots, option->cacheSize, option->maxMemory);
    if (dd == NULL) return(NULL);

    Cudd_Srandom(dd, option->seed);
    if (option->maxMemHard != 0) {
	Cudd_SetMaxMemory(dd,option->maxMemHard);
    }
    Cudd_SetMaxLive(dd,option->maxLive);
    Cudd_SetGroupcheck(dd,option->groupcheck);
    if (option->autoDyn & 1) {
	Cudd_AutodynEnable(dd,option->autoMethod);
    }
    dd->nextDyn = option->firstReorder;
    dd->countDead = (option->countDead == FALSE) ? ~0 : 0;
    dd->maxGrowth = 1.0 + ((float) option->maxGrowth / 100.0);
    dd->recomb = option->recomb;
    dd->arcviolation = option->arcviolation;
    dd->symmviolation = option->symmviolation;
    dd->populationSize = option->populationSize;
    dd->numberXovers = option->numberXovers;
    result = ntrReadTree(dd,option->treefile,nvars);
    if (result == 0) {
	Cudd_Quit(dd);
	return(NULL);
    }
#ifndef DD_STATS
    result = Cudd_EnableReorderingReporting(dd);
    if (result == 0) {
	(void) fprintf(stderr,
		       "Error reported by Cudd_EnableReorderingReporting\n");
	Cudd_Quit(dd);
	return(NULL);
    }
#endif

    return(dd);

} /* end of startCudd */


/**
  @brief Reads the variable group tree from a file.

  @return 1 if successful; 0 otherwise.

  @sideeffect None

*/
static int
ntrReadTree(
  DdManager * dd,
  char * treefile,
  int  nvars)
{
    FILE *fp;
    MtrNode *root;

    if (treefile == NULL) {
	return(1);
    }

    if ((fp = fopen(treefile,"r")) == NULL) {
	(void) fprintf(stderr,"Unable to open %s\n",treefile);
	return(0);
    }

    root = Mtr_ReadGroups(fp,ddMax(Cudd_ReadSize(dd),nvars));
    if (root == NULL) {
	return(0);
    }

    Cudd_SetTree(dd,root);

    return(1);

} /* end of ntrReadTree */
