\tiny
\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#include "Data.h"
#include "Rule.h"
#include "RuleSet.h"
#include "WhichStack.h"
#include "defines.h"
#include <sstream>
#include <ctime>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cmath>
using namespace std;

/**
 * Prints help information for Which.
**/
void printHelp( string comStr );

int main( int argc, char **argv )
{
	time_t t = time(NULL);
	string files[3] = { "none", "none", "none" }, tarFile;
	int locAtt = 0, 
	  stackSize = INFINITY, 
	  picks = 2000,
	  check = 200,
	  reportNo = 5,
	  discBins = 7,
	  scoreType = LIFT,
	  microAmt = 0;
	float improvement = 0.2, alpha = 1, beta = 1, gamma = 1, seed = time(NULL);

	bool statOnly = false, wekaP = false, noeff = false, justRule = false, isTar3 = false;

	// Parse the command-line arguments.
	for ( int command = 1; command < argc; command += 2 )
	{
	  string comStr = argv[command], dumb;
	  stringstream ss( stringstream::in | stringstream::out );
	  ss << argv[command+1] << endl;
	  if ( comStr == "-t" ) ss >> files[0];
	  else if ( comStr == "-T" ) ss >> files[1];
	  else if ( comStr == "-E" ) ss >> files[2];
	  else if ( comStr == "-rep" ) ss >> reportNo;
	  else if ( comStr == "-score" )
	  {
	    string type;
	    ss >> type;
	    if ( type == "lift" ) scoreType = LIFT;
	    else if ( type == "effort" ) scoreType = EFFORT;
	    else if ( type == "pdpf" ) scoreType = PDPF;
	    else if (type == "probsupt" ) scoreType = PROBSUPT;
	    else if ( type == "pd/effort" ) scoreType = PDOVEREFFORT;
	    else if ( type == "pd/loc" ) scoreType = PDOVERLOC;
	    else if ( type == "ripper" ) scoreType = RIPPER;
	    else if ( type == "precision" ) scoreType = PRECISION;
	    else if ( type == "accuracy" ) scoreType = ACCURACY;
	  }
	  else if ( comStr == "-ssize" ) ss >> stackSize;
	  else if ( comStr == "-imp" ) ss >> improvement;
	  else if ( comStr == "-picks" ) ss >> picks;
	  else if ( comStr == "-check" ) ss >> check;
	  else if ( comStr == "-loc" ) { ss >> locAtt; locAtt--; }
	  else if ( comStr == "-bins" ) ss >> discBins;
	  else if ( comStr == "-alpha" ) ss >> alpha;
	  else if ( comStr == "-beta" ) ss >> beta;
	  else if ( comStr == "-gamma" ) ss >> gamma;
	  else if ( comStr == "-micro" ) ss >> microAmt;
	  else if ( comStr == "-stat" ) { ss >> dumb; statOnly = true; command--; }
	  else if ( comStr == "-noeff" ) { ss >> dumb; noeff = true; command--; }
	  else if ( comStr == "-rule" ) { ss >> dumb; justRule = true; command--; }
	  else if ( comStr == "-seed" ) ss >> seed;
	  else if ( comStr == "-p" ) { ss >> dumb; wekaP = true; command--; }
	  else if ( comStr == "-tar3" ) { ss >> tarFile; isTar3 = true; }
	  else printHelp( comStr );
	}

	// Set up the data according to the read in arguments.
	srand( seed );
	Data *train = new Data(), *test = new Data(), *effort = new Data();
	train->read( files[0] );
	if ( files[1] == "none" ) files[1] = files[0];
	test->read( files[1] );
	
	if ( microAmt > 0 ) train->microsample( microAmt );

	if ( !noeff )
	{
	  train->calcPDPFEst( locAtt );
	  test->calcPDPFEst( locAtt );
	}
	
	if ( scoreType == PDOVERLOC ) 
	{
	  train->normalizeAttribute( locAtt );
	  test->normalizeAttribute( locAtt );
	}

	train->discretizeEqFreq( discBins, test );
	train->calcLift();
	test->calcLift();

	// Only works on binary classes
	if ( train->getNumClasses() == 2 )
	{
	  train->calcProbSupt();
	  test->calcProbSupt();
	}
	else if ( scoreType == PROBSUPT )
	{
	  cerr << "Cannot use probability * support on a more-than-two class system. Exiting" << endl;
	  exit( 1 );
	}

	if ( isTar3 )
	{
	  Rule *tarRule = new Rule();
	  tarRule->createFromFile( tarFile, test, LIFT );
	  tarRule->print( cout );
	}

	// Create and setup the WhichStack
	WhichStack *stack = new WhichStack( stackSize );
	stack->create( train, scoreType, alpha, beta, gamma );
	stack->select( picks, check, improvement );
	exit(1);
	if ( !statOnly && !wekaP )
	{
	  for ( int r = 0; r < reportNo; r++ )
	  {
	    stack->getRule( r )->setData( test );
	    stack->getRule( r )->score();
	    if ( justRule ) stack->getRule( r )->printRule( cout );
	    else stack->getRule( r )->print( cout );
	    cout << endl;
	  }
	  
	  float hours = (time(NULL)-t)/3600.0;
	  float minutes = (hours-floor(hours))*60;
	  float seconds = (minutes-floor(minutes))*60;
	  cout << "It took " << floor(hours) << " hour(s), " << floor(minutes) << " minute(s), and " << seconds << " second(s) to run." << endl;
	}
	else if ( statOnly )
	{
	  for ( int r = 0; r < reportNo; r++ )
	  {
	    stack->getRule( r )->setData( test );
	    stack->getRule( r )->score();
	    cout << "Correctly Classified Instances xxx " << stack->getRule( r )->getScore()/(float)100.0 << endl;
	    cout << stack->getRule( r )->getPD() << "," << stack->getRule( r )->getPF() << endl;
	  }
	  cout << endl;
	}
	else if ( wekaP )
	{
	  stack->getBest()->setData( test );
	  stack->getBest()->score();
	  stack->getBest()->printGotWant( cout, test );
	  cout << endl;
	}

	return 0;
}

void printHelp( string comStr )
{
  if ( comStr != "-?" )
	cout << comStr << " is not a valid option." << endl << endl;

  cout << "Usage:" << endl;
  cout << "./which [options]" << endl;
  cout << "[options]" << endl;
  cout << "\t-t\t\t" << "Sets the train file." << endl;
  cout << "\t-T\t\t" << "Sets the test file." << endl;
  cout << "\t-E\t\t" << "Sets the file to read in the lines of code from" << endl;
  cout << "\t-rep\t\t" << "Sets the number of Rules to report." << endl;
  cout << "\t-score\t\t" << "Sets the type of scoring" << endl;
  cout << "\t\t\t\t" << "lift -" << "Scores the Rules via lift." << endl;
  cout << "\t\t\t\t" << "effort -" << "Scores the Rules via effort." << endl;
  cout << "\t\t\t\t" << "pdpf -" << "Scores the Rules via probability of detection and probability of false alarm." << endl;
  cout << "\t\t\t\t" << "probsupt -" << "Scores the Rules via the equation pd^2/(pd+pf)." << endl;
  cout << "\t\t\t\t" << "pd/effort -" << "Scores the Rules via pd/effort." << endl;
  cout << "\t\t\t\t" << "ripper -" << "Scores the Rules via Ripper's method according to ROC n' Rule paper." << endl;;
  cout << "\t\t\t\t" << "precision -" << "Scores the Rules via precision's method according to ROC n' Rule paper." << endl;;
  cout << "\t\t\t\t" << "pd/loc -" << "Scores the Rules via pd over the sum of the LOC it fires on.  LOCs are normalized for this." << endl;
  cout << "\t\t\t\t" << "accuracy -" << "Scores the rules via accuracy.  This will be a low score as it is synthetic in thatwe cannot assume a binary class system." << endl;
  cout << "\t-ssize\t\t" << "Sets the size of the stack( -1 for infinite size." << endl;
  cout << "\t-imp\t\t" << "Sets the minimum improvement required per -check picks. Stopping criteria." << endl;
  cout << "\t-picks\t\t" << "Sets the max number of picks for this run of Which." << endl;
  cout << "\t-check\t\t" << "Sets how many picks in a row before a -imp case is checked." << endl;
  cout << "\t-loc\t\t" << "If scoring type is effort, this is the location in the file of the line-of-code attribute." << endl;
  cout << "\t-bins\t\t" << "How many bins to use to discretize the data." << endl;
  cout << "\t-alpha\t\t" << "Sets the weight of PD in all scoring methods that use it." << endl;
  cout << "\t-beta\t\t" << "Sets the weight of PF in all scoring methods that use it." << endl;
  cout << "\t-gamma\t\t" << "Sets the weight of effort in all scoring methods that use it." << endl;
  cout << "\t-micro\t\t" << "Creates a data set of even distribution of classes from the train set and removes all but the amount sent in." << endl;
  cout << "\t-stat\t\t" << "Output only the stats of each rule." << endl;
  cout << "\t-p\t\t" << "Tells Which to print the got want table." << endl;
  cout << "\t-noeff\t\t" << "Tells which to ignore effort calculation." << endl;
  cout << "\t-rule\t\t" << "Tells which to only print the Rule in a condensed format." << endl;
  cout << "\t-seed\t\t" << "Tells which which seed to use for the random number generator." << endl;
  cout << "\t-tar3\t\t" << "Tells which to read in a file and score it." << endl;
  cout << "\t-?\t\t" << "Prints this help file." << endl << endl;

  exit( 0 );
}
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for main.cpp}
\label{fig:main}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#ifndef _whichstack_h_
#define _whichstack_h_

#include <vector>
#include <iostream>
class Rule;
class Data;
//enum RULE_TYPE;

/**
 * Represents a Which-specific stack.  It is sorted and has special facilities geared towards Which.
**/
class WhichStack
{
		public:
		/**
		 * Empty Constructor.
		**/
		WhichStack();

		/**
		 * Creates a WhichStack that has a maximum size.
		 * @param maxSize The maximum size this WhichStack can be.  If it is -1, the size if infinite.
		**/
		WhichStack( int maxSize );

		/**
		 * Destructor.
		**/
		~WhichStack();

		/**
		 * Creates a WhichStack having Rules of single attribute-value pairs.
		 * @param data The data file to use to create the Rules from.
		 * @param type The type of Rules to create.
		 * @param alpha The weight for pd.
		 * @param beta The weight of pf.
		 * @param gamma The weight for effort.
		**/
		void create( Data *data, int type, float alpha = 1, float beta = 1, float gamma = 1 );

