/**CFile****************************************************************

  FileName    [reoTransfer.c]

  PackageName [REO: A specialized DD reordering engine.]

  Synopsis    [Transfering a DD from the CUDD manager into REO"s internal data structures and back.]

  Author      [Alan Mishchenko]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - October 15, 2002.]

  Revision    [$Id: reoTransfer.c,v 1.0 2002/15/10 03:00:00 alanmi Exp $]

***********************************************************************/

#include "reo.h"

ABC_NAMESPACE_IMPL_START


////////////////////////////////////////////////////////////////////////
///                        DECLARATIONS                              ///
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
///                    FUNCTION DEFINITIONS                          ///
////////////////////////////////////////////////////////////////////////

/**Function*************************************************************

  Synopsis    [Transfers the DD into the internal reordering data structure.]

  Description [It is important that the hash table is lossless.]

  SideEffects []

  SeeAlso     []

***********************************************************************/
reo_unit * reoTransferNodesToUnits_rec( reo_man * p, DdNode * F )
{
	DdManager * dd = p->dd;
	reo_unit * pUnit;
	int HKey = -1; // Suppress "might be used uninitialized"
        int fComp;
	
	fComp = Cudd_IsComplement(F);
	F = Cudd_Regular(F);

	// check the hash-table
	if ( F->ref != 1 )
	{
		// search cache - use linear probing
		for ( HKey = hashKey2(p->Signature,F,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize )
			if ( p->HTable[HKey].Arg1 == (reo_unit *)F )
			{
				pUnit = p->HTable[HKey].Arg2;  
				assert( pUnit );
				// increment the edge counter
				pUnit->n++;
				return Unit_NotCond( pUnit, fComp );
			}
	}
	// the entry in not found in the cache
	
	// create a new entry
	pUnit         = reoUnitsGetNextUnit( p );
	pUnit->n      = 1;
	if ( cuddIsConstant(F) )
	{
		pUnit->lev    = REO_CONST_LEVEL;
		pUnit->pE     = (reo_unit*)(ABC_PTRUINT_T)(cuddV(F));
		pUnit->pT     = NULL;
		// check if the diagram that is being reordering has complement edges
		if ( F != dd->one )
			p->fThisIsAdd = 1;
		// insert the unit into the corresponding plane
		reoUnitsAddUnitToPlane( &(p->pPlanes[p->nSupp]), pUnit ); // increments the unit counter
	}
	else
	{
		pUnit->lev    = p->pMapToPlanes[F->index];
		pUnit->pE     = reoTransferNodesToUnits_rec( p, cuddE(F) );
		pUnit->pT     = reoTransferNodesToUnits_rec( p, cuddT(F) );
		// insert the unit into the corresponding plane
		reoUnitsAddUnitToPlane( &(p->pPlanes[pUnit->lev]), pUnit ); // increments the unit counter
	}

	// add to the hash table
	if ( F->ref != 1 )
	{
		// the next free entry is already found - it is pointed to by HKey
		// while we traversed the diagram, the hash entry to which HKey points,
		// might have been used. Make sure that its signature is different.
		for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize );
		p->HTable[HKey].Sign = p->Signature;
		p->HTable[HKey].Arg1 = (reo_unit *)F;
		p->HTable[HKey].Arg2 = pUnit;
	}

	// increment the counter of nodes
	p->nNodesCur++;
	return Unit_NotCond( pUnit, fComp );
}

/**Function*************************************************************

  Synopsis    [Creates the DD from the internal reordering data structure.]

  Description [It is important that the hash table is lossless.]

  SideEffects []

  SeeAlso     []

***********************************************************************/
DdNode * reoTransferUnitsToNodes_rec( reo_man * p, reo_unit * pUnit )
{
	DdManager * dd = p->dd;
	DdNode * bRes, * E, * T;
	int HKey = -1; // Suppress "might be used uninitialized"
        int fComp;

	fComp = Cudd_IsComplement(pUnit);
	pUnit = Unit_Regular(pUnit);

	// check the hash-table
	if ( pUnit->n != 1 )
	{
		for ( HKey = hashKey2(p->Signature,pUnit,p->nTableSize); p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize )
			if ( p->HTable[HKey].Arg1 == pUnit )
			{
				bRes = (DdNode*) p->HTable[HKey].Arg2;  
				assert( bRes );
				return Cudd_NotCond( bRes, fComp );
			}
	}

	// treat the case of constants
	if ( Unit_IsConstant(pUnit) )
	{
		bRes = cuddUniqueConst( dd, ((double)((int)(ABC_PTRUINT_T)(pUnit->pE))) );
		cuddRef( bRes );
	}
	else
	{
		// split and recur on children of this node
		E = reoTransferUnitsToNodes_rec( p, pUnit->pE );
		if ( E == NULL )
			return NULL;
		cuddRef(E);

		T = reoTransferUnitsToNodes_rec( p, pUnit->pT );
		if ( T == NULL )
		{
			Cudd_RecursiveDeref(dd, E);
			return NULL;
		}
		cuddRef(T);
		
		// consider the case when Res0 and Res1 are the same node
		assert( E != T );
		assert( !Cudd_IsComplement(T) );

		bRes = cuddUniqueInter( dd, p->pMapToDdVarsFinal[pUnit->lev], T, E );
		if ( bRes == NULL ) 
		{
			Cudd_RecursiveDeref(dd,E);
			Cudd_RecursiveDeref(dd,T);
			return NULL;
		}
		cuddRef( bRes );
		cuddDeref( E );
		cuddDeref( T );
	}

	// do not keep the result if the ref count is only 1, since it will not be visited again
	if ( pUnit->n != 1 )
	{
		 // while we traversed the diagram, the hash entry to which HKey points,
		 // might have been used. Make sure that its signature is different.
		 for ( ; p->HTable[HKey].Sign == p->Signature; HKey = (HKey+1) % p->nTableSize );
		 p->HTable[HKey].Sign = p->Signature;
		 p->HTable[HKey].Arg1 = pUnit;
		 p->HTable[HKey].Arg2 = (reo_unit *)bRes;  

		 // add the DD to the referenced DD list in order to be able to store it in cache
		 p->pRefNodes[p->nRefNodes++] = bRes;  Cudd_Ref( bRes ); 
		 // no need to do this, because the garbage collection will not take bRes away
		 // it is held by the diagram in the making
	}
	// increment the counter of nodes
	p->nNodesCur++;
	cuddDeref( bRes );
	return Cudd_NotCond( bRes, fComp );
}

////////////////////////////////////////////////////////////////////////
///                         END OF FILE                              ///
////////////////////////////////////////////////////////////////////////

ABC_NAMESPACE_IMPL_END

