/**CFile***********************************************************************
  FileName    [zSubSet.c]
  PackageName [extra]
  Synopsis    [Experimental version of some ZDD operators.]
  Description [External procedures included in this module:
		    
		    -  Extra_zddSubSet();
		    
 -  Extra_zddSupSet();
		    
 -  Extra_zddNotSubSet();
		    
 -  Extra_zddNotSupSet();
		    
 -  Extra_zddMaxNotSupSet();
			
 -  Extra_zddEmptyBelongs();
			
 -  Extra_zddIsOneSubset();
		    
 
	       Internal procedures included in this module:
		    
		    -  extraZddSubSet();
		    
 -  extraZddSupSet();
		    
 -  extraZddNotSubSet();
		    
 -  extraZddNotSupSet();
		    
 -  extraZddMaxNotSupSet();
		    
 
	       Static procedures included in this module:
		    
          SubSet, SupSet, NotSubSet, NotSupSet were introduced 
		  by O.Coudert to solve problems arising in two-level SOP 
		  minimization. See O. Coudert, "Two-Level Logic Minimization: 
		  An Overview", Integration. Vol. 17, No. 2, pp. 97-140, Oct 1994.
	      ]
  SeeAlso     []
  Author      [Alan Mishchenko]
  Copyright   []
  Revision    [$zSubSet.c, v.1.2, November 16, 2000, alanmi $]
******************************************************************************/
#include "extraBdd.h"
ABC_NAMESPACE_IMPL_START
/*---------------------------------------------------------------------------*/
/* Constant declarations                                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Stucture declarations                                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Type declarations                                                         */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Variable declarations                                                     */
/*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*/
/* Macro declarations                                                        */
/*---------------------------------------------------------------------------*/
/**AutomaticStart*************************************************************/
/*---------------------------------------------------------------------------*/
/* Static function prototypes                                                */
/*---------------------------------------------------------------------------*/
/**AutomaticEnd***************************************************************/
/*---------------------------------------------------------------------------*/
/* Definition of exported functions                                          */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
  Synopsis    [Computes subsets in X that are contained in some of the subsets of Y.]
  Description []
  SideEffects []
  SeeAlso     [Extra_zddNotSubSet, Extra_zddSupSet, Extra_zddNotSupSet]