		/**
		 * Pushes a Rule onto the WhichStack in the position based on the Rule's score.
		 * If the Rule would be last on a WhichStack of finite size that is full, the item
		 * will not be pushed.
		 * --- THE RULE WILL NOT BE DELETED IF IT IS NOT ADDED ---
		 * @param r The Rule to push onto the WhichStack.
		 * @return True if the Rule made it onto the WhichStack, false otherwise.
		**/
		bool push( Rule *r );

		/**
		 * Calls pickTwo a series of times to attempt to create a "best" Rules.
		 * @param count The number of times to call PickTwo total.
		 * @param check How many pickTwo calls to allow to pass
		 * before a check is made to make sure improvement is still happening.
		 * @param improve A decimal number representing the percentage of increase
		 * in score a current "best" Rule must have since the last check
		 * in order to continue calling pickTwo.
		 * @return The true number of times pickTwo was called.  A number <= count.
		**/
		int select( int count = 2000, int check = 200, float improve = 0.2 );

		/**
		 * Based on a weighted distribution, picks two Rules from the WhichStack and combines them.
		 * @return True if the new Rule made it onto the WhichStack, false otherwise.
		**/
		bool pickTwo();

		/**
		 * Gets the number of Rules in the WhichStack.
		 * @return The number of Rules in the WhichStack.
		**/
		unsigned int size();

		/**
		 * Gets the best Rule in the WhichStack.
		 * @return The top of the WhichStack.
		**/
		Rule *getBest();

		/**
		 * Gets the Rule indexed by index.
		 * @param index The index of the Rule to get( 0 is the same as calling getBest() );
		 * @return The Rule at index index.
		**/
		Rule *getRule( int index );

		/**
		 * Prints the first n Rules in the WhichStack.
		 * @param stream The stream to print to.
		 * @param n The number of Rules to print.
		 * @return The stream;
		**/
		std::ostream &report( std::ostream &stream, int n );

		/**
		 * Outputs the WhichStack to a stream.
		 * @param stream The stream to output to.
		**/
		void print( std::ostream& stream );

		bool push( int[], float (*scoreFcn)( Rule * ) );

	protected:
		/**
		 * Checks to see if a Rule is already in this WhichStack.
		 * @param r The Rulet to look for.
		 * @return True if r is in this WhichStack, false otherwise.
		**/
		bool contains( Rule *r );

		/**
		 * Picks a Rule from the WhichStack.
		 * @param scores The vector of scores for the rule.
		 * @param max The maximum number to select.
		 * @return The position in the WhichStack of the chosen rule.
		**/
		int pick( std::vector< float > scores, float sum );

		std::vector< Rule * > mRules;
		int mMaxSize;
};

#endif
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for WhichStack.h}
\label{fig:whichstackh}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#include "WhichStack.h"
#include "Rule.h"
#include "Data.h"
#include "defines.h"
#include <cmath>
#include <vector>
using namespace std;

WhichStack::WhichStack()
{
	mMaxSize = INFINITY;
}

WhichStack::WhichStack( int maxSize )
{
	mMaxSize = maxSize;
}

WhichStack::~WhichStack()
{
	Rule *r;
	while ( mRules.size() > 0 )
	{
		r = mRules.back();
		mRules.pop_back();
		delete r;
	}
}

void WhichStack::create( Data *data, int type, float alpha, float beta, float gamma )
{
  RULE_TYPE t = (RULE_TYPE)type;
	for ( unsigned int att = 0; att < data->getNumAtts(); att++ )
	{
		for ( unsigned int val = 0; val < data->getNumAttVals( data->getAttName( att ) ); val++ )
		{
			Rule *r = new Rule( att, val, data, t );
			r->setWeights( alpha, beta, gamma );
			r->setTargetClass( data->getNumClasses() );
			r->score();
			if ( !( push( r ) ) ) delete r;
		}
	}
}

bool WhichStack::push( int attval[], float (*scoreFcn)( Rule * ) )
{
  Rule *r = new Rule( attval[0], attval[1], NULL, SPECIAL, scoreFcn );
  r->score();

  if ( !push( r ) ) delete r;

  return true;
}

int WhichStack::select( int count, int check, float improve )
{
  int currCount = 0;
  bool noIncrease = false;
  Rule *oldBest, *newBest;
  
  if ( size() <= 0 ) return 0;

  oldBest = getBest();
  while ( !noIncrease && currCount < count )
  {
    pickTwo();
    cout << currCount << " " << getBest()->getScore()/100.0 << endl;
    if ( check > 0 && ( currCount + 1 ) % check == 0 )
    {
      newBest = getBest();
      noIncrease = newBest->getScore()/oldBest->getScore() - 1.0 < improve;
      oldBest = getBest();
    }
    currCount++;
  }
  
  return currCount;
}

bool WhichStack::contains( Rule *r )
{
	for ( unsigned int i = 0; i < mRules.size(); i++ )
		if ( mRules[i]->isEqualTo( r ) )
			return true;

	return false;
}

int WhichStack::pick( vector< float > scores, float sum )
{
	float x = randomNum( 0, sum );
	for ( unsigned int i = 0; i < mRules.size(); i++ )
	{
		if ( x < scores[i] )
			return i;
		x -= scores[i];
	}
	return -1;
}

bool WhichStack::push( Rule *r )
{
	static int i = 0;
	bool wasInserted = false;
	
	if ( contains( r ) )
	{
		return false;
	}
	if ( mRules.size() == 0 ) 
		mRules.push_back( r );
	else if ( r->getScore() < mRules.back()->getScore() && mMaxSize > mRules.size() && mMaxSize != INFINITY )
	{
		mRules.push_back( r );
	}
	else
	{
		for ( vector< Rule * >::iterator ri = mRules.begin(); ri < mRules.end() && !wasInserted; ri++ )
		{
			Rule *current = *ri;
			if ( r->compare( current ) > 0 ||
				 ( r->compare( current ) == 0 && r->getSize() < current->getSize() ) )
			{
				ri = mRules.insert( ri, r );
				wasInserted = true;
			}
		}
		// If we didn't get in and the WhichStack is full, we are done.
		if ( !wasInserted && mRules.size() >= mMaxSize && mMaxSize != INFINITY ) return false;
		if ( !wasInserted && ( mRules.size() < mMaxSize || mMaxSize != INFINITY ) ) mRules.push_back( r );
		if ( wasInserted && mRules.size() >= mMaxSize && mMaxSize != INFINITY )
		{
			Rule *back = mRules.back();
			mRules.pop_back();
			delete back;
		}
	}

	return true;
}

bool WhichStack::pickTwo()
{
	vector< float > scores( mRules.size() );
	Rule *r;
	int first, second;
	float sum, smallestVal;

	// If the WhichStack has 1 or 0 elements, this can't do anything, so return failure.
	if ( mRules.size() <= 1 ) return false;
	// If there are less than 5 things, just combine them all and see if anything happens.
	else if ( mRules.size() < 5 )
	{
		bool worked = false;
		for ( unsigned int i = 0; i < mRules.size(); i++ )
			for ( unsigned int j = 0; j < mRules.size(); j++ )
				if ( j != i )
				{
					Rule *c = mRules[i]->combine( mRules[j] );
					c->score();
					if ( push( c ) ) worked = true;
				}
		return worked;
	}

	// Otherwise, do a standard weighted stochastic picking of two items.
	// To allow for negative scoring, find the lowest negative value
	// and shift it and all other scores up to make the lowest value 0.00001.
	smallestVal = scores[0];
	for ( unsigned int curRule = 1; curRule < mRules.size(); curRule++ )
	  smallestVal = min( smallestVal, scores[curRule] );

	scores[0] = mRules[0]->getScore() + smallestVal + 0.0001;
	sum = scores[0];

	for ( unsigned int curRule = 1; curRule < mRules.size(); curRule++ )
	{
	  scores[curRule] = mRules[curRule]->getScore() + scores[curRule-1] + smallestVal + 0.0001;
	  sum += scores[curRule];
	}

	first = pick( scores, sum );
	// Keep picking a stack item over until it is not the first stack item picked.
	// This prevents a combine of the same rule which gives us nothing.
	do
	{
	  second = pick( scores, sum );
	} while ( first == second );

	r = mRules[first]->combine( mRules[second] );
	r->score();

	if ( push( r ) ) 
	{
		// If this new Rule is at the top of the WhichStack, attempt to
		// do a greedy back-select on it until the smaller Rules
		// aren't scoring as well as the bigger ones.
		if ( false && r->isEqualTo( mRules.front() ) && r->getSize() > 1 )
		{
			Rule *bs = r->backSelect();
			while ( bs != NULL )
			{
				push( bs );
				bs = bs->backSelect();
			}
		}
		return true;
	}
	else
	{
		delete r;
		return false;
	}
}

unsigned int WhichStack::size()
{
	return mRules.size();
}

Rule *WhichStack::getBest()
{
	return mRules.front();
}

Rule *WhichStack::getRule( int index )
{
  if ( index < 0 || index >= mRules.size() )
  {
    cerr << index << " is out of range, exiting." << endl;
    exit( 0 );
  }

  return mRules[index];
}

ostream &WhichStack::report( ostream &stream, int n )
{
	for ( unsigned int i = 0; i < n && i < mRules.size(); i++ )
	{
		mRules[i]->print( stream );
		stream << endl;
	}
	return stream;
}

void WhichStack::print( ostream& stream )
{
	for ( unsigned int i = 0; i < mRules.size(); i++ )
	{
		mRules[i]->print( stream );
		stream << endl;
	}
}
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for WhichStack.cpp}
\label{fig:whichstackcpp}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#ifndef _pickobject_h_
#define _pickobject_h_

#include <iostream>
#include <vector>

union InstanceElement;
class Data;

/**
 * Represents a set of disjunctions for a given attribute.
**/
struct DisjunctionSet
{
	int mAttribute;
	std::vector< int > mValues;
};

enum RULE_TYPE { LIFT, EFFORT, PROBSUPT, INFOGAIN, PDPF, PDOVEREFFORT, PDOVERLOC, RIPPER, PRECISION, ACCURACY, SPECIAL };

/**
 * Represents a Rule for Which.  Contains a series of attributes and the ranges they can have for a rule to fire.
 * Rules in Which are a series of conjunctions of disjunctions.
 * EG: ( a = 3 + a = 2 )( b = 9 + b = 5 )( ... )
**/
class Rule
{
	public:
		/**
		 * Creates an empty Rule.  After this constructer the Rule will have no attributes to fire on.
		**/
		Rule();

