// File: benchmarks.cc
// Author: Jeff Bilmes
// Created: Tue Oct 30 11:31:21 1990
// Copyright (C) International Computer Science Institute, 1990
//
//  C++ versions of the performance benchmarks.
//
// COPYRIGHT NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY
// and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
// LICENSE contained in the file: "sather/doc/license.txt" of the Sather
// distribution. The license is also available from ICSI, 1947 Center
// St., Suite 600, Berkeley CA 94704, USA.


#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>

enum bool { true = 1, false = 0 };


// ***********************************************************
//  BENCHMARK ABSTRACTION
// ***********************************************************

class benchmarks {

 protected:
  char *shortName;

  struct rusage rus; // r usages start
  struct rusage rue; // r usage end

  int defaultIters;
  bool isFloatingPointBenchMark;
  int seed;
  
  benchmarks(char*name) : 
    shortName(name),
    seed(0),isFloatingPointBenchMark(false),
    defaultIters(10) {}

  // quick and dumb random number generator
  void initrand() { seed = 74755; }
  int rand() { seed = (seed*1309+13849) & 65535; return seed; }


  void startTiming() { getrusage(RUSAGE_SELF,&rus); }
  void finishTiming() { getrusage(RUSAGE_SELF,&rue); }
  void reportTiming() { 
    struct timeval utime;
    float utimef;
    struct timeval stime;
    float stimef;

    /* user time */
    utime.tv_sec = rue.ru_utime.tv_sec - rus.ru_utime.tv_sec ;
    if ( rue.ru_utime.tv_usec < rus.ru_utime.tv_usec ) {
      utime.tv_sec--;
      utime.tv_usec = 1000000l - rus.ru_utime.tv_usec +
	rue.ru_utime.tv_usec;
    } else
      utime.tv_usec = rue.ru_utime.tv_usec -
	rus.ru_utime.tv_usec ;
    utimef = (float)utime.tv_sec + (float)utime.tv_usec/1e6;
    utimef /= (float)defaultIters;
    /* system time */
    stime.tv_sec = rue.ru_stime.tv_sec - rus.ru_stime.tv_sec ;
    if ( rue.ru_stime.tv_usec < rus.ru_stime.tv_usec ) {
      stime.tv_sec--;
      stime.tv_usec = 1000000l - rus.ru_stime.tv_usec +
	rue.ru_stime.tv_usec;
    } else
      stime.tv_usec = rue.ru_stime.tv_usec -
	rus.ru_stime.tv_usec ;

    stimef = (float)stime.tv_sec + (float)stime.tv_usec/1e6;
    stimef /= (float)defaultIters;
    /*
    printf("User: %d:%d System: %d:%d CPU %d:%d\n",
	  utime.tv_sec,utime.tv_usec,
	  stime.tv_sec,stime.tv_usec,
	  utime.tv_sec+stime.tv_sec,utime.tv_usec+stime.tv_usec);
	  */
    printf("User: %f System: %f CPU %f\n",
	  utimef, stimef, utimef+stimef);
  }

 public:
  void measurePerformance() { 
    printf("Measuring Performance of %s\n",shortName);
    startTiming(); 
    for (int i=0;i<defaultIters;i++)
      run(); 
    finishTiming(); 
    reportTiming(); 
  }
  virtual void run() {}

};



// ***********************************************************
//  PERMUTATIONS
// ***********************************************************

class perm : public benchmarks {

 protected:


  float base;

  int permcount;
  int permrange;
  int *permarray;


  void swap(int i, int j);
  void initialize();
  void permute(int n);


 public:
  int pctr;
  void run();
  perm(char *name="perm");
  ~perm();
};


void perm::swap(int i, int j) { 
  int t = permarray[i]; 
  permarray[i] = permarray[j];
  permarray[j] = t;
}

void perm::initialize() { 
  permarray = new int[permrange+1];
  for (int i=1;i<=permrange;i++)
    permarray[i] = (i-1);
}

void perm::permute(int n) {
  pctr ++;
  if (n != 1) {
    permute(n-1);
    for (int k = (n-1); k >= 1; k-- ) {
      swap(n,k);
      permute(n-1);
      swap(n,k);
    }
  }
}