******************************************************************************/
DdNode	*
Extra_zddSubSet(
  DdManager * dd,
  DdNode * X,
  DdNode * Y)
{
    DdNode	*res;
    int		autoDynZ;
    autoDynZ = dd->autoDynZ;
    dd->autoDynZ = 0;
    do {
	dd->reordered = 0;
	res = extraZddSubSet(dd, X, Y);
    } while (dd->reordered == 1);
    dd->autoDynZ = autoDynZ;
    return(res);
} /* end of Extra_zddSubSet */
/**Function********************************************************************
  Synopsis    [Computes subsets in X that contain some of the subsets of Y.]
  Description []
  SideEffects []
  SeeAlso     [Extra_zddSubSet, Extra_zddNotSubSet, Extra_zddNotSupSet]
******************************************************************************/
DdNode	*
Extra_zddSupSet(
  DdManager * dd,
  DdNode * X,
  DdNode * Y)
{
    DdNode	*res;
    int		autoDynZ;
    autoDynZ = dd->autoDynZ;
    dd->autoDynZ = 0;
    do {
	dd->reordered = 0;
	res = extraZddSupSet(dd, X, Y);
    } while (dd->reordered == 1);
    dd->autoDynZ = autoDynZ;
    return(res);
} /* end of Extra_zddSupSet */
/**Function********************************************************************
  Synopsis    [Computes subsets in X that are not contained in any of the subsets of Y.]
  Description []
  SideEffects []
  SeeAlso     [Extra_zddSubSet, Extra_zddSupSet, Extra_zddNotSupSet]
******************************************************************************/
DdNode	*
Extra_zddNotSubSet(
  DdManager * dd,
  DdNode * X,
  DdNode * Y)
{
    DdNode	*res;
    int		autoDynZ;
    autoDynZ = dd->autoDynZ;
    dd->autoDynZ = 0;
    do {
	dd->reordered = 0;
	res = extraZddNotSubSet(dd, X, Y);
    } while (dd->reordered == 1);
    dd->autoDynZ = autoDynZ;
    return(res);
} /* end of Extra_zddNotSubSet */
/**Function********************************************************************
  Synopsis    [Computes subsets in X that do not contain any of the subsets of Y.]
  Description []
  SideEffects []
  SeeAlso     [Extra_zddSubSet, Extra_zddSupSet, Extra_zddNotSubSet]
******************************************************************************/
DdNode	*
Extra_zddNotSupSet(
  DdManager * dd,
  DdNode * X,
  DdNode * Y)
{
    DdNode	*res;
    int		autoDynZ;
    autoDynZ = dd->autoDynZ;
    dd->autoDynZ = 0;
    do {
	dd->reordered = 0;
	res = extraZddNotSupSet(dd, X, Y);
    } while (dd->reordered == 1);
    dd->autoDynZ = autoDynZ;
    return(res);
} /* end of Extra_zddNotSupSet */
/**Function********************************************************************
  Synopsis    [Computes the maximal of subsets in X not contained in any of the subsets of Y.]
  Description []
  SideEffects []
  SeeAlso     [Extra_zddSubSet, Extra_zddSupSet, Extra_zddSubSet, Extra_zddNotSupSet]
******************************************************************************/
DdNode	*
Extra_zddMaxNotSupSet(
  DdManager * dd,
  DdNode * X,
  DdNode * Y)
{
    DdNode	*res;
    int		autoDynZ;
    autoDynZ = dd->autoDynZ;
    dd->autoDynZ = 0;
    do {
	dd->reordered = 0;
	res = extraZddMaxNotSupSet(dd, X, Y);
    } while (dd->reordered == 1);
    dd->autoDynZ = autoDynZ;
    return(res);
} /* end of Extra_zddMaxNotSupSet */
/**Function********************************************************************
  Synopsis    [Returns 1 if ZDD contains the empty combination; 0 otherwise.]
  Description []
  SideEffects []
  SeeAlso     []
******************************************************************************/
int 
Extra_zddEmptyBelongs(
  DdManager *dd, 
  DdNode* zS )
{
	while ( zS->index != CUDD_MAXINDEX )
		zS = cuddE( zS );
	return (int)( zS == z1 );
} /* end of Extra_zddEmptyBelongs */
/**Function********************************************************************
  Synopsis    [Returns 1 if the set is empty or consists of one subset only.]
  Description []
  SideEffects []
  SeeAlso     []
******************************************************************************/
int 
Extra_zddIsOneSubset(
  DdManager * dd, 
  DdNode * zS )
{
	while ( zS->index != CUDD_MAXINDEX )
	{
		assert( cuddT(zS) != z0 );
		if ( cuddE(zS) != z0 )
			return 0;
		zS = cuddT( zS );
	}
	return (int)( zS == z1 );
} /* end of Extra_zddEmptyBelongs */
/*---------------------------------------------------------------------------*/
/* Definition of internal functions                                          */
/*---------------------------------------------------------------------------*/
/**Function********************************************************************
  Synopsis [Performs the recursive step of Extra_zddSubSet.]
  Description []
  SideEffects [None]
  SeeAlso     []
******************************************************************************/
DdNode* extraZddSubSet( DdManager *dd, DdNode *X, DdNode *Y )
{	
	DdNode *zRes;
    statLine(dd); 
	/* any comb is a subset of itself */
	if ( X == Y ) 
		return X;
	/* if X is empty, the result is empty */
	if ( X == z0 ) 
		return z0;
	/* combs in X are notsubsets of non-existant combs in Y */
	if ( Y == z0 ) 
		return z0;
	/* the empty comb is contained in all combs of Y */
	if ( X == z1 ) 
		return z1;
	/* only {()} is the subset of {()} */
	if ( Y == z1 ) /* check whether the empty combination is present in X */ 
		return ( Extra_zddEmptyBelongs( dd, X )? z1: z0 );
    /* check cache */
    zRes = cuddCacheLookup2Zdd(dd, extraZddSubSet, X, Y);
    if (zRes)
    	return(zRes);
	else
	{
		DdNode *zRes0, *zRes1, *zTemp;
		int TopLevelX = dd->permZ[ X->index ];
		int TopLevelY = dd->permZ[ Y->index ];
		if ( TopLevelX < TopLevelY )
		{
			/* compute combs of X without var that are notsubsets of combs with Y */
			zRes = extraZddSubSet( dd, cuddE( X ), Y );
			if ( zRes == NULL )  return NULL;
		}
		else if ( TopLevelX == TopLevelY )
		{
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )
				return NULL;
			cuddRef( zTemp );
			/* compute combs of X without var that are notsubsets of combs is Temp */
			zRes0 = extraZddSubSet( dd, cuddE( X ), zTemp );
			if ( zRes0 == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes0 );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			/* combs of X with var that are notsubsets of combs in Y with var */
			zRes1 = extraZddSubSet( dd, cuddT( X ), cuddT( Y ) );
			if ( zRes1 == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zRes1 );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else /* if ( TopLevelX > TopLevelY ) */
		{
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )  return NULL;
			cuddRef( zTemp );
			/* compute combs that are notsubsets of Temp */
			zRes = extraZddSubSet( dd, X, zTemp );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			cuddDeref( zRes );
		}
		/* insert the result into cache */
	    cuddCacheInsert2(dd, extraZddSubSet, X, Y, zRes);
		return zRes;
	}
} /* end of extraZddSubSet */
/**Function********************************************************************
  Synopsis [Performs the recursive step of Extra_zddSupSet.]
  Description []
  SideEffects [None]
  SeeAlso     []
******************************************************************************/
DdNode* extraZddSupSet( DdManager *dd, DdNode *X, DdNode *Y )
{	
	DdNode *zRes;
    statLine(dd); 
	/* any comb is a superset of itself */
	if ( X == Y ) 
		return X;
	/* no comb in X is superset of non-existing combs */
	if ( Y == z0 ) 
		return z0;	
	/* any comb in X is the superset of the empty comb */
	if ( Extra_zddEmptyBelongs( dd, Y ) ) 
		return X;
	/* if X is empty, the result is empty */
	if ( X == z0 ) 
		return z0;
	/* if X is the empty comb (and Y does not contain it!), return empty */
	if ( X == z1 ) 
		return z0;
    /* check cache */
    zRes = cuddCacheLookup2Zdd(dd, extraZddSupSet, X, Y);
    if (zRes)
    	return(zRes);
	else
	{
		DdNode *zRes0, *zRes1, *zTemp;
		int TopLevelX = dd->permZ[ X->index ];
		int TopLevelY = dd->permZ[ Y->index ];
		if ( TopLevelX < TopLevelY )
		{
			/* combinations of X without label that are supersets of combinations with Y */
			zRes0 = extraZddSupSet( dd, cuddE( X ), Y );
			if ( zRes0 == NULL )  return NULL;
			cuddRef( zRes0 );
			/* combinations of X with label that are supersets of combinations with Y */
			zRes1 = extraZddSupSet( dd, cuddT( X ), Y );
			if ( zRes1 == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zRes1 );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else if ( TopLevelX == TopLevelY )
		{
			/* combs of X without var that are supersets of combs of Y without var */
			zRes0 = extraZddSupSet( dd, cuddE( X ), cuddE( Y ) );
			if ( zRes0 == NULL )  return NULL;
			cuddRef( zRes0 );
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zTemp );
			/* combs of X with label that are supersets of combs in Temp */
			zRes1 = extraZddSupSet( dd, cuddT( X ), zTemp );
			if ( zRes1 == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes1 );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else /* if ( TopLevelX > TopLevelY ) */
		{
			/* combs of X that are supersets of combs of Y without label */
			zRes = extraZddSupSet( dd, X, cuddE( Y ) );
			if ( zRes == NULL )  return NULL;
		}
		/* insert the result into cache */
	    cuddCacheInsert2(dd, extraZddSupSet, X, Y, zRes);
		return zRes;
	}
} /* end of extraZddSupSet */
/**Function********************************************************************
  Synopsis [Performs the recursive step of Extra_zddNotSubSet.]
  Description []
  SideEffects [None]
  SeeAlso     []
******************************************************************************/
DdNode* extraZddNotSubSet( DdManager *dd, DdNode *X, DdNode *Y )
{	
	DdNode *zRes;
    statLine(dd); 
	/* any comb is a subset of itself */
	if ( X == Y ) 
		return z0;
	/* combs in X are notsubsets of non-existant combs in Y */
	if ( Y == z0 ) 
		return X;	
	/* only {()} is the subset of {()} */
	if ( Y == z1 ) /* remove empty combination from X */
		return cuddZddDiff( dd, X, z1 );
	/* if X is empty, the result is empty */
	if ( X == z0 ) 
		return z0;
	/* the empty comb is contained in all combs of Y */
	if ( X == z1 ) 
		return z0;
    /* check cache */
    zRes = cuddCacheLookup2Zdd(dd, extraZddNotSubSet, X, Y);
    if (zRes)
    	return(zRes);
	else
	{
		DdNode *zRes0, *zRes1, *zTemp;
		int TopLevelX = dd->permZ[ X->index ];
		int TopLevelY = dd->permZ[ Y->index ];
		if ( TopLevelX < TopLevelY )
		{
			/* compute combs of X without var that are notsubsets of combs with Y */
			zRes0 = extraZddNotSubSet( dd, cuddE( X ), Y );
			if ( zRes0 == NULL )  
				return NULL;
			cuddRef( zRes0 );
			/* combs of X with var cannot be subsets of combs without var in Y */
			zRes1 = cuddT( X );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddDeref( zRes0 );
		}
		else if ( TopLevelX == TopLevelY )
		{
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )  
				return NULL;
			cuddRef( zTemp );
			/* compute combs of X without var that are notsubsets of combs is Temp */
			zRes0 = extraZddNotSubSet( dd, cuddE( X ), zTemp );
			if ( zRes0 == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes0 );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			/* combs of X with var that are notsubsets of combs in Y with var */
			zRes1 = extraZddNotSubSet( dd, cuddT( X ), cuddT( Y ) );
			if ( zRes1 == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zRes1 );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else /* if ( TopLevelX > TopLevelY ) */
		{
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )  
				return NULL;
			cuddRef( zTemp );
			/* compute combs that are notsubsets of Temp */
			zRes = extraZddNotSubSet( dd, X, zTemp );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			cuddDeref( zRes );
		}
		/* insert the result into cache */
	    cuddCacheInsert2(dd, extraZddNotSubSet, X, Y, zRes);
		return zRes;
	}
} /* end of extraZddNotSubSet */
/**Function********************************************************************
  Synopsis [Performs the recursive step of Extra_zddNotSupSet.]
  Description []
  SideEffects [None]
  SeeAlso     []
******************************************************************************/
DdNode* extraZddNotSupSet( DdManager *dd, DdNode *X, DdNode *Y )
{	
	DdNode *zRes;
    statLine(dd); 
	/* any comb is a superset of itself */
	if ( X == Y ) 
		return z0;
	/* no comb in X is superset of non-existing combs */
	if ( Y == z0 ) 
		return X;	
	/* any comb in X is the superset of the empty comb */
	if ( Extra_zddEmptyBelongs( dd, Y ) ) 
		return z0;
	/* if X is empty, the result is empty */
	if ( X == z0 ) 
		return z0;
	/* if X is the empty comb (and Y does not contain it!), return it */
	if ( X == z1 ) 
		return z1;
    /* check cache */
    zRes = cuddCacheLookup2Zdd(dd, extraZddNotSupSet, X, Y);
    if (zRes)
    	return(zRes);
	else
	{
		DdNode *zRes0, *zRes1, *zTemp;
		int TopLevelX = dd->permZ[ X->index ];
		int TopLevelY = dd->permZ[ Y->index ];
		if ( TopLevelX < TopLevelY )
		{
			/* combinations of X without label that are supersets of combinations of Y */
			zRes0 = extraZddNotSupSet( dd, cuddE( X ), Y );
			if ( zRes0 == NULL )  
				return NULL;
			cuddRef( zRes0 );
			/* combinations of X with label that are supersets of combinations of Y */
			zRes1 = extraZddNotSupSet( dd, cuddT( X ), Y );
			if ( zRes1 == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zRes1 );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else if ( TopLevelX == TopLevelY )
		{
			/* combs of X without var that are not supersets of combs of Y without var */
			zRes0 = extraZddNotSupSet( dd, cuddE( X ), cuddE( Y ) );
			if ( zRes0 == NULL )  
				return NULL;
			cuddRef( zRes0 );
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zTemp );
			/* combs of X with label that are supersets of combs in Temp */
			zRes1 = extraZddNotSupSet( dd, cuddT( X ), zTemp );
			if ( zRes1 == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes1 );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else /* if ( TopLevelX > TopLevelY ) */
		{
			/* combs of X that are supersets of combs of Y without label */
			zRes = extraZddNotSupSet( dd, X, cuddE( Y ) );
			if ( zRes == NULL )  return NULL;
		}
		/* insert the result into cache */
	    cuddCacheInsert2(dd, extraZddNotSupSet, X, Y, zRes);
		return zRes;
	}
} /* end of extraZddNotSupSet */
/**Function********************************************************************
  Synopsis [Performs the recursive step of Extra_zddMaxNotSupSet.]
  Description []
  SideEffects [None]
  SeeAlso     []
******************************************************************************/
DdNode* extraZddMaxNotSupSet( DdManager *dd, DdNode *X, DdNode *Y )
{	
	DdNode *zRes;
    statLine(dd); 
	/* any comb is a superset of itself */
	if ( X == Y ) 
		return z0;
	/* no comb in X is superset of non-existing combs */
	if ( Y == z0 ) 
		return extraZddMaximal( dd, X );	
	/* any comb in X is the superset of the empty comb */
	if ( Extra_zddEmptyBelongs( dd, Y ) ) 
		return z0;
	/* if X is empty, the result is empty */
	if ( X == z0 ) 
		return z0;
	/* if X is the empty comb (and Y does not contain it!), return it */
	if ( X == z1 ) 
		return z1;
    /* check cache */
    zRes = cuddCacheLookup2Zdd(dd, extraZddMaxNotSupSet, X, Y);
    if (zRes)
    	return(zRes);
	else
	{
		DdNode *zRes0, *zRes1, *zTemp;
		int TopLevelX = dd->permZ[ X->index ];
		int TopLevelY = dd->permZ[ Y->index ];
		if ( TopLevelX < TopLevelY )
		{
			/* combinations of X without label that are supersets of combinations with Y */
			zRes0 = extraZddMaxNotSupSet( dd, cuddE( X ), Y );
			if ( zRes0 == NULL )  
				return NULL;
			cuddRef( zRes0 );
			/* combinations of X with label that are supersets of combinations with Y */
			zRes1 = extraZddMaxNotSupSet( dd, cuddT( X ), Y );
			if ( zRes1 == NULL )  
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zRes1 );
			/* ---------------------------------------------------- */
			/* remove subsets without this element covered by subsets with this element */
			zRes0 = extraZddNotSubSet(dd, zTemp = zRes0, zRes1);
			if ( zRes0 == NULL )
			{
				Cudd_RecursiveDerefZdd(dd, zTemp);
				Cudd_RecursiveDerefZdd(dd, zRes1);
				return NULL;
			}
			cuddRef( zRes0 );
			Cudd_RecursiveDerefZdd(dd, zTemp);
			/* ---------------------------------------------------- */
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else if ( TopLevelX == TopLevelY )
		{
			/* combs of X without var that are supersets of combs of Y without var */
			zRes0 = extraZddMaxNotSupSet( dd, cuddE( X ), cuddE( Y ) );
			if ( zRes0 == NULL )  
				return NULL;
			cuddRef( zRes0 );
			/* merge combs of Y with and without var */
			zTemp = cuddZddUnion( dd, cuddE( Y ), cuddT( Y ) );
			if ( zTemp == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				return NULL;
			}
			cuddRef( zTemp );
			/* combs of X with label that are supersets of combs in Temp */
			zRes1 = extraZddMaxNotSupSet( dd, cuddT( X ), zTemp );
			if ( zRes1 == NULL )
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zTemp );
				return NULL;
			}
			cuddRef( zRes1 );
			Cudd_RecursiveDerefZdd( dd, zTemp );
			/* ---------------------------------------------------- */
			/* remove subsets without this element covered by subsets with this element */
			zRes0 = extraZddNotSubSet(dd, zTemp = zRes0, zRes1);
			if ( zRes0 == NULL )
			{
				Cudd_RecursiveDerefZdd(dd, zTemp);
				Cudd_RecursiveDerefZdd(dd, zRes1);
				return NULL;
			}
			cuddRef( zRes0 );
			Cudd_RecursiveDerefZdd(dd, zTemp);
			/* ---------------------------------------------------- */
			/* compose Res0 and Res1 with the given ZDD variable */
			zRes = cuddZddGetNode( dd, X->index, zRes1, zRes0 );
			if ( zRes == NULL ) 
			{
				Cudd_RecursiveDerefZdd( dd, zRes0 );
				Cudd_RecursiveDerefZdd( dd, zRes1 );
				return NULL;
			}
			cuddDeref( zRes0 );
			cuddDeref( zRes1 );
		}
		else /* if ( TopLevelX > TopLevelY ) */
		{
			/* combs of X that are supersets of combs of Y without label */
			zRes = extraZddMaxNotSupSet( dd, X, cuddE( Y ) );
			if ( zRes == NULL )  return NULL;
		}
		/* insert the result into cache */
	    cuddCacheInsert2(dd, extraZddMaxNotSupSet, X, Y, zRes);
		return zRes;
	}
} /* end of extraZddMaxNotSupSet */
/*---------------------------------------------------------------------------*/
/* Definition of static functions                                            */
/*---------------------------------------------------------------------------*/
ABC_NAMESPACE_IMPL_END