Monday 30 September 2013

Parser for converting IBM Power Grid Benchmarks into SPICE netlist

The following program written in c++ converts IBM Power Grid Benchmarks into SPICE netlist. The IBM Power Grid Benchmarks are available for download from here.

Header File
 /* Name - Nahit Pawar 
  * MTech - Electronic Systems - IITB  
  *  
  * Description - parser_PG.hpp 
  */ 
 class parser_PG 
 { 
 public: 
  string edgeType; 
  string sourceSymbol; 
  string sinkSymbol; 
  double branchValue; 
   
  parser_PG() : edgeType(""), sourceSymbol(""), sinkSymbol(""), branchValue(0) 
  { } 
 };   

Main File
 /*  Name: Nahit Pawar  
  *  MTech - Electronic Systems - IIT Bombay   
  *    
  *  Description - main.cpp  
  */  
 #include <iostream>  
 #include <fstream>  
 #include <sstream>  
 #include <vector>  
 #include <set>  
 #include <map>  
 #include <utility>  
   
 #include <cstdlib>  
    
 using namespace std;  
   
   
 #include "parser_PG.hpp"  
   
 typedef map<string,int>::value_type entry;  
   
 int main(int argc, char* argv[])  
 {  
  if(argc != 3)  
  {  
   cout<<"Error: circuit file not found"<<endl;  
   exit(1);  
  }  
     
  ifstream in_file(argv[1]);  
  ofstream out_file(argv[2]);   
  ofstream out_map("map_ibm_test_ckt");  
    
  if(!in_file.is_open() || !out_file.is_open())  
  {  
   cout<<"Error: Can't open input file"<<endl;  
   exit(1);  
  }  
    
  stringstream SS;  
    
  parser_PG parPG;  
  vector<parser_PG> EdgeList;  
    
  string temp;  
  temp.reserve(100);  
    
  const string delim("*");  
  string::size_type begIdx, endIdx;  
    
  uint NumOfEdges=0;  
  uint NumOfNodes=0;  
  uint NumOfCurrentSors=0;  
  uint NumOfVoltageSors=0;  
  uint NumOfResistance=0;  
    
  while(!in_file.eof())  
  {  
   getline(in_file, temp);  
     
   if(!temp.compare(".op")) break;  
     
   begIdx = temp.find_first_of(delim);  
   if(begIdx != string::npos) continue;  
     
   NumOfEdges++;    
  }  
    
  in_file.close();   
  in_file.open(argv[1]);  
    
  EdgeList.reserve(NumOfEdges);  
    
  while(!in_file.eof())  
  {  
   getline(in_file, temp);  
     
   if(!temp.compare(".op")) break;  
     
   begIdx = temp.find_first_of(delim);  
   if(begIdx != string::npos) continue;  
       
   SS.clear();  
   SS.str("");  
     
   SS.str(temp);  
     
   SS >> parPG.edgeType >> parPG.sourceSymbol >> parPG.sinkSymbol >> parPG.branchValue;  
     
   EdgeList.push_back(parPG);  
     
  }  
   
  set<string> source_sink;  
  pair< set<string>::iterator, bool > check;  
    
  map<string,int> symToNum;  
  map<string,int>::iterator sourceNum;  
  map<string,int>::iterator sinkNum;  
  pair< map<string,int>::iterator, bool > status;  
     
  set<string>::iterator setIter;  
    
  status = symToNum.insert(entry("0",NumOfNodes));  
  if(status.second == true) NumOfNodes++;  
    
  for(int i=0; i<EdgeList.size(); i++)  
  {  
   status = symToNum.insert(entry(EdgeList[i].sourceSymbol,NumOfNodes));  
   if(status.second == true) NumOfNodes++;  
   status = symToNum.insert(entry(EdgeList[i].sinkSymbol,NumOfNodes));  
   if(status.second == true) NumOfNodes++;  
  }  
   
    
  string elements("riVvR");  
  string edgeType;  
   
  for(int i=0; i<EdgeList.size(); i++)  
  {  
   sourceNum = symToNum.find(EdgeList[i].sourceSymbol);  
   sinkNum = symToNum.find(EdgeList[i].sinkSymbol);  
     
   begIdx = (EdgeList[i].edgeType).find_first_of(elements);  
   if(begIdx != string::npos)  
   {  
    endIdx = (EdgeList[i].edgeType).find_first_not_of(elements, begIdx);  
    edgeType = (EdgeList[i].edgeType).substr(begIdx, endIdx);  
      
    if(edgeType == "rr")  
    {  
      EdgeList[i].edgeType = "R";  
      NumOfResistance++;  
    }  
    else if(edgeType == "v")  
    {  
      EdgeList[i].edgeType = "V";  
      NumOfVoltageSors++;  
    }  
    else if(edgeType == "V")  
    {  
      EdgeList[i].edgeType = "R";  
      NumOfResistance++;  
    }  
    else if(edgeType == "i")  
    {  
      EdgeList[i].edgeType = "I";  
      NumOfCurrentSors++;  
    }  
    else if(edgeType == "R")  
    {  
      EdgeList[i].edgeType = "R";  
      NumOfResistance++;  
    }  
      
   }  
     
   out_file << EdgeList[i].edgeType <<i+1<< " " << (*sourceNum).second << " " << (*sinkNum).second << " " << EdgeList[i].branchValue << endl;  
  }  
    
  out_file << ".end";  
    
  cout << "Total Number of Edges = " << NumOfEdges << endl;  
  cout << "Total Number of Nodes = " << NumOfNodes << endl;  
  cout << "Total Number of Current sources = " << NumOfCurrentSors << endl;  
  cout << "Total Number of Voltage sources(including shorts) = " << NumOfVoltageSors << endl;  
  cout << "Total Number of Resistance(including shorts) = " << NumOfResistance << endl;  
    
  return 0;  
 }  
   