void perm::run() { 
  pctr = 0;
  for(int i=0;i<permcount;i++) {
    initialize(); permute(7);
  }
  if (pctr != 8660*permcount)
    fprintf(stderr,"Error in perm\n");
}
     
perm::perm(char *name="perm") 
     : benchmarks(name),base(1.75),permcount(5),permrange(10),pctr(0)
{ 
  permarray = new int[permrange+1];
}

perm::~perm() { 
  delete permarray; 
}




class xperm : public perm 
{
  class vector {
    int *array;
    int size;
    xperm* myXPerm;
    
  public:
    vector(xperm *mxp, int sz);
    
    void permSwap(int a,int b);
    void perminitialize();
    void permute(int n);
  };
  vector vec;

 public:

  xperm();

  void run();

};

    
vector::vector(xperm *mxp, int sz) : size(sz),myXPerm(mxp) { 
  array = new int[sz+1]; 
}
    
void vector::permSwap(int a,int b) { 
  int t=array[a];array[a]=array[b];array[b]=t; 
}
void vector::perminitialize() { 
  for(int i=1;i<=size;i++) 
    array[i] = i-1;
}
    
void vector::permute(int n) 
{
  myXPerm->pctr++;
  if (n != 1) {
    permute(n-1);
    for (int k = (n-1); k >= 1; k-- ) {
      permSwap(n,k);
      permute(n-1);
      permSwap(n,k);
    }
  }
}

xperm::xperm() : perm("xperm"),vec(this,permrange) {}

void xperm::run() { 
  pctr = 0;
  for(int i=0;i<permcount;i++) {
    vec.perminitialize(); vec.permute(7);
  }
  if (pctr != 8660*permcount)
    fprintf(stderr,"Error in perm\n");
}


// ***********************************************************
//  TOWERS
// ***********************************************************


class towers : public benchmarks {

  class element {
  public:
    int discsize;
    int next;
  };

 protected:
  int maxcells;
  int stackrange;
  element *cellspace;
  int *stack;
  int freelist;
  int movesdone;

  void error(char *emsg);
  void makenull(int i);

  int getelement();
  void push(int i, int s);
  void init(int s,int n);
  int pop(int s);
  void moveFrom(int s1, int s2);

  void towerI(int pegi, int pegj, int numDisks);


 public:  

  towers(char *name="towers");

  void run();

};



void towers::error(char *emsg) {
  fprintf(stderr,"Error in towers: %s\n",emsg);
}

void towers::makenull(int i) { stack[i] = 0; }
     
int towers::getelement() {
  int res;
  if (freelist > 0) {
    res = freelist;
    freelist = cellspace[freelist].next;
    return res;
  } else
    error("out of space");
}
     
void towers::push(int i, int s) {
  int localel;
  if (stack[s] > 0)
    if (cellspace[stack[s]].discsize <= i)
      error("disc size error");
  
  localel = getelement();
  cellspace[localel].next = stack[s];
  stack[s] = localel;
  cellspace[localel].discsize = i;
}
     
void towers::init(int s,int n) {
  makenull(s);
  for (int discctr = n; discctr>=1; discctr --) 
    push(discctr,s);
}

int towers::pop(int s) {
  int temp1; int temp;
  if (stack[s] <= 0)
    error("nothing to pop");
  temp1 = cellspace[stack[s]].discsize;
  temp = cellspace[stack[s]].next;
  cellspace[stack[s]].next = freelist;
  freelist = stack[s];
  stack[s] = temp;
  return temp1;
}

void towers::moveFrom(int s1, int s2) {
  push(pop(s1),s2);
  movesdone++;
}

void towers::towerI(int pegi, int pegj, int numDisks) {
  if (numDisks == 1)
    moveFrom(pegi,pegj);
  else {
    int other = 6 - pegi - pegj;
    towerI(pegi,other,numDisks-1);
    moveFrom(pegi,pegj);
    towerI(other,pegj,numDisks-1);
  }
}

towers::towers(char *name="towers") : benchmarks(name),maxcells(18),stackrange(3) 
{}

void towers::run() {
  int i;
  cellspace = new element[maxcells+1];
  for (i=1;i<=maxcells;i++)
    cellspace[i].next = (i-1);
  stack = new int[stackrange+1];
  freelist = maxcells;
  init(1,14);
  makenull(2);
  makenull(3);
  movesdone = 0;
  towerI(1,2,14);
  if (movesdone != 16383)
    fprintf(stderr,"Error in running %s\n",shortName);
}






