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

  FileName    [fxuHeapS.c]

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

  Synopsis    [The priority queue for variables.]

  Author      [MVSIS Group]
  
  Affiliation [UC Berkeley]

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

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

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

#include "fxuInt.h"

ABC_NAMESPACE_IMPL_START


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

#define FXU_HEAP_SINGLE_WEIGHT(pSingle)           ((pSingle)->Weight)
#define FXU_HEAP_SINGLE_CURRENT(p, pSingle)       ((p)->pTree[(pSingle)->HNum])
#define FXU_HEAP_SINGLE_PARENT_EXISTS(p, pSingle) ((pSingle)->HNum > 1)
#define FXU_HEAP_SINGLE_CHILD1_EXISTS(p, pSingle) (((pSingle)->HNum << 1) <= p->nItems)
#define FXU_HEAP_SINGLE_CHILD2_EXISTS(p, pSingle) ((((pSingle)->HNum << 1)+1) <= p->nItems)
#define FXU_HEAP_SINGLE_PARENT(p, pSingle)        ((p)->pTree[(pSingle)->HNum >> 1])
#define FXU_HEAP_SINGLE_CHILD1(p, pSingle)        ((p)->pTree[(pSingle)->HNum << 1])
#define FXU_HEAP_SINGLE_CHILD2(p, pSingle)        ((p)->pTree[((pSingle)->HNum << 1)+1])
#define FXU_HEAP_SINGLE_ASSERT(p, pSingle)        assert( (pSingle)->HNum >= 1 && (pSingle)->HNum <= p->nItemsAlloc )

