You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							1340 lines
						
					
					
						
							38 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							1340 lines
						
					
					
						
							38 KiB
						
					
					
				
								/**CFile***********************************************************************
							 | 
						|
								
							 | 
						|
								  FileName    [cuddZddGroup.c]
							 | 
						|
								
							 | 
						|
								  PackageName [cudd]
							 | 
						|
								
							 | 
						|
								  Synopsis    [Functions for ZDD group sifting.]
							 | 
						|
								
							 | 
						|
								  Description [External procedures included in this file:
							 | 
						|
										<ul>
							 | 
						|
										<li> Cudd_MakeZddTreeNode()
							 | 
						|
										</ul>
							 | 
						|
									Internal procedures included in this file:
							 | 
						|
										<ul>
							 | 
						|
										<li> cuddZddTreeSifting()
							 | 
						|
										</ul>
							 | 
						|
									Static procedures included in this module:
							 | 
						|
										<ul>
							 | 
						|
										<li> zddTreeSiftingAux()
							 | 
						|
										<li> zddCountInternalMtrNodes()
							 | 
						|
										<li> zddReorderChildren()
							 | 
						|
										<li> zddFindNodeHiLo()
							 | 
						|
										<li> zddUniqueCompareGroup()
							 | 
						|
										<li> zddGroupSifting()
							 | 
						|
										<li> zddGroupSiftingAux()
							 | 
						|
										<li> zddGroupSiftingUp()
							 | 
						|
										<li> zddGroupSiftingDown()
							 | 
						|
										<li> zddGroupMove()
							 | 
						|
										<li> zddGroupMoveBackward()
							 | 
						|
										<li> zddGroupSiftingBackward()
							 | 
						|
										<li> zddMergeGroups()
							 | 
						|
										</ul>]
							 | 
						|
								
							 | 
						|
								  Author      [Fabio Somenzi]
							 | 
						|
								
							 | 
						|
								  Copyright   [Copyright (c) 1995-2012, 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.]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								
							 | 
						|
								#include "util.h"
							 | 
						|
								#include "cuddInt.h"
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Constant declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Stucture declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Type declarations                                                         */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Variable declarations                                                     */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								#ifndef lint
							 | 
						|
								static char rcsid[] DD_UNUSED = "$Id: cuddZddGroup.c,v 1.22 2012/02/05 01:07:19 fabio Exp $";
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								static	int	*entry;
							 | 
						|
								extern	int	zddTotalNumberSwapping;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								static  int     extsymmcalls;
							 | 
						|
								static  int     extsymm;
							 | 
						|
								static  int     secdiffcalls;
							 | 
						|
								static  int     secdiff;
							 | 
						|
								static  int     secdiffmisfire;
							 | 
						|
								#endif
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								static	int	pr = 0;	/* flag to enable printing while debugging */
							 | 
						|
											/* by depositing a 1 into it */
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Macro declarations                                                        */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								/**AutomaticStart*************************************************************/
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Static function prototypes                                                */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								static int zddTreeSiftingAux (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								static int zddCountInternalMtrNodes (DdManager *table, MtrNode *treenode);
							 | 
						|
								#endif
							 | 
						|
								static int zddReorderChildren (DdManager *table, MtrNode *treenode, Cudd_ReorderingType method);
							 | 
						|
								static void zddFindNodeHiLo (DdManager *table, MtrNode *treenode, int *lower, int *upper);
							 | 
						|
								static int zddUniqueCompareGroup (int *ptrX, int *ptrY);
							 | 
						|
								static int zddGroupSifting (DdManager *table, int lower, int upper);
							 | 
						|
								static int zddGroupSiftingAux (DdManager *table, int x, int xLow, int xHigh);
							 | 
						|
								static int zddGroupSiftingUp (DdManager *table, int y, int xLow, Move **moves);
							 | 
						|
								static int zddGroupSiftingDown (DdManager *table, int x, int xHigh, Move **moves);
							 | 
						|
								static int zddGroupMove (DdManager *table, int x, int y, Move **moves);
							 | 
						|
								static int zddGroupMoveBackward (DdManager *table, int x, int y);
							 | 
						|
								static int zddGroupSiftingBackward (DdManager *table, Move *moves, int size);
							 | 
						|
								static void zddMergeGroups (DdManager *table, MtrNode *treenode, int low, int high);
							 | 
						|
								
							 | 
						|
								/**AutomaticEnd***************************************************************/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of exported functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Creates a new ZDD variable group.]
							 | 
						|
								
							 | 
						|
								  Description [Creates a new ZDD variable group. The group starts at
							 | 
						|
								  variable and contains size variables. The parameter low is the index
							 | 
						|
								  of the first variable. If the variable already exists, its current
							 | 
						|
								  position in the order is known to the manager. If the variable does
							 | 
						|
								  not exist yet, the position is assumed to be the same as the index.
							 | 
						|
								  The group tree is created if it does not exist yet.
							 | 
						|
								  Returns a pointer to the group if successful; NULL otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [The ZDD variable tree is changed.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     [Cudd_MakeTreeNode]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								MtrNode *
							 | 
						|
								Cudd_MakeZddTreeNode(
							 | 
						|
								  DdManager * dd /* manager */,
							 | 
						|
								  unsigned int  low /* index of the first group variable */,
							 | 
						|
								  unsigned int  size /* number of variables in the group */,
							 | 
						|
								  unsigned int  type /* MTR_DEFAULT or MTR_FIXED */)
							 | 
						|
								{
							 | 
						|
								    MtrNode *group;
							 | 
						|
								    MtrNode *tree;
							 | 
						|
								    unsigned int level;
							 | 
						|
								
							 | 
						|
								    /* If the variable does not exist yet, the position is assumed to be
							 | 
						|
								    ** the same as the index. Therefore, applications that rely on
							 | 
						|
								    ** Cudd_bddNewVarAtLevel or Cudd_addNewVarAtLevel to create new
							 | 
						|
								    ** variables have to create the variables before they group them.
							 | 
						|
								    */
							 | 
						|
								    level = (low < (unsigned int) dd->sizeZ) ? dd->permZ[low] : low;
							 | 
						|
								
							 | 
						|
								    if (level + size - 1> (int) MTR_MAXHIGH)
							 | 
						|
									return(NULL);
							 | 
						|
								
							 | 
						|
								    /* If the tree does not exist yet, create it. */
							 | 
						|
								    tree = dd->treeZ;
							 | 
						|
								    if (tree == NULL) {
							 | 
						|
									dd->treeZ = tree = Mtr_InitGroupTree(0, dd->sizeZ);
							 | 
						|
									if (tree == NULL)
							 | 
						|
									    return(NULL);
							 | 
						|
									tree->index = dd->invpermZ[0];
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Extend the upper bound of the tree if necessary. This allows the
							 | 
						|
								    ** application to create groups even before the variables are created.
							 | 
						|
								    */
							 | 
						|
								    tree->size = ddMax(tree->size, level + size);
							 | 
						|
								
							 | 
						|
								    /* Create the group. */
							 | 
						|
								    group = Mtr_MakeGroup(tree, level, size, type);
							 | 
						|
								    if (group == NULL)
							 | 
						|
									return(NULL);
							 | 
						|
								
							 | 
						|
								    /* Initialize the index field to the index of the variable currently
							 | 
						|
								    ** in position low. This field will be updated by the reordering
							 | 
						|
								    ** procedure to provide a handle to the group once it has been moved.
							 | 
						|
								    */
							 | 
						|
								    group->index = (MtrHalfWord) low;
							 | 
						|
								
							 | 
						|
								    return(group);
							 | 
						|
								
							 | 
						|
								} /* end of Cudd_MakeZddTreeNode */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of internal functions                                          */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Tree sifting algorithm for ZDDs.]
							 | 
						|
								
							 | 
						|
								  Description [Tree sifting algorithm for ZDDs. Assumes that a tree
							 | 
						|
								  representing a group hierarchy is passed as a parameter. It then
							 | 
						|
								  reorders each group in postorder fashion by calling
							 | 
						|
								  zddTreeSiftingAux.  Assumes that no dead nodes are present.  Returns
							 | 
						|
								  1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								int
							 | 
						|
								cuddZddTreeSifting(
							 | 
						|
								  DdManager * table /* DD table */,
							 | 
						|
								  Cudd_ReorderingType method /* reordering method for the groups of leaves */)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    int nvars;
							 | 
						|
								    int result;
							 | 
						|
								    int tempTree;
							 | 
						|
								
							 | 
						|
								    /* If no tree is provided we create a temporary one in which all
							 | 
						|
								    ** variables are in a single group. After reordering this tree is
							 | 
						|
								    ** destroyed.
							 | 
						|
								    */
							 | 
						|
								    tempTree = table->treeZ == NULL;
							 | 
						|
								    if (tempTree) {
							 | 
						|
									table->treeZ = Mtr_InitGroupTree(0,table->sizeZ);
							 | 
						|
									table->treeZ->index = table->invpermZ[0];
							 | 
						|
								    }
							 | 
						|
								    nvars = table->sizeZ;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (pr > 0 && !tempTree)
							 | 
						|
									(void) fprintf(table->out,"cuddZddTreeSifting:");
							 | 
						|
								    Mtr_PrintGroups(table->treeZ,pr <= 0);
							 | 
						|
								#endif
							 | 
						|
								#if 0
							 | 
						|
								    /* Debugging code. */
							 | 
						|
								    if (table->tree && table->treeZ) {
							 | 
						|
									(void) fprintf(table->out,"\n");
							 | 
						|
									Mtr_PrintGroups(table->tree, 0);
							 | 
						|
									cuddPrintVarGroups(table,table->tree,0,0);
							 | 
						|
									for (i = 0; i < table->size; i++) {
							 | 
						|
									    (void) fprintf(table->out,"%s%d",
							 | 
						|
											   (i == 0) ? "" : ",", table->invperm[i]);
							 | 
						|
									}
							 | 
						|
									(void) fprintf(table->out,"\n");
							 | 
						|
									for (i = 0; i < table->size; i++) {
							 | 
						|
									    (void) fprintf(table->out,"%s%d",
							 | 
						|
											   (i == 0) ? "" : ",", table->perm[i]);
							 | 
						|
									}
							 | 
						|
									(void) fprintf(table->out,"\n\n");
							 | 
						|
									Mtr_PrintGroups(table->treeZ,0);
							 | 
						|
									cuddPrintVarGroups(table,table->treeZ,1,0);
							 | 
						|
									for (i = 0; i < table->sizeZ; i++) {
							 | 
						|
									    (void) fprintf(table->out,"%s%d",
							 | 
						|
											   (i == 0) ? "" : ",", table->invpermZ[i]);
							 | 
						|
									}
							 | 
						|
									(void) fprintf(table->out,"\n");
							 | 
						|
									for (i = 0; i < table->sizeZ; i++) {
							 | 
						|
									    (void) fprintf(table->out,"%s%d",
							 | 
						|
											   (i == 0) ? "" : ",", table->permZ[i]);
							 | 
						|
									}
							 | 
						|
									(void) fprintf(table->out,"\n");
							 | 
						|
								    }
							 | 
						|
								    /* End of debugging code. */
							 | 
						|
								#endif
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								    extsymmcalls = 0;
							 | 
						|
								    extsymm = 0;
							 | 
						|
								    secdiffcalls = 0;
							 | 
						|
								    secdiff = 0;
							 | 
						|
								    secdiffmisfire = 0;
							 | 
						|
								
							 | 
						|
								    (void) fprintf(table->out,"\n");
							 | 
						|
								    if (!tempTree)
							 | 
						|
									(void) fprintf(table->out,"#:IM_NODES  %8d: group tree nodes\n",
							 | 
						|
										       zddCountInternalMtrNodes(table,table->treeZ));
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Initialize the group of each subtable to itself. Initially
							 | 
						|
								    ** there are no groups. Groups are created according to the tree
							 | 
						|
								    ** structure in postorder fashion.
							 | 
						|
								    */
							 | 
						|
								    for (i = 0; i < nvars; i++)
							 | 
						|
									table->subtableZ[i].next = i;
							 | 
						|
								
							 | 
						|
								    /* Reorder. */
							 | 
						|
								    result = zddTreeSiftingAux(table, table->treeZ, method);
							 | 
						|
								
							 | 
						|
								#ifdef DD_STATS		/* print stats */
							 | 
						|
								    if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
							 | 
						|
									(table->groupcheck == CUDD_GROUP_CHECK7 ||
							 | 
						|
									 table->groupcheck == CUDD_GROUP_CHECK5)) {
							 | 
						|
									(void) fprintf(table->out,"\nextsymmcalls = %d\n",extsymmcalls);
							 | 
						|
									(void) fprintf(table->out,"extsymm = %d",extsymm);
							 | 
						|
								    }
							 | 
						|
								    if (!tempTree && method == CUDD_REORDER_GROUP_SIFT &&
							 | 
						|
									table->groupcheck == CUDD_GROUP_CHECK7) {
							 | 
						|
									(void) fprintf(table->out,"\nsecdiffcalls = %d\n",secdiffcalls);
							 | 
						|
									(void) fprintf(table->out,"secdiff = %d\n",secdiff);
							 | 
						|
									(void) fprintf(table->out,"secdiffmisfire = %d",secdiffmisfire);
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    if (tempTree)
							 | 
						|
									Cudd_FreeZddTree(table);
							 | 
						|
								    return(result);
							 | 
						|
								
							 | 
						|
								} /* end of cuddZddTreeSifting */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								/* Definition of static functions                                            */
							 | 
						|
								/*---------------------------------------------------------------------------*/
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Visits the group tree and reorders each group.]
							 | 
						|
								
							 | 
						|
								  Description [Recursively visits the group tree and reorders each
							 | 
						|
								  group in postorder fashion.  Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddTreeSiftingAux(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  MtrNode * treenode,
							 | 
						|
								  Cudd_ReorderingType method)
							 | 
						|
								{
							 | 
						|
								    MtrNode  *auxnode;
							 | 
						|
								    int res;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    Mtr_PrintGroups(treenode,1);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    auxnode = treenode;
							 | 
						|
								    while (auxnode != NULL) {
							 | 
						|
									if (auxnode->child != NULL) {
							 | 
						|
									    if (!zddTreeSiftingAux(table, auxnode->child, method))
							 | 
						|
										return(0);
							 | 
						|
									    res = zddReorderChildren(table, auxnode, CUDD_REORDER_GROUP_SIFT);
							 | 
						|
									    if (res == 0)
							 | 
						|
										return(0);
							 | 
						|
									} else if (auxnode->size > 1) {
							 | 
						|
									    if (!zddReorderChildren(table, auxnode, method))
							 | 
						|
										return(0);
							 | 
						|
									}
							 | 
						|
									auxnode = auxnode->younger;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of zddTreeSiftingAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Counts the number of internal nodes of the group tree.]
							 | 
						|
								
							 | 
						|
								  Description [Counts the number of internal nodes of the group tree.
							 | 
						|
								  Returns the count.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddCountInternalMtrNodes(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  MtrNode * treenode)
							 | 
						|
								{
							 | 
						|
								    MtrNode *auxnode;
							 | 
						|
								    int     count,nodeCount;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    nodeCount = 0;
							 | 
						|
								    auxnode = treenode;
							 | 
						|
								    while (auxnode != NULL) {
							 | 
						|
									if (!(MTR_TEST(auxnode,MTR_TERMINAL))) {
							 | 
						|
									    nodeCount++;
							 | 
						|
									    count = zddCountInternalMtrNodes(table,auxnode->child);
							 | 
						|
									    nodeCount += count;
							 | 
						|
									}
							 | 
						|
									auxnode = auxnode->younger;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(nodeCount);
							 | 
						|
								
							 | 
						|
								} /* end of zddCountInternalMtrNodes */
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Reorders the children of a group tree node according to
							 | 
						|
								  the options.]
							 | 
						|
								
							 | 
						|
								  Description [Reorders the children of a group tree node according to
							 | 
						|
								  the options. After reordering puts all the variables in the group
							 | 
						|
								  and/or its descendents in a single group. This allows hierarchical
							 | 
						|
								  reordering.  If the variables in the group do not exist yet, simply
							 | 
						|
								  does nothing. Returns 1 if successful; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddReorderChildren(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  MtrNode * treenode,
							 | 
						|
								  Cudd_ReorderingType method)
							 | 
						|
								{
							 | 
						|
								    int lower;
							 | 
						|
								    int upper;
							 | 
						|
								    int result;
							 | 
						|
								    unsigned int initialSize;
							 | 
						|
								
							 | 
						|
								    zddFindNodeHiLo(table,treenode,&lower,&upper);
							 | 
						|
								    /* If upper == -1 these variables do not exist yet. */
							 | 
						|
								    if (upper == -1)
							 | 
						|
									return(1);
							 | 
						|
								
							 | 
						|
								    if (treenode->flags == MTR_FIXED) {
							 | 
						|
									result = 1;
							 | 
						|
								    } else {
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
									(void) fprintf(table->out," ");
							 | 
						|
								#endif
							 | 
						|
									switch (method) {
							 | 
						|
									case CUDD_REORDER_RANDOM:
							 | 
						|
									case CUDD_REORDER_RANDOM_PIVOT:
							 | 
						|
									    result = cuddZddSwapping(table,lower,upper,method);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_SIFT:
							 | 
						|
									    result = cuddZddSifting(table,lower,upper);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_SIFT_CONVERGE:
							 | 
						|
									    do {
							 | 
						|
										initialSize = table->keysZ;
							 | 
						|
										result = cuddZddSifting(table,lower,upper);
							 | 
						|
										if (initialSize <= table->keysZ)
							 | 
						|
										    break;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
										else
							 | 
						|
										    (void) fprintf(table->out,"\n");
							 | 
						|
								#endif
							 | 
						|
									    } while (result != 0);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_SYMM_SIFT:
							 | 
						|
									    result = cuddZddSymmSifting(table,lower,upper);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_SYMM_SIFT_CONV:
							 | 
						|
									    result = cuddZddSymmSiftingConv(table,lower,upper);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_GROUP_SIFT:
							 | 
						|
									    result = zddGroupSifting(table,lower,upper);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_LINEAR:
							 | 
						|
									    result = cuddZddLinearSifting(table,lower,upper);
							 | 
						|
									    break;
							 | 
						|
									case CUDD_REORDER_LINEAR_CONVERGE:
							 | 
						|
									    do {
							 | 
						|
										initialSize = table->keysZ;
							 | 
						|
										result = cuddZddLinearSifting(table,lower,upper);
							 | 
						|
										if (initialSize <= table->keysZ)
							 | 
						|
										    break;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
										else
							 | 
						|
										    (void) fprintf(table->out,"\n");
							 | 
						|
								#endif
							 | 
						|
									    } while (result != 0);
							 | 
						|
									    break;
							 | 
						|
									default:
							 | 
						|
									    return(0);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Create a single group for all the variables that were sifted,
							 | 
						|
								    ** so that they will be treated as a single block by successive
							 | 
						|
								    ** invocations of zddGroupSifting.
							 | 
						|
								    */
							 | 
						|
								    zddMergeGroups(table,treenode,lower,upper);
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (pr > 0) (void) fprintf(table->out,"zddReorderChildren:");
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    return(result);
							 | 
						|
								
							 | 
						|
								} /* end of zddReorderChildren */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Finds the lower and upper bounds of the group represented
							 | 
						|
								  by treenode.]
							 | 
						|
								
							 | 
						|
								  Description [Finds the lower and upper bounds of the group represented
							 | 
						|
								  by treenode.  The high and low fields of treenode are indices.  From
							 | 
						|
								  those we need to derive the current positions, and find maximum and
							 | 
						|
								  minimum.]
							 | 
						|
								
							 | 
						|
								  SideEffects [The bounds are returned as side effects.]
							 | 
						|
								
							 | 
						|
								  SeeAlso     []
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								zddFindNodeHiLo(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  MtrNode * treenode,
							 | 
						|
								  int * lower,
							 | 
						|
								  int * upper)
							 | 
						|
								{
							 | 
						|
								    int low;
							 | 
						|
								    int high;
							 | 
						|
								
							 | 
						|
								    /* Check whether no variables in this group already exist.
							 | 
						|
								    ** If so, return immediately. The calling procedure will know from
							 | 
						|
								    ** the values of upper that no reordering is needed.
							 | 
						|
								    */
							 | 
						|
								    if ((int) treenode->low >= table->sizeZ) {
							 | 
						|
									*lower = table->sizeZ;
							 | 
						|
									*upper = -1;
							 | 
						|
									return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    *lower = low = (unsigned int) table->permZ[treenode->index];
							 | 
						|
								    high = (int) (low + treenode->size - 1);
							 | 
						|
								
							 | 
						|
								    if (high >= table->sizeZ) {
							 | 
						|
									/* This is the case of a partially existing group. The aim is to
							 | 
						|
									** reorder as many variables as safely possible.  If the tree
							 | 
						|
									** node is terminal, we just reorder the subset of the group
							 | 
						|
									** that is currently in existence.  If the group has
							 | 
						|
									** subgroups, then we only reorder those subgroups that are
							 | 
						|
									** fully instantiated.  This way we avoid breaking up a group.
							 | 
						|
									*/
							 | 
						|
									MtrNode *auxnode = treenode->child;
							 | 
						|
									if (auxnode == NULL) {
							 | 
						|
									    *upper = (unsigned int) table->sizeZ - 1;
							 | 
						|
									} else {
							 | 
						|
									    /* Search the subgroup that strands the table->sizeZ line.
							 | 
						|
									    ** If the first group starts at 0 and goes past table->sizeZ
							 | 
						|
									    ** upper will get -1, thus correctly signaling that no reordering
							 | 
						|
									    ** should take place.
							 | 
						|
									    */
							 | 
						|
									    while (auxnode != NULL) {
							 | 
						|
										int thisLower = table->permZ[auxnode->low];
							 | 
						|
										int thisUpper = thisLower + auxnode->size - 1;
							 | 
						|
										if (thisUpper >= table->sizeZ && thisLower < table->sizeZ)
							 | 
						|
										    *upper = (unsigned int) thisLower - 1;
							 | 
						|
										auxnode = auxnode->younger;
							 | 
						|
									    }
							 | 
						|
									}
							 | 
						|
								    } else {
							 | 
						|
									/* Normal case: All the variables of the group exist. */
							 | 
						|
									*upper = (unsigned int) high;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    /* Make sure that all variables in group are contiguous. */
							 | 
						|
								    assert(treenode->size >= *upper - *lower + 1);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of zddFindNodeHiLo */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Comparison function used by qsort.]
							 | 
						|
								
							 | 
						|
								  Description [Comparison function used by qsort to order the variables
							 | 
						|
								  according to the number of keys in the subtables.  Returns the
							 | 
						|
								  difference in number of keys between the two variables being
							 | 
						|
								  compared.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddUniqueCompareGroup(
							 | 
						|
								  int * ptrX,
							 | 
						|
								  int * ptrY)
							 | 
						|
								{
							 | 
						|
								#if 0
							 | 
						|
								    if (entry[*ptrY] == entry[*ptrX]) {
							 | 
						|
									return((*ptrX) - (*ptrY));
							 | 
						|
								    }
							 | 
						|
								#endif
							 | 
						|
								    return(entry[*ptrY] - entry[*ptrX]);
							 | 
						|
								
							 | 
						|
								} /* end of zddUniqueCompareGroup */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Sifts from treenode->low to treenode->high.]
							 | 
						|
								
							 | 
						|
								  Description [Sifts from treenode->low to treenode->high. If
							 | 
						|
								  croupcheck == CUDD_GROUP_CHECK7, it checks for group creation at the
							 | 
						|
								  end of the initial sifting. If a group is created, it is then sifted
							 | 
						|
								  again. After sifting one variable, the group that contains it is
							 | 
						|
								  dissolved.  Returns 1 in case of success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupSifting(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  int  lower,
							 | 
						|
								  int  upper)
							 | 
						|
								{
							 | 
						|
								    int		*var;
							 | 
						|
								    int		i,j,x,xInit;
							 | 
						|
								    int		nvars;
							 | 
						|
								    int		classes;
							 | 
						|
								    int		result;
							 | 
						|
								    int		*sifted;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
								    unsigned	previousSize;
							 | 
						|
								#endif
							 | 
						|
								    int		xindex;
							 | 
						|
								
							 | 
						|
								    nvars = table->sizeZ;
							 | 
						|
								
							 | 
						|
								    /* Order variables to sift. */
							 | 
						|
								    entry = NULL;
							 | 
						|
								    sifted = NULL;
							 | 
						|
								    var = ALLOC(int,nvars);
							 | 
						|
								    if (var == NULL) {
							 | 
						|
									table->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									goto zddGroupSiftingOutOfMem;
							 | 
						|
								    }
							 | 
						|
								    entry = ALLOC(int,nvars);
							 | 
						|
								    if (entry == NULL) {
							 | 
						|
									table->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									goto zddGroupSiftingOutOfMem;
							 | 
						|
								    }
							 | 
						|
								    sifted = ALLOC(int,nvars);
							 | 
						|
								    if (sifted == NULL) {
							 | 
						|
									table->errorCode = CUDD_MEMORY_OUT;
							 | 
						|
									goto zddGroupSiftingOutOfMem;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Here we consider only one representative for each group. */
							 | 
						|
								    for (i = 0, classes = 0; i < nvars; i++) {
							 | 
						|
									sifted[i] = 0;
							 | 
						|
									x = table->permZ[i];
							 | 
						|
									if ((unsigned) x >= table->subtableZ[x].next) {
							 | 
						|
									    entry[i] = table->subtableZ[x].keys;
							 | 
						|
									    var[classes] = i;
							 | 
						|
									    classes++;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    qsort((void *)var,classes,sizeof(int),(DD_QSFP)zddUniqueCompareGroup);
							 | 
						|
								
							 | 
						|
								    /* Now sift. */
							 | 
						|
								    for (i = 0; i < ddMin(table->siftMaxVar,classes); i++) {
							 | 
						|
									if (zddTotalNumberSwapping >= table->siftMaxSwap)
							 | 
						|
									    break;
							 | 
						|
								        if (util_cpu_time() - table->startTime > table->timeLimit) {
							 | 
						|
								            table->autoDynZ = 0; /* prevent further reordering */
							 | 
						|
								            break;
							 | 
						|
								        }
							 | 
						|
									xindex = var[i];
							 | 
						|
									if (sifted[xindex] == 1) /* variable already sifted as part of group */
							 | 
						|
									    continue;
							 | 
						|
									x = table->permZ[xindex]; /* find current level of this variable */
							 | 
						|
									if (x < lower || x > upper)
							 | 
						|
									    continue;
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
									previousSize = table->keysZ;
							 | 
						|
								#endif
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									/* x is bottom of group */
							 | 
						|
									assert((unsigned) x >= table->subtableZ[x].next);
							 | 
						|
								#endif
							 | 
						|
									result = zddGroupSiftingAux(table,x,lower,upper);
							 | 
						|
									if (!result) goto zddGroupSiftingOutOfMem;
							 | 
						|
								
							 | 
						|
								#ifdef DD_STATS
							 | 
						|
									if (table->keysZ < previousSize) {
							 | 
						|
									    (void) fprintf(table->out,"-");
							 | 
						|
									} else if (table->keysZ > previousSize) {
							 | 
						|
									    (void) fprintf(table->out,"+");
							 | 
						|
									} else {
							 | 
						|
									    (void) fprintf(table->out,"=");
							 | 
						|
									}
							 | 
						|
									fflush(table->out);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
									/* Mark variables in the group just sifted. */
							 | 
						|
									x = table->permZ[xindex];
							 | 
						|
									if ((unsigned) x != table->subtableZ[x].next) {
							 | 
						|
									    xInit = x;
							 | 
						|
									    do {
							 | 
						|
										j = table->invpermZ[x];
							 | 
						|
										sifted[j] = 1;
							 | 
						|
										x = table->subtableZ[x].next;
							 | 
						|
									    } while (x != xInit);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									if (pr > 0) (void) fprintf(table->out,"zddGroupSifting:");
							 | 
						|
								#endif
							 | 
						|
								    } /* for */
							 | 
						|
								
							 | 
						|
								    FREE(sifted);
							 | 
						|
								    FREE(var);
							 | 
						|
								    FREE(entry);
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								zddGroupSiftingOutOfMem:
							 | 
						|
								    if (entry != NULL)	FREE(entry);
							 | 
						|
								    if (var != NULL)	FREE(var);
							 | 
						|
								    if (sifted != NULL)	FREE(sifted);
							 | 
						|
								
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupSifting */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Sifts one variable up and down until it has taken all
							 | 
						|
								  positions. Checks for aggregation.]
							 | 
						|
								
							 | 
						|
								  Description [Sifts one variable up and down until it has taken all
							 | 
						|
								  positions. Checks for aggregation. There may be at most two sweeps,
							 | 
						|
								  even if the group grows.  Assumes that x is either an isolated
							 | 
						|
								  variable, or it is the bottom of a group. All groups may not have
							 | 
						|
								  been found. The variable being moved is returned to the best position
							 | 
						|
								  seen during sifting.  Returns 1 in case of success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupSiftingAux(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  int  x,
							 | 
						|
								  int  xLow,
							 | 
						|
								  int  xHigh)
							 | 
						|
								{
							 | 
						|
								    Move *move;
							 | 
						|
								    Move *moves;	/* list of moves */
							 | 
						|
								    int  initialSize;
							 | 
						|
								    int  result;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingAux from %d to %d\n",xLow,xHigh);
							 | 
						|
								    assert((unsigned) x >= table->subtableZ[x].next); /* x is bottom of group */
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    initialSize = table->keysZ;
							 | 
						|
								    moves = NULL;
							 | 
						|
								
							 | 
						|
								    if (x == xLow) { /* Sift down */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									/* x must be a singleton */
							 | 
						|
									assert((unsigned) x == table->subtableZ[x].next);
							 | 
						|
								#endif
							 | 
						|
									if (x == xHigh) return(1);	/* just one variable */
							 | 
						|
								
							 | 
						|
									if (!zddGroupSiftingDown(table,x,xHigh,&moves))
							 | 
						|
									    goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
									/* at this point x == xHigh, unless early term */
							 | 
						|
								
							 | 
						|
									/* move backward and stop at best position */
							 | 
						|
									result = zddGroupSiftingBackward(table,moves,initialSize);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(table->keysZ <= (unsigned) initialSize);
							 | 
						|
								#endif
							 | 
						|
									if (!result) goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
								
							 | 
						|
								    } else if (cuddZddNextHigh(table,x) > xHigh) { /* Sift up */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									/* x is bottom of group */
							 | 
						|
									assert((unsigned) x >= table->subtableZ[x].next);
							 | 
						|
								#endif
							 | 
						|
									/* Find top of x's group */
							 | 
						|
									x = table->subtableZ[x].next;
							 | 
						|
								
							 | 
						|
									if (!zddGroupSiftingUp(table,x,xLow,&moves))
							 | 
						|
									    goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
									/* at this point x == xLow, unless early term */
							 | 
						|
								
							 | 
						|
									/* move backward and stop at best position */
							 | 
						|
									result = zddGroupSiftingBackward(table,moves,initialSize);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(table->keysZ <= (unsigned) initialSize);
							 | 
						|
								#endif
							 | 
						|
									if (!result) goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
								
							 | 
						|
								    } else if (x - xLow > xHigh - x) { /* must go down first: shorter */
							 | 
						|
									if (!zddGroupSiftingDown(table,x,xHigh,&moves))
							 | 
						|
									    goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
									/* at this point x == xHigh, unless early term */
							 | 
						|
								
							 | 
						|
									/* Find top of group */
							 | 
						|
									if (moves) {
							 | 
						|
									    x = moves->y;
							 | 
						|
									}
							 | 
						|
									while ((unsigned) x < table->subtableZ[x].next)
							 | 
						|
									    x = table->subtableZ[x].next;
							 | 
						|
									x = table->subtableZ[x].next;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									/* x should be the top of a group */
							 | 
						|
									assert((unsigned) x <= table->subtableZ[x].next);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
									if (!zddGroupSiftingUp(table,x,xLow,&moves))
							 | 
						|
									    goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
								
							 | 
						|
									/* move backward and stop at best position */
							 | 
						|
									result = zddGroupSiftingBackward(table,moves,initialSize);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(table->keysZ <= (unsigned) initialSize);
							 | 
						|
								#endif
							 | 
						|
									if (!result) goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
								
							 | 
						|
								    } else { /* moving up first: shorter */
							 | 
						|
									/* Find top of x's group */
							 | 
						|
									x = table->subtableZ[x].next;
							 | 
						|
								
							 | 
						|
									if (!zddGroupSiftingUp(table,x,xLow,&moves))
							 | 
						|
									    goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
									/* at this point x == xHigh, unless early term */
							 | 
						|
								
							 | 
						|
									if (moves) {
							 | 
						|
									    x = moves->x;
							 | 
						|
									}
							 | 
						|
									while ((unsigned) x < table->subtableZ[x].next)
							 | 
						|
									    x = table->subtableZ[x].next;
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									/* x is bottom of a group */
							 | 
						|
									assert((unsigned) x >= table->subtableZ[x].next);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
									if (!zddGroupSiftingDown(table,x,xHigh,&moves))
							 | 
						|
									    goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
								
							 | 
						|
									/* move backward and stop at best position */
							 | 
						|
									result = zddGroupSiftingBackward(table,moves,initialSize);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									assert(table->keysZ <= (unsigned) initialSize);
							 | 
						|
								#endif
							 | 
						|
									if (!result) goto zddGroupSiftingAuxOutOfMem;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    while (moves != NULL) {
							 | 
						|
									move = moves->next;
							 | 
						|
									cuddDeallocMove(table, moves);
							 | 
						|
									moves = move;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								zddGroupSiftingAuxOutOfMem:
							 | 
						|
								    while (moves != NULL) {
							 | 
						|
									move = moves->next;
							 | 
						|
									cuddDeallocMove(table, moves);
							 | 
						|
									moves = move;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupSiftingAux */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Sifts up a variable until either it reaches position xLow
							 | 
						|
								  or the size of the DD heap increases too much.]
							 | 
						|
								
							 | 
						|
								  Description [Sifts up a variable until either it reaches position
							 | 
						|
								  xLow or the size of the DD heap increases too much. Assumes that y is
							 | 
						|
								  the top of a group (or a singleton).  Checks y for aggregation to the
							 | 
						|
								  adjacent variables. Records all the moves that are appended to the
							 | 
						|
								  list of moves received as input and returned as a side effect.
							 | 
						|
								  Returns 1 in case of success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupSiftingUp(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  int  y,
							 | 
						|
								  int  xLow,
							 | 
						|
								  Move ** moves)
							 | 
						|
								{
							 | 
						|
								    Move *move;
							 | 
						|
								    int  x;
							 | 
						|
								    int  size;
							 | 
						|
								    int  gxtop;
							 | 
						|
								    int  limitSize;
							 | 
						|
								
							 | 
						|
								    limitSize = table->keysZ;
							 | 
						|
								
							 | 
						|
								    x = cuddZddNextLow(table,y);
							 | 
						|
								    while (x >= xLow) {
							 | 
						|
									gxtop = table->subtableZ[x].next;
							 | 
						|
									if (table->subtableZ[x].next == (unsigned) x &&
							 | 
						|
									    table->subtableZ[y].next == (unsigned) y) {
							 | 
						|
									    /* x and y are self groups */
							 | 
						|
									    size = cuddZddSwapInPlace(table,x,y);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    assert(table->subtableZ[x].next == (unsigned) x);
							 | 
						|
									    assert(table->subtableZ[y].next == (unsigned) y);
							 | 
						|
								#endif
							 | 
						|
									    if (size == 0) goto zddGroupSiftingUpOutOfMem;
							 | 
						|
									    move = (Move *)cuddDynamicAllocNode(table);
							 | 
						|
									    if (move == NULL) goto zddGroupSiftingUpOutOfMem;
							 | 
						|
									    move->x = x;
							 | 
						|
									    move->y = y;
							 | 
						|
									    move->flags = MTR_DEFAULT;
							 | 
						|
									    move->size = size;
							 | 
						|
									    move->next = *moves;
							 | 
						|
									    *moves = move;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingUp (2 single groups):\n");
							 | 
						|
								#endif
							 | 
						|
									    if ((double) size > (double) limitSize * table->maxGrowth)
							 | 
						|
										return(1);
							 | 
						|
									    if (size < limitSize) limitSize = size;
							 | 
						|
									} else { /* group move */
							 | 
						|
									    size = zddGroupMove(table,x,y,moves);
							 | 
						|
									    if (size == 0) goto zddGroupSiftingUpOutOfMem;
							 | 
						|
									    if ((double) size > (double) limitSize * table->maxGrowth)
							 | 
						|
										return(1);
							 | 
						|
									    if (size < limitSize) limitSize = size;
							 | 
						|
									}
							 | 
						|
									y = gxtop;
							 | 
						|
									x = cuddZddNextLow(table,y);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								zddGroupSiftingUpOutOfMem:
							 | 
						|
								    while (*moves != NULL) {
							 | 
						|
									move = (*moves)->next;
							 | 
						|
									cuddDeallocMove(table, *moves);
							 | 
						|
									*moves = move;
							 | 
						|
								    }
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupSiftingUp */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Sifts down a variable until it reaches position xHigh.]
							 | 
						|
								
							 | 
						|
								  Description [Sifts down a variable until it reaches position xHigh.
							 | 
						|
								  Assumes that x is the bottom of a group (or a singleton).  Records
							 | 
						|
								  all the moves.  Returns 1 in case of success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupSiftingDown(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  int  x,
							 | 
						|
								  int  xHigh,
							 | 
						|
								  Move ** moves)
							 | 
						|
								{
							 | 
						|
								    Move *move;
							 | 
						|
								    int  y;
							 | 
						|
								    int  size;
							 | 
						|
								    int  limitSize;
							 | 
						|
								    int  gybot;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    /* Initialize R */
							 | 
						|
								    limitSize = size = table->keysZ;
							 | 
						|
								    y = cuddZddNextHigh(table,x);
							 | 
						|
								    while (y <= xHigh) {
							 | 
						|
									/* Find bottom of y group. */
							 | 
						|
									gybot = table->subtableZ[y].next;
							 | 
						|
									while (table->subtableZ[gybot].next != (unsigned) y)
							 | 
						|
									    gybot = table->subtableZ[gybot].next;
							 | 
						|
								
							 | 
						|
									if (table->subtableZ[x].next == (unsigned) x &&
							 | 
						|
									    table->subtableZ[y].next == (unsigned) y) {
							 | 
						|
									    /* x and y are self groups */
							 | 
						|
									    size = cuddZddSwapInPlace(table,x,y);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    assert(table->subtableZ[x].next == (unsigned) x);
							 | 
						|
									    assert(table->subtableZ[y].next == (unsigned) y);
							 | 
						|
								#endif
							 | 
						|
									    if (size == 0) goto zddGroupSiftingDownOutOfMem;
							 | 
						|
								
							 | 
						|
									    /* Record move. */
							 | 
						|
									    move = (Move *) cuddDynamicAllocNode(table);
							 | 
						|
									    if (move == NULL) goto zddGroupSiftingDownOutOfMem;
							 | 
						|
									    move->x = x;
							 | 
						|
									    move->y = y;
							 | 
						|
									    move->flags = MTR_DEFAULT;
							 | 
						|
									    move->size = size;
							 | 
						|
									    move->next = *moves;
							 | 
						|
									    *moves = move;
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingDown (2 single groups):\n");
							 | 
						|
								#endif
							 | 
						|
									    if ((double) size > (double) limitSize * table->maxGrowth)
							 | 
						|
										return(1);
							 | 
						|
									    if (size < limitSize) limitSize = size;
							 | 
						|
									    x = y;
							 | 
						|
									    y = cuddZddNextHigh(table,x);
							 | 
						|
									} else { /* Group move */
							 | 
						|
									    size = zddGroupMove(table,x,y,moves);
							 | 
						|
									    if (size == 0) goto zddGroupSiftingDownOutOfMem;
							 | 
						|
									    if ((double) size > (double) limitSize * table->maxGrowth)
							 | 
						|
										return(1);
							 | 
						|
									    if (size < limitSize) limitSize = size;
							 | 
						|
									}
							 | 
						|
									x = gybot;
							 | 
						|
									y = cuddZddNextHigh(table,x);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								zddGroupSiftingDownOutOfMem:
							 | 
						|
								    while (*moves != NULL) {
							 | 
						|
									move = (*moves)->next;
							 | 
						|
									cuddDeallocMove(table, *moves);
							 | 
						|
									*moves = move;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupSiftingDown */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Swaps two groups and records the move.]
							 | 
						|
								
							 | 
						|
								  Description [Swaps two groups and records the move. Returns the
							 | 
						|
								  number of keys in the DD table in case of success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupMove(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  int  x,
							 | 
						|
								  int  y,
							 | 
						|
								  Move ** moves)
							 | 
						|
								{
							 | 
						|
								    Move *move;
							 | 
						|
								    int  size;
							 | 
						|
								    int  i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
							 | 
						|
								    int  swapx,swapy;
							 | 
						|
								#if defined(DD_DEBUG) && defined(DD_VERBOSE)
							 | 
						|
								    int  initialSize,bestSize;
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    /* We assume that x < y */
							 | 
						|
								    assert(x < y);
							 | 
						|
								#endif
							 | 
						|
								    /* Find top, bottom, and size for the two groups. */
							 | 
						|
								    xbot = x;
							 | 
						|
								    xtop = table->subtableZ[x].next;
							 | 
						|
								    xsize = xbot - xtop + 1;
							 | 
						|
								    ybot = y;
							 | 
						|
								    while ((unsigned) ybot < table->subtableZ[ybot].next)
							 | 
						|
									ybot = table->subtableZ[ybot].next;
							 | 
						|
								    ytop = y;
							 | 
						|
								    ysize = ybot - ytop + 1;
							 | 
						|
								
							 | 
						|
								#if defined(DD_DEBUG) && defined(DD_VERBOSE)
							 | 
						|
								    initialSize = bestSize = table->keysZ;
							 | 
						|
								#endif
							 | 
						|
								    /* Sift the variables of the second group up through the first group */
							 | 
						|
								    for (i = 1; i <= ysize; i++) {
							 | 
						|
									for (j = 1; j <= xsize; j++) {
							 | 
						|
									    size = cuddZddSwapInPlace(table,x,y);
							 | 
						|
									    if (size == 0) goto zddGroupMoveOutOfMem;
							 | 
						|
								#if defined(DD_DEBUG) && defined(DD_VERBOSE)
							 | 
						|
									    if (size < bestSize)
							 | 
						|
										bestSize = size;
							 | 
						|
								#endif
							 | 
						|
									    swapx = x; swapy = y;
							 | 
						|
									    y = x;
							 | 
						|
									    x = cuddZddNextLow(table,y);
							 | 
						|
									}
							 | 
						|
									y = ytop + i;
							 | 
						|
									x = cuddZddNextLow(table,y);
							 | 
						|
								    }
							 | 
						|
								#if defined(DD_DEBUG) && defined(DD_VERBOSE)
							 | 
						|
								    if ((bestSize < initialSize) && (bestSize < size))
							 | 
						|
									(void) fprintf(table->out,"Missed local minimum: initialSize:%d  bestSize:%d  finalSize:%d\n",initialSize,bestSize,size);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* fix groups */
							 | 
						|
								    y = xtop; /* ytop is now where xtop used to be */
							 | 
						|
								    for (i = 0; i < ysize - 1; i++) {
							 | 
						|
									table->subtableZ[y].next = cuddZddNextHigh(table,y);
							 | 
						|
									y = cuddZddNextHigh(table,y);
							 | 
						|
								    }
							 | 
						|
								    table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
							 | 
						|
												    /* it to top of its group */
							 | 
						|
								    x = cuddZddNextHigh(table,y);
							 | 
						|
								    newxtop = x;
							 | 
						|
								    for (i = 0; i < xsize - 1; i++) {
							 | 
						|
									table->subtableZ[x].next = cuddZddNextHigh(table,x);
							 | 
						|
									x = cuddZddNextHigh(table,x);
							 | 
						|
								    }
							 | 
						|
								    table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
							 | 
						|
												    /* it to top of its group */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (pr > 0) (void) fprintf(table->out,"zddGroupMove:\n");
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Store group move */
							 | 
						|
								    move = (Move *) cuddDynamicAllocNode(table);
							 | 
						|
								    if (move == NULL) goto zddGroupMoveOutOfMem;
							 | 
						|
								    move->x = swapx;
							 | 
						|
								    move->y = swapy;
							 | 
						|
								    move->flags = MTR_DEFAULT;
							 | 
						|
								    move->size = table->keysZ;
							 | 
						|
								    move->next = *moves;
							 | 
						|
								    *moves = move;
							 | 
						|
								
							 | 
						|
								    return(table->keysZ);
							 | 
						|
								
							 | 
						|
								zddGroupMoveOutOfMem:
							 | 
						|
								    while (*moves != NULL) {
							 | 
						|
									move = (*moves)->next;
							 | 
						|
									cuddDeallocMove(table, *moves);
							 | 
						|
									*moves = move;
							 | 
						|
								    }
							 | 
						|
								    return(0);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupMove */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Undoes the swap two groups.]
							 | 
						|
								
							 | 
						|
								  Description [Undoes the swap two groups.  Returns 1 in case of
							 | 
						|
								  success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupMoveBackward(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  int  x,
							 | 
						|
								  int  y)
							 | 
						|
								{
							 | 
						|
								    int size;
							 | 
						|
								    int i,j,xtop,xbot,xsize,ytop,ybot,ysize,newxtop;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    /* We assume that x < y */
							 | 
						|
								    assert(x < y);
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    /* Find top, bottom, and size for the two groups. */
							 | 
						|
								    xbot = x;
							 | 
						|
								    xtop = table->subtableZ[x].next;
							 | 
						|
								    xsize = xbot - xtop + 1;
							 | 
						|
								    ybot = y;
							 | 
						|
								    while ((unsigned) ybot < table->subtableZ[ybot].next)
							 | 
						|
									ybot = table->subtableZ[ybot].next;
							 | 
						|
								    ytop = y;
							 | 
						|
								    ysize = ybot - ytop + 1;
							 | 
						|
								
							 | 
						|
								    /* Sift the variables of the second group up through the first group */
							 | 
						|
								    for (i = 1; i <= ysize; i++) {
							 | 
						|
									for (j = 1; j <= xsize; j++) {
							 | 
						|
									    size = cuddZddSwapInPlace(table,x,y);
							 | 
						|
									    if (size == 0)
							 | 
						|
										return(0);
							 | 
						|
									    y = x;
							 | 
						|
									    x = cuddZddNextLow(table,y);
							 | 
						|
									}
							 | 
						|
									y = ytop + i;
							 | 
						|
									x = cuddZddNextLow(table,y);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* fix groups */
							 | 
						|
								    y = xtop;
							 | 
						|
								    for (i = 0; i < ysize - 1; i++) {
							 | 
						|
									table->subtableZ[y].next = cuddZddNextHigh(table,y);
							 | 
						|
									y = cuddZddNextHigh(table,y);
							 | 
						|
								    }
							 | 
						|
								    table->subtableZ[y].next = xtop; /* y is bottom of its group, join */
							 | 
						|
												    /* to its top */
							 | 
						|
								    x = cuddZddNextHigh(table,y);
							 | 
						|
								    newxtop = x;
							 | 
						|
								    for (i = 0; i < xsize - 1; i++) {
							 | 
						|
									table->subtableZ[x].next = cuddZddNextHigh(table,x);
							 | 
						|
									x = cuddZddNextHigh(table,x);
							 | 
						|
								    }
							 | 
						|
								    table->subtableZ[x].next = newxtop; /* x is bottom of its group, join */
							 | 
						|
												    /* to its top */
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
								    if (pr > 0) (void) fprintf(table->out,"zddGroupMoveBackward:\n");
							 | 
						|
								#endif
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupMoveBackward */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Determines the best position for a variables and returns
							 | 
						|
								  it there.]
							 | 
						|
								
							 | 
						|
								  Description [Determines the best position for a variables and returns
							 | 
						|
								  it there.  Returns 1 in case of success; 0 otherwise.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static int
							 | 
						|
								zddGroupSiftingBackward(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  Move * moves,
							 | 
						|
								  int  size)
							 | 
						|
								{
							 | 
						|
								    Move *move;
							 | 
						|
								    int  res;
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    for (move = moves; move != NULL; move = move->next) {
							 | 
						|
									if (move->size < size) {
							 | 
						|
									    size = move->size;
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    for (move = moves; move != NULL; move = move->next) {
							 | 
						|
									if (move->size == size) return(1);
							 | 
						|
									if ((table->subtableZ[move->x].next == move->x) &&
							 | 
						|
									(table->subtableZ[move->y].next == move->y)) {
							 | 
						|
									    res = cuddZddSwapInPlace(table,(int)move->x,(int)move->y);
							 | 
						|
									    if (!res) return(0);
							 | 
						|
								#ifdef DD_DEBUG
							 | 
						|
									    if (pr > 0) (void) fprintf(table->out,"zddGroupSiftingBackward:\n");
							 | 
						|
									    assert(table->subtableZ[move->x].next == move->x);
							 | 
						|
									    assert(table->subtableZ[move->y].next == move->y);
							 | 
						|
								#endif
							 | 
						|
									} else { /* Group move necessary */
							 | 
						|
									    res = zddGroupMoveBackward(table,(int)move->x,(int)move->y);
							 | 
						|
									    if (!res) return(0);
							 | 
						|
									}
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    return(1);
							 | 
						|
								
							 | 
						|
								} /* end of zddGroupSiftingBackward */
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								/**Function********************************************************************
							 | 
						|
								
							 | 
						|
								  Synopsis    [Merges groups in the DD table.]
							 | 
						|
								
							 | 
						|
								  Description [Creates a single group from low to high and adjusts the
							 | 
						|
								  idex field of the tree node.]
							 | 
						|
								
							 | 
						|
								  SideEffects [None]
							 | 
						|
								
							 | 
						|
								******************************************************************************/
							 | 
						|
								static void
							 | 
						|
								zddMergeGroups(
							 | 
						|
								  DdManager * table,
							 | 
						|
								  MtrNode * treenode,
							 | 
						|
								  int  low,
							 | 
						|
								  int  high)
							 | 
						|
								{
							 | 
						|
								    int i;
							 | 
						|
								    MtrNode *auxnode;
							 | 
						|
								    int saveindex;
							 | 
						|
								    int newindex;
							 | 
						|
								
							 | 
						|
								    /* Merge all variables from low to high in one group, unless
							 | 
						|
								    ** this is the topmost group. In such a case we do not merge lest
							 | 
						|
								    ** we lose the symmetry information. */
							 | 
						|
								    if (treenode != table->treeZ) {
							 | 
						|
									for (i = low; i < high; i++)
							 | 
						|
									    table->subtableZ[i].next = i+1;
							 | 
						|
									table->subtableZ[high].next = low;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /* Adjust the index fields of the tree nodes. If a node is the
							 | 
						|
								    ** first child of its parent, then the parent may also need adjustment. */
							 | 
						|
								    saveindex = treenode->index;
							 | 
						|
								    newindex = table->invpermZ[low];
							 | 
						|
								    auxnode = treenode;
							 | 
						|
								    do {
							 | 
						|
									auxnode->index = newindex;
							 | 
						|
									if (auxnode->parent == NULL ||
							 | 
						|
										(int) auxnode->parent->index != saveindex)
							 | 
						|
									    break;
							 | 
						|
									auxnode = auxnode->parent;
							 | 
						|
								    } while (1);
							 | 
						|
								    return;
							 | 
						|
								
							 | 
						|
								} /* end of zddMergeGroups */
							 |