class xtowers : public benchmarks {

  class disk {
  public:
    int discSize;
    disk *next;
    bool operator >= (disk& d);
  };

 protected:
  int maxcells;
  int stackrange;
  disk *sentinel;
  disk **stack;
  int movesdone;

  
  disk* discSize(int i);

  void error(char *emsg);
  void makenull(int i);

  disk *pop(int s);
  void push(disk* d, int s);
  void init(int s,int n);
  void moveFrom(int s1, int s2);
  void towerI(int pegi, int pegj, int numDisks);

 public:  

  xtowers(char *name="xtowers");
  void run();

};


bool disk::operator >= (disk& d) { return (bool)(discSize >= d.discSize); }

disk* xtowers::discSize(int i) 
{ disk *tmp=new disk; tmp->discSize = i; return tmp; }

void xtowers::error(char *emsg) {
  fprintf(stderr,"Error in towers: %s\n",emsg);
}

void xtowers::makenull(int i) { 
  stack[i] = sentinel; 
}

disk *  xtowers::pop(int s) { 
  disk *res;
  if (sentinel == stack[s])
    error("Nothing to pop");
  res = stack[s];
  stack[s] = res->next;
  return res;
}

void xtowers::push(disk* d, int s) {
  disk *localel;
  localel = stack[s];
  if (*d >= *localel)
    error("disc size error");
  d->next = localel;
  stack[s] = d;
}


void xtowers::init(int s,int n) {
  for (int discctr = n; discctr>=1; discctr --) 
    push(discSize(discctr),s);
}

void xtowers::moveFrom(int s1, int s2) {
  push(pop(s1),s2);
  movesdone++;
}

void xtowers::towerI(int pegi, int pegj, int numDisks) {
  if (numDisks == 1)
    moveFrom(pegi,pegj);
  else {
    int other = 3 - pegi - pegj;
    towerI(pegi,other,numDisks-1);
    moveFrom(pegi,pegj);
    towerI(other,pegj,numDisks-1);
  }
}

xtowers::xtowers(char *name="xtowers") : benchmarks(name),maxcells(18),stackrange(3) {
  sentinel = discSize(15);
}

void xtowers::run() {
  stack = new disk*[stackrange];
  
  makenull(0);
  makenull(1);
  makenull(2);
  init(0,14);
  movesdone = 0;
  towerI(0,1,14);
  if (movesdone != 16383)
    fprintf(stderr,"Error in running %s\n",shortName);
}


     
     

// ***********************************************************
//  8 QUEENS
// ***********************************************************


class queens : public benchmarks {

  int queencount;
  bool *a,*b,*c;
  int *x;

  bool tryI(int i);
  void doQueens();

 public:

  queens(char *name="queens");
  void run();

};



bool queens::tryI(int i) {
  int j = 0;
  bool q = false;
  while (!q && (j!=8)) {
    j++;
    q = false;
    if (b[j] && a[i+j] && c[(i-j)+7]) {
      x[i] = j;
      b[j] = false;
      a[i+j] = false;
      c[(i-j)+7] = false;
      if (i<8) {
	q = tryI(i+1);
	if (!q) {
	  b[j] = true;
	  a[i+j] = true;
	  c[(i-j)+7] = true;
	}
      } else
	q = true;
    }
  }
  return q;
}

void queens::doQueens() {
  a = new bool[17];
  b = new bool[9];
  c = new bool[15];
  x = new int[9];
  int i = -7;
  
  while (i <= 16) {
    if ((i>=1) && (i<=8)) 
      b[i] = true;
    if (i>=2) a[i] = true;
    if (i<=7) c[i+7] = true;
    i++;
  }
  if (!tryI(1))
    fprintf(stderr,"Error in queens\n");
}


queens::queens(char *name="queens") : benchmarks(name),queencount(50) 
{}
     

void queens::run() {
  for (int i=0;i<queencount;i++)
    doQueens();
}


class xqueens : public benchmarks { 

  int queencount;

  bool freeMajs[15];
  bool freeRows[8];
  bool freeMins[15];
  int qrows[8];

  bool try(int col);
  void doQueens();
  public:

  xqueens(char *name="xqueens");
  void run();

};


bool xqueens::try(int col) {
  for (int row=0;row<8;row++) {
    if (freeRows[row] && freeMajs[col + row] && freeMins[(col - row) + 7]) {
      qrows[col] = row;
      // qrows printString printLine.
	freeRows[row] = false;
      freeMajs[col + row] = false;
      freeMins[(col - row) + 7] = false;
      if (col == 7)
	return true;
      if (try(col+1))
	return true;
      freeRows[row] = true;
      freeMajs[col + row] = true;
      freeMins[(col - row) + 7] =  true;
    }
  }
  return false;
}

void xqueens::doQueens() {
  if (!try(0))
    fprintf(stderr,"Error in xqueens\n");
}


xqueens::xqueens(char *name="xqueens") : benchmarks(name),queencount(50) {
  for (int i=0;i<15;i++) freeMajs[i] = true;
  for (i=0;i<8;i++) freeRows[i] = true;
  for (i=0;i<15;i++) freeMins[i] = true;
}

void xqueens::run() {
  for (int i=0;i<queencount;i++) {
    xqueens xq = *this;
    xq.doQueens();
  }
}





// ***********************************************************
//  Multiplication of integer matrices
// ***********************************************************

typedef int (*matrix)[41];

class intmm : public benchmarks {

  const int rowsize;



  matrix ma;
  matrix mb;
  matrix mr;

  int newValue();

  matrix newMatrix();
  matrix initmatrix();
  int innerproductOf(matrix ma,matrix mb,int row,int column);

  public:

  intmm(char *name="intmm");
  void run();

};


int intmm::newValue() { return rand(); }

matrix intmm::newMatrix() {
  return (matrix)(new int[41*41]);
}

matrix intmm::initmatrix() {
  matrix m = newMatrix();
  for (int i=1;i<=rowsize;i++)
    for (int j=1;j<=rowsize;j++) {
      int temp = newValue();
      m[i][j] = temp - ((temp / 120) * 120) - 60;
    }
  return m;
}

int intmm::innerproductOf(matrix ma,matrix mb,int row,int column) {
  int res = 0;
  for (int i=1;i<=rowsize;i++)
    res += ma[row][i]*mb[i][column];
  return res;
}


  
intmm::intmm(char *name="intmm") : benchmarks(name),rowsize(40) {
}


void intmm::run() {
  initrand();
  ma = initmatrix();
  mb = initmatrix();
  mr = newMatrix();
  for (int i = 1; i <= rowsize; i++)
    for (int j=1;j<=rowsize;j++)
      mr[i][j] = innerproductOf(ma,mb,i,j);
}


// -----------------------------------------------------------

#define ROWSIZE 40
class xintmm : public benchmarks {

  class xvector : public benchmarks {
    public:
      int rowsize;
      int (*values)[(ROWSIZE)];

      xvector();
      void init();
      int* operator[](int i) { return values[i]; }
      xvector operator*(xvector &vec);
      int innerProductWith(int *row,xvector &vec,int col);
  };

  public:

   xintmm();
   void run();

};


xvector::xvector() : rowsize(ROWSIZE), benchmarks("xvector")
{
  values = (int(*)[ROWSIZE])(new int[(ROWSIZE)*(ROWSIZE)]);
};

void xvector::init() {
  for (int i=0;i<rowsize;i++) 
    for (int j=0;j<rowsize;j++) {
      int temp = rand();
      values[i][j] = temp - ((temp / 120) * 120) - 60;
    }
}

xvector xvector::operator*(xvector &vec) {
  xvector r;
  for (int i=0;i<rowsize;i++) 
    for (int j=0;j<rowsize;j++) {
      r[i][j] = innerProductWith(values[i],vec,j);
    }
  return r;
}

int xvector::innerProductWith(int *row,xvector &vec,int col) {
  int res = 0;
  for (int i=0;i<rowsize;i++)
    res += row[i]*vec[i][col];
  return res;
}

xintmm::xintmm() : benchmarks("xintmm") 
{}

void xintmm::run() { 
  initrand();
  xvector a;
  xvector b;
  a.init();
  b.init();
  xvector r = a*b;
}

// ***********************************************************
// PUZZLE
// A compute-bound program from Forest Baskett.
// ***********************************************************