		/**
		 * Creates a Rule with one conjunction.( if attribute = attributeValue then... )
		 * @param attribute The numerical index of the attribute in the data set.
		 * @param value The numerical index of the attribute's value in the data set.
		 * @param d A pointer to the data set to score this Rule with.
		 * @param type The type of Rule this is.
		 * @param the method to use to score this rule. Only needed for type = SPECIAL
		**/
		Rule( int attribute, int value, Data *d, RULE_TYPE type, float (*scoreFnc)( Rule * ) = NULL );

		/**
		 * Destructor.
		**/
		~Rule();

		void *getComponent();
		void setComponent( void *com );
		std::vector< DisjunctionSet * > *getRuleSet();

		void setData( Data *d );
		void setWeights( float alpha, float beta, float gamma );
		void setTargetClass( int targetClass );

			
		float getScore();
		float getSupport();
		float getPD();
		float getPF();
		float getEffort();
		int getSize();

		/**
		 * Creates a cloned version of this Rule.  The new Rule is completely seperate of this Rule.
		 * @return The newly cloned Rule.
		**/
		Rule *clone();

		/**
		 * Creates a Rule from reading in a file.
		 * @param fName The name of the file.
		 * @param Data The data set to score and create this Rule with.
		 * @param type The type of Rule this is.
		 * @param the method to use to score this rule. Only needed for type = SPECIAL
		 * Returns false if no Rule was created.  True otherwise.
		 **/
		bool createFromFile( std::string fName, Data *d, RULE_TYPE type, float (*scoreFcn)( Rule * ) = NULL );

		/**
		 * Compares two Rules' scores.
		 * @param r The Rule to compare to this one.
		 * @returns >0 if r is greater than this Rule, 0 if r is equal to this Rule, <0 if r is less than this Rule.
		**/
		float compare( Rule *r );

		/**
		 * Checks to see if an instance of data is satisfied by this Rule.
		 * @param instance The instance of data.
		**/
		bool isSatisfied( std::vector< InstanceElement * > *instance );

		/**
		 * Scores the Rule based on which type of Rule it is.
		**/
		void score();

		/**
		 * Checks to see if an attribute index is already in the Rule.
		 * @param attribute The attribute index to search for.
		 * @return -1 if the attribute does not exist, the index of the attribute otherwise.
		**/
		int findAttribute( int attribute );

		/**
		 * Checks to see if an attribute value is already in the Rule.
		 * @param attribute The attribute whose value is to be searched for.
		 * @param value The value of the attribute to search.
		 * @return -1 if the value is not found, the index of the value otherwise.
		**/
		int findAttributeValue( int attribute, int value );

		/**
		 * Checks to see if a certain attribute value is in the Rule.
		 * @param attribute The attribute index to check the value of.
		 * @param value The value index of the attribute.
		 * @return True if it attribute = value is in this Rule, false otherwise.
		**/
		bool hasComponent( int attribute, int value );

		/**
		 * Checks to see if two Rules have the same component sets.
		 * @param r The Rule to compare to this one.
		 * @return True if r == this, false otherwise.
		**/
		bool isEqualTo( Rule *r );

		/**
		 * Adds a new component to the Rule.
		 * @param atribute The attribute to add.
		 * @param vale The value of the attribute to add.
		 * @return True if it was added, false if it already was in the rule.
		**/
		bool addComponent( int attribute, int value );

		/**
		 * Combines two Rules by adding together their disjunctions and conjunctions.  If this Rule and r are
		 * equivalent, the new Rule is just a clone of the first rule.
		 * @param r The Rule to add to this one.
		 * @return A pointer to a new Rule that is created from this one.
		**/
		Rule *combine( Rule *r );

		/**
		 * Attempts to create a better, smaller rule.
		 * @return The smaller rule.
		**/
		Rule *backSelect();

		/**
		 * Prints a Weka-like got want matrix to allow for evaluation alongside the Weka.
		 * @param stream The stream to print o.
		 * @param eData The data containing the proper line of code information.
		**/
		void printGotWant( std::ostream& stream, Data *eData );

		/**
		 * Prints the Rule in the format:
		 * A =		[ 1 OR 2 ]
		 * AND B =	[ 2 ]
		 * AND C =	[ 1 OR 4 ]
		 * Score:	###
		 * <optional scoring metrics>
		 * @param stream The stream to print the Rule to.
		**/
		void print( std::ostream& stream );

		/**
		 * Prints just the Rule portion in the format.
		 * A = [ 1 OR 2 ] AND B = [ 2 ] AND C = [ 1 OR 4 ] => class
		 * @param stream The stream to print tte Rule to.
		**/
		void printRule( std::ostream& stream ); 

	protected:
		void scoreLift();
		float calcDist();
		void scoreEffort();
		void scoreProbSupt();
		void scoreInfoGain();
		void scorePDPF();
		void scorePDOverEffort();
		void scorePDOverLOC();
		void scoreRipper();
		void scorePrecision();
		void scoreSpecial();
		void scoreAccuracy();

		Data *mData;
		std::vector< DisjunctionSet * > mPicked;
		float mScore;
		int mSize, mTargetClass;
		float mPD, mPF, mEffort, mAlpha, mBeta, mGamma, mProbBest, mProbRest;
		float mSupport;
		RULE_TYPE mType;
		float (*mScoreFcn)( Rule * );
		void *mComponent;
};

#endif
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for Rule.h}
\label{fig:ruleh}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#include "Rule.h"
#include "Data.h"
#include "defines.h"
#include "WhichStack.h"
#include <cmath>
using namespace std;

Rule::Rule()
{
	mAlpha = 1;
	mBeta = 1000;
	mGamma = 1;
	mGamma = 0;
	mPD = mPF = mEffort = mProbBest = mProbRest = 0;
	mSize = 1;
	mTargetClass = 1;
	mComponent = NULL;
}

Rule::Rule( int attribute, int value, Data *d, RULE_TYPE type, float (*scoreFcn)( Rule * ) )
{
  mPicked.push_back( new DisjunctionSet() );
  mPicked[0]->mAttribute = attribute;
  mPicked[0]->mValues.push_back( value );
  mScoreFcn = scoreFcn;
  mData = d;
  mType = type;

  mAlpha = 1;
  mBeta = 1000;
  mGamma = 1;
  mGamma = 0;
  mPD = mPF = mEffort = mProbBest = mProbRest = 0;
  mSize = 1;
  mTargetClass = 1;  
  mComponent = NULL;
}

Rule::~Rule()
{
	DisjunctionSet *d;
	while ( mPicked.size() > 0 )
	{
		d = mPicked.back();
		mPicked.pop_back();
		delete d;
	}
	delete mComponent;
}

void Rule::setData( Data *d ) { mData = d; }

void Rule::setWeights( float alpha, float beta, float gamma )
{
	mAlpha = alpha;
	mBeta = beta;
	mGamma = gamma;
}


float Rule::getScore() { return mScore; }
float Rule::getSupport() { return mSupport; }
float Rule::getPD() { return mPD; }
float Rule::getPF() { return mPF; }
float Rule::getEffort() { return mEffort; }
int Rule::getSize() { return mSize; }
void *Rule::getComponent() { return mComponent; }
void Rule::setComponent( void *com ) { mComponent = com; }
void Rule::setTargetClass( int targetClass ) { mTargetClass = targetClass; }
vector< DisjunctionSet * > *Rule::getRuleSet() { return &mPicked; }

Rule *Rule::clone()
{
	Rule *toRet = new Rule();
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
	{
		toRet->mPicked.push_back( new DisjunctionSet() );
		toRet->mPicked[att]->mAttribute = mPicked[att]->mAttribute;
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
			toRet->mPicked[att]->mValues.push_back( mPicked[att]->mValues[val] );
	}
	
	toRet->mData = mData;
	toRet->mSize = mSize;
	toRet->mScore = mScore;
	toRet->mSupport = mSupport;
	toRet->mProbBest = mProbBest;
	toRet->mProbRest = mProbRest;
	toRet->mEffort = mEffort;
	toRet->mPD = mPD;
	toRet->mPF = mPF;
	toRet->mAlpha = mAlpha;
	toRet->mBeta = mBeta;
	toRet->mGamma = mGamma;
	toRet->mTargetClass = mTargetClass;
	toRet->mScoreFcn = mScoreFcn;
	toRet->mComponent = NULL;

	return toRet;
}

bool Rule::createFromFile( string fName, Data *data, RULE_TYPE type, float (*scoreFcn)( Rule * ) )
{
  ifstream rFile( fName.c_str() );
  int attVal[2] = { -1, -1 };
  string tok, att;
  bool ruleCreated = false;

  if ( !rFile.is_open() )
  {
    cerr << "File " << fName << " could not be open.  Exiting." << endl;
    exit( 1 );
  }

  mData = data;
  mType = type;
  mScoreFcn = scoreFcn;
  
  rFile >> tok;
  while ( tok != "END" )
  {
    if ( attVal[0] == -1 )
    {
      att = tok +  ' ';
      attVal[0] = mData->getAttIndex( att );
      if ( attVal[0] == mData->getNumAtts() + 1 )
      {
	cerr << att << " was found in " << fName << " but not in the Data set. Exiting" << endl;
	exit( 1 );
      }
      cout << attVal[0] << endl;
    }
    else
    {
      attVal[1] = mData->getAttValIndex( att, tok );
      if ( attVal[1] == mData->getNumAttVals( att ) )
      {
	cerr << tok << " was foind in " << fName << " but not in the Data set. Exiting." << endl;
	exit( 1 );
      }
      addComponent( attVal[0], attVal[1] );
      ruleCreated = true;
      attVal[0] = -1;
    }
    rFile >> tok;
  }

  score();

  return ruleCreated;
}

float Rule::compare( Rule *r )
{
	return mScore - r->mScore;
}

bool Rule::isSatisfied( vector< InstanceElement * > *instance )
{
	Rule *r = new Rule();
	for ( unsigned int i = 0; i < instance->size() - 1; i++ )
	  //if ( !( instance->at(i)->mIsUnknown ) )
	    r->addComponent( i, instance->at(i)->mIndex );

	for ( unsigned int att = 0; att < mPicked.size(); att++ )
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
			if ( !( r->hasComponent( mPicked[att]->mAttribute, mPicked[att]->mValues[val] ) ) )
			{
				delete r;
				return false;
			}

	delete r;
	return true;
}

