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

  FileName    [liveness_sim.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Liveness property checking.]

  Synopsis    [Main implementation module.]

  Author      [Sayak Ray]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - January 1, 2009.]

  Revision    [$Id: liveness_sim.c,v 1.00 2009/01/01 00:00:00 alanmi Exp $]

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

#include <stdio.h>
#include "base/main/main.h"
#include "aig/aig/aig.h"
#include "aig/saig/saig.h"
#include <string.h>

ABC_NAMESPACE_IMPL_START


#define PROPAGATE_NAMES
//#define DUPLICATE_CKT_DEBUG

extern Aig_Man_t * Abc_NtkToDar( Abc_Ntk_t * pNtk, int fExors, int fRegisters );
extern Abc_Ntk_t * Abc_NtkFromAigPhase( Aig_Man_t * pMan );
//char *strdup(const char *string);


/*******************************************************************
LAYOUT OF PI VECTOR:
 
+------------------------------------------------------------------------------------------------------------------------------------+
| TRUE ORIGINAL PI (n) | SAVE(PI) (1) | ORIGINAL LO (k) | SAVED(LO) (1) | SHADOW_ORIGINAL LO (k) | LIVENESS LO (l) | FAIRNESS LO (f) |
+------------------------------------------------------------------------------------------------------------------------------------+
<------------True PI----------------->|<----------------------------LO--------------------------------------------------------------->

LAYOUT OF PO VECTOR:

+-----------------------------------------------------------------------------------------------------------+
| SOLE PO (1) | ORIGINAL LI (k) | SAVED LI (1) | SHADOW_ORIGINAL LI (k) | LIVENESS LI (l) | FAIRNESS LI (f) |
+-----------------------------------------------------------------------------------------------------------+
<--True PO--->|<--------------------------------------LI---------------------------------------------------->

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

static void printVecPtrOfString( Vec_Ptr_t *vec )
{
	int i;

	for( i=0; i< Vec_PtrSize( vec ); i++ )
	{
		printf("vec[%d] = %s\n", i, (char *)Vec_PtrEntry(vec, i) );
	}
}

static int getPoIndex( Aig_Man_t *pAig, Aig_Obj_t *pPivot )
{
	int i;
	Aig_Obj_t *pObj;

	Saig_ManForEachPo( pAig, pObj, i )
	{
		if( pObj == pPivot )
			return i;
	}
	return -1;
}

static char * retrieveTruePiName( Abc_Ntk_t *pNtkOld, Aig_Man_t *pAigOld, Aig_Man_t *pAigNew, Aig_Obj_t *pObjPivot )
{
	Aig_Obj_t *pObjOld, *pObj;
	Abc_Obj_t *pNode;
	int index;

	assert( Saig_ObjIsPi( pAigNew, pObjPivot ) );
	Aig_ManForEachCi( pAigNew, pObj, index )
		if( pObj == pObjPivot )
			break;
	assert( index < Aig_ManCiNum( pAigNew ) - Aig_ManRegNum( pAigNew ) );
	if( index == Saig_ManPiNum( pAigNew ) - 1 )
		return "SAVE_BIERE";
	else
	{
		pObjOld = Aig_ManCi( pAigOld, index );
		pNode = Abc_NtkPi( pNtkOld, index );
		assert( pObjOld->pData == pObjPivot );
		return Abc_ObjName( pNode );
	}
}

static char * retrieveLOName( Abc_Ntk_t *pNtkOld, Aig_Man_t *pAigOld, Aig_Man_t *pAigNew, Aig_Obj_t *pObjPivot, Vec_Ptr_t *vLive, Vec_Ptr_t * vFair )
{
	Aig_Obj_t *pObjOld, *pObj;
	Abc_Obj_t *pNode;
	int index, oldIndex, originalLatchNum = Saig_ManRegNum(pAigOld), strMatch, i;
	char *dummyStr = (char *)malloc( sizeof(char) * 50 );

	assert( Saig_ObjIsLo( pAigNew, pObjPivot ) );
	Saig_ManForEachLo( pAigNew, pObj, index )
		if( pObj == pObjPivot )
			break;
	if( index < originalLatchNum )
	{
		oldIndex = Saig_ManPiNum( pAigOld ) + index;
		pObjOld = Aig_ManCi( pAigOld, oldIndex );
		pNode = Abc_NtkCi( pNtkOld, oldIndex );
		assert( pObjOld->pData == pObjPivot );
		return Abc_ObjName( pNode );
	}
	else if( index == originalLatchNum )
		return "SAVED_LO";
	else if( index > originalLatchNum && index < 2 * originalLatchNum + 1 )
	{
		oldIndex = Saig_ManPiNum( pAigOld ) + index - originalLatchNum - 1;
		pObjOld = Aig_ManCi( pAigOld, oldIndex );
		pNode = Abc_NtkCi( pNtkOld, oldIndex );
		sprintf( dummyStr, "%s__%s", Abc_ObjName( pNode ), "SHADOW");
		return dummyStr;
	}
	else if( index >= 2 * originalLatchNum + 1 && index < 2 * originalLatchNum + 1 + Vec_PtrSize( vLive ) )
	{
		oldIndex = index - 2 * originalLatchNum - 1;
		strMatch = 0;
		Saig_ManForEachPo( pAigOld, pObj, i )
		{
			pNode = Abc_NtkPo( pNtkOld, i );
			if( strstr( Abc_ObjName( pNode ), "assert_fair" ) != NULL )
			{
				if( strMatch == oldIndex )
				{
					sprintf( dummyStr, "%s__%s", Abc_ObjName( pNode ), "LIVENESS");
					return dummyStr;
				}
				else
					strMatch++;
			}
		}
	}
	else if( index >= 2 * originalLatchNum + 1 + Vec_PtrSize( vLive ) && index < 2 * originalLatchNum + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) )
	{
		oldIndex = index - 2 * originalLatchNum - 1 - Vec_PtrSize( vLive );
		strMatch = 0;
		Saig_ManForEachPo( pAigOld, pObj, i )
		{
			pNode = Abc_NtkPo( pNtkOld, i );
			if( strstr( Abc_ObjName( pNode ), "assume_fair" ) != NULL )
			{
				if( strMatch == oldIndex )
				{
					sprintf( dummyStr, "%s__%s", Abc_ObjName( pNode ), "FAIRNESS");
					return dummyStr;
				}
				else
					strMatch++;
			}
		}
	}
	else
		return "UNKNOWN";
    return NULL;
}

extern Vec_Ptr_t *vecPis, *vecPiNames;
extern Vec_Ptr_t *vecLos, *vecLoNames;


static int Aig_ManCiCleanupBiere( Aig_Man_t * p )
{
    int nPisOld = Aig_ManCiNum(p);
	
    p->nObjs[AIG_OBJ_CI] = Vec_PtrSize( p->vCis );
    if ( Aig_ManRegNum(p) )
        p->nTruePis = Aig_ManCiNum(p) - Aig_ManRegNum(p);
	
    return nPisOld - Aig_ManCiNum(p);
}


static int Aig_ManCoCleanupBiere( Aig_Man_t * p )
{
    int nPosOld = Aig_ManCoNum(p);

    p->nObjs[AIG_OBJ_CO] = Vec_PtrSize( p->vCos );
    if ( Aig_ManRegNum(p) )
        p->nTruePos = Aig_ManCoNum(p) - Aig_ManRegNum(p);
    return nPosOld - Aig_ManCoNum(p);
}

static Aig_Man_t * LivenessToSafetyTransformationSim( Abc_Ntk_t * pNtk, Aig_Man_t * p, Vec_Ptr_t *vLive, Vec_Ptr_t *vFair )
{
	Aig_Man_t * pNew;
	int i, nRegCount;
	Aig_Obj_t * pObjSavePi;
	Aig_Obj_t *pObjSavedLo, *pObjSavedLi;
	Aig_Obj_t *pObj, *pMatch;
	Aig_Obj_t *pObjSaveOrSaved, *pObjSavedLoAndEquality;
	Aig_Obj_t *pObjShadowLo, *pObjShadowLi, *pObjShadowLiDriver;
	Aig_Obj_t *pObjXor, *pObjXnor, *pObjAndAcc, *pObjAndAccDummy;
	Aig_Obj_t *pObjLive, *pObjFair, *pObjSafetyGate;
	Aig_Obj_t *pObjSafetyPropertyOutput;
	Aig_Obj_t *pDriverImage;
	char *nodeName;
	int piCopied = 0, liCopied = 0, loCopied = 0, liCreated = 0, loCreated = 0, liveLatch = 0, fairLatch = 0;
	
	vecPis = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
	vecPiNames = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);

	vecLos = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
	vecLoNames = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );

#ifdef DUPLICATE_CKT_DEBUG
	printf("\nCode is compiled in DEBUG mode, the input-output behavior will be the same as the original circuit\n");
	printf("Press any key to continue...");
	scanf("%c", &c);
#endif

	//****************************************************************
	// Step1: create the new manager
	// Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
	// nodes, but this selection is arbitrary - need to be justified
	//****************************************************************
	pNew = Aig_ManStart( 2 * Aig_ManObjNumMax(p) );
	pNew->pName = Abc_UtilStrsav( "live2safe" );
    pNew->pSpec = NULL;
    
	//****************************************************************
	// Step 2: map constant nodes
	//****************************************************************
    pObj = Aig_ManConst1( p );
    pObj->pData = Aig_ManConst1( pNew );

	//****************************************************************
    // Step 3: create true PIs
	//****************************************************************
    Saig_ManForEachPi( p, pObj, i )
	{
		piCopied++;
		pObj->pData = Aig_ObjCreateCi(pNew);
		Vec_PtrPush( vecPis, pObj->pData );
		nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkPi( pNtk, i ) ));
		Vec_PtrPush( vecPiNames, nodeName );
	}

	//****************************************************************
	// Step 4: create the special Pi corresponding to SAVE
	//****************************************************************
#ifndef DUPLICATE_CKT_DEBUG
	pObjSavePi = Aig_ObjCreateCi( pNew );
	nodeName = Abc_UtilStrsav("SAVE_BIERE"),
	Vec_PtrPush( vecPiNames, nodeName );
#endif
		
	//****************************************************************
	// Step 5: create register outputs
	//****************************************************************
    Saig_ManForEachLo( p, pObj, i )
    {
		loCopied++;
		pObj->pData = Aig_ObjCreateCi(pNew);
		Vec_PtrPush( vecLos, pObj->pData );
		nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ));
		Vec_PtrPush( vecLoNames, nodeName );
    }

	//****************************************************************
	// Step 6: create "saved" register output
	//****************************************************************
#ifndef DUPLICATE_CKT_DEBUG
	loCreated++;
	pObjSavedLo = Aig_ObjCreateCi( pNew );
	Vec_PtrPush( vecLos, pObjSavedLo );
	nodeName = Abc_UtilStrsav("SAVED_LO");
	Vec_PtrPush( vecLoNames, nodeName );
#endif

	//****************************************************************
	// Step 7: create the OR gate and the AND gate directly fed by "SAVE" Pi
	//****************************************************************
#ifndef DUPLICATE_CKT_DEBUG
	pObjSaveOrSaved = Aig_Or( pNew, pObjSavePi, pObjSavedLo );
	//pObjSaveAndNotSaved = Aig_And( pNew, pObjSavePi, Aig_Not(pObjSavedLo) );
#endif

	//********************************************************************
	// Step 8: create internal nodes
	//********************************************************************
    Aig_ManForEachNode( p, pObj, i )
	{
		pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
	}

	//********************************************************************
	// Step 9: create the safety property output gate
	// create the safety property output gate, this will be the sole true PO 
	// of the whole circuit, discuss with Sat/Alan for an alternative implementation
	//********************************************************************
#ifndef DUPLICATE_CKT_DEBUG
	pObjSafetyPropertyOutput = Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );
#endif

	//********************************************************************
	// DEBUG: To recreate the same circuit, at least from the input and output
	// behavior, we need to copy the original PO
	//********************************************************************
#ifdef DUPLICATE_CKT_DEBUG
	Saig_ManForEachPo( p, pObj, i )
	{
		Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pObj) );
	}
#endif

	// create register inputs for the original registers
    nRegCount = 0;
	
	Saig_ManForEachLo( p, pObj, i )
    {
		pMatch = Saig_ObjLoToLi( p, pObj );
        //Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pMatch) );
		Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pMatch)->pData, Aig_ObjFaninC0( pMatch ) ) );
        nRegCount++;
		liCopied++;
    }

	// create register input corresponding to the register "saved"
#ifndef DUPLICATE_CKT_DEBUG
	pObjSavedLi = Aig_ObjCreateCo( pNew, pObjSaveOrSaved );
	nRegCount++;
	liCreated++;

	pObjAndAcc = NULL;

	// create the family of shadow registers, then create the cascade of Xnor and And gates for the comparator 
	Saig_ManForEachLo( p, pObj, i )
	{
		pObjShadowLo = Aig_ObjCreateCi( pNew );

#ifdef PROPAGATE_NAMES
		Vec_PtrPush( vecLos, pObjShadowLo );
		nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ) ) + 10 );
		sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ), "SHADOW" );
		Vec_PtrPush( vecLoNames, nodeName );
#endif

		pObjShadowLiDriver = Aig_Mux( pNew, pObjSavePi, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
		pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
		nRegCount++;
		loCreated++; liCreated++;
		
		pObjXor = Aig_Exor( pNew, (Aig_Obj_t *)pObj->pData, pObjShadowLo );
		pObjXnor = Aig_Not( pObjXor );
		if( pObjAndAcc == NULL )
			pObjAndAcc = pObjXnor;
		else
		{
			pObjAndAccDummy = pObjAndAcc;
			pObjAndAcc = Aig_And( pNew, pObjXnor, pObjAndAccDummy );
		}
	}

	// create the AND gate whose output will be the signal "looped"
	pObjSavedLoAndEquality = Aig_And( pNew, pObjSavedLo, pObjAndAcc );
	
	// create the master AND gate and corresponding AND and OR logic for the liveness properties
	pObjAndAcc = NULL;
	if( vLive == NULL || Vec_PtrSize( vLive ) == 0 )
		printf("\nCircuit without any liveness property\n");
	else
	{
		Vec_PtrForEachEntry( Aig_Obj_t *, vLive, pObj, i )
		{
			//assert( Aig_ObjIsNode( Aig_ObjChild0( pObj ) ) );
			//Aig_ObjPrint( pNew, pObj );
			liveLatch++;
			pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
			pObjShadowLo = Aig_ObjCreateCi( pNew );

#ifdef PROPAGATE_NAMES
		Vec_PtrPush( vecLos, pObjShadowLo );
		nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
		sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "LIVENESS" );
		Vec_PtrPush( vecLoNames, nodeName );
#endif

			pObjShadowLiDriver = Aig_Or( pNew, Aig_Mux(pNew, pObjSavePi, Aig_Not(Aig_ManConst1(pNew)), pObjShadowLo), 
												Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
			pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
			nRegCount++;
			loCreated++; liCreated++;
			
			if( pObjAndAcc == NULL )
				pObjAndAcc = pObjShadowLo;
			else
			{
				pObjAndAccDummy = pObjAndAcc;
				pObjAndAcc = Aig_And( pNew, pObjShadowLo, pObjAndAccDummy );
			}
		}
	}

	if( pObjAndAcc != NULL )
		pObjLive = pObjAndAcc;
	else
		pObjLive = Aig_ManConst1( pNew );
	
	// create the master AND gate and corresponding AND and OR logic for the fairness properties
	pObjAndAcc = NULL;
	if( vFair == NULL || Vec_PtrSize( vFair ) == 0 )
		printf("\nCircuit without any fairness property\n");
	else
	{
		Vec_PtrForEachEntry( Aig_Obj_t *, vFair, pObj, i )
		{
			fairLatch++;
			//assert( Aig_ObjIsNode( Aig_ObjChild0( pObj ) ) );
			pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
			pObjShadowLo = Aig_ObjCreateCi( pNew );

#ifdef PROPAGATE_NAMES
		Vec_PtrPush( vecLos, pObjShadowLo );
		nodeName = (char *)malloc( strlen( Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ) ) + 12 );
		sprintf( nodeName, "%s__%s", Abc_ObjName( Abc_NtkPo( pNtk, getPoIndex( p, pObj ) ) ), "FAIRNESS" );
		Vec_PtrPush( vecLoNames, nodeName );
#endif

			pObjShadowLiDriver = Aig_Or( pNew, Aig_Mux(pNew, pObjSavePi, Aig_Not(Aig_ManConst1(pNew)), pObjShadowLo), 
									Aig_And( pNew, pDriverImage, pObjSaveOrSaved ) );
			pObjShadowLi = Aig_ObjCreateCo( pNew, pObjShadowLiDriver );
			nRegCount++;
			loCreated++; liCreated++;
			
			if( pObjAndAcc == NULL )
				pObjAndAcc = pObjShadowLo;
			else
			{
				pObjAndAccDummy = pObjAndAcc;
				pObjAndAcc = Aig_And( pNew, pObjShadowLo, pObjAndAccDummy );
			}
		}
	}

	if( pObjAndAcc != NULL )
		pObjFair = pObjAndAcc;
	else
		pObjFair = Aig_ManConst1( pNew );
	
	//pObjSafetyGate = Aig_Exor( pNew, Aig_Not(Aig_ManConst1( pNew )), Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) ) );
	pObjSafetyGate = Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) );
	
	Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyGate );
#endif

	Aig_ManSetRegNum( pNew, nRegCount );

	Aig_ManCiCleanupBiere( pNew );
	Aig_ManCoCleanupBiere( pNew );
	
	Aig_ManCleanup( pNew );
	assert( Aig_ManCheck( pNew ) );
	
#ifndef DUPLICATE_CKT_DEBUG
	assert((Aig_Obj_t *)Vec_PtrEntry(pNew->vCos, Saig_ManPoNum(pNew)+Aig_ObjCioId(pObjSavedLo)-Saig_ManPiNum(p)-1) == pObjSavedLi);
	assert( Saig_ManPoNum( pNew ) == 1 );
	assert( Saig_ManPiNum( p ) + 1 == Saig_ManPiNum( pNew ) );
	assert( Saig_ManRegNum( pNew ) == Saig_ManRegNum( p ) * 2 + 1 + liveLatch + fairLatch );
#endif

	return pNew;
}


static Aig_Man_t * LivenessToSafetyTransformationOneStepLoopSim( Abc_Ntk_t * pNtk, Aig_Man_t * p, Vec_Ptr_t *vLive, Vec_Ptr_t *vFair )
{
	Aig_Man_t * pNew;
	int i, nRegCount;
	Aig_Obj_t * pObjSavePi;
	Aig_Obj_t *pObj, *pMatch;
	Aig_Obj_t *pObjSavedLoAndEquality;
	Aig_Obj_t *pObjXor, *pObjXnor, *pObjAndAcc, *pObjAndAccDummy;
	Aig_Obj_t *pObjLive, *pObjFair, *pObjSafetyGate;
	Aig_Obj_t *pObjSafetyPropertyOutput;
	Aig_Obj_t *pDriverImage;
	Aig_Obj_t *pObjCorrespondingLi;


	char *nodeName;
	int piCopied = 0, liCopied = 0, loCopied = 0;//, liCreated = 0, loCreated = 0, piVecIndex = 0;
	
	vecPis = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);
	vecPiNames = Vec_PtrAlloc( Saig_ManPiNum( p ) + 1);

	vecLos = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );
	vecLoNames = Vec_PtrAlloc( Saig_ManRegNum( p )*2 + 1 + Vec_PtrSize( vLive ) + Vec_PtrSize( vFair ) );

	//****************************************************************
	// Step1: create the new manager
	// Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
	// nodes, but this selection is arbitrary - need to be justified
	//****************************************************************
	pNew = Aig_ManStart( 2 * Aig_ManObjNumMax(p) );
	pNew->pName = Abc_UtilStrsav( "live2safe" );
    pNew->pSpec = NULL;
    
	//****************************************************************
	// Step 2: map constant nodes
	//****************************************************************
    pObj = Aig_ManConst1( p );
    pObj->pData = Aig_ManConst1( pNew );

	//****************************************************************
    // Step 3: create true PIs
	//****************************************************************
    Saig_ManForEachPi( p, pObj, i )
	{
		piCopied++;
		pObj->pData = Aig_ObjCreateCi(pNew);
		Vec_PtrPush( vecPis, pObj->pData );
		nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkPi( pNtk, i ) ));
		Vec_PtrPush( vecPiNames, nodeName );
	}

	//****************************************************************
	// Step 4: create the special Pi corresponding to SAVE
	//****************************************************************
	pObjSavePi = Aig_ObjCreateCi( pNew );
	nodeName = "SAVE_BIERE",
	Vec_PtrPush( vecPiNames, nodeName );
		
	//****************************************************************
	// Step 5: create register outputs
	//****************************************************************
    Saig_ManForEachLo( p, pObj, i )
    {
		loCopied++;
		pObj->pData = Aig_ObjCreateCi(pNew);
		Vec_PtrPush( vecLos, pObj->pData );
		nodeName = Abc_UtilStrsav(Abc_ObjName( Abc_NtkCi( pNtk, Abc_NtkPiNum(pNtk) + i ) ));
		Vec_PtrPush( vecLoNames, nodeName );
    }

	//****************************************************************
	// Step 6: create "saved" register output
	//****************************************************************

#if 0
	loCreated++;
	pObjSavedLo = Aig_ObjCreateCi( pNew );
	Vec_PtrPush( vecLos, pObjSavedLo );
	nodeName = "SAVED_LO";
	Vec_PtrPush( vecLoNames, nodeName );
#endif

	//****************************************************************
	// Step 7: create the OR gate and the AND gate directly fed by "SAVE" Pi
	//****************************************************************
#if 0
	pObjSaveOrSaved = Aig_Or( pNew, pObjSavePi, pObjSavedLo );
	pObjSaveAndNotSaved = Aig_And( pNew, pObjSavePi, Aig_Not(pObjSavedLo) );
#endif

	//********************************************************************
	// Step 8: create internal nodes
	//********************************************************************
    Aig_ManForEachNode( p, pObj, i )
	{
		pObj->pData = Aig_And( pNew, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
	}

	//********************************************************************
	// Step 9: create the safety property output gate
	// create the safety property output gate, this will be the sole true PO 
	// of the whole circuit, discuss with Sat/Alan for an alternative implementation
	//********************************************************************

	pObjSafetyPropertyOutput = Aig_ObjCreateCo( pNew, (Aig_Obj_t *)Aig_ObjFanin0(pObj)->pData );

	// create register inputs for the original registers
    nRegCount = 0;
	
	Saig_ManForEachLo( p, pObj, i )
    {
		pMatch = Saig_ObjLoToLi( p, pObj );
        //Aig_ObjCreateCo( pNew, Aig_ObjChild0Copy(pMatch) );
		Aig_ObjCreateCo( pNew, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pMatch)->pData, Aig_ObjFaninC0( pMatch ) ) );
        nRegCount++;
		liCopied++;
    }

#if 0
	// create register input corresponding to the register "saved"
	pObjSavedLi = Aig_ObjCreateCo( pNew, pObjSaveOrSaved );
	nRegCount++;
	liCreated++;
#endif

	pObjAndAcc = NULL;

	//****************************************************************************************************
	//For detection of loop of length 1 we do not need any shadow register, we only need equality detector
	//between Lo_j and Li_j and then a cascade of AND gates
	//****************************************************************************************************

	Saig_ManForEachLo( p, pObj, i )
	{
		pObjCorrespondingLi = Saig_ObjLoToLi( p, pObj );
		
		pObjXor = Aig_Exor( pNew, (Aig_Obj_t *)pObj->pData,  Aig_NotCond( (Aig_Obj_t *)Aig_ObjFanin0( pObjCorrespondingLi )->pData, Aig_ObjFaninC0( pObjCorrespondingLi ) ) );
		pObjXnor = Aig_Not( pObjXor );
		
		if( pObjAndAcc == NULL )
			pObjAndAcc = pObjXnor;
		else
		{
			pObjAndAccDummy = pObjAndAcc;
			pObjAndAcc = Aig_And( pNew, pObjXnor, pObjAndAccDummy );
		}
	}

	// create the AND gate whose output will be the signal "looped"
	pObjSavedLoAndEquality = Aig_And( pNew, pObjSavePi, pObjAndAcc );
	
	// create the master AND gate and corresponding AND and OR logic for the liveness properties
	pObjAndAcc = NULL;
	if( vLive == NULL || Vec_PtrSize( vLive ) == 0 )
		printf("\nCircuit without any liveness property\n");
	else
	{
		Vec_PtrForEachEntry( Aig_Obj_t *, vLive, pObj, i )
		{
			pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
			if( pObjAndAcc == NULL )
				pObjAndAcc = pDriverImage;
			else
			{
				pObjAndAccDummy = pObjAndAcc;
				pObjAndAcc = Aig_And( pNew, pDriverImage, pObjAndAccDummy );
			}
		}
	}

	if( pObjAndAcc != NULL )
		pObjLive = pObjAndAcc;
	else
		pObjLive = Aig_ManConst1( pNew );
	
	// create the master AND gate and corresponding AND and OR logic for the fairness properties
	pObjAndAcc = NULL;
	if( vFair == NULL || Vec_PtrSize( vFair ) == 0 )
		printf("\nCircuit without any fairness property\n");
	else
	{
		Vec_PtrForEachEntry( Aig_Obj_t *, vFair, pObj, i )
		{
			pDriverImage = Aig_NotCond((Aig_Obj_t *)Aig_Regular(Aig_ObjChild0( pObj ))->pData, Aig_ObjFaninC0(pObj));
			if( pObjAndAcc == NULL )
				pObjAndAcc = pDriverImage;
			else
			{
				pObjAndAccDummy = pObjAndAcc;
				pObjAndAcc = Aig_And( pNew, pDriverImage, pObjAndAccDummy );
			}
		}
	}

	if( pObjAndAcc != NULL )
		pObjFair = pObjAndAcc;
	else
		pObjFair = Aig_ManConst1( pNew );
	
	pObjSafetyGate = Aig_And( pNew, pObjSavedLoAndEquality, Aig_And( pNew, pObjFair, Aig_Not( pObjLive ) ) );
	
	Aig_ObjPatchFanin0( pNew, pObjSafetyPropertyOutput, pObjSafetyGate );

	Aig_ManSetRegNum( pNew, nRegCount );

	printf("\nSaig_ManPiNum = %d, Reg Num = %d, before everything, before Pi cleanup\n", Vec_PtrSize( pNew->vCis ), pNew->nRegs );

	Aig_ManCiCleanupBiere( pNew );
	Aig_ManCoCleanupBiere( pNew );

	Aig_ManCleanup( pNew );
	
	assert( Aig_ManCheck( pNew ) );
	
	return pNew;
}



static Vec_Ptr_t * populateLivenessVector( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
	Abc_Obj_t * pNode;
	int i, liveCounter = 0;
	Vec_Ptr_t * vLive;

	vLive = Vec_PtrAlloc( 100 );
	Abc_NtkForEachPo( pNtk, pNode, i )
		if( strstr( Abc_ObjName( pNode ), "assert_fair") != NULL )
		{
			Vec_PtrPush( vLive, Aig_ManCo( pAig, i ) );
			liveCounter++;
		}
	printf("\nNumber of liveness property found = %d\n", liveCounter);
	return vLive;
}

static Vec_Ptr_t * populateFairnessVector( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
	Abc_Obj_t * pNode;
	int i, fairCounter = 0;
	Vec_Ptr_t * vFair;

	vFair = Vec_PtrAlloc( 100 );
	Abc_NtkForEachPo( pNtk, pNode, i )
		if( strstr( Abc_ObjName( pNode ), "assume_fair") != NULL )
		{
			Vec_PtrPush( vFair, Aig_ManCo( pAig, i ) );
			fairCounter++;
		}
	printf("\nNumber of fairness property found = %d\n", fairCounter);
	return vFair;
}

static void updateNewNetworkNameManager( Abc_Ntk_t *pNtk, Aig_Man_t *pAig, Vec_Ptr_t *vPiNames, Vec_Ptr_t *vLoNames )
{
	Aig_Obj_t *pObj;
	int i, ntkObjId;

	pNtk->pManName = Nm_ManCreate( Abc_NtkCiNum( pNtk ) );

	Saig_ManForEachPi( pAig, pObj, i )
	{
		ntkObjId = Abc_NtkCi( pNtk, i )->Id;
		//printf("Pi %d, Saved Name = %s, id = %d\n", i, Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), Vec_PtrEntry(vPiNames, i), NULL ), ntkObjId);  
		Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), (char *)Vec_PtrEntry(vPiNames, i), NULL );
	}
	Saig_ManForEachLo( pAig, pObj, i )
	{
		ntkObjId = Abc_NtkCi( pNtk, Saig_ManPiNum( pAig ) + i )->Id;
		//printf("Lo %d, Saved name = %s, id = %d\n", i, Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), Vec_PtrEntry(vLoNames, i), NULL ), ntkObjId);  
		Nm_ManStoreIdName( pNtk->pManName, ntkObjId, Aig_ObjType(pObj), (char *)Vec_PtrEntry(vLoNames, i), NULL );
	}
}


int Abc_CommandAbcLivenessToSafetySim( Abc_Frame_t * pAbc, int argc, char ** argv )
{
	FILE * pOut, * pErr;
    Abc_Ntk_t * pNtk, * pNtkTemp, *pNtkNew, *pNtkOld;
	Aig_Man_t * pAig, *pAigNew;
	int c;
	Vec_Ptr_t * vLive, * vFair;
		        
	pNtk = Abc_FrameReadNtk(pAbc);
    pOut = Abc_FrameReadOut(pAbc);
    pErr = Abc_FrameReadErr(pAbc);

	if ( pNtk == NULL )
    {
        fprintf( pErr, "Empty network.\n" );
        return 1;
    }

	if( !Abc_NtkIsStrash( pNtk ) )
	{
		printf("\nThe input network was not strashed, strashing....\n");
		pNtkTemp = Abc_NtkStrash( pNtk, 0, 0, 0 );
		pNtkOld = pNtkTemp;
		pAig = Abc_NtkToDar( pNtkTemp, 0, 1 );
		vLive = populateLivenessVector( pNtk, pAig );
		vFair = populateFairnessVector( pNtk, pAig );
	}
	else
	{
		pAig = Abc_NtkToDar( pNtk, 0, 1 );
		pNtkOld = pNtk;
		vLive = populateLivenessVector( pNtk, pAig );
		vFair = populateFairnessVector( pNtk, pAig );
	}

#if 0
	Aig_ManPrintStats( pAig );
	printf("\nDetail statistics*************************************\n");
	printf("Number of true primary inputs = %d\n", Saig_ManPiNum( pAig ));
	printf("Number of true primary outputs = %d\n", Saig_ManPoNum( pAig ));
	printf("Number of true latch outputs = %d\n", Saig_ManCiNum( pAig ) - Saig_ManPiNum( pAig ));
	printf("Number of true latch inputs = %d\n", Saig_ManCoNum( pAig ) - Saig_ManPoNum( pAig ));
	printf("Numer of registers = %d\n", Saig_ManRegNum( pAig ) );
	printf("\n*******************************************************\n");
#endif

	c = Extra_UtilGetopt( argc, argv, "1" );
	if( c == '1' )
		pAigNew = LivenessToSafetyTransformationOneStepLoopSim( pNtk, pAig, vLive, vFair );
	else
		pAigNew = LivenessToSafetyTransformationSim( pNtk, pAig, vLive, vFair );
	
#if 0
	Aig_ManPrintStats( pAigNew );
	printf("\nDetail statistics*************************************\n");
	printf("Number of true primary inputs = %d\n", Saig_ManPiNum( pAigNew ));
	printf("Number of true primary outputs = %d\n", Saig_ManPoNum( pAigNew ));
	printf("Number of true latch outputs = %d\n", Saig_ManCiNum( pAigNew ) - Saig_ManPiNum( pAigNew ));
	printf("Number of true latch inputs = %d\n", Saig_ManCoNum( pAigNew ) - Saig_ManPoNum( pAigNew ));
	printf("Numer of registers = %d\n", Saig_ManRegNum( pAigNew ) );
	printf("\n*******************************************************\n");
#endif

	pNtkNew = Abc_NtkFromAigPhase( pAigNew );

	if ( !Abc_NtkCheck( pNtkNew ) )
        fprintf( stdout, "Abc_NtkCreateCone(): Network check has failed.\n" );
	
	updateNewNetworkNameManager( pNtkNew, pAigNew, vecPiNames,vecLoNames );
	Abc_FrameSetCurrentNetwork( pAbc, pNtkNew );

	//Saig_ManForEachPi( pAigNew, pObj, i )
	//	printf("Name of %d-th Pi = %s\n", i, retrieveTruePiName( pNtk, pAig, pAigNew, pObj ) );

	//Saig_ManForEachLo( pAigNew, pObj, i )
	//	printf("Name of %d-th Lo = %s\n", i, retrieveLOName( pNtk, pAig, pAigNew, pObj, vLive, vFair ) );

	//printVecPtrOfString( vecPiNames );
	//printVecPtrOfString( vecLoNames );

#if 0
#ifndef DUPLICATE_CKT_DEBUG
	Saig_ManForEachPi( pAigNew, pObj, i )
		assert( strcmp( (char *)Vec_PtrEntry(vecPiNames, i), retrieveTruePiName( pNtk, pAig, pAigNew, pObj ) ) == 0 );
		//printf("Name of %d-th Pi = %s, %s\n", i, retrieveTruePiName( pNtk, pAig, pAigNew, pObj ), (char *)Vec_PtrEntry(vecPiNames, i) );

	Saig_ManForEachLo( pAigNew, pObj, i )
		assert( strcmp( (char *)Vec_PtrEntry(vecLoNames, i), retrieveLOName( pNtk, pAig, pAigNew, pObj, vLive, vFair ) ) == 0 );
#endif	
#endif
		
	return 0;

}
ABC_NAMESPACE_IMPL_END