class puzzle : public benchmarks {

  public:

    const int puzzleSize;
    const int classmax;
    const int typemax;
    const int d;
    int n;
    int kount;

    puzzle();
    int *piececount;
    int *mclass;
    int *piecemax;
    bool *puzzl;
    bool **p;

    bool fitI(int i,int j);

    int placeI(int i,int j);
    void removeI(int i,int j);
    bool trial(int j);

    void run1();
    void run2();
    void run3();
    void run4();
    void run5();
    void run6();
    void run7();
    void run8();
    void run9();
    void run10();
    void run11();
    void run12();
    void run13();
    void run14();
    void run15();
    void run16();

    void runLast();
    void run();

};



puzzle::puzzle() : benchmarks("puzzle"),
  puzzleSize(511),classmax(3),typemax(12),d(8),
  n(0),kount(0) 
{}

bool puzzle::fitI(int i,int j) {
  for (int k=0;k<=piecemax[i];k++) { 
    if (p[i][k] && puzzl[j+k])
      return false;
  }
  return true;
};

int puzzle::placeI(int i,int j) {
  for (int k=0;k<=piecemax[i];k++)
    if (p[i][k])
      puzzl[j+k] = true;
  piececount[mclass[i]] --;
  for (k=j;k<=puzzleSize;k++)
    if (!puzzl[k])
      return k;
  return 0;
};

void puzzle::removeI(int i,int j) {
  for (int k=0;k<=piecemax[i];k++) {
    if (p[i][k])
      puzzl[j+k] = false;
  }
  piececount[mclass[i]]++ ;
}


bool puzzle::trial(int j){ 
  kount ++;
  for (int i=0;i<=typemax;i++) {
    if (piececount[mclass[i]]) {
      if (fitI(i,j)) {
	int k;
	k = placeI(i,j);
	if (trial(k) || (k == 0))
	  return true;
	else
	  removeI(i,j);
      }
    }
  }
  return false;
}

void puzzle::run1() {
  piececount = new int[classmax+1];
  mclass = new int[typemax+1];
  piecemax = new int[typemax+1];
  puzzl = new bool[puzzleSize + 1];
  p = new bool*[typemax+1];
  for (int i=0; i<=typemax;i++) 
    p[i] = new bool[puzzleSize+1];
  
  for (i=0;i<=puzzleSize;i++) 
    puzzl[i] = true;
}

void puzzle::run2() { 
  for (int i=1;i<=5;i++)
    for (int j=1;j<=5;j++) 
      for (int k=1;k<=5;k++)
	puzzl[i + (d * (j + (d * k)))] = false;
}

void puzzle::run3() {
  for (int i=0;i<=typemax;i++)
    for (int m=0;m<=puzzleSize;m++)
      p[i][m] = false;
}

void puzzle::run4() {
  for (int i=0;i<=3;i++)
    for(int j=0;j<=1;j++)
      for(int k=0;k<=0;k++)
	p[0][i + (d * (j + (d * k)))] = true;
  mclass[0] = 0;
  piecemax[0] = 3 + (d * 1) + (d * d * 0);
}

void puzzle::run5()  { 
  for (int i=0;i<=1;i++)
    for (int j=0;j<=0;j++)
      for (int k=0;k<=3;k++)
	p[1][i + (d * (j + (d * k)))] = true;
  mclass[1] = 0;
  piecemax[1] = 1 + (d * 0) + (d * d * 3);
}

void puzzle::run6() {
  for (int i=0;i<=0;i++)
    for (int j=0;j<=3;j++)
      for (int k=0;k<=1;k++)
	p[2][i + (d * (j + (d * k)))] = true;
  mclass[2] = 0;
  piecemax[2] = 0 + (d * 3) + (d * d * 1);
}

void puzzle::run7() {
  for (int i=0;i<=1;i++)
    for (int j=0;j<=3;j++)
      for (int k=0;k<=0;k++)
	p[3][i + (d * (j + (d * k)))] = true;
  mclass[3] = 0;
  piecemax[3] = 1 + (d * 3) + (d * d * 0);
}