void Rule::score()
{
  	switch( mType )
	{
		case LIFT: scoreLift(); break;
		case EFFORT: scoreEffort(); break;
		case PROBSUPT: scoreProbSupt(); break;
		case INFOGAIN: scoreInfoGain(); break;
		case PDPF: scorePDPF(); break;
		case PDOVEREFFORT: scorePDOverEffort(); break;
	        case PDOVERLOC: scorePDOverLOC(); break;
	        case SPECIAL: scoreSpecial(); break;
	        case ACCURACY: scoreAccuracy(); break;
		default: scoreInfoGain(); break;
	}
	mScore *= 100;
}

void Rule::scoreLift()
{
	vector< vector< InstanceElement * > * > instances = mData->getInstanceSet();
	vector< int > freqs( mData->getNumClasses() );
	mScore = 0;
	int totInst = 0;
	mPD = mPF = 0;

	for ( unsigned int c = 0; c < freqs.size(); c++ ) freqs[c] = 0;
	for ( unsigned int i = 0; i < instances.size(); i++ )
		if ( isSatisfied( instances[i] ) )
		{
			freqs[mData->getClassIndex( instances[i] )]++;
			if ( mData->getClassIndex( instances[i] ) == mTargetClass ) mPD++;
			else mPF++;
			totInst++;
		}

	for ( unsigned int i = 0; i < freqs.size(); i++ )
		mScore += freqs[i] * pow( (double)2, (double)(i+1) );

	if ( totInst == 0 || mData->getLift() == 0 ) mScore = 0;
	else mScore = mScore/(float)totInst/(float)mData->getLift();
	
	if ( instances.size() == 0 ) mSupport = 0;
	else mSupport = totInst/(float)instances.size() * 100;

	if ( mSupport < 0 || mScore < 0.001 ) mScore = 0.0;
	mPD = mPD/(float)mData->getClassFreqs()[mTargetClass];
	mPF = mPF/(float)mData->getClassFreqs()[0];
}

float Rule::calcDist()
{
	return sqrt( (double)mPD * mPD * mAlpha +
				 (1-mPF) * (1-mPF) * mBeta +  
				 (1-mEffort) * (1-mEffort) * mGamma ) / 
				 sqrt( (double)mAlpha + mBeta + mGamma );
}

void Rule::scoreEffort()
{
	vector< vector< InstanceElement * > *> instances = mData->getInstanceSet();
	vector< int > LOCs = mData->getLOCs();
	int freqBest = 0, freqRest = 0;
	mPD = mPF = mEffort = 0;

	for ( unsigned int item = 0; item < instances.size(); item++ )
	{
		if ( isSatisfied( instances[item] ) )
		{
			mEffort += LOCs[item];
			if ( mData->getClassIndex( instances[item] ) == mTargetClass ) freqBest++;
			else freqRest++;
		}
	}

	if ( mData->getTotLOC() <= 0 ) mEffort = 0;
	else mEffort /= (float)mData->getTotLOC();

	if ( mData->getClassFreqs().back() <= 0 ) mPD = 0;
	else mPD = freqBest/(float)mData->getClassFreqs()[mTargetClass];

	if ( freqBest + freqRest <= 0 )  mPF = 0;
	else mPF = freqRest/(float)(freqBest + freqRest );

	if ( mData->getClassFreqs().back() <= 0 ) mSupport = 0;
	else mSupport = freqBest/(float)(mData->getClassFreqs().back()) * 100;

	if ( mPD <= .2 || mPF > 0.8 || mEffort > 0.8 ) mScore = 0.0;
	else mScore = calcDist();
}

void Rule::scoreProbSupt()
{
	const vector< vector< int* > > *freqTable = mData->getFrequencyTable();
	int restCnt = mData->getClassFreqs()[0], bestCnt = mData->getClassFreqs()[1]; 
	mProbBest = mProbRest = 1;
	
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
	{
		int restSum = 0, bestSum = 0;
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
		{
			restSum += freqTable->at( mPicked[att]->mAttribute )[ mPicked[att]->mValues[val]][0];
			bestSum += freqTable->at( mPicked[att]->mAttribute )[ mPicked[att]->mValues[val]][1];
		}
		if ( restSum + bestSum == 0 )
		{
			mProbRest = 0;
			mProbBest = 0;
		}
		else
		{
			mProbRest *= restSum/(float)( restSum + bestSum );
			mProbBest *= bestSum/(float)( restSum + bestSum );
		}
	}

	if ( restCnt == 0 ) mProbRest = 0;
	else mProbRest /= (float)( restCnt );

	if ( bestCnt == 0 ) mProbBest = 0;
	else mProbBest /= (float)( bestCnt );

	if ( mProbBest + mProbRest  == 0 ) mScore = 0;
	else mScore = ( mProbBest * mProbBest )/(float)( mProbBest + mProbRest );

	mPD = mProbBest;
	mPF = mProbRest;
	mSupport = mProbBest;
}

void Rule::scoreInfoGain()
{
	int *classFreqs = new int[mData->getNumClasses()];
	int numHit = 0;
	vector< vector< InstanceElement * > * > data = mData->getInstanceSet();

	// Initialize the frequency counts to zero.
	mScore = 0;
	for ( int c = 0; c < mData->getNumClasses(); c++ ) classFreqs[c] = 0;

	// Get the class counts of the instances of data this rule hits.
	for ( unsigned int item = 0; item < data.size(); item++ )
		if ( isSatisfied( data[item] ) )
		{
			classFreqs[ mData->getClassIndex( data[item]) ]++;
			numHit++;
		}
	
	// Get this entropy for this Rule.
	if ( numHit > 0 )
	{
		for ( int c = 0; c < mData->getNumClasses(); c++ )
			if ( classFreqs[c] != 0 )
			{
				float a = -( classFreqs[c]/(float)numHit );
				float b = log( -a )/log( 2.0 );
				mScore += a * b;
			}
		mSupport = numHit/(float)data.size();
		mScore = 100 - mScore;
	}
}

void Rule::scorePDPF()
{
	int bestCnt = 0, restCnt = 0;
	for ( unsigned int item = 0; item < mData->getInstanceSet().size(); item++ )
	{
		if ( isSatisfied( mData->getInstanceSet()[item] ) )
		{
			if ( mData->getClassIndex( mData->getInstanceSet()[item] ) == mTargetClass ) bestCnt++;
			else restCnt++;
		}
	}

	mPD = bestCnt/(float)( mData->getClassFreqs()[mTargetClass] );
	mPF = restCnt/(float)( mData->getClassFreqs()[0] );
	mSupport = mPD;
	mScore = sqrt( mPD * mPD * mAlpha + (1-mPF) * (1-mPF) * mBeta )/sqrt( mAlpha + mBeta ) * 100;
}

void Rule::scorePDOverEffort()
{
	float bestCnt = 0, restCnt = 0, totLoc = 0;
	for ( unsigned int item = 0; item < mData->getInstanceSet().size(); item++ )
	{
		if ( isSatisfied( mData->getInstanceSet()[item] ) )
		{
			if ( mData->getClassIndex( mData->getInstanceSet()[item] ) == mTargetClass ) bestCnt++;
			else restCnt++;
			totLoc += mData->getLOCs()[item];
		}
	}

	mPD = bestCnt/(float)( mData->getClassFreqs()[mTargetClass] );
	mPF = restCnt/(float)( mData->getClassFreqs()[0] );
	if ( mData->getTotLOC() > 0 ) mEffort = totLoc/(float)( mData->getTotLOC() );
	else mEffort = 0;
	mSupport = mPD;
	if ( mEffort > 0 ) mScore = ( mPD ) / mEffort;
	else mScore = 0;
}

void Rule::scorePDOverLOC()
{
  scorePDOverEffort();
  mEffort *= mData->getTotLOC();
  if ( mPD == 0 && mEffort == 0) mScore = 0;
  else if ( mEffort == 0 ) mScore = mPD;
  else mScore = mPD/(float)mEffort;    
}

void Rule::scoreRipper()
{
  int p, n;
  scorePDOverLOC();
  mEffort = 0;
  p = mPD * mData->getClassFreqs()[1];
  n = mPF * mData->getClassFreqs()[0];
  if ( p + n  == 0 ) mScore = 0;
  else mScore = (float)p/(float)(p+n) - (float)n/(float)(p+n);
}

void Rule::scorePrecision()
{
  int p, n;
  scorePDOverLOC();
  mEffort = 0;
  p = mPD * mData->getClassFreqs()[1];
  n = mPF * mData->getClassFreqs()[0];
  if ( p + n  == 0 ) mScore = 0;
  else mScore = (float)p/(float)(p+n);
}

void Rule::scoreAccuracy()
{
  int total = mData->getInstanceSet().size();
  mPD = 0;

  for ( unsigned int item = 0; item < mData->getInstanceSet().size(); item++ )
    if ( isSatisfied( mData->getInstanceSet()[item] ) &&
	 mData->getClassIndex( mData->getInstanceSet()[item] ) == mTargetClass ) 
      mPD++;

  mSupport = mPF = 0;
  if ( total > 0 )  mScore = (float)mPD / (float)total * 100;
  else mScore = 0;
}

void Rule::scoreSpecial()
{
  mScore = mScoreFcn( this );
}

int Rule::findAttribute( int attribute )
{
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
		if ( mPicked[att]->mAttribute == attribute )
			return att;

	return -1;
}

int Rule::findAttributeValue( int attribute, int value )
{
	int att = findAttribute( attribute );
	if ( att == -1 ) return -1;

	for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
		if ( mPicked[att]->mValues[val] == value )
			return val;

	return -1;
}

bool Rule::hasComponent( int attribute, int value )
{
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
		if ( mPicked[att]->mAttribute == attribute )
			for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
				if ( mPicked[att]->mValues[val] == value )
					return true;

	return false;
}

bool Rule::isEqualTo( Rule *r )
{
	// If the rules don't have the same conjunctions, they can't be equal.
	if ( mPicked.size() != r->mPicked.size() ) return false;

	for ( unsigned int att = 0; att < mPicked.size(); att++ )
	{
		int rAtt = r->findAttribute( mPicked[att]->mAttribute );

		// If this attribute doesn't exist in r, they can't be equal.
		if ( rAtt == -1 ) return false;

		// If this attribute's disjuntions aren't the same size as r's, they can't be equal.
		if ( this->mPicked[att]->mValues.size() != r->mPicked[rAtt]->mValues.size() ) return false;

		// If we are here, that means that Rule r has the same number of attributes.
		// the current attribute is in r, and that the number of disjunctions in r
		// are the same as this one's.  now we much check to see if the actual indexes match.
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
			if ( r->findAttributeValue( mPicked[att]->mAttribute, mPicked[att]->mValues[0] ) == -1 )
				return false;
	}

	return true;
}

