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

  FileName    [fxuHeapD.c]

  PackageName [MVSIS 2.0: Multi-valued logic synthesis system.]

  Synopsis    [The priority queue for double cube divisors.]

  Author      [MVSIS Group]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - February 1, 2003.]

  Revision    [$Id: fxuHeapD.c,v 1.0 2003/02/01 00:00:00 alanmi Exp $]

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

#include "fxuInt.h"

ABC_NAMESPACE_IMPL_START


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

#define FXU_HEAP_DOUBLE_WEIGHT(pDiv)           ((pDiv)->Weight)
#define FXU_HEAP_DOUBLE_CURRENT(p, pDiv)       ((p)->pTree[(pDiv)->HNum])
#define FXU_HEAP_DOUBLE_PARENT_EXISTS(p, pDiv) ((pDiv)->HNum > 1)
#define FXU_HEAP_DOUBLE_CHILD1_EXISTS(p, pDiv) (((pDiv)->HNum << 1) <= p->nItems)
#define FXU_HEAP_DOUBLE_CHILD2_EXISTS(p, pDiv) ((((pDiv)->HNum << 1)+1) <= p->nItems)
#define FXU_HEAP_DOUBLE_PARENT(p, pDiv)        ((p)->pTree[(pDiv)->HNum >> 1])
#define FXU_HEAP_DOUBLE_CHILD1(p, pDiv)        ((p)->pTree[(pDiv)->HNum << 1])
#define FXU_HEAP_DOUBLE_CHILD2(p, pDiv)        ((p)->pTree[((pDiv)->HNum << 1)+1])
#define FXU_HEAP_DOUBLE_ASSERT(p, pDiv)        assert( (pDiv)->HNum >= 1 && (pDiv)->HNum <= p->nItemsAlloc )