void puzzle::run8() {
  for (int i=0;i<=3;i++)
    for(int j=0;j<=0;j++)
      for(int k=0;k<=1;k++)
	p[4][i + (d * (j + (d * k)))] = true;
  mclass[4] = 0;
  piecemax[4] =  3 + (d * 0) + (d * d * 1);
}

void puzzle::run9() {
  for (int i=0;i<=0;i++)
    for (int j=0;j<=1;j++)
      for (int k=0;k<=3;k++)
	p[5][i + (d * (j + (d * k)))] = true;
  mclass[5] = 0;
  piecemax[5] = 0 + (d * 1) + (d * d * 3);
}

void puzzle::run10() {
  for(int i=0;i<=2;i++)
    for(int j=0;j<=0;j++)
      for(int k=0;k<=0;k++)
	p[6][i + (d * (j + (d * k)))] = true;
  mclass[6] = 1;
  piecemax[6] = 2 + (d * 0) + (d * d * 0);
}

void puzzle::run11() {
  for (int i=0;i<=0;i++)
    for (int j=0;j<=2;j++) 
      for (int k=0;k<=0;k++)
	p[7][i + (d * (j + (d * k)))] = true;
  mclass[7] = 1;
  piecemax[7] = 0 + (d * 2) + (d * d * 0);
}

void puzzle::run12() {
  for (int i=0;i<=0;i++)
    for (int j=0;j<=0;j++) 
      for (int k=0;k<=2;k++)
	p[8][i + (d * (j + (d * k)))] = true;
  mclass[8] = 1;
  piecemax[8] = 0 + (d * 0) + (d * d * 2);
}

void puzzle::run13() {
  for (int i=0;i<=1;i++)
    for (int j=0;j<=1;j++) 
      for (int k=0;k<=0;k++)
	p[9][i + (d * (j + (d * k)))] = true;
  mclass[9] = 2;
  piecemax[9] = 1 + (d * 1) + (d * d * 0);
}

void puzzle::run14() {
  for (int i=0;i<=1;i++)
    for (int j=0;j<=0;j++) 
      for (int k=0;k<=1;k++)
	p[10][i + (d * (j + (d * k)))] = true;
  mclass[10] = 2;
  piecemax[10] = 1 + (d * 0) + (d * d * 1);
}

void puzzle::run15() {
  for (int i=0;i<=0;i++)
    for (int j=0;j<=1;j++) 
      for (int k=0;k<=1;k++)
	p[11][i + (d * (j + (d * k)))] = true;
  mclass[11] = 2;
  piecemax[11] = 0 + (d * 1) + (d * d * 1);
}

void puzzle::run16() {
  for (int i=0;i<=1;i++)
    for (int j=0;j<=1;j++) 
      for (int k=0;k<=1;k++)
	p[12][i + (d * (j + (d * k)))] = true;
  mclass[12] = 3;
  piecemax[12] = 1 + (d * 1) + (d * d * 1);
}

void puzzle::runLast() {
  int m;
  piececount[0] = 13;
  piececount[1] = 3;
  piececount[2] = 1;
  piececount[3] = 1;
  
  m = 1 + (d * (1 + (d * 1)));
  kount =  0;
  if (fitI(0, m))
    n = placeI(0,m);
  else 
    fprintf(stderr,"Error1 in Puzzle\n");
  if (!trial(n))
    fprintf(stderr,"Error2 in Puzzle\n");
  else if (kount != 2005)
    fprintf(stderr,"Error3 in Puzzle\n");
}


void puzzle::run() {
  run1(); 
  run2();  
  run3();  
  run4();  
  run5();  
  run6();  
  run7();  
  run8();
  run9(); 
  run10();
  run11();
  run12();
  run13();
  run14();
  run15();
  run16();
  runLast();
}





// ***********************************************************
// QUICK
// Sorts an array using quicksort
// ***********************************************************

class quick : public benchmarks { 

  public:

    int sortelements;
    int *sortlist;
    int biggest;
    int littlest;

    quick(char *name="quick");
    
    void initarr();
    void quicksortL(int l, int r);
    void run();
};


quick::quick(char *name="quick") : benchmarks(name),
  sortelements(5000),
  biggest(0),littlest(0) 
{}