bool Rule::addComponent( int attribute, int value )
{
	int attLoc = findAttribute( attribute );
	if ( attLoc != -1 )
	{
		if ( findAttributeValue( attribute, value ) != -1 ) return false;
		else mPicked[attLoc]->mValues.push_back( value );
	}
	else
	{
		mPicked.push_back( new DisjunctionSet() );
		mPicked.back()->mAttribute = attribute;
		mPicked.back()->mValues.push_back( value );
	}

	mSize++;
	return true;
}

Rule *Rule::combine( Rule *r )
{
	Rule *toRet = clone();
	vector< DisjunctionSet *>::iterator ai;

	// Combine Rule r with this
	if ( r == NULL ) return toRet;
	for ( unsigned int att = 0; att < r->mPicked.size(); att++ )
		for ( unsigned int val = 0; val < r->mPicked[att]->mValues.size(); val++ )
			toRet->addComponent( r->mPicked[att]->mAttribute, r->mPicked[att]->mValues[val] );

	// If a set of DisjunctionSet covers every attribute range for an attribute, remove that
	// DisjunctionSet from the new Rule.
	ai = toRet->mPicked.begin();
	while ( ai != toRet->mPicked.end() && mData != NULL )
	{
		if ( (*ai)->mValues.size() == mData->getNumAttVals( mData->getAttName( (*ai)->mAttribute ) ) )
		{
			toRet->mSize -= (*ai)->mValues.size();
			ai = toRet->mPicked.erase( ai );
		}
		else
			ai++;
	}

	toRet->mData = mData;
	toRet->mType = mType;
	return toRet;
}

Rule *Rule::backSelect()
{
	Rule *w, *toRet;
	vector< DisjunctionSet *>::iterator attItr;
	vector< int >::iterator valItr;
	int att, val;

	// Get the lowest scoring attr-val pair.
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
	{
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
		{
			Rule *r = new Rule( mPicked[att]->mAttribute, mPicked[att]->mValues[val], mData, mType );
			r->score();
			if ( att == 0 && val == 0 ) w = r;
			else if ( r->mScore < w->mScore )
			{
				delete w;
				w = r;
			}
			else delete r;
		}
	}

	toRet = clone();

	att = toRet->findAttribute( w->mPicked[0]->mAttribute );
	val = toRet->findAttributeValue( w->mPicked[0]->mAttribute, w->mPicked[0]->mValues[0] );
	attItr = toRet->mPicked.begin();
	valItr = toRet->mPicked[att]->mValues.begin();
	for ( unsigned int a = 0; a < att; a++ ) attItr++;
	for ( unsigned int v = 0; v < val; v++ ) valItr++;

	toRet->mPicked[att]->mValues.erase( valItr );
	toRet->mSize--;
	if ( toRet->mPicked[att]->mValues.size() == 0 )
	{
		DisjunctionSet *ds = *attItr;
		toRet->mPicked.erase( attItr );
		delete ds;
	}

	toRet->score();
	if ( toRet->mScore > mScore ) return toRet;
	else 
	{
		delete toRet;
		return NULL;
	}
}

void Rule::printGotWant( ostream& stream, Data *eData )
{
	int hit = 0;
	vector< vector< InstanceElement * > * > items = mData->getInstanceSet();
	for ( unsigned int item = 0; item < items.size(); item++ )
	{
		if ( isSatisfied( items[item] ) )
		{
			hit++;
			stream << hit << " " << mData->getClassName( mTargetClass ) 
				   << " xxx " << mData->getClassName( eData->getClassIndex( items[item] ) ) 
				   << " (" << eData->getLOCs()[item] << ")" << endl;
		}
	}
}

void Rule::print( ostream &stream )
{
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
	{
		if ( att != 0 ) 
		{
			stream << "AND ";
			stream.width( 26 );
		}
		else stream.width( 30 );
		stream.flags( ios::left );
		stream << mData->getAttName( mPicked[att]->mAttribute );
		stream << " = [ ";
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
		{
			if ( val != 0 ) stream << " OR ";
			stream << mData->getAttValName( mData->getAttName(  mPicked[att]->mAttribute )
				     , mPicked[att]->mValues[val] ) << "(" << mPicked[att]->mValues[val]+1 << ")";
		}
		stream << " ]" << endl;
	}
	stream << "Score:" << mScore/100 << endl;
	stream << "Support:" << mSupport << endl;
	stream << "PD:" << mPD << endl;
	stream << "PF:" << mPF << endl;
}

void Rule::printRule( ostream& stream )
{
	for ( unsigned int att = 0; att < mPicked.size(); att++ )
	{
		string conj = att == 0 ? "" : " AND ";
		stream << conj << mData->getAttName( mPicked[att]->mAttribute ) << " = [ ";
		for ( unsigned int val = 0; val < mPicked[att]->mValues.size(); val++ )
		{
			string disj = val == 0 ? "" : " OR ";
			stream << disj << mData->getAttValName( mData->getAttName( mPicked[att]->mAttribute ),
													mPicked[att]->mValues[val] );
		}
		stream << " ]";
		if ( (att+1) % 4 == 0 ) stream << endl << "\t\t";
	}
	stream << endl;
}
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for Rule.cpp}
\label{fig:rulecpp}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#ifndef _data_h_
#define _data_h_
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <map>

class Rule;

union InstanceElement
{
	int mIndex;
	float mValue;
};

struct ListItem
{
        float mVal;
	int mPos;

	ListItem(){}

	ListItem( float val, int pos )
	{
		mVal = val;
		mPos = pos;
	}

	bool operator<( const ListItem &li ) const
	{
		return mVal < li.mVal;
	}
};

/**
 * This class represents a data file.  It facilitates the structures necessary to easily
 * get infomormation from the data.
**/
class Data
{
	public:
		/**
		 * Empty Constructor.
		**/
		Data();

		/**
		 * Destructor.
		**/
		~Data();

		/**
		 * Reads in the training ARFF file and creates the Data instance.
		 * @param fName The name of the file to read in.
		 * @return The file stream.
		**/
		void read( std::string fName );

		/**
		 * This method will discretize the attributes that are continuous using
		 * an equal interval discretization method.
		 * @param bins The number of bins to use.
		 * @param combine Another data set to combine with this one in the discretization.
		**/
		void discretizeEqInt( int bins, Data *combine );

		/**
		 * This method will discretize the attribtues that are continous using
		 * an equal frequency discretization method.
		 * @param bins The number of bins to use.
		 * @param combine Another data set to combine with this one in the discretization. If this is null,
		 * this is ignored.
		**/
		void discretizeEqFreq( int bins, Data *combine = NULL );

		/**
		 * This method will subsample the data.  That is, remove instances of data that are not the
		 * desired class until the percentage of the desired class in the entire data set is met.
		 * @param desClass The index of the desired class.
		 * @param per The desired percent.  If this is smaller than the percent makeup already, this method
		 * does nothing.
		 * @return true if the set has been altered, false otherwise.
		**/
		bool subsample( unsigned int desClass, float per );

		/**
		 * This method will microsample that data.  This involves having an equal distribution of
		 * all classes and a total number of each class being equal to amount.
		 * @param amount The number of each class to be left in the data set.
		 * @return The actual number of each class left in the data set.  If amount > size( class ) than it will only remove from other classes.
		**/
		unsigned int microsample( unsigned int amount );
		
		/**
		 * This method will normalize an attribute so that each value is between 0 and 1 and the
		 * greatest attribute is equal to 1.
		 * @param attIndex The index of the attribute to normalize.
		 **/
		void normalizeAttribute( int attIndex );

		/**
		 * Creates a copy of the Data with the attributes and instance information.
		 * @return The copied Data.
		**/
		Data *clone();
		
		/**
		 * This method will remove all instances of data from the data set that are covered by
		 * a given rule.
		 * @param rule The rule to check coverage.
		 * @return true if the set was altered, false otherwise.
		**/
		bool cover( Rule *rule );

		/**
		 * Compares two ListItems.
		 * @param l1 The first ListItem.
		 * @param l2 The second Listitem.
		 * @return 0 if l1 = l2, -1 if l1 < l2, or 1 if l1 > l2.
		**/
		int compareListItems( ListItem l1, ListItem l2 );

		/**
		 * Calculates the base lift of the data.
		**/
		void calcLift();

		/**
		 * Calulates the base infomation needed for Effort scoring.
		 * @param LOC The attribue that is the lines of code.
		**/
		void calcPDPFEst( unsigned int LOC );
		
		/**
		 * Calculates the frequency counts of each attribute-value pair.
		 * Assumes all data is discrete.
		 * Assumes only 2 ordered classes.( Best is second class )
		**/
		void calcProbSupt();

		/**
		 * Gets the base lift of the data.
		 * @return The base lift.
		**/
		float getLift();

		/**
		 * Gets the total lines of code in this data instance.
		 @return The total lines of code.
		**/
		int getTotLOC();

		/**
		 * Gets the lines of code per instance.
		 * @return A vector containing the lines of code per instance.
		**/
		std::vector< int > getLOCs();

		/**
		 * Gets the instance set.
		 * @return The instance set.
		**/
		std::vector< std::vector< InstanceElement * > * > getInstanceSet();

		/**
		 * Gets the number of attributes.
		 * @return The number of attributes.
		**/
		unsigned int getNumAtts();

		/**
		 * Gets the number of class values.
		 * @return The number of class values.
		**/
		unsigned int getNumClasses();

		/**
		 * Gets the class index for a given instance.
		 * @param An instance of data.
		 * @return The class index.
		**/
		unsigned int getClassIndex( std::vector< InstanceElement * > *instance );

		/**
		 * Gets the number of values for a given attribute.
		 * @param att The attribute.
		 * @return the number of values for att.
		**/
		unsigned int getNumAttVals( std::string att );

		/**
		 * Gets the attribute name of the index'th attribute.
		 * @param index The name to return.
		 * @return The name of the attribute at index.
		**/
		std::string getAttName( int index );

		/**
		 * Gets the index of an attribute if the string sent in matches it.
		 * @param name The name of the attribute to find the index of.
		 * @return The index if found, number of attributes + 1 otherwise.
		 **/
		unsigned int getAttIndex( std::string name );		

		/**
		 * Gets the index of an attribute value if the string sent in matches it.
		 * @param attName The name of the attribute.
		 * @param valName The name of the attribute value to match.
		 * @return The index if found, number of attribute values + 1 otherwise.
		 **/
		unsigned int getAttValIndex( std::string attName, std::string valName );

