/**
  The HYBRIDSIM project (started 2010)
  For hierarchical symbolic analog IC analysis including sensitivity.

  Students involved in this project:
  	MA, Diming		(MS class 2008)
  	XU, Hui  			(MS class 2009)
  	LI, Xiaopeng 		(MS class 2009)

  Software Architect:
  	SHI, Guoyong		(Prof.)

  Shanghai Jiao Tong University (SJTU)
  School of Microelectronics
  (c) 2010; All Rights Reserved.
*/


/**************************************************************************************
*        Symbolic Circuit Analysis With GPDDs (Graph Pair Decision Diagram)
* GPDDnode.cpp
* Member functions for class GPDDnode.
* GPDDnode is the nodes in GPDD.
*
* CHEN Weiwei		GShi	06/03/31
* School of Microelectronics, Shanghai Jiaotong Univ.
* {chenweiwei, shiguoyong}@ic.sjtu.edu.cn
**************************************************************************************/

#include <vector>
#include <cstdio>

#include "GPDDnode.h"

using std::ostream;
using std::endl;
using std::cerr;
using std::hex;
using std::vector;
// using std::printf;
// using std::fflush;

GPDDnode::GPDDnode()
{
	theSymbol = NULL;
	SymbolIndex	= -1;
	
	Sign_IN = 1;
	Sign_OUT = 1;
	Vertex_IN = NULL;
	Vertex_OUT = NULL;
	pGraph_L = NULL;
	pGraph_R = NULL;
	val_ptr = NULL;
//	sCoeffList   = NULL;
//	sPowerList  = NULL;

	// Add by xuhui
	sens_ptr = NULL;
}	
		
//GPDDnode::GPDDnode(int SymbI, int ss, int so, Subgraph * LT, Subgraph *RT)
GPDDnode::GPDDnode(SymbNode *symbnode, int ss, int so, Subgraph * LT, Subgraph *RT)
{
	theSymbol = symbnode;

	if (!theSymbol) {
		cout << LINE_INFO << "Serious error:" << endl;
		cout << "\n\tMust provide an existing SymbNode for GPDDnode construction." << endl;
		exit(0);
	}
	
	SymbolIndex = theSymbol->symbindex;
	
	Sign_IN = ss;
	Sign_OUT = so;
	Vertex_IN = NULL;
	Vertex_OUT = NULL;
	pGraph_L = LT;
	pGraph_R = RT;
	val_ptr = NULL;

//	sCoeffList   = NULL;
//	sPowerList  = NULL;
//	tag = 1;
//
//	Add by Xu Hui
	sens_ptr = NULL;
}
		
GPDDnode::~GPDDnode()
{
	pGraph_L	= NULL;
	pGraph_R	= NULL;
	
	// int i;
	// sCoeffNode *pScoeffNode;
/*	if(sCoeffList)
	{
#ifndef HASHSCOEFFNODE 
		for(i = 0; i < sCoeffList->size(); i ++)
		{
			pScoeffNode = (*sCoeffList)[i];
			delete pScoeffNode;
		}
		sCoeffList->clear();
#endif
		delete sCoeffList;
	}

	if(sPowerList)
	{
		sPowerList->clear();
		delete sPowerList;
	}*/
}

unsigned GPDDnode::Hash(unsigned i)
{
//	int value = (((int)pGraph_L << 7)^ ((int)pGraph_R << 15) ^ (SymbolIndex < 1));
	long value = ((((long)pGraph_L << 3) + ((long)pGraph_R << 15)) ^ (~SymbolIndex));
	return (value ^ i) % GPDD_PRIME;
}

int GPDDnode::Compare(Comparable * p)
{
	GPDDnode * n= (GPDDnode *) p;		// recast

	ASSERT( p->isa() == GPDDNODE, "not a GPDD Node Object");
 
	if (( SymbolIndex ^ n->GetSymbolIndex()) || 
			((long)pGraph_L ^ (long)n->GetSubgraph_L()) ||
		  	((long)pGraph_R ^ (long)n->GetSubgraph_R()))
	{
		if ((long)this > (long)n)
			return 1;
		if ((long)this < (long)n)
			return -1;
	}
	return 0;
}
		
// Use the addresses of two graphs to generate the entry key to a HashTree.

unsigned GPDDnode::HashTreeID()
{
	return ((((long)pGraph_L) ^ ((long)pGraph_R))) % GPDD_PRIME;
}


/**
	(Same code as GRASS4, improved. G. Shi, 09-04-2010.)
*/
void GPDDnode::PrintGPDDnode(ostream &out)
{
//	out << "\n\tBDD Vertex Index = " << SymbolIndex << " at [" << (void*) this  << "] \t" 
//		<< hex << "Ref = [" << reference << "]";
	
	out << "\n\tVertex Name \"";
	
	if (theSymbol)
		out << theSymbol->symbname;
	else
		out << " ";
	
	out << "\" [#" << SymbolIndex << "] at (" << (void*) this  << ")    " 
		<< hex << "Ref = [" << reference << "]"
		<< endl;
	
	if (Vertex_IN)
	{
		out << "\t\t[Pointer_IN ]--> [#" << dec << Vertex_IN->GetSymbolIndex() 
			<< "] at (" << hex << (void *) Vertex_IN << ")" ;
	}
	else
	{
		out << "\t\t[Pointer_IN ]--> NULL";
	}
	out << endl;
	
	if (Vertex_OUT)
	{
		out << "\t\t[Pointer_OUT]--> [#" << dec << Vertex_OUT->GetSymbolIndex() 
			<< "] at (" << hex << (void *) Vertex_OUT << ")";
	}
	else
	{
		out << "\t\t[Pointer_OUT]--> NULL";
	}
	out << endl;
	
//	out << "\t\tSign_IN = " << dec << (Sign_IN == +1? '+' : '-') 
//		<< " /\\ Sign_OUT = " << (Sign_OUT == +1? '+' : '-');

	out << "\t\t(" << dec << (Sign_IN == +1? '+' : '-') 
		<< ") /\\ (" << (Sign_OUT == +1? '+' : '-') << ")";
	
	out << endl;
}