void quick::initarr() {
  initrand();
  biggest = -1000000;
  littlest = 1000000;
  sortlist = new int[sortelements+1];
  for (int i=1;i<=sortelements;i++) {
    int temp = rand();
    sortlist[i] = temp - ((temp / 100000) * 100000) - 50000;
    if (sortlist[i] > biggest)
      biggest = sortlist[i];
    if (sortlist[i] < littlest)
      littlest = sortlist[i];
  }
}

void quick::quicksortL(int l, int r) {
  // quicksort the array from start to finish 
    int i=l,j=r,x,w;
  x = sortlist[(l + r) / 2 ];
  do {
    while (sortlist[i] < x)
      i++;
    while (x < sortlist[j])
      j -- ;
    if (i <= j) {
      w = sortlist[i];
      sortlist[i] = sortlist[j];
      sortlist[j] = w;
      i++; j--;
    }
  } while (i <= j);
  
  if (l < j)
    quicksortL(l,j);
  if (i < r)
    quicksortL(i,r);
}

void quick::run() {
  initarr();
  quicksortL(1,sortelements);
  if (sortlist[1] != littlest || sortlist[sortelements] != biggest)
    fprintf(stderr,"Error in Quick.\n");
}



class xquick: public benchmarks {

  protected:

  int numVals;

  class xqvector : public benchmarks {
    public:

    int *values;
    int numVals;
    int biggest;
    int littlest;

    xqvector(int size=5000);
    int& operator[](int i);
    void initarr();
    void quickSort();
    void quickSortFrom(int l,int r);
  };

  public:

  xquick(char *name="xquick");

  void run();
				      
};



xqvector::xqvector(int size=5000) : benchmarks("xqvector"),numVals(size) 
{
  values = new int[size];
}

int& xqvector::operator[](int i) 
{ 
  return values[i]; 
}

void xqvector::initarr()
{
   biggest = -1000000;
   littlest = 1000000;
   for (int i=0;i<numVals;i++) {
     int temp = rand();
     values[i] = temp - ((temp / 100000) * 100000) - 50000;
     if (values[i] > biggest)
       biggest = values[i];
     if (values[i] < littlest)
       littlest = values[i];
   }
}

void xqvector::quickSort() { 
  quickSortFrom(0,numVals-1); 
}

void xqvector::quickSortFrom(int l,int r) {
  int i=l, j=r,x,w;
  x = values[(l + r) / 2];
  do {
    while (values[i] < x)
      i++;
    while (x < values[j])
      j--;
    if (i <= j) {
      w = values[i];
      values[i] = values[j];
      values[j] = w;
      i++; j--;
    }
  } while ( i <= j );
  
  if (l < j) 
    quickSortFrom(l,j);
  if (i < r)
    quickSortFrom(i,r);
}

xquick::xquick(char *name) : benchmarks(name), numVals(5000) {
}

void xquick::run() {
  initrand();
  xqvector xqv(numVals);
  xqv.initarr();
  xqv.quickSort();
  if (xqv[0] != xqv.littlest || xqv[numVals-1] != xqv.biggest)
    fprintf(stderr,"Error in xquick\n");
}



// ***********************************************************
// BUBBLE
// Sorts an array using bubblesort
// ***********************************************************


class bubble : public quick { 

  public:

   bubble(char *name="bubble");
   void run();

};


bubble::bubble(char *name) : quick(name) {
}

void bubble::run() {
  int top;
  sortelements = 500;
  initarr();
  top = 500;
  while (top > 1) { 
    int i = 1;
    while (i < top) {
      if (sortlist[i] > sortlist[i+1]) {
	int tmp = sortlist[i];
	sortlist[i] = sortlist[i+1];
	sortlist[i+1] = tmp;
      }
      i++;
    }
    top--;
  }
  if (sortlist[1] != littlest || sortlist[sortelements] != biggest)
    fprintf(stderr,"Error3 in bubble\n");
}


class xbubble : public xquick {

  public:
  class xbvector : public xqvector {
    public:
    xbvector(int size) : xqvector(size) {}
    void bubbleSort();
  };

  xbubble();
  void run();

};

void xbvector::bubbleSort()
{
  for (int top = (numVals-1); top >= 1; top -- )  {
    for (int i=0;i<top;i++) {
      if (values[i] > values[i+1]) {
	int j = values[i];
	values[i] = values[i+1];
	values[i+1] = j;
      }
    }
  }
}