		/**
		 * Gets the name of the attribute value at the index'th value.
		 * @param att The name of the attribute.
		 * @param index the value to get.
		 * @return The name of the attribute value at the index.
		**/
		std::string getAttValName( std::string att, int index );

		/**
		 * Gets the class name at the index'th location.
		 * @param index The index of the class to get.
		 * @return The class name in string form.
		**/
		std::string getClassName( int index );

		/**
		 * Gets the class frequency vector.
		 * @return The class frequency vector.
		**/
		std::vector< int > getClassFreqs();

		/**
		 * Gets the frequency count table for best^2/(best+rest)
		 * @return A jagged array with each 2-dimensinal access containing
		 * a length two array with the first element being the rest count and
		 * the second element being the best count of this attribute-value pair.
		**/
		const std::vector< std::vector< int * > > *getFrequencyTable();

		/**
		 * This method will print the attributes.
		**/
		void printAttributes();

		/**
		 * This method will print the data set.
		**/
		void printDataSet( std::ostream &stream );

		/**
		 * This method prints the class names and frequencies.
		**/
		void printClassDist();

		/**
		 * This method will print one instance of the data set.
		 * @param inst The instance number to print.
		**/
		void printInstance( int inst );

		/**
		 * This method will print all of the attribute value best and rest frequencies.
		 * @param stream The stream to print to.
		**/
		void printFrequencyTable( std::ostream &stream );
		
	protected:
		void processAttribute( std::string line );
		void processInstance( std::string line );
		std::string preprocessString( std::string line );
		int find( std::string att, std::vector< std::string > &l );

		std::string mFileName;
		std::string mClassName;
		std::vector< int > mClassFreqs;
		std::vector< std::vector< int * > > mAttrValFreqs;
		std::vector< std::string > mAtts;
		std::vector< bool > mIsReal;
		std::map< std::string, std::vector< std::string > > mAttVals;
		std::vector< std::vector< InstanceElement * > * > mInstances;
		std::vector< int > mLOCs;
		float mLift;
		int mTotLOC;
};

#endif
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for Data.h}
\label{fig:datah}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#include "Data.h"
#include "Rule.h"
#include "defines.h"
#include <iostream>
#include <algorithm>
#include <cmath>
#include <sstream>
using namespace std;

Data::Data() {}

Data::~Data() 
{
	while ( mInstances.size() > 0  )
	{
		vector< InstanceElement * > *i = mInstances.back();
		while ( i->size() > 0 )
		{
			InstanceElement *ie = i->back();
			i->pop_back();
			delete ie;
		}
		mInstances.pop_back();
		delete i;
	}

	while ( mAttrValFreqs.size() > 0 )
	{
		vector< int * > tmpV = mAttrValFreqs.back();
		while ( tmpV.size() > 0 )
		{
			int *tmp = tmpV.back();
			tmpV.pop_back();
			delete tmp;
		}
		mAttrValFreqs.pop_back();
	}
}

void Data::read( string fName )
{
	ifstream file( fName.c_str() );
	mFileName = fName;
	if ( !file.is_open() )
	{
		cerr << "Error opening file " << fName << ". Exiting." << endl;
		exit( 0 );
	}

	string line;
	bool atData = false;
	int index;
	while ( !file.eof() )
	{
		getline( file, line, '\n' );
		for ( unsigned int i = 0; i < line.length(); i++ )
			if ( line[i] >= 'A' && line[i] <= 'Z' ) line[i] = line[i] - 'A' + 'a';

		// Skip blank lines
		if ( line.empty() || line.find( "@relation" ) != string::npos || line.find( "%" ) != string::npos ) continue;
		
		if ( line.find( "@data" ) != string::npos )
		{
			mClassName = mAtts[ mAtts.size()-1 ];
			mClassFreqs.resize( mAttVals[mClassName].size() );
			for ( unsigned int i = 0; i < mClassFreqs.size(); i++ ) mClassFreqs[i] = 0;
			atData = true;
			continue;
		}

		if ( !atData ) processAttribute( preprocessString( line ) );
		else processInstance( preprocessString( line ) );
	}
}

void Data::discretizeEqInt( int bins, Data *combine )
{
  vector< vector< InstanceElement * > * > allData;
  
  if ( combine == NULL ) 
  {
		allData.resize( mInstances.size() );
		for ( unsigned int i = 0; i < mInstances.size(); i++ )
		{
			allData[i] = new vector< InstanceElement * >( mInstances[i]->size() );
			for ( unsigned int j = 0; j < mInstances[i]->size(); j++ )
			{
				allData[i]->at(j) = new InstanceElement();
				if ( mIsReal[j] ) allData[i]->at(j)->mValue = mInstances[i]->at( j )->mValue;
				else allData[i]->at(j)->mIndex = mInstances[i]->at( j )->mIndex;
			}
		}
  }
  else
  {
    for ( unsigned int i = 0; i < mInstances.size(); i++ )
    {
	   allData.push_back( new vector< InstanceElement * >() );
	   for ( unsigned int j = 0; j < mInstances[i]->size(); j++ )
	   {
		   allData.back()->push_back( new InstanceElement() );
		   //allData.back()->at( j )->mIsUnknown = false;
		   //if ( mInstances[i]->at( j )->mIsUnknown ) allData.back()->at( j )->mIsUnknown = true;
		   /*else*/ if ( mIsReal[j] ) allData.back()->at( j )->mValue = mInstances[i]->at( j )->mValue;
		   else allData.back()->at( j )->mIndex = mInstances[i]->at( j )->mIndex;
	  }
	}

    for ( unsigned int i = 0; i < combine->mInstances.size(); i++ )
    {
		allData.push_back( new vector< InstanceElement * >() );
		for ( unsigned int j = 0; j < combine->mInstances[i]->size(); j++ )
		{
			allData.back()->push_back( new InstanceElement() );
			//allData.back()->at( j )->mIsUnknown = false;
			//if ( combine->mInstances[i]->at( j )->mIsUnknown ) allData.back()->at( j )->mIsUnknown = true;
			/*else*/ if ( combine->mIsReal[j] ) allData.back()->at( j )->mValue = combine->mInstances[i]->at( j )->mValue;
			else allData.back()->at( j )->mIndex = combine->mInstances[i]->at( j )->mIndex;
		}
	}
  }

  for ( unsigned int att = 0; att < mAtts.size(); att++ )
  {
    if ( mIsReal[att] )
    {
      mAttVals[mAtts[att]].resize(bins);
	  if ( combine != NULL )
		combine->mAttVals[mAtts[att]].resize(bins);


	  if ( allData[0]->at(att)->mValue < 0.0001 ) allData[0]->at(att)->mValue = 0.0001;
	  allData[0]->at(att)->mValue = log10( allData[0]->at(att)->mValue );
	  //allData[0]->at(att)->mValue = allData[0]->at(att)->mValue;
      float minima = allData[0]->at(att)->mValue, maxima = minima;
      for ( unsigned int item = 1; item < allData.size(); item++ )
      {
	    if ( allData[item]->at(att)->mValue < 0.0001 ) allData[item]->at(att)->mValue = 0.0001;
	    allData[item]->at(att)->mValue = log10( allData[item]->at(att)->mValue );
		//allData[item]->at(att)->mValue = allData[item]->at(att)->mValue;
		minima = min( minima, allData[item]->at(att)->mValue );
		maxima = max( maxima, allData[item]->at(att)->mValue );
      }
	  int binCnts[10] = {0,0,0,0,0,0,0,0,0,0};
      for ( unsigned int item = 1; item < allData.size(); item++ )
	  {
		  int binNo = (allData[item]->at(att)->mValue-minima)/(maxima-minima)*bins;
		  binCnts[binNo]++;
		  if ( item < mInstances.size() )
			  mInstances[item]->at(att)->mIndex = binNo;
		  else
			  combine->mInstances[item-mInstances.size()]->at(att)->mIndex = binNo;
      }

	  for ( int b = 0; b < 10; b++ )
		cout << "Bin " << b+1 << ": " << binCnts[b]/(float)allData.size()*100 << endl;
	  cout << endl;

	  float incr = (maxima-minima)/(float)bins;
	  for ( unsigned int b = 0; b < bins; b++ )
	  {
		  stringstream ss( stringstream::in | stringstream::out );
		  //ss << "[ " << pow(10,b*incr+minima) << " to " << pow(10, (b+1)*incr+minima) << " ]" << endl;
		  ss << "[ " << b*incr+minima << " to " << (b+1)*incr+minima << " ]" << endl;
		  getline( ss, mAttVals[mAtts[att]][b] );
		  if ( combine != NULL )
			combine->mAttVals[mAtts[att]][b] = mAttVals[mAtts[att]][b];
	  }

      mIsReal[att] = false;
	  if ( combine != NULL ) combine->mIsReal[att] = false;
    }
  }  
}