Saturday 17 August 2013

Mini Tank Game in C using windows 16-bit graphics

This was my first game which is coded and developed,  when I was enjoying my first year summer holidays of my B.Tech in 2008. It was written using Borland's Turbo C++ IDE.
The theme is like this - You have your tank and aliens can appear anywhere from left to right with random speed. The task is you have 14 shoot to kill 14 aliens.
At the time of development the only thing I knew was Logic operation, Functions and 16-bit windows graphics so it was a very big thing for me at that time.
Follow the link to download full code: https://github.com/leonahi/mini-tank.git

Monday 22 July 2013

Sqlite3 and Python: How to join two database tables created in Python using Sqlite3 module

I am assuming that readers of this post has working knowledge of python and sqlite3 module, if not I have added detailed comments where necessary.
In brief what it does is it takes two database tables and joins them together, including any duplicate columns only once.
For example: If first database table has columns (Id, Date, time, col1, col2, col3) and second database table has columns (Id, Data, time, col4, col5, col6) then output of function join_database() will be a new database table containing columns(Id, Date, Time, col1, col2, col3, col4, col5, col6).
You are always welcome to download the source code from here.


 import sqlite3 as lite  
 import sys  
   
 def join_database(database1Name, database2Name, database3Name):  
  ''' Join two database 'database1Name' and 'database2Name' into database 'database3Name' '''  
    
  con1 = lite.connect(database1Name)      # Connect to Database1  
  con2 = lite.connect(database2Name)      # Connect to Database2  
  con3 = lite.connect(database3Name)      # Connect to Database3  
   
  con1.row_factory = lite.Row         # For reading column names from Database1  
  con2.row_factory = lite.Row         # For reading column names from Database2  
   
  con1_new = lite.connect(database1Name)    # Create new connection with Database1 for reading data  
  con2_new = lite.connect(database2Name)    # Create new connection with Database2 for reading data  
   
  with con1, con2, con3, con1_new, con2_new:  
   cur1 = con1.cursor()            # Get cursor from connection 1 (con1)  
   cur2 = con2.cursor()            # Get cursor from connection 2 (con2)  
   cur3 = con3.cursor()            # Get cursor from connection 3 (con2)  
    
   cur1_new = con1_new.cursor()        # Get connection from connection 1_new (con1_new)  
   cur2_new = con2_new.cursor()        # Get connection from connection 2_new (con2_new)  
     
   cur1.execute("SELECT * FROM your_table_name")  # Select all column names from table your_table_name in Database1 (Why column names see line no. 11)  
   cur2.execute("SELECT * FROM your_table_name")  # Select all column names from table your_table_name in Database2 (Why column names see line no. 12)  
    
   row_1 = cur1.fetchone()      # Fetch column names from database1 table  
   row_2 = cur2.fetchone()      # Fetch column names from database2 table  
    
   columnNames = row_1.keys()    # Read column names from Database1  
     
   for item in row_2.keys():     # Append column names from Database1 with Database2, including duplicate column names only once (See description)  
    if item not in row_1.keys():  
     columnNames.append(item)  
    
   cur3.execute("CREATE TABLE IF NOT EXISTS your_table_name(Id INTEGER PRIMARY KEY, Date TEXT(10), Time TEXT(8))")  # You can change this line according to your needs  
     
   for col in columnNames[3:]:  
    cur3.execute("ALTER TABLE your_table_name ADD {} DOUBLE".format(col)) # You can change the data type(here it is DOUBLE) according to your needs  
    
   cur1_new.execute("SELECT * FROM your_table_name")  # Select complete data at once from table your_table_name in database1  
   cur2_new.execute("SELECT * FROM your_table_name")  # Select complete data at once from table your_table_name in database2  
    
   rows1 = cur1_new.fetchall()   # Read all rows from Database1  
   rows2 = cur2_new.fetchall()   # Read all rows from Database2  
    
   rows1 = [r[1:] for r in rows1]  # Except first row in rows1 read all rows  
   rows2 = [r[3:] for r in rows2]  # Except first three rows in rows2 read all rows  
    
   rows = [r1 + r2 for r1, r2 in zip(rows1, rows2)] #Combine each rows in rows1 and rows2 element wise  
    
   ques = []            # Use by sqlite for inserting into table  
     
   ques = ["?"]*len(columnNames[1:])  # Generate list [?, ?, ?, ?,........till length equals length of columnNames[1:]  
   ques = ",".join(ques)        # Generate string "?,?,?,?,?........"  
     
   columnNames = ",".join(columnNames[1:]) # Generate string "col1, col2, col3............"  
      
   for item in rows:        # Insert combined data into new Database3  
    cur3.execute("INSERT INTO your_table_name({0}) VALUES ({1})".format(columnNames, ques), item)  
      
 if __name__ == '__main__':  
  pass  