int GPDDnode_tag::Compare(Comparable *p)
{
	GPDDnode_tag * n = (GPDDnode_tag *) p;		// recast
	
	if ((n->label_left ^ label_left) || (n->label_right ^ label_right))
	{
		if ((long) this > (long) n)
			return 1;
		else
			return -1;
	}

	return 0;
}

sCoeffNode::~sCoeffNode()
{
///	delete val_ptr;
}


unsigned sCoeffNode::Hash(unsigned i)
{
	return ((Vertex_IN->label << 3) ^ (Vertex_OUT->label << 7));
}

int sCoeffNode::Compare(Comparable *p)
{
	sCoeffNode * n = (sCoeffNode *) p;
	
	if((n->Vertex_IN->label ^ Vertex_IN->label) || (n->Vertex_OUT->label ^ Vertex_OUT->label) 
		|| n->pExpNode->Sign_OUT ^ pExpNode->Sign_OUT || n->pExpNode->Sign_IN ^ pExpNode->Sign_IN)
	{
		if ((long) this > (long) n)
			return 1;
		else
			return -1;
	}

	return 0;
}
	
unsigned sCoeffNode::HashGraphID()
{
//	return abs(Vertex_IN->label * pNode->GetSignS() * TAG_PRIME1 + Vertex_OUT->label * pNode->GetSignO()) % TAG_PRIME2;
	return abs(Vertex_IN->label * pExpNode->Sign_IN * TAG_PRIME1 + Vertex_OUT->label * pExpNode->Sign_OUT) % TAG_PRIME2;
}
			
/*complex_t sCoeffNode::GetValue()
{
	if (!val_ptr) {
		cout << LINE_INFO << "Pointer (val_ptr) NULL." << endl;
		exit(0);
	}
	return *val_ptr;
}*/
	
/*complex_t *sCoeffNode::GetValueP()
{
	return val_ptr;
}*/

// int ExpGPDDnode::cnt = 0;

ExpGPDDnode::ExpGPDDnode()
{
	// id = cnt++;
	// printf("ExpGPDDnode constructor[%-3d]: this = %p\n", id, this);
	Vertex_OUT	= NULL;
	Vertex_IN	= NULL;
	pGPDDnode	= NULL;
	sCoeffList   = NULL;
	sPowerList  = NULL;
	visit_flag	= false;
	SymbCountArray = NULL;
}

ExpGPDDnode::ExpGPDDnode(ExpGPDDnode* pS, ExpGPDDnode* pO, GPDDnode* pT, int symbindex, short ss, short so)
{
	// id = cnt++;
	// printf("ExpGPDDnode copy constructor[%-3d]: this = %p\n", id, this);
	Vertex_OUT	= NULL;
	Vertex_IN	= pS;
	Vertex_OUT	= pO;
	pGPDDnode	= pT;
	
	SymbolIndex	= symbindex;
	Sign_OUT	= so;
	Sign_IN		= ss;
	sCoeffList   = NULL;
	sPowerList  = NULL;
	visit_flag	= false;
	SymbCountArray = NULL;
}

ExpGPDDnode::~ExpGPDDnode()
{
	// printf("ExpGPDDnode destructor[%-3d]: this = %p->", id, this);
	// fflush(stdout);
	if (sCoeffList)
	{
#ifndef HASHSCOEFFNODE 
		for (std::vector<sCoeffNode*>::iterator it = sCoeffList->begin();
				 it != sCoeffList->end();
				 ++it)
		{
			// (*it)->print();
			delete *it;
		}
#endif
		delete sCoeffList;
		sCoeffList = 0;
	}

	if (sPowerList)
	{
		sPowerList->clear();
		delete sPowerList;
		sPowerList = 0;
	}

	if (SymbCountArray)
	{
		delete[] SymbCountArray;
		SymbCountArray = 0;
	}
	// printf("<-\n");
}

unsigned ExpGPDDnode::Hash(unsigned i)
{
	return (long)pGPDDnode;
//	return i;
}

int ExpGPDDnode::Compare(Comparable *p)
{
	ExpGPDDnode * n = (ExpGPDDnode *) p;
	if((long)this->pGPDDnode ^ (long)n->pGPDDnode || this->Sign_IN ^ n->Sign_IN || this->Sign_OUT ^ n->Sign_OUT 
		)//|| (!this->pGPDDnode && (this->SymbolIndex ^ n->SymbolIndex)))
	{
		if ((long)this > (long)n)
			return 1;
		else
			return -1;
	}

	return 0;
}
	
unsigned ExpGPDDnode::HashTreeID()
{
	return SymbolIndex % TAG_PRIME2;
}