void Data::discretizeEqFreq( int bins, Data *combine )
{
	vector< vector < InstanceElement * > * > allData;

	if ( combine == NULL ) 
	{
		allData.resize( mInstances.size() );
		for ( unsigned int i = 0; i < mInstances.size(); i++ )
		{
			allData[i] = new vector< InstanceElement * >( mInstances[i]->size() );
			for ( unsigned int j = 0; j < mInstances[i]->size(); j++ )
			{
				allData[i]->at(j) = new InstanceElement();
				if ( mIsReal[j] ) allData[i]->at(j)->mValue = mInstances[i]->at( j )->mValue;
				else allData[i]->at(j)->mIndex = mInstances[i]->at( j )->mIndex;
			}
		}
	}
	else
	{
		for ( unsigned int i = 0; i < mInstances.size(); i++ )
		{
			allData.push_back( new vector< InstanceElement * >() );
			for ( unsigned int j = 0; j < mInstances[i]->size(); j++ )
			{
				allData.back()->push_back( new InstanceElement() );
				if ( mIsReal[j] ) allData.back()->at( j )->mValue = mInstances[i]->at( j )->mValue;
				else allData.back()->at( j )->mIndex = mInstances[i]->at( j )->mIndex;
			}
		}

		for ( unsigned int i = 0; i < combine->mInstances.size(); i++ )
		{
			allData.push_back( new vector< InstanceElement * >() );
			for ( unsigned int j = 0; j < combine->mInstances[i]->size(); j++ )
			{
				allData.back()->push_back( new InstanceElement() );
				if ( combine->mIsReal[j] ) allData.back()->at( j )->mValue = combine->mInstances[i]->at( j )->mValue;
				else allData.back()->at( j )->mIndex = combine->mInstances[i]->at( j )->mIndex;
			}
		}
	}


	for ( unsigned int att = 0; att < mAtts.size(); att++ )
	{
		if ( mIsReal[att] )
		{
			// Get a vector of all the values this continuous attribute has.
			vector< ListItem > mItems( allData.size() );
			float *mins = new float[bins], *maxes = new float[bins];
			
			for ( int b = 0; b < bins; b++ )
			{
				mins[b] = allData[0]->at( att )->mValue;
				maxes[b] = allData[0]->at( att )->mValue;
			}

			for ( unsigned int i = 0; i < allData.size(); i++ )
			{
				//if ( allData[i]->at( att )->mValue < 0.00001 ) allData[i]->at( att )->mValue = 0.00001;
				mItems[i].mPos = i;
				//mItems[i].mVal = log10( allData[i]->at( att )->mValue );
				mItems[i].mVal = allData[i]->at( att )->mValue;
			}

			sort( mItems.begin(), mItems.end() );

			// Change this attribute to discrete.
			mAttVals[mAtts[att]].resize( bins );
			if ( combine != NULL )
				combine->mAttVals[combine->mAtts[att]].resize( bins );
			
			for ( unsigned int i = 0; i < mItems.size(); i++ )
			{
				int binNo = floor(i/(float)mItems.size() * bins);
				unsigned int pos = mItems[i].mPos;

				mins[binNo] = min( mins[binNo], mItems[i].mVal );
				maxes[binNo] = max( mins[binNo], mItems[i].mVal );
				if ( pos < mInstances.size() ) mInstances[pos]->at( att )->mIndex = binNo;
				else combine->mInstances[pos - mInstances.size()]->at( att )->mIndex = binNo;
			}
			
			mIsReal[att] = false;
			if ( combine != NULL ) combine->mIsReal[att] = false;

			// Change the AttVal vector for this attribute to bin number of elements that
			// best describe this attribute's bins.
			for ( unsigned int b = 0; b < bins; b++ )
			{
				stringstream ss( stringstream::in | stringstream::out );
				//ss << "[ " << pow(10, (mins[b])) << " to " << pow(10, (maxes[b])) << " ]" << endl;
				ss << "[ " << (mins[b]) << " to " << (maxes[b]) << " ]" << endl;
				getline( ss, mAttVals[mAtts[att]][b] );
				if ( combine != NULL )
					combine->mAttVals[combine->mAtts[att]][b] = mAttVals[mAtts[att]][b];
			}
			
			delete mins;
			delete maxes;
		}
	}

	while ( allData.size() > 0 )
	{
		vector< InstanceElement * > *b = allData.back();
		allData.pop_back();
		while ( b->size() > 0 )
		{
			InstanceElement *ie = b->back();
			b->pop_back();
			delete ie;
		}
		delete b;
	}
}

bool Data::subsample( unsigned int desClass, float per )
{
	// If the desiered class index is not within the bounds of the
	// number of class values, error and exit.
	if ( desClass < 0 || desClass >= mClassFreqs.size() )
	{
		cerr << desClass << " out of range, exiting." << endl;
		exit( 1 );
	}

	// Check to make sure percentage is a valid percentage.
	if ( per < 0 || per > 1 )
	{
		cerr << per << " is not a valid percentage( 0-1 ), exiting." << endl;
		exit( 1 );
	}

	float natPer;
	int desSum, toRemove;

	// Calculate the natural percentage.
	natPer = mClassFreqs[desClass]/(float)mInstances.size();

	// If the natural percentage is greater than or equal to the
	// desired percentage, return false.
	if ( natPer >= per ) return false;

	desSum = floor( (natPer*mInstances.size())/per ); 
	toRemove = mInstances.size() - desSum;
	if ( toRemove < 0 ) toRemove = 0;

	// Remove toRemove amount of non desired classes from set.
	for ( unsigned int i = 0; i < toRemove; i++ )
	{
		int inst = 0, cnt = 0;
		vector< vector< InstanceElement * > * >::iterator instItr; 
		InstanceElement *ie;
		do
		{
			inst = randomNum( 0,mInstances.size()-1 );
		} while ( getClassIndex( mInstances[inst] ) == desClass );
		instItr = mInstances.begin();
		while ( cnt++ < inst && instItr++ != mInstances.begin() );
		while ( (*instItr)->size() > 0 )
		{
			ie = (*instItr)->back();
			(*instItr)->pop_back();
			delete ie;
		}
		mInstances.erase( instItr );
		delete (*instItr );
	}

	// Recalculate the class frequencies.
	for ( unsigned int i = 0; i < mClassFreqs.size(); i++ ) mClassFreqs[i] = 0;
	for ( unsigned int i = 0; i < mInstances.size(); i++ )
		mClassFreqs[getClassIndex( mInstances[i] )]++;

	return true;
}

unsigned int Data::microsample( unsigned int amount )
{
  for ( unsigned int c = 0; c < mClassFreqs.size(); c++ )
    if ( mClassFreqs[c] < amount ) amount = mClassFreqs[c];

  for ( unsigned int c = 0; c < mClassFreqs.size(); c++ )
  {
    unsigned int toRemove = mClassFreqs[c] - amount;
    for ( unsigned int r = 0; r < toRemove; r++ )
    {
      unsigned int inst = randomNum( 0, mInstances.size() - 1 );
      vector< vector< InstanceElement * > *>::iterator instItr = mInstances.begin();
      while ( getClassIndex( mInstances[inst] ) != c )
      {
	inst = randomNum( 0, mInstances.size() - 1 );
      }
      for ( unsigned int i = 0; i < inst; i++ ) instItr++;
      while ( (*instItr)->size() > 0 )
      {
	InstanceElement *ie = (*instItr)->back();
	(*instItr)->pop_back();
	delete ie;
      }
      vector< InstanceElement *> *t = *instItr;
      mInstances.erase( instItr );
      delete  t;
    }
  }

  for ( unsigned int c = 0; c < mClassFreqs.size(); c++ )
    mClassFreqs[c] = amount;

  return amount;
}

void Data::normalizeAttribute( int attIndex )
{
  float tot = 0;
  if ( attIndex < 0 || attIndex > mAtts.size() )
  {
    cerr << "Can not normalize. Attribute index " << attIndex << " is out of range. Exiting." << endl;
    exit( 1 );
  }
  else if ( !mIsReal[attIndex] )
  {
    cerr << "Can not normalize. Attribute " << mAtts[attIndex] << " is not real. Exiting." << endl;
    exit( 1 );
  }

  for ( unsigned int item = 0; item < mInstances.size(); item++ )
  {
    tot += mInstances[item]->at(attIndex)->mValue;
  }
  
  for ( unsigned int item = 0; item < mInstances.size(); item++ )
  {
    mInstances[item]->at(attIndex)->mValue /= (float)tot;
  }
}

Data *Data::clone()
{
	Data *toRet = new Data();
	toRet->read( mFileName );

	return toRet;
}

bool Data::cover( Rule *rule )
{
	vector< vector< InstanceElement * > * >::iterator instItr = mInstances.begin();
	bool removed = false;

	while ( instItr != mInstances.end() )
	{
		if ( rule->isSatisfied( *instItr ) )
		{
			vector< InstanceElement * > *tmp = (*instItr);
			removed = true;
			instItr = mInstances.erase( instItr );
			// Clean up memory to avoid leaks.
			while ( tmp->size() > 0 )
			{
				InstanceElement *ie = tmp->back();
				tmp->pop_back();
				delete ie;
			}
			delete tmp;
		}
		else
		{
			instItr++;
		}
	}

	// Recalculate the class frequencies.
	for ( unsigned int i = 0; i < mClassFreqs.size(); i++ ) mClassFreqs[i] = 0;
	for ( unsigned int i = 0; i < mInstances.size(); i++ )
		mClassFreqs[getClassIndex( mInstances[i] )]++;

	return removed;
}

void Data::calcLift()
{
	mLift = 0;
	for ( unsigned int f = 0; f < mClassFreqs.size(); f++ )
		mLift += mClassFreqs[f] * pow( (double)2, (double)(f+1) );
	mLift /= mInstances.size();
}

void Data::calcPDPFEst( unsigned int LOC )
{
  	if ( LOC < 0 || LOC >= mAtts.size() )
	{
		cerr << LOC << " is out of range. Exiting." << endl;
		exit( 1 );
	}
	if ( !( mIsReal[LOC] ) )
	{
		cerr << "Attribute " << mAtts[LOC] << " is not a continuous attribute. Exiting." << endl;
		exit( 1 );
	}

	mTotLOC = 0;
	mLOCs.resize( mInstances.size() );
	for ( unsigned int i = 0; i < mInstances.size(); i++ )
	{
	  mLOCs[i] = mInstances[i]->at( LOC )->mValue;
	  mTotLOC += mLOCs[i];
	}
}

void Data::calcProbSupt()
{
	// If any attribute is continuous, the data has not been discretized and this would fail, 
	// so exit.
	for ( unsigned int r = 0; r < mIsReal.size(); r++ )
	{
		if ( mIsReal[r] )
		{
			cerr << "Attribute " << mAtts[r] << " is continuous, cannot calculate frequency counts. Exiting." << endl;
			exit( 0 );
		}
	}

	// Create the frequency table.  This is essentially a jagged array.
	mAttrValFreqs.resize( mAtts.size()-1 );
	for ( unsigned int att = 0; att < mAtts.size()-1; att++ ) 
	{
		mAttrValFreqs[att].resize( mAttVals[mAtts[att]].size() );
		for ( unsigned int bore = 0; bore < mAttrValFreqs[att].size(); bore++ )
		{
			mAttrValFreqs[att][bore] = new int[2];
			mAttrValFreqs[att][bore][0] = 0;
			mAttrValFreqs[att][bore][1] = 0;
		}
	}
	// Read the data line by line and count the frequency of best and rest
	// class for each attribute-value pair.
	for ( unsigned int item = 0; item < mInstances.size(); item++ )
	{
	  for ( unsigned int att = 0; att < mAtts.size()-1; att++ )
	  {
	    mAttrValFreqs[att][mInstances[item]->at(att)->mIndex][getClassIndex( mInstances[item] )]++;
	  }
	}
}

float Data::getLift()
{
	return mLift;
}

int Data::getTotLOC()
{
	return mTotLOC;
}

vector< int > Data::getLOCs()
{
	return mLOCs;
}

vector< vector< InstanceElement * > * > Data::getInstanceSet()
{
	return mInstances;
}
unsigned int Data::getNumAtts()
{
	return mAtts.size()-1;
}

unsigned int Data::getNumClasses()
{
	return getNumAttVals( mClassName );
}