static void Fxu_HeapDoubleResize( Fxu_HeapDouble * p );                  
static void Fxu_HeapDoubleSwap( Fxu_Double ** pDiv1, Fxu_Double ** pDiv2 );  
static void Fxu_HeapDoubleMoveUp( Fxu_HeapDouble * p, Fxu_Double * pDiv );  
static void Fxu_HeapDoubleMoveDn( Fxu_HeapDouble * p, Fxu_Double * pDiv );  

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fxu_HeapDouble * Fxu_HeapDoubleStart()
{
    Fxu_HeapDouble * p;
    p = ABC_ALLOC( Fxu_HeapDouble, 1 );
    memset( p, 0, sizeof(Fxu_HeapDouble) );
    p->nItems      = 0;
    p->nItemsAlloc = 10000;
    p->pTree       = ABC_ALLOC( Fxu_Double *, p->nItemsAlloc + 1 );
    p->pTree[0]    = NULL;
    return p;
}


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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleResize( Fxu_HeapDouble * p )
{
    p->nItemsAlloc *= 2;
    p->pTree = ABC_REALLOC( Fxu_Double *, p->pTree, p->nItemsAlloc + 1 );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleStop( Fxu_HeapDouble * p )
{
    ABC_FREE( p->pTree );
    ABC_FREE( p );
}


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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoublePrint( FILE * pFile, Fxu_HeapDouble * p )
{
    Fxu_Double * pDiv;
    int Counter = 1;
    int Degree  = 1;

    Fxu_HeapDoubleCheck( p );
    fprintf( pFile, "The contents of the heap:\n" );
    fprintf( pFile, "Level %d:  ", Degree );
    Fxu_HeapDoubleForEachItem( p, pDiv )
    {
        assert( Counter == p->pTree[Counter]->HNum );
        fprintf( pFile, "%2d=%3d  ", Counter, FXU_HEAP_DOUBLE_WEIGHT(p->pTree[Counter]) );
        if ( ++Counter == (1 << Degree) )
        {
            fprintf( pFile, "\n" );
            Degree++;
            fprintf( pFile, "Level %d:  ", Degree );
        }
    }
    fprintf( pFile, "\n" );
    fprintf( pFile, "End of the heap printout.\n" );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleCheck( Fxu_HeapDouble * p )
{
    Fxu_Double * pDiv;
    Fxu_HeapDoubleForEachItem( p, pDiv )
    {
        assert( pDiv->HNum == p->i );
        Fxu_HeapDoubleCheckOne( p, pDiv );
    }
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleCheckOne( Fxu_HeapDouble * p, Fxu_Double * pDiv )
{
    int Weight1, Weight2;
    if ( FXU_HEAP_DOUBLE_CHILD1_EXISTS(p,pDiv) )
    {
        Weight1 = FXU_HEAP_DOUBLE_WEIGHT(pDiv);
        Weight2 = FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD1(p,pDiv) );
        assert( Weight1 >= Weight2 );
    }
    if ( FXU_HEAP_DOUBLE_CHILD2_EXISTS(p,pDiv) )
    {
        Weight1 = FXU_HEAP_DOUBLE_WEIGHT(pDiv);
        Weight2 = FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD2(p,pDiv) );
        assert( Weight1 >= Weight2 );
    }
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleInsert( Fxu_HeapDouble * p, Fxu_Double * pDiv )
{
    if ( p->nItems == p->nItemsAlloc )
        Fxu_HeapDoubleResize( p );
    // put the last entry to the last place and move up
    p->pTree[++p->nItems] = pDiv;
    pDiv->HNum = p->nItems;
    // move the last entry up if necessary
    Fxu_HeapDoubleMoveUp( p, pDiv );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleUpdate( Fxu_HeapDouble * p, Fxu_Double * pDiv )
{
//printf( "Updating divisor %d.\n", pDiv->Num );

    FXU_HEAP_DOUBLE_ASSERT(p,pDiv);
    if ( FXU_HEAP_DOUBLE_PARENT_EXISTS(p,pDiv) && 
         FXU_HEAP_DOUBLE_WEIGHT(pDiv) > FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_PARENT(p,pDiv) ) )
        Fxu_HeapDoubleMoveUp( p, pDiv );
    else if ( FXU_HEAP_DOUBLE_CHILD1_EXISTS(p,pDiv) && 
        FXU_HEAP_DOUBLE_WEIGHT(pDiv) < FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD1(p,pDiv) ) )
        Fxu_HeapDoubleMoveDn( p, pDiv );
    else if ( FXU_HEAP_DOUBLE_CHILD2_EXISTS(p,pDiv) && 
        FXU_HEAP_DOUBLE_WEIGHT(pDiv) < FXU_HEAP_DOUBLE_WEIGHT( FXU_HEAP_DOUBLE_CHILD2(p,pDiv) ) )
        Fxu_HeapDoubleMoveDn( p, pDiv );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleDelete( Fxu_HeapDouble * p, Fxu_Double * pDiv )
{
    FXU_HEAP_DOUBLE_ASSERT(p,pDiv);
    // put the last entry to the deleted place
    // decrement the number of entries
    p->pTree[pDiv->HNum] = p->pTree[p->nItems--];
    p->pTree[pDiv->HNum]->HNum = pDiv->HNum;
    // move the top entry down if necessary
    Fxu_HeapDoubleUpdate( p, p->pTree[pDiv->HNum] );
    pDiv->HNum = 0;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fxu_Double * Fxu_HeapDoubleReadMax( Fxu_HeapDouble * p )
{
    if ( p->nItems == 0 )
        return NULL;
    return p->pTree[1];     
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fxu_Double * Fxu_HeapDoubleGetMax( Fxu_HeapDouble * p )
{
    Fxu_Double * pDiv;
    if ( p->nItems == 0 )
        return NULL;
    // prepare the return value
    pDiv = p->pTree[1];
    pDiv->HNum = 0;
    // put the last entry on top
    // decrement the number of entries
    p->pTree[1] = p->pTree[p->nItems--];
    p->pTree[1]->HNum = 1;
    // move the top entry down if necessary
    Fxu_HeapDoubleMoveDn( p, p->pTree[1] );
    return pDiv;     
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int  Fxu_HeapDoubleReadMaxWeight( Fxu_HeapDouble * p )
{
    if ( p->nItems == 0 )
        return -1;
    else
        return FXU_HEAP_DOUBLE_WEIGHT(p->pTree[1]);
}



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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleSwap( Fxu_Double ** pDiv1, Fxu_Double ** pDiv2 )
{
    Fxu_Double * pDiv;
    int Temp;
    pDiv   = *pDiv1;
    *pDiv1 = *pDiv2;
    *pDiv2 = pDiv;
    Temp          = (*pDiv1)->HNum;
    (*pDiv1)->HNum = (*pDiv2)->HNum;
    (*pDiv2)->HNum = Temp;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleMoveUp( Fxu_HeapDouble * p, Fxu_Double * pDiv )
{
    Fxu_Double ** ppDiv, ** ppPar;
    ppDiv = &FXU_HEAP_DOUBLE_CURRENT(p, pDiv);
    while ( FXU_HEAP_DOUBLE_PARENT_EXISTS(p,*ppDiv) )
    {
        ppPar = &FXU_HEAP_DOUBLE_PARENT(p,*ppDiv);
        if ( FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) > FXU_HEAP_DOUBLE_WEIGHT(*ppPar) )
        {
            Fxu_HeapDoubleSwap( ppDiv, ppPar );
            ppDiv = ppPar;
        }
        else
            break;
    }
}
 
/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapDoubleMoveDn( Fxu_HeapDouble * p, Fxu_Double * pDiv )
{
    Fxu_Double ** ppChild1, ** ppChild2, ** ppDiv;
    ppDiv = &FXU_HEAP_DOUBLE_CURRENT(p, pDiv);
    while ( FXU_HEAP_DOUBLE_CHILD1_EXISTS(p,*ppDiv) )
    { // if Child1 does not exist, Child2 also does not exists

        // get the children
        ppChild1 = &FXU_HEAP_DOUBLE_CHILD1(p,*ppDiv);
        if ( FXU_HEAP_DOUBLE_CHILD2_EXISTS(p,*ppDiv) )
        {
            ppChild2 = &FXU_HEAP_DOUBLE_CHILD2(p,*ppDiv);

            // consider two cases
            if ( FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild1) &&
                 FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild2) )
            { // Div is larger than both, skip
                break;
            }
            else
            { // Div is smaller than one of them, then swap it with larger 
                if ( FXU_HEAP_DOUBLE_WEIGHT(*ppChild1) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild2) )
                {
                    Fxu_HeapDoubleSwap( ppDiv, ppChild1 );
                    // update the pointer
                    ppDiv = ppChild1;
                }
                else
                {
                    Fxu_HeapDoubleSwap( ppDiv, ppChild2 );
                    // update the pointer
                    ppDiv = ppChild2;
                }
            }
        }
        else // Child2 does not exist
        {
            // consider two cases
            if ( FXU_HEAP_DOUBLE_WEIGHT(*ppDiv) >= FXU_HEAP_DOUBLE_WEIGHT(*ppChild1) )
            { // Div is larger than Child1, skip
                break;
            }
            else
            { // Div is smaller than Child1, then swap them
                Fxu_HeapDoubleSwap( ppDiv, ppChild1 );
                // update the pointer
                ppDiv = ppChild1;
            }
        }
    }
}


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


ABC_NAMESPACE_IMPL_END