Tuesday 26 February 2013

Matrix Multiplication serial and parallel codes(OpenCL and OpenMP) and their respective speed ups

Below i have written parallel codes for Matrix Multiplication(C = AxB), i used OpenCL and OpenMP for this. Though at this stage i am beginner in OpenMP, therefore OpenMP code is bit trivial. Beside this i have tabulated their respective speed ups on three different machines. Serial code is same as OpenMP code except #pragma  line. The order of matrix A and B is 1000x1000 each initialized to 1.
 // OpenCL Matrix Multiplication kernel
 __kernel void matrixMultiply(__global float* A,\ 
                __global float* B,\ 
                __global float* C,\ 
                const uint Ndim,\ 
                const uint Mdim,\ 
                const uint Pdim) 
 { 
  int idx = get_global_id(0); 
  float A_private[1000]; 
  float tmp; 
  if(idx < Ndim) 
  { 
   for(int k=0; k<Pdim; k++) 
    A_private[k] = A[idx*Pdim + k]; 
   for(int j=0; j<Mdim ;j++) 
   { 
    tmp = 0.0;  
    for(int k=0; k<Pdim; k++) 
    { 
     tmp += A_private[k]*B[k*Mdim + j]; 
    } 
    C[idx*Mdim + j] = tmp; 
   } 
  } 
 } 

 // OpenMP Matrix Multiplication   
 #pragma omp parallel for shared(A, B, C, ROWA, COLA, COLB)  
  for(int i = 0; i < ROWA; i++)  
  {  
   for(int j = 0; j < COLB; j++)  
   {  
    C[j + i*COLB] = 0;  
    for(int k = 0; k < COLA; k++)  
    {  
     C[j + i*COLB] += A[i*COLA + k]*B[j + COLB*k];  // dot-product  
    }  
   }  
  }  