xbubble::xbubble() : xquick("xbubble") {
}

void xbubble::run() { 
  initrand();
  xbvector xbv(500);
  xbv.initarr();
  xbv.bubbleSort();
  if (xbv[0] != xbv.littlest || xbv[xbv.numVals-1] != xbv.biggest)
    fprintf(stderr,"Error in xbubble\n");  
}

// ***********************************************************
// TREE
// sorts and array using treesort
// ***********************************************************

class tree : public quick {

  class node {
    public:
    node *left;
    node *right;
    int val;
    node(int n) { val = n; left = right = NULL; }
  };

  public:
  tree::tree() : quick("tree") {}
  void insert(int n,node *t);
  bool checkTree(node * p);
  void run();

};

void tree::insert(int n,node *t) {
  // insert n into tree
    if (n > t->val) {
      if (t->left == NULL)
	t->left = new node(n);
      else
	insert(n,t->left);
    } else if (n < t->val) {
      if (t->right == NULL)
	t->right = new node(n);
      else 
	insert(n,t->right);
    } else 
      fprintf(stderr,"adding a duplicate value to tree\n");
}

bool tree::checkTree(node * p) {
  // check by inorder traversal
  bool result = true;
  if (p->left != NULL) {
    if (p->left->val <= p->val)
      result = false;
    else
      result = checkTree(p->left) && result;
  }
  if (p->right != NULL) {
    if (p->right->val >= p->val)
      result = false;
    else 
      result = checkTree(p->right) && result;
  }
  return result;
}


void tree::run() {
  node *tree;
  initarr();
  tree = new node(sortlist[1]);
  for (int i=2;i<=sortelements;i++)
    insert(sortlist[i],tree);
  if (!checkTree(tree))
    fprintf(stderr,"Error in Tree.\n");
}

// ------------------------------------------------------------------------


class xtree : public quick {
  class xnode { 
    public:
    bool checkTree();
    void insert(int n);
    xnode(int n) { val = n; left = right = NULL; }
    
    xnode *left;
    xnode *right;
    int val;
  };

  public:
  void run();
  xtree::xtree() : quick("xtree") {}
  
};

void xtree::run() {
  xnode *tree;
  initarr();
  tree = new xnode(sortlist[0]);
  for (int i=1;i<=sortelements;i++)
    tree->insert(sortlist[i]);
  if (!tree->checkTree())
    fprintf(stderr,"Error in tree\n");
};


bool xnode::checkTree() {
  bool res=true;
  if (left != NULL)
    res = left->val < val && left->checkTree();
  if (right != NULL)
    res = right->val > val && right->checkTree();
  return res;
}

void xnode::insert(int n) {
  if (n < val) {
    if (left == NULL)
      left = new xnode(n);
    else
      left->insert(n);
  } else if (n > val) {
    if (right == NULL)
      right = new xnode(n);
    else
      right->insert(n);
  } else
    fprintf(stderr,"error in xtree: adding duplicate\n");
}


// END OF STANFORD INTEGER BENCHMARKS


// ***********************************************************
// SIEVE
// ***********************************************************

// ***********************************************************
// SUMTO
// ***********************************************************

// ***********************************************************
// SUMFROMTO
// ***********************************************************

// ***********************************************************
// SUMTOCONST
// ***********************************************************

// ***********************************************************
// ATALLPUT
// ***********************************************************

// richards OS benchmark??



// ***********************************************************
// MAIN
// ***********************************************************

main()
{
  printf("C++ benchmarks\n");

  bubble bb;
  bb.measurePerformance();

  xbubble xbb;
  xbb.measurePerformance();

  tree tr;
  tr.measurePerformance();

  xtree xtr;
  xtr.measurePerformance();

  puzzle p;
  p.measurePerformance();

  quick q;
  q.measurePerformance();

  xquick xq;
  xq.measurePerformance();

  intmm imm;
  imm.measurePerformance();

  xintmm ximm;
  ximm.measurePerformance();

  perm pm;
  pm.measurePerformance();

  xperm xpm;
  xpm.measurePerformance();

  towers twrs;
  twrs.measurePerformance();

  xtowers xtwrs;
  xtwrs.measurePerformance();

  queens quns;
  quns.measurePerformance();

  xqueens xquns;
  xquns.measurePerformance();


}