unsigned int Data::getClassIndex( vector< InstanceElement * > *instance )
{
	return instance->at( instance->size() - 1 )->mIndex;
}

unsigned int Data::getNumAttVals( string att )
{
	if ( find( att, mAtts ) == -1 )
	{
		cerr << "Attribute " << att << " does not exist!" << endl;
		exit( 0 );
	}

	return mAttVals[att].size()-1;
}

string Data::getAttName( int index )
{
	if ( index >= 0 && index < mAtts.size() )
		return mAtts[index];
	
	cerr << "Index of " << index << " out of range!" << endl;
	exit( 0 );
}

string Data::getAttValName( string att, int index )
{
	if ( find( att, mAtts ) == -1 )
	{
		cerr << "Attribute " << att << " does not exist!" << endl;
		exit( 0 );
	}

	if ( index >= 0 && index < mAttVals[att].size() )
		return mAttVals[att][index];

	cerr << "Index of " << index << " out of range for attribute = " << att << endl;
	exit( 0 );
}

unsigned int Data::getAttIndex( string name )
{
  for ( unsigned int i = 0; i < mAtts.size(); i++ )
  {
    cout << "|" << mAtts[i] << "|" << endl;
    if ( mAtts[i] == name )
      return i;
  }
  return mAtts.size() + 1;
}

unsigned int Data::getAttValIndex( string attName, string valName )
{
  if ( mAttVals[attName].size() ==  0 )
  {
    cerr << attName << " is not a valid attribute name. Exiting." << endl;
    exit( 1 );
  }

  for ( unsigned int i = 0; i < mAttVals[attName].size(); i++ )
  {
    cout << "|" << mAttVals[attName][i] << "|" << endl;
    if ( mAttVals[attName][i] == valName )
      return i;
  }

  return mAttVals[attName].size() + 1;
}

string Data::getClassName( int index )
{
	if ( index >= 0 && index < mAttVals[mClassName].size() )
		return mAttVals[mClassName][index];

	cerr << "Index of " << index << " out of range for class( " << mClassName << " )" << endl;
	exit( 0 );
}

vector< int > Data::getClassFreqs()
{
	return mClassFreqs;
}

const vector< vector< int * > > *Data::getFrequencyTable()
{
	return &mAttrValFreqs;
}

void Data::printAttributes()
{
	for ( unsigned int att = 0; att < mAtts.size()-1; att++ )
	{
		cout << mAtts[att] << ": ";
		if ( mIsReal[att] )
			cout << "continuous";
		else
		{
			cout << mAttVals[mAtts[att]][0];
			for ( unsigned int val = 1; val < mAttVals[mAtts[att]].size(); val ++ )
			{
				cout << ", " << mAttVals[mAtts[att]][val];
				if ( (val+1) % 5 == 0 ) cout << endl;
			}
		}
		cout << endl << endl;
	}

	cout << endl << "Class" << endl;
	cout << mClassName << ": " << mAttVals[mClassName][0];
	for ( unsigned int cVal = 1; cVal < mAttVals[mClassName].size(); cVal++ )
		cout << ", " << mAttVals[mClassName][cVal];
	cout << endl;
}

void Data::printDataSet( ostream &stream )
{
	for ( unsigned int inst = 0; inst < mInstances.size(); inst++ )
	{
	  //if ( mInstances[inst]->at(0)->mIsUnknown ) stream << ",UNKNOWN";
	  /*else*/ if ( mIsReal[0] ) stream << mInstances[inst]->at(0)->mValue;
	  else stream << mAttVals[mAtts[0]][mInstances[inst]->at(0)->mIndex];
	  for ( unsigned int att = 1; att < mAtts.size(); att++ )
	    //if ( mInstances[inst]->at(att)->mIsUnknown ) stream << ",UNKNOWN";
	    /*else*/ if ( mIsReal[att] ) stream << "," << mInstances[inst]->at(att)->mValue;
	    else stream << "," << mAttVals[mAtts[att]][mInstances[inst]->at(att)->mIndex];
	  stream << endl;
	}
}

void Data::printClassDist()
{
	for ( unsigned int c = 0; c < mAttVals[mClassName].size(); c++ )
		cout << mAttVals[mClassName][c] << ": " << mClassFreqs[c] << "[ " << mClassFreqs[c]/(float)mInstances.size() << " ]" << endl;
}

void Data::printInstance( int inst )
{
	// If inst is out of range, print message and exit.
	if ( inst < 0 || inst > mInstances.size() )
	{
		cerr << inst << " is out of range, exiting." << endl;
		exit( 0 );
	}

	cout << mAttVals[mAtts[0]][mInstances[inst]->at(0)->mIndex];
	for ( unsigned int i = 1; i < mInstances[inst]->size(); i++ )
	{
		if ( (i+1) % 4 == 0 ) cout << endl;
		cout << ", " << mAttVals[mAtts[i]][mInstances[inst]->at(i)->mIndex];
	}
	cout << endl << endl;
}

void Data::printFrequencyTable( ostream &stream )
{
	cout << "<attribute>: <value_1>( rest_count, best_count ), ..." << endl;
	cout << "-----------------------------------------------------" << endl;
	for ( unsigned int att = 0; att < mAttrValFreqs.size(); att++ )
	{
		stream << mAtts[att] << ": " << mAttVals[mAtts[att]][0] << "( " << mAttrValFreqs[att][0][0] << ", " 
			   << mAttrValFreqs[att][0][1] << " )";
		for ( unsigned int val = 1; val < mAttrValFreqs[att].size(); val++ )
		{
			if ( (val+1)%6 == 0 ) stream << "\t\t" << endl;
			stream << ", " << mAttVals[mAtts[att]][val] << "( " << mAttrValFreqs[att][val][0] << ", " 
				   << mAttrValFreqs[att][val][1] << " )";
		}
		stream << endl;
	}
}

void Data::processAttribute( std::string line )
{
	string name = line.substr( line.find( "@attribute" ) + 11 );
	name = name.substr( name.find_first_not_of( " " ) );
	//cout << "|" << name << "|" << endl;
	string vals = name.substr( name.find( " " ) );
	vals = vals.substr( vals.find_first_not_of( " " ) );
	//cout << "|" << vals << "|" << endl;
	string test;
	bool done = false;

	name = name.substr( 0, name.find( vals ) );
	mAtts.push_back( name );
	vals = vals.substr( vals.find_first_of( " " ) + 1 );
	test = vals.substr( 0, vals.find_last_of( " " ) );
	// If the attribute is real number, set the flag that says so and exit.
	if ( test.compare( "real" ) == 0 || test.compare( "number" ) == 0 ||
		 test.compare( "integer" ) == 0 || test.compare( "continuous" ) == 0 ||
		 test.compare( "numeric" ) == 0 )
	{
		mIsReal.push_back( true );
		return;
	}
	mIsReal.push_back( false );
	vals = vals.substr( vals.find( "{" )+1 );
	vals = vals.substr( 0, vals.find( "}" ) );
	while ( !done )
	{
		int index = vals.find( "," ); 
		if ( index == string::npos ) 
		{
			index = vals.length();
			done = true;
		}
		string val = vals.substr( 0, index);
		if ( !done ) vals = vals.substr( index+1 );
		while ( val[0] == ' ' ) val = val.substr( 1 );
		mAttVals[name].push_back( val );
	}
}

void Data::processInstance( std::string line )
{
        if ( line.find( "?" ) != string::npos ) return;

	int index;
	InstanceElement *ie;
	vector< InstanceElement * > *instance = new vector< InstanceElement * >();
	stringstream ss(stringstream::in | stringstream::out);
	for ( unsigned int i = 0; i < mAtts.size()-1; i++ )
	{
		string val = line.substr( 0, line.find( "," ) );

		index = find( val, mAttVals[mAtts[i]] );
		//if ( val == "?" )
		//{
		//  ie = new InstanceElement();
		//  ie->mIsUnknown = true;
		//}
		/*else*/ if ( mIsReal[i] )
		{
			ie = new InstanceElement();
			while ( val[0] == ' ' ) val = val.substr( 1 );
			ss << val << endl;
			ss >> ie->mValue;
			//ie->mIsUnknown = false;
			instance->push_back( ie );

		}
		else if ( index != -1 ) 	
		{
			ie = new InstanceElement();
			ie->mIndex = index;
			//ie->mIsUnknown = false;
			instance->push_back( ie );
		}
		else
		{
			cerr << "Data file corrupt." << endl;
			cerr << "\'" << val << "\' is not a part of " << mAtts[i] << endl;
			exit( 0 );
		}

		line = line.substr( line.find( "," ) + 1 );
	}

	index = find( line, mAttVals[mClassName] );
	if ( index != -1 ) 
	{
		ie = new InstanceElement();
		ie->mIndex = index;
		//ie->mIsUnknown = false;
		instance->push_back( ie );
		mClassFreqs[index]++;
	}
	else
	{
		cerr << "Data file corrupt." << endl;
		cerr << "\'" <<line << "\'" << " is not a valid class value." << endl;
		exit( 0 );
	}

	mInstances.push_back( instance );
}

string Data::preprocessString( string line )
{
	int pos = line.find( ", " );
	for ( unsigned int i = 0; i < line.length(); i++ )
		if ( line[i] == '\t' ) line[i] = ' ';

	// Turn situations like @attribute a1 {1,    2,    3,    4}
	// into @attribute a1 {1,2,3,4}
	while ( pos != string::npos )
	{
		while ( pos+1 < line.length() && line[pos+1] == ' ' )
			line = line.erase( pos+1, 1 );
		pos = line.find( ", " );
	}

	return line;
}

int Data::find( string att, vector<string> &l)
{
	for ( unsigned int i = 0; i < l.size(); i++ )
		if ( att.compare( l[i] ) == 0 )
			return i;

	return -1;
}
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for Data.cpp}
\label{fig:datacpp}
\dbsp
\end{figure}

\begin{figure}[!ht]
\ssp
\lstset{language=Python}
\lstset{backgroundcolor=\color{listinggray}}
\lstset{frameround=tttt}
\lstset{basicstyle=\scriptsize}
\lstset{showstringspaces=false, showspaces=false, showtabs=false}
\begin{center}
\begin{lstlisting}[frame=trBL]{}
\begin{verbatim}
#ifndef _defines_h_
#define _defines_h_

#define INFINITY -1
#define randomNum(f,t) rand()/(float)RAND_MAX * (t-f) + f;

#endif
\end{verbatim}
\end{lstlisting}
\end{center}
\caption{Source Code for defines.h}
\label{fig:definesh}
\dbsp
\end{figure}
\normalsize