ProcessorSerialOpenMPOpenCL
Intel Xeon E5 Max Threads – 325.93 sec.750 sec.258 sec
Intel Core i7 Max Threads – 89.84 sec2.49 sec1.90 sec
Intel Atom N550 Max Threads – 487.06 sec34.237 sec11.34 sec

Saturday 2 February 2013

Parser for Harwell-Boeing(HB) sparse matrix file format

Harwell-Boeing(HB) sparse matrix file format is used to store information related to sparse matrix. The matrix inside this file is stored in compressed column storage format, which is very efficient in terms of memory requirements. So the same compressed column storage can be used to represent matrix in memory. For more information about HB file format click here.
  • Below i have written a small function read_HB_file() of class HBSparseMatrixFF that reads the HB file and stores the matrix and its related information in compressed column storage format, you can use my class sparseMatrix to store this information. This routine is limited in capability i.e it only reads real, assembled sparse matrix with no right hand side. You can download files in HB format from here.
  • GitHub link
 class sparseMatrix  
 {  
 public:  
  unsigned int numRow;    // Number of rows  
  unsigned int numCol;    // Number of columns  
  unsigned int numElement;  // Number non zero elements of the sparse matrix   
  unsigned int* ROWIND;    // Row index of the matrix (Size = numElement)  
  unsigned int* COLPTR;    // Column pointer of the matrix (Size = numCol+1)  
  double* VALUES;       // Non zero elements in the sparse matrix (Size = numElement)  
  sparseMatrix();  
  ~sparseMatrix();  
 };  
 inline sparseMatrix::sparseMatrix() : numRow(0), numCol(0), numElement(0)  
 {  
  ROWIND = NULL;  
  COLPTR = NULL;  
  VALUES = NULL;  
 }  
 inline sparseMatrix::~sparseMatrix()  
 {  
  delete [] ROWIND;  
  delete [] COLPTR;  
  delete [] VALUES;  
 }  

 class HBSparseMatrixFF  
 {  
 private:  
 //--------------Line 1-------------------------   
  string title;         // TITLE  
  string key;          // KEY  
 //--------------Line 2-------------------------   
  unsigned int totcrd;     // TOTCRD - Total Number of data lines.  
  unsigned int ptrcrd;     // PTRCRD - Number of data lines for pointer.  
  unsigned int indcrd;     // INDCRD - Number of data lines for row or variable indices.  
  unsigned int valcrd;     // VALCRD - Number of data lines for numercal values of matrix entries.  
  unsigned int rhscrd;     // RHSCRD - Number of data lines for right hand side vectors, starting guesses, and solutions.  
 //--------------Line 3-------------------------   
  string mxtype;        // MXTYPE - Matrix type.  
  unsigned int nrow;      // NROW  - Number of rows or variables.  
  unsigned int ncol;      // NCOL  - Number of columns or elements.  
  unsigned int nnzero;     // NNZERO - Number of row or variable indices.  
  unsigned int neltvl;     // NELTVL - Number of elemental matrix entries.  
 //--------------Line 4-------------------------   
  string ptrfmt;        // PTRFMT - FORTRAN I/O format for pointers  
  string indfmt;        // INDFMT - FORTRAN I/O format for row or variable indices  
  string valfmt;        // VALFMT - FORTRAN I/O format for matrix entries  
  string rhsfmt;        // RHSFMT - FORTRAN I/O format for right hand sides, initial guesses, and solutions  
 //--------------Line 5-------------------------   
  string rhstyp;        // RHSTYP - Describes the right hand side information  
  unsigned int nrhs;      // NRHS  - Integer, the number of right hand sides  
  unsigned int nrhsix;     // NRHSIX - Integer, number of row indices  
  void error(ifstream& file)  
  {  
   if(file.eof())  
   {  
    cout<<"Fatal error : Input file format is not correct"<<endl;  
    exit(1);  
   }  
  }  
  void checkMatrixType(string& mxtype);  
 public:  
  HBSparseMatrixFF() : totcrd(0), ptrcrd(0), indcrd(0), valcrd(0), rhscrd(0), nrow(0), ncol(0), nnzero(0), neltvl(0)  
  {}  
  void read_HB_file(ifstream& file, unsigned int& numRow, unsigned int& numCol, unsigned int& numElement, unsigned int*& COLPTR, unsigned int*& ROWIND, double*& VALUES);  
 };  
 void HBSparseMatrixFF::read_HB_file(ifstream& file, unsigned int& numRow, unsigned int& numCol, unsigned int& numElement, unsigned int*& COLPTR, unsigned int*& ROWIND, double*& VALUES)  
 {  
  stringstream SS;  
  string LINE;  
  LINE.reserve(80);  
 //------------------Reading first line-------------------  
  title.reserve(72);  
  key.reserve(8);  
  getline(file, LINE);  
  error(file);  
  title = LINE.substr(0,71);  
  key = LINE.substr(72,79);  
 //------------------Reading second line------------------  
  getline(file, LINE);  
  error(file);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  SS >> totcrd >> ptrcrd >> indcrd >> valcrd >> rhscrd;  
 //------------------Reading third line--------------------   
  mxtype.reserve(3);  
  getline(file, LINE);  
  error(file);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  SS >> mxtype >> nrow >> ncol >> nnzero >> neltvl;  
 //------------------Reading fourth line--------------------  
  ptrfmt.reserve(16);   
  indfmt.reserve(16);   
  valfmt.reserve(20);   
  rhsfmt.reserve(20);  
  getline(file, LINE);  
  error(file);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  SS >> ptrfmt >> indfmt >> valfmt >> rhsfmt;   
 //-------------------Reading fifth line (only if 0 < rhscrd!)---------------------  
 rhstyp.reserve(3);  
 if(rhscrd > 0)  
 {  
  getline(file, LINE);  
  error(file);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  SS >> rhstyp >> nrhs >> nrhsix;  
  cout<<"Sorry! this code only reads HB sparse matrix file format with no right hand side"<<endl;  
  exit(1);  
 }  
 checkMatrixType(mxtype);              // Check type of matrix (This code only reads real, assembled matrix)  
 numRow = nrow;  
 numCol = ncol;  
 numElement = nnzero;  
 COLPTR = new unsigned int[ncol+1]();  
 ROWIND = new unsigned int[nnzero]();   
 VALUES = new double[nnzero]();  
 unsigned int temp_ui;  
 unsigned int k=0;  
 for(int i=0; i<ptrcrd; i++)            // Storing Column pointer  
 {  
  getline(file, LINE);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  while(SS.good())  
  {  
   SS >> temp_ui;  
   COLPTR[k] = temp_ui;  
   k++;  
   if(k==ncol+1) break;  
  }  
 }  
 k=0;  
 for(int i=0; i<indcrd; i++)            // Storing Row index   
 {  
  getline(file, LINE);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  while(SS.good())  
  {  
   SS >> temp_ui;  
   ROWIND[k] = temp_ui;  
   k++;  
   if(k==nnzero) break;  
  }  
 }  
 double temp_d;  
 k=0;  
 for(int i=0; i<valcrd; i++)             // Storing Non zero entries  
 {  
  getline(file, LINE);  
  SS.clear();  
  SS.str("");  
  SS.str(LINE);  
  while(SS.good())  
  {  
   SS >> temp_d;  
   VALUES[k] = temp_d;  
   k++;  
   if(k==nnzero) break;  
  }  
 }  
 LINE.clear();  
 }  
 inline void HBSparseMatrixFF::checkMatrixType(string& mxtype)  
 {  
  if(mxtype[0]!='R')  
  {  
   cout<<"Sorry! This code reads only real valued matrices"<<endl;  
   exit(1);  
  }  
  if(mxtype[2]!='A')  
  {  
   cout<<"Sorry! This code only reads assembled matrices"<<endl;  
   exit(1);  
  }  
 }