static void Fxu_HeapSingleResize( Fxu_HeapSingle * p );                  
static void Fxu_HeapSingleSwap( Fxu_Single ** pSingle1, Fxu_Single ** pSingle2 );  
static void Fxu_HeapSingleMoveUp( Fxu_HeapSingle * p, Fxu_Single * pSingle );  
static void Fxu_HeapSingleMoveDn( Fxu_HeapSingle * p, Fxu_Single * pSingle );  

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

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fxu_HeapSingle * Fxu_HeapSingleStart()
{
    Fxu_HeapSingle * p;
    p = ABC_ALLOC( Fxu_HeapSingle, 1 );
    memset( p, 0, sizeof(Fxu_HeapSingle) );
    p->nItems      = 0;
    p->nItemsAlloc = 2000;
    p->pTree       = ABC_ALLOC( Fxu_Single *, p->nItemsAlloc + 10 );
    p->pTree[0]    = NULL;
    return p;
}


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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleResize( Fxu_HeapSingle * p )
{
    p->nItemsAlloc *= 2;
    p->pTree = ABC_REALLOC( Fxu_Single *, p->pTree, p->nItemsAlloc + 10 );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleStop( Fxu_HeapSingle * p )
{
    int i;
    i = 0;
    ABC_FREE( p->pTree );
    i = 1;
    ABC_FREE( p );
}


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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSinglePrint( FILE * pFile, Fxu_HeapSingle * p )
{
    Fxu_Single * pSingle;
    int Counter = 1;
    int Degree  = 1;

    Fxu_HeapSingleCheck( p );
    fprintf( pFile, "The contents of the heap:\n" );
    fprintf( pFile, "Level %d:  ", Degree );
    Fxu_HeapSingleForEachItem( p, pSingle )
    {
        assert( Counter == p->pTree[Counter]->HNum );
        fprintf( pFile, "%2d=%3d  ", Counter, FXU_HEAP_SINGLE_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_HeapSingleCheck( Fxu_HeapSingle * p )
{
    Fxu_Single * pSingle;
    Fxu_HeapSingleForEachItem( p, pSingle )
    {
        assert( pSingle->HNum == p->i );
        Fxu_HeapSingleCheckOne( p, pSingle );
    }
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleCheckOne( Fxu_HeapSingle * p, Fxu_Single * pSingle )
{
    int Weight1, Weight2;
    if ( FXU_HEAP_SINGLE_CHILD1_EXISTS(p,pSingle) )
    {
        Weight1 = FXU_HEAP_SINGLE_WEIGHT(pSingle);
        Weight2 = FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD1(p,pSingle) );
        assert( Weight1 >= Weight2 );
    }
    if ( FXU_HEAP_SINGLE_CHILD2_EXISTS(p,pSingle) )
    {
        Weight1 = FXU_HEAP_SINGLE_WEIGHT(pSingle);
        Weight2 = FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD2(p,pSingle) );
        assert( Weight1 >= Weight2 );
    }
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleInsert( Fxu_HeapSingle * p, Fxu_Single * pSingle )
{
    if ( p->nItems == p->nItemsAlloc )
        Fxu_HeapSingleResize( p );
    // put the last entry to the last place and move up
    p->pTree[++p->nItems] = pSingle;
    pSingle->HNum = p->nItems;
    // move the last entry up if necessary
    Fxu_HeapSingleMoveUp( p, pSingle );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleUpdate( Fxu_HeapSingle * p, Fxu_Single * pSingle )
{
    FXU_HEAP_SINGLE_ASSERT(p,pSingle);
    if ( FXU_HEAP_SINGLE_PARENT_EXISTS(p,pSingle) && 
         FXU_HEAP_SINGLE_WEIGHT(pSingle) > FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_PARENT(p,pSingle) ) )
        Fxu_HeapSingleMoveUp( p, pSingle );
    else if ( FXU_HEAP_SINGLE_CHILD1_EXISTS(p,pSingle) && 
        FXU_HEAP_SINGLE_WEIGHT(pSingle) < FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD1(p,pSingle) ) )
        Fxu_HeapSingleMoveDn( p, pSingle );
    else if ( FXU_HEAP_SINGLE_CHILD2_EXISTS(p,pSingle) && 
        FXU_HEAP_SINGLE_WEIGHT(pSingle) < FXU_HEAP_SINGLE_WEIGHT( FXU_HEAP_SINGLE_CHILD2(p,pSingle) ) )
        Fxu_HeapSingleMoveDn( p, pSingle );
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleDelete( Fxu_HeapSingle * p, Fxu_Single * pSingle )
{
    int Place = pSingle->HNum;
    FXU_HEAP_SINGLE_ASSERT(p,pSingle);
    // put the last entry to the deleted place
    // decrement the number of entries
    p->pTree[Place] = p->pTree[p->nItems--];
    p->pTree[Place]->HNum = Place;
    // move the top entry down if necessary
    Fxu_HeapSingleUpdate( p, p->pTree[Place] );
    pSingle->HNum = 0;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fxu_Single * Fxu_HeapSingleReadMax( Fxu_HeapSingle * p )
{
    if ( p->nItems == 0 )
        return NULL;
    return p->pTree[1];
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
Fxu_Single * Fxu_HeapSingleGetMax( Fxu_HeapSingle * p )
{
    Fxu_Single * pSingle;
    if ( p->nItems == 0 )
        return NULL;
    // prepare the return value
    pSingle = p->pTree[1];
    pSingle->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_HeapSingleMoveDn( p, p->pTree[1] );
    return pSingle;     
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
int  Fxu_HeapSingleReadMaxWeight( Fxu_HeapSingle * p )
{
    if ( p->nItems == 0 )
        return -1;
    return FXU_HEAP_SINGLE_WEIGHT(p->pTree[1]);
}



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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleSwap( Fxu_Single ** pSingle1, Fxu_Single ** pSingle2 )
{
    Fxu_Single * pSingle;
    int Temp;
    pSingle   = *pSingle1;
    *pSingle1 = *pSingle2;
    *pSingle2 = pSingle;
    Temp          = (*pSingle1)->HNum;
    (*pSingle1)->HNum = (*pSingle2)->HNum;
    (*pSingle2)->HNum = Temp;
}

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

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleMoveUp( Fxu_HeapSingle * p, Fxu_Single * pSingle )
{
    Fxu_Single ** ppSingle, ** ppPar;
    ppSingle = &FXU_HEAP_SINGLE_CURRENT(p, pSingle);
    while ( FXU_HEAP_SINGLE_PARENT_EXISTS(p,*ppSingle) )
    {
        ppPar = &FXU_HEAP_SINGLE_PARENT(p,*ppSingle);
        if ( FXU_HEAP_SINGLE_WEIGHT(*ppSingle) > FXU_HEAP_SINGLE_WEIGHT(*ppPar) )
        {
            Fxu_HeapSingleSwap( ppSingle, ppPar );
            ppSingle = ppPar;
        }
        else
            break;
    }
}
 
/**Function*************************************************************

  Synopsis    []

  Description []
               
  SideEffects []

  SeeAlso     []

***********************************************************************/
void Fxu_HeapSingleMoveDn( Fxu_HeapSingle * p, Fxu_Single * pSingle )
{
    Fxu_Single ** ppChild1, ** ppChild2, ** ppSingle;
    ppSingle = &FXU_HEAP_SINGLE_CURRENT(p, pSingle);
    while ( FXU_HEAP_SINGLE_CHILD1_EXISTS(p,*ppSingle) )
    { // if Child1 does not exist, Child2 also does not exists

        // get the children
        ppChild1 = &FXU_HEAP_SINGLE_CHILD1(p,*ppSingle);
        if ( FXU_HEAP_SINGLE_CHILD2_EXISTS(p,*ppSingle) )
        {
            ppChild2 = &FXU_HEAP_SINGLE_CHILD2(p,*ppSingle);

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


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