<commit_before>

#include "histoBook.h"
#include "TKey.h"
#include "TObject.h"

// constructor sets the name of the file for saving
histoBook::histoBook( string name, string input, string inDir ){

	if (name.find(  ".root") != std::string::npos){
		filename = name;
	} else
		filename = name + ".root";

	currentDir = "/";

	file = new TFile( filename.c_str(), "recreate" );
	file->cd();

	// make the legend and draw it once to apply styles etc.
	// for some reason needed to make styling work on the first draw
	legend = new TLegend( 0.65, 0.65, 0.9, 0.9);
	legend->SetFillColor( kWhite );
	legend->Draw();
	legend->Clear();

	globalStyle();

	// if an input was given merge it into the live record
	if ( input.length() >= 5 ){
		TFile * fin = new TFile( input.c_str() );
		cd ( inDir );
		fin->cd( inDir.c_str() );
		loadRootDir( gDirectory, inDir );
	}

}
// destructor
histoBook::~histoBook(){

	delete legend;

	save();
	file->Close();
}
void histoBook::save() {

	file->Write();
}

void histoBook::loadRootDir( TDirectory* tDir, string path ){

	//cout << "histoBook.loadRootDir] Path : " << path << endl;

	TList* list;

	if ( tDir ){
		list = tDir->GetListOfKeys();
	} else {
		cout << "[histoBook.loadRootDir] Bad Directory Given " << endl;
		return;
	}

	TIter next(list);
	TKey* key;
	TObject* obj;

	while ( (key = (TKey*)next()) ) {

		obj = key->ReadObj() ;

		if ( 0 == strcmp(obj->IsA()->GetName(),"TDirectoryFile") ){
			TDirectoryFile* dir = (TDirectoryFile*)obj;

			string nPath = path + dir->GetName();
			if ( path == (string) "" )
				nPath = path + dir->GetName();
			else
				nPath = path + "/" + dir->GetName();

			cd( nPath );
			loadRootDir( dir, nPath );
		} else if ( obj ){
			if (    (strcmp(obj->IsA()->GetName(),"TProfile")!=0) && (!obj->InheritsFrom("TH2") && (!obj->InheritsFrom("TH1"))) ) {
				// not a 1d or 2d histogram
			} else {
				// add it to the book
				//cout << "Adding : " << obj->GetName() << endl;
				add( obj->GetName(), (TH1*)obj->Clone( obj->GetName() ) );
			}

		}
	}

}

void histoBook::add( string name, TH1* h ){

	string oName = name;
	if ( name.length() <= 1 || !h )
		return;

	name = currentDir + name;

	// dont allow duplicated name overites
	if ( book[ name ] ){
		cout << "[histoBook.add] Duplicate histogram name in this directory " << currentDir << " / " << oName << endl;
		return;
	}

	// save the histo to the map
	book[ name ] = h;

}
/*
*
* TODO:: add support for full subdirectory trees
*/
string histoBook::cd( string sdir  ){

	string old = currentDir;

	char* csdir = (char*)sdir.c_str();
	file->cd();

	if ( file->GetDirectory( csdir ) ){
		file->cd( csdir );
	} else {
		cout << "[histoBook.cd] creating directory " << sdir << endl;
		file->mkdir( csdir );
		file->cd( csdir );
	}

	currentDir = sdir;

	return old;
}

void histoBook::make( xmlConfig * config, string nodeName ){

	if ( config && config->nodeExists( nodeName ) ){

		string hName = config->tagName( nodeName );
		if ( "" == hName )
			hName = nodeName;

		string type = config->getString( nodeName + ":type", "1D" );

		if ( "1D" == type ){
			make1D( hName, config->getString( nodeName + ":title", hName ),
					config->getInt( nodeName + ":nBinsX", 1 ), config->getDouble( nodeName + ":x1", 0 ),
					config->getDouble( nodeName + ":x2", 1 ) );

		} else if ( "2D" == type ){
			make2D( hName, config->getString( nodeName + ":title", hName ),
					config->getInt( nodeName + ":nBinsX", 1 ), config->getDouble( nodeName + ":x1", 0 ),
					config->getDouble( nodeName + ":x2", 1 ),
					config->getInt( nodeName + ":nBinsY", 1 ), config->getDouble( nodeName + ":y1", 0 ),
					config->getDouble( nodeName + ":y2", 1 ) );
		} else if ( "1F" == type ){

		}
	}

}

void histoBook::make1F( string name, string title, uint nBins, double low, double hi  ){

	TH1F* h;
	h = new TH1F( name.c_str(), title.c_str(), nBins, low, hi );

	this->add( name, h );
}

void histoBook::make1D( string name, string title, uint nBins, double low, double hi  ){

	TH1D* h;
	h = new TH1D( name.c_str(), title.c_str(), nBins, low, hi );

	this->add( name, h );
}

void histoBook::make1D( string name, string title, uint nBins, const Double_t* bins  ){

	TH1D* h;
	h = new TH1D( name.c_str(), title.c_str(), nBins, bins );

	this->add( name, h );
}

void histoBook::make2D( string name, string title, uint nBinsX, double lowX, double hiX, uint nBinsY, double lowY, double hiY ){

	TH2D* h;

	h = new TH2D( name.c_str(), title.c_str(), nBinsX, lowX, hiX, nBinsY, lowY, hiY );

	this->add( name, h );
}
void histoBook::make2D( string name, string title, uint nBinsX, const Double_t* xBins, uint nBinsY, double lowY, double hiY ){

	TH2D* h;
	h = new TH2D( name.c_str(), title.c_str(), nBinsX, xBins, nBinsY, lowY, hiY );

	this->add( name, h );
}

TH1* histoBook::get( string name, string sdir  ){
	if ( sdir.compare("") == 0)
		sdir = currentDir;
	return book[ ( sdir  + name  ) ];
}
TH2* histoBook::get2D( string name, string sdir  ){
	if ( sdir.compare("") == 0)
		sdir = currentDir;
	return (TH2*)book[ ( sdir  + name  ) ];
}

void histoBook::fill( string name, double bin, double weight ){
	if ( get( name ) != 0)
		get( name )->Fill( bin, weight );
}

void histoBook::globalStyle(){

	gStyle->SetCanvasColor(kWhite);     // background is no longer mouse-dropping white
  	gStyle->SetPalette(1,0);            // blue to red false color palette. Use 9 for b/w
  	gStyle->SetCanvasBorderMode(0);     // turn off canvas borders
  	gStyle->SetPadBorderMode(0);
  	gStyle->SetPaintTextFormat("5.2f");  // What precision to put numbers if plotted with "TEXT"

  	// For publishing:
  	gStyle->SetLineWidth(2.);
  	gStyle->SetTextSize(0.7);
  	gStyle->SetLabelSize(0.05,"xy");
  	gStyle->SetTitleSize(0.05,"xy");
  	gStyle->SetTitleOffset(1.0,"x");
  	gStyle->SetTitleOffset(1.5,"y");
  	gStyle->SetPadTopMargin(0.1);
  	gStyle->SetPadRightMargin(0.1);
  	gStyle->SetPadBottomMargin(0.16);
  	gStyle->SetPadLeftMargin(0.2);

  	gStyle->SetFillColor(-1);
	gStyle->SetFillStyle(4000);

}

histoBook* histoBook::style( string histName ){
	styling = histName;
	return this;
}

histoBook* histoBook::set( string param, string p1, string p2, string p3, string p4 ){

	// force the param name to lowercase
	transform(param.begin(), param.end(), param.begin(), ::tolower);

    TH1* h = get( styling );
    if ( h ){

	    if ( "title" == param ){
	    	h->SetTitle( p1.c_str() );
	    } else if ( "x" == param ){
	    	h->GetXaxis()->SetTitle( p1.c_str() );
	    } else if ( "y" == param ){
	    	h->GetYaxis()->SetTitle( p1.c_str() );
	    } else if ( "legend" == param ){
	    	if ( p2 == "")
	    		p2="lpf";
	    	legend->AddEntry( h, p1.c_str(), p2.c_str() );
			legend->Draw();
	    } else if ( "draw" == param ){
	    	drawOption = p1;
	    }
	}

	return this;
}

histoBook* histoBook::set( string param, double p1, double p2, double p3, double p4  ){

	transform(param.begin(), param.end(), param.begin(), ::tolower);

    TH1* h = get( styling );
    if ( h ){

	    if ( "linecolor" == param ){

	    	h->SetLineColor( (int) p1 );
	    } else if ( "domain" == param ){
	    	double min = p1;
	    	double max = p2;
		    h->GetXaxis()->SetRangeUser( min, max );
	    } else if ( "dynamicdomain" == param ){
	    	double thresh = p1;
	    	int min = (int)p2;
	    	int max = (int)p3;
	    	int axis = (int)p4;		// 1 = x, 2 = y

	    	if ( 1 != axis && 2 != axis )
	    		axis = 1;

	    	if ( thresh >= 0) {
	    		if ( -1 >= min )
	    			min = h->FindFirstBinAbove( thresh, axis );
	    		if ( -1 >= max )
	    			max = h->FindLastBinAbove( thresh, axis );
	    	}

	    	if ( 1 == axis )
		  	  h->GetXaxis()->SetRange( min, max );
		  	else if ( 2 == axis )
		  		h->GetYaxis()->SetRange( min, max );

	    }  else if ( "range" == param ){

	    	double min = p1;
	    	double max = p2;

	    	h->GetYaxis()->SetRangeUser( min, max );
	    } else if ( "markercolor" == param ) {
	    	h->SetMarkerColor( (int)p1 );
	    } else if ( "markerstyle" == param ) {
	    	h->SetMarkerStyle( (int)p1 );
	    } else if ( "legend" == param ){
	    	// p1 - alignmentX
	    	// p2 - alignmentY
	    	// p3 - width
	    	// p4 - height

	    	// make sure option is valid
	    	if ( !(legendAlignment::center == p1 || legendAlignment::left == p1 || legendAlignment::right == p1) )
	    		p1 = legendAlignment::best;
	    	if ( !(legendAlignment::center == p2 || legendAlignment::top == p2 || legendAlignment::bottom == p2) )
	    		p2 = legendAlignment::best;
	    	placeLegend( p1, p2, p3, p4 );
	    } else if ( "numberofticks" == param ){
	    	// p1 - # of primary divisions
	    	// p2 - # of secondary divisions
	    	// p3 - axis : 0 or 1 = x, 2 = y

	    	if ( p2 == -1 )
	    		p2 = 0;

		    if ( 2 == (int)p3 )
		    	h->GetYaxis()->SetNdivisions( (int) p1, (int) p2, 0, true );
		    else
		    	h->GetXaxis()->SetNdivisions( (int) p1, (int) p2, 0, true );
	    }

    }

	return this;
}

histoBook* histoBook::draw(string name, Option_t* opt ){

	// no parameters
	if ( name == ""){
		TH1* h = get( styling );
		if ( h ){
			// use the draw option set in its styling
			h->Draw( drawOption.c_str() );
			drawOption = "";
		}
	} else {
		TH1* h = get( name );
		if ( h ){
			h->Draw( opt );
		}
	}

	return this;
}

histoBook* histoBook::placeLegend( int alignmentX, int alignmentY, double width, double height ){

	double mR = 1 - gPad->GetRightMargin();
	double mL = gPad->GetLeftMargin();
	double mT = 1- gPad->GetTopMargin();
	double mB = gPad->GetBottomMargin();

	double x1, x2, y1, y2;

	if ( width <= 0 || width > 1 )
		width = .2;
	if ( height <= 0 || height > 1 )
		height = .2;

	// alignment best needs a current histo
	if ( !(get( styling )) ){
		if ( legendAlignment::best == alignmentX )
			alignmentX = legendAlignment::right;
		if ( legendAlignment::best == alignmentY )
			alignmentY = legendAlignment::top;
	} else {

		//TODO

	}

	if ( 	legendAlignment::left ==  alignmentX ){
		x1 =  mL ;
		x2 =  mL + width;
	}
	if ( 	legendAlignment::right ==  alignmentX ){
		x1 =  mR - width;
		x2 =  mR ;
	}
	if ( 	legendAlignment::center ==  alignmentX ){
		x1 =  0.55 - width/2.0;
		x2 =  0.55 + width/2.0;
	}
	if ( 	legendAlignment::top ==  alignmentY ){
		y1 =  mT - height;
		y2 = mT ;
	}
	if ( 	legendAlignment::bottom ==  alignmentY ){
		y1 =  mB ;
		y2 =  mB + height;
	}
	if ( 	legendAlignment::center ==  alignmentY ){
		y1 =  0.55 - height/2.0;
		y2 =  0.55 + height/2.0;
	}
	legend->SetX1NDC( x1 );
	legend->SetX2NDC( x2 );
	legend->SetY1NDC( y1 );
	legend->SetY2NDC( y2 );

	return this;
}<commit_msg>test upstream<commit_after>

#include "histoBook.h"
#include "TKey.h"
#include "TObject.h"

// constructor sets the name of the file for saving
histoBook::histoBook( string name, string input, string inDir ){

	if (name.find(  ".root") != std::string::npos){
		filename = name;
	} else
		filename = name + ".root";

	currentDir = "/";

	file = new TFile( filename.c_str(), "recreate" );
	file->cd();

	// make the legend and draw it once to apply styles etc.
	// for some reason needed to make styling work on the first draw
	legend = new TLegend( 0.65, 0.65, 0.9, 0.9);
	legend->SetFillColor( kWhite );
	legend->Draw();
	legend->Clear();

	globalStyle();

	// if an input was given merge it into the live record
	if ( input.length() >= 5 ){
		TFile * fin = new TFile( input.c_str() );
		cd ( inDir );
		fin->cd( inDir.c_str() );
		loadRootDir( gDirectory, inDir );
	}

}
// destructor
histoBook::~histoBook(){

	delete legend;

	save();
	file->Close();
}
void histoBook::save() {

	file->Write();
}

void histoBook::loadRootDir( TDirectory* tDir, string path ){

	//cout << "histoBook.loadRootDir] Path : " << path << endl;

	TList* list;

	if ( tDir ){
		list = tDir->GetListOfKeys();
	} else {
		cout << "[histoBook.loadRootDir] Bad Directory Given " << endl;
		return;
	}

	TIter next(list);
	TKey* key;
	TObject* obj;

	while ( (key = (TKey*)next()) ) {

		obj = key->ReadObj() ;

		if ( 0 == strcmp(obj->IsA()->GetName(),"TDirectoryFile") ){
			TDirectoryFile* dir = (TDirectoryFile*)obj;

			string nPath = path + dir->GetName();
			if ( path == (string) "" )
				nPath = path + dir->GetName();
			else
				nPath = path + "/" + dir->GetName();

			cd( nPath );
			loadRootDir( dir, nPath );
		} else if ( obj ){
			if (    (strcmp(obj->IsA()->GetName(),"TProfile")!=0) && (!obj->InheritsFrom("TH2") && (!obj->InheritsFrom("TH1"))) ) {
				// not a 1d or 2d histogram
			} else {
				// add it to the book
				//cout << "Adding : " << obj->GetName() << endl;
				add( obj->GetName(), (TH1*)obj->Clone( obj->GetName() ) );
			}

		}
	}

}

void histoBook::add( string name, TH1* h ){

	string oName = name;
	if ( name.length() <= 1 || !h )
		return;

	name = currentDir + name;

	// dont allow duplicated name overites
	if ( book[ name ] ){
		cout << "[histoBook.add] Duplicate histogram name in this directory " << currentDir << " / " << oName << endl;
		return;
	}

	// save the histo to the map
	book[ name ] = h;

}
/*
*
* TODO:: add support for full subdirectory trees
*/
string histoBook::cd( string sdir  ){

	string old = currentDir;

	char* csdir = (char*)sdir.c_str();
	file->cd();

	if ( file->GetDirectory( csdir ) ){
		file->cd( csdir );
	} else {
		cout << "[histoBook.cd] creating directory " << sdir << endl;
		file->mkdir( csdir );
		file->cd( csdir );
	}

	currentDir = sdir;

	return old;
}

void histoBook::make( xmlConfig * config, string nodeName ){

	if ( config && config->nodeExists( nodeName ) ){

		string hName = config->tagName( nodeName );
		if ( "" == hName )
			hName = nodeName;

		string type = config->getString( nodeName + ":type", "1D" );

		if ( "1D" == type ){
			make1D( hName, config->getString( nodeName + ":title", hName ),
					config->getInt( nodeName + ":nBinsX", 1 ), config->getDouble( nodeName + ":x1", 0 ),
					config->getDouble( nodeName + ":x2", 1 ) );

		} else if ( "2D" == type ){
			make2D( hName, config->getString( nodeName + ":title", hName ),
					config->getInt( nodeName + ":nBinsX", 1 ), config->getDouble( nodeName + ":x1", 0 ),
					config->getDouble( nodeName + ":x2", 1 ),
					config->getInt( nodeName + ":nBinsY", 1 ), config->getDouble( nodeName + ":y1", 0 ),
					config->getDouble( nodeName + ":y2", 1 ) );
		} else if ( "1F" == type ){
			// test comment
		}
	}

}

void histoBook::make1F( string name, string title, uint nBins, double low, double hi  ){

	TH1F* h;
	h = new TH1F( name.c_str(), title.c_str(), nBins, low, hi );

	this->add( name, h );
}

void histoBook::make1D( string name, string title, uint nBins, double low, double hi  ){

	TH1D* h;
	h = new TH1D( name.c_str(), title.c_str(), nBins, low, hi );

	this->add( name, h );
}

void histoBook::make1D( string name, string title, uint nBins, const Double_t* bins  ){

	TH1D* h;
	h = new TH1D( name.c_str(), title.c_str(), nBins, bins );

	this->add( name, h );
}

void histoBook::make2D( string name, string title, uint nBinsX, double lowX, double hiX, uint nBinsY, double lowY, double hiY ){

	TH2D* h;

	h = new TH2D( name.c_str(), title.c_str(), nBinsX, lowX, hiX, nBinsY, lowY, hiY );

	this->add( name, h );
}
void histoBook::make2D( string name, string title, uint nBinsX, const Double_t* xBins, uint nBinsY, double lowY, double hiY ){

	TH2D* h;
	h = new TH2D( name.c_str(), title.c_str(), nBinsX, xBins, nBinsY, lowY, hiY );

	this->add( name, h );
}

TH1* histoBook::get( string name, string sdir  ){
	if ( sdir.compare("") == 0)
		sdir = currentDir;
	return book[ ( sdir  + name  ) ];
}
TH2* histoBook::get2D( string name, string sdir  ){
	if ( sdir.compare("") == 0)
		sdir = currentDir;
	return (TH2*)book[ ( sdir  + name  ) ];
}

void histoBook::fill( string name, double bin, double weight ){
	if ( get( name ) != 0)
		get( name )->Fill( bin, weight );
}

void histoBook::globalStyle(){

	gStyle->SetCanvasColor(kWhite);     // background is no longer mouse-dropping white
  	gStyle->SetPalette(1,0);            // blue to red false color palette. Use 9 for b/w
  	gStyle->SetCanvasBorderMode(0);     // turn off canvas borders
  	gStyle->SetPadBorderMode(0);
  	gStyle->SetPaintTextFormat("5.2f");  // What precision to put numbers if plotted with "TEXT"

  	// For publishing:
  	gStyle->SetLineWidth(2.);
  	gStyle->SetTextSize(0.7);
  	gStyle->SetLabelSize(0.05,"xy");
  	gStyle->SetTitleSize(0.05,"xy");
  	gStyle->SetTitleOffset(1.0,"x");
  	gStyle->SetTitleOffset(1.5,"y");
  	gStyle->SetPadTopMargin(0.1);
  	gStyle->SetPadRightMargin(0.1);
  	gStyle->SetPadBottomMargin(0.16);
  	gStyle->SetPadLeftMargin(0.2);

  	gStyle->SetFillColor(-1);
	gStyle->SetFillStyle(4000);

}

histoBook* histoBook::style( string histName ){
	styling = histName;
	return this;
}

histoBook* histoBook::set( string param, string p1, string p2, string p3, string p4 ){

	// force the param name to lowercase
	transform(param.begin(), param.end(), param.begin(), ::tolower);

    TH1* h = get( styling );
    if ( h ){

	    if ( "title" == param ){
	    	h->SetTitle( p1.c_str() );
	    } else if ( "x" == param ){
	    	h->GetXaxis()->SetTitle( p1.c_str() );
	    } else if ( "y" == param ){
	    	h->GetYaxis()->SetTitle( p1.c_str() );
	    } else if ( "legend" == param ){
	    	if ( p2 == "")
	    		p2="lpf";
	    	legend->AddEntry( h, p1.c_str(), p2.c_str() );
			legend->Draw();
	    } else if ( "draw" == param ){
	    	drawOption = p1;
	    }
	}

	return this;
}

histoBook* histoBook::set( string param, double p1, double p2, double p3, double p4  ){

	transform(param.begin(), param.end(), param.begin(), ::tolower);

    TH1* h = get( styling );
    if ( h ){

	    if ( "linecolor" == param ){

	    	h->SetLineColor( (int) p1 );
	    } else if ( "domain" == param ){
	    	double min = p1;
	    	double max = p2;
		    h->GetXaxis()->SetRangeUser( min, max );
	    } else if ( "dynamicdomain" == param ){
	    	double thresh = p1;
	    	int min = (int)p2;
	    	int max = (int)p3;
	    	int axis = (int)p4;		// 1 = x, 2 = y

	    	if ( 1 != axis && 2 != axis )
	    		axis = 1;

	    	if ( thresh >= 0) {
	    		if ( -1 >= min )
	    			min = h->FindFirstBinAbove( thresh, axis );
	    		if ( -1 >= max )
	    			max = h->FindLastBinAbove( thresh, axis );
	    	}

	    	if ( 1 == axis )
		  	  h->GetXaxis()->SetRange( min, max );
		  	else if ( 2 == axis )
		  		h->GetYaxis()->SetRange( min, max );

	    }  else if ( "range" == param ){

	    	double min = p1;
	    	double max = p2;

	    	h->GetYaxis()->SetRangeUser( min, max );
	    } else if ( "markercolor" == param ) {
	    	h->SetMarkerColor( (int)p1 );
	    } else if ( "markerstyle" == param ) {
	    	h->SetMarkerStyle( (int)p1 );
	    } else if ( "legend" == param ){
	    	// p1 - alignmentX
	    	// p2 - alignmentY
	    	// p3 - width
	    	// p4 - height

	    	// make sure option is valid
	    	if ( !(legendAlignment::center == p1 || legendAlignment::left == p1 || legendAlignment::right == p1) )
	    		p1 = legendAlignment::best;
	    	if ( !(legendAlignment::center == p2 || legendAlignment::top == p2 || legendAlignment::bottom == p2) )
	    		p2 = legendAlignment::best;
	    	placeLegend( p1, p2, p3, p4 );
	    } else if ( "numberofticks" == param ){
	    	// p1 - # of primary divisions
	    	// p2 - # of secondary divisions
	    	// p3 - axis : 0 or 1 = x, 2 = y

	    	if ( p2 == -1 )
	    		p2 = 0;

		    if ( 2 == (int)p3 )
		    	h->GetYaxis()->SetNdivisions( (int) p1, (int) p2, 0, true );
		    else
		    	h->GetXaxis()->SetNdivisions( (int) p1, (int) p2, 0, true );
	    }

    }

	return this;
}

histoBook* histoBook::draw(string name, Option_t* opt ){

	// no parameters
	if ( name == ""){
		TH1* h = get( styling );
		if ( h ){
			// use the draw option set in its styling
			h->Draw( drawOption.c_str() );
			drawOption = "";
		}
	} else {
		TH1* h = get( name );
		if ( h ){
			h->Draw( opt );
		}
	}

	return this;
}

histoBook* histoBook::placeLegend( int alignmentX, int alignmentY, double width, double height ){

	double mR = 1 - gPad->GetRightMargin();
	double mL = gPad->GetLeftMargin();
	double mT = 1- gPad->GetTopMargin();
	double mB = gPad->GetBottomMargin();

	double x1, x2, y1, y2;

	if ( width <= 0 || width > 1 )
		width = .2;
	if ( height <= 0 || height > 1 )
		height = .2;

	// alignment best needs a current histo
	if ( !(get( styling )) ){
		if ( legendAlignment::best == alignmentX )
			alignmentX = legendAlignment::right;
		if ( legendAlignment::best == alignmentY )
			alignmentY = legendAlignment::top;
	} else {

		//TODO

	}

	if ( 	legendAlignment::left ==  alignmentX ){
		x1 =  mL ;
		x2 =  mL + width;
	}
	if ( 	legendAlignment::right ==  alignmentX ){
		x1 =  mR - width;
		x2 =  mR ;
	}
	if ( 	legendAlignment::center ==  alignmentX ){
		x1 =  0.55 - width/2.0;
		x2 =  0.55 + width/2.0;
	}
	if ( 	legendAlignment::top ==  alignmentY ){
		y1 =  mT - height;
		y2 = mT ;
	}
	if ( 	legendAlignment::bottom ==  alignmentY ){
		y1 =  mB ;
		y2 =  mB + height;
	}
	if ( 	legendAlignment::center ==  alignmentY ){
		y1 =  0.55 - height/2.0;
		y2 =  0.55 + height/2.0;
	}
	legend->SetX1NDC( x1 );
	legend->SetX2NDC( x2 );
	legend->SetY1NDC( y1 );
	legend->SetY2NDC( y2 );

	return this;
}<|endoftext|>


<commit_before>#include "TargetCorpus.h"
#include <string>
#include <stdlib.h>
#include <cstring>

void TargetCorpus::Create( string fileName )
{
  ifstream textFile;
  char line[LINE_MAX_LENGTH];

  // count the number of words first;
  textFile.open(fileName.c_str());
  istream *fileP = &textFile;
  m_size = 0;
  m_sentenceCount = 0;
  while(!fileP->eof()) {
    SAFE_GETLINE((*fileP), line, LINE_MAX_LENGTH, '\n');
    if (fileP->eof()) break;
    vector< WORD_ID > words = m_vcb.Tokenize( line );
    m_size += words.size();
    m_sentenceCount++;
  }
  textFile.close();
  cerr << m_size << " words" << endl;

  // allocate memory
  m_array = (WORD_ID*) calloc( sizeof( WORD_ID ), m_size );
  m_sentenceEnd = (INDEX*) calloc( sizeof( INDEX ), m_sentenceCount );

  // fill the array
  int wordIndex = 0;
  int sentenceId = 0;
  textFile.open(fileName.c_str());
  fileP = &textFile;
  while(!fileP->eof()) {
    SAFE_GETLINE((*fileP), line, LINE_MAX_LENGTH, '\n');
    if (fileP->eof()) break;
    vector< WORD_ID > words = m_vcb.Tokenize( line );
    vector< WORD_ID >::const_iterator i;

    for( i=words.begin(); i!=words.end(); i++) {
      m_array[ wordIndex++ ] = *i;
    }
    m_sentenceEnd[ sentenceId++ ] = wordIndex-1;
  }
  textFile.close();
  cerr << "done reading " << wordIndex << " words, " << sentenceId << " sentences." << endl;
}

TargetCorpus::~TargetCorpus()
{
  free(m_array);
  free(m_sentenceEnd);
}

WORD TargetCorpus::GetWordFromId( const WORD_ID id ) const
{
  return m_vcb.GetWord( id );
}

WORD TargetCorpus::GetWord( INDEX sentence, char word )
{
  return m_vcb.GetWord( GetWordId( sentence, word ) );
}

WORD_ID TargetCorpus::GetWordId( INDEX sentence, char word )
{
  if (sentence == 0) {
    return m_array[ word ];
  }
  return m_array[ m_sentenceEnd[ sentence-1 ] + 1 + word ] ;
}

char TargetCorpus::GetSentenceLength( INDEX sentence )
{
  if (sentence == 0) {
    return (char) m_sentenceEnd[ 0 ]+1;
  }
  return (char) ( m_sentenceEnd[ sentence ] - m_sentenceEnd[ sentence-1 ] );
}

void TargetCorpus::Save( string fileName )
{
  FILE *pFile = fopen ( (fileName + ".tgt").c_str() , "w" );

  fwrite( &m_size, sizeof(INDEX), 1, pFile );
  fwrite( m_array, sizeof(WORD_ID), m_size, pFile ); // corpus

  fwrite( &m_sentenceCount, sizeof(INDEX), 1, pFile );
  fwrite( m_sentenceEnd, sizeof(INDEX), m_sentenceCount, pFile); // sentence index
  fclose( pFile );

  m_vcb.Save( fileName + ".tgt-vcb" );
}

void TargetCorpus::Load( string fileName )
{
  FILE *pFile = fopen ( (fileName + ".tgt").c_str() , "r" );
  cerr << "loading from " << fileName << ".tgt" << endl;

  fread( &m_size, sizeof(INDEX), 1, pFile );
  cerr << "words in corpus: " << m_size << endl;
  m_array = (WORD_ID*) calloc( sizeof(WORD_ID), m_size );
  fread( m_array, sizeof(WORD_ID), m_size, pFile ); // corpus

  fread( &m_sentenceCount, sizeof(INDEX), 1, pFile );
  cerr << "sentences in corpus: " << m_sentenceCount << endl;
  m_sentenceEnd = (INDEX*) calloc( sizeof(INDEX), m_sentenceCount );
  fread( m_sentenceEnd, sizeof(INDEX), m_sentenceCount, pFile); // sentence index
  fclose( pFile );
  m_vcb.Load( fileName + ".tgt-vcb" );
}<commit_msg>minor warning<commit_after>#include "TargetCorpus.h"
#include <string>
#include <stdlib.h>
#include <cstring>

void TargetCorpus::Create( string fileName )
{
  ifstream textFile;
  char line[LINE_MAX_LENGTH];

  // count the number of words first;
  textFile.open(fileName.c_str());
  istream *fileP = &textFile;
  m_size = 0;
  m_sentenceCount = 0;
  while(!fileP->eof()) {
    SAFE_GETLINE((*fileP), line, LINE_MAX_LENGTH, '\n');
    if (fileP->eof()) break;
    vector< WORD_ID > words = m_vcb.Tokenize( line );
    m_size += words.size();
    m_sentenceCount++;
  }
  textFile.close();
  cerr << m_size << " words" << endl;

  // allocate memory
  m_array = (WORD_ID*) calloc( sizeof( WORD_ID ), m_size );
  m_sentenceEnd = (INDEX*) calloc( sizeof( INDEX ), m_sentenceCount );

  // fill the array
  int wordIndex = 0;
  int sentenceId = 0;
  textFile.open(fileName.c_str());
  fileP = &textFile;
  while(!fileP->eof()) {
    SAFE_GETLINE((*fileP), line, LINE_MAX_LENGTH, '\n');
    if (fileP->eof()) break;
    vector< WORD_ID > words = m_vcb.Tokenize( line );
    vector< WORD_ID >::const_iterator i;

    for( i=words.begin(); i!=words.end(); i++) {
      m_array[ wordIndex++ ] = *i;
    }
    m_sentenceEnd[ sentenceId++ ] = wordIndex-1;
  }
  textFile.close();
  cerr << "done reading " << wordIndex << " words, " << sentenceId << " sentences." << endl;
}

TargetCorpus::~TargetCorpus()
{
  free(m_array);
  free(m_sentenceEnd);
}

WORD TargetCorpus::GetWordFromId( const WORD_ID id ) const
{
  return m_vcb.GetWord( id );
}

WORD TargetCorpus::GetWord( INDEX sentence, char word )
{
  return m_vcb.GetWord( GetWordId( sentence, word ) );
}

WORD_ID TargetCorpus::GetWordId( INDEX sentence, char word )
{
  if (sentence == 0) {
    return m_array[ word ];
  }
  return m_array[ m_sentenceEnd[ sentence-1 ] + 1 + word ] ;
}

char TargetCorpus::GetSentenceLength( INDEX sentence )
{
  if (sentence == 0) {
    return (char) m_sentenceEnd[ 0 ]+1;
  }
  return (char) ( m_sentenceEnd[ sentence ] - m_sentenceEnd[ sentence-1 ] );
}

void TargetCorpus::Save( string fileName )
{
  FILE *pFile = fopen ( (fileName + ".tgt").c_str() , "w" );

  fwrite( &m_size, sizeof(INDEX), 1, pFile );
  fwrite( m_array, sizeof(WORD_ID), m_size, pFile ); // corpus

  fwrite( &m_sentenceCount, sizeof(INDEX), 1, pFile );
  fwrite( m_sentenceEnd, sizeof(INDEX), m_sentenceCount, pFile); // sentence index
  fclose( pFile );

  m_vcb.Save( fileName + ".tgt-vcb" );
}

void TargetCorpus::Load( string fileName )
{
  FILE *pFile = fopen ( (fileName + ".tgt").c_str() , "r" );
  cerr << "loading from " << fileName << ".tgt" << endl;

  fread( &m_size, sizeof(INDEX), 1, pFile );
  cerr << "words in corpus: " << m_size << endl;
  m_array = (WORD_ID*) calloc( sizeof(WORD_ID), m_size );
  fread( m_array, sizeof(WORD_ID), m_size, pFile ); // corpus

  fread( &m_sentenceCount, sizeof(INDEX), 1, pFile );
  cerr << "sentences in corpus: " << m_sentenceCount << endl;
  m_sentenceEnd = (INDEX*) calloc( sizeof(INDEX), m_sentenceCount );
  fread( m_sentenceEnd, sizeof(INDEX), m_sentenceCount, pFile); // sentence index
  fclose( pFile );
  m_vcb.Load( fileName + ".tgt-vcb" );
}

<|endoftext|>


<commit_before>/******************************************************************************
 *
 *  Author(s): Christopher Dyken <christopher.dyken@sintef.no>
 *
 *
 *  Copyright (C) 2012 by SINTEF.  All rights reserved.
 *
 ******************************************************************************/
#include <atomic>
#include "utils/Logger.hpp"
#include "ASyncReader.hpp"
#include "cornerpoint/Tessellator.hpp"
#include "eclipse/EclipseReader.hpp"
#include "utils/PerfTimer.hpp"

static const std::string package = "ASyncReader";

ASyncReader::ASyncReader( boost::shared_ptr<tinia::model::ExposedModel> model )
    : m_ticket_counter(1),
      m_model( model ),
      m_worker( worker, this )
{
    Logger log = getLogger( package + ".ASyncReader" );
    m_model->addElement<bool>( "asyncreader_working", false, "Loading and preprocessing" );
    m_model->addElement<std::string>( "asyncreader_what", "Idle" );
    m_model->addConstrainedElement<int>( "asyncreader_progress", 0, 0, 100, "Progress" );
    m_model->addElement<int>( "asyncreader_ticket", 0 );
}

bool
ASyncReader::issueReadProject( const std::string& file,
                               const int refine_i,
                               const int refine_j,
                               const int refine_k,
                               const bool triangulate)
{
    Logger log = getLogger( package + ".read" );
    Command cmd;
    cmd.m_type = Command::READ_PROJECT;
    cmd.m_project_file = file;
    cmd.m_refine_i = refine_i;
    cmd.m_refine_j = refine_j;
    cmd.m_refine_k = refine_k;
    cmd.m_triangulate = triangulate;
    postCommand( cmd );
    return true;
}

bool
ASyncReader::issueReadSolution( const dataset::Project<float>::Solution& solution_location )
{
    Command cmd;
    cmd.m_type = Command::READ_SOLUTION;
    cmd.m_solution_location = solution_location;
    postCommand( cmd );
    return true;
}

bool
ASyncReader::getProject( boost::shared_ptr< dataset::Project<float> >& project,
                         boost::shared_ptr< render::GridTessBridge>&  tess_bridge )
{
    std::unique_lock<std::mutex> lock( m_rsp_queue_lock );
    for(auto it = m_rsp_queue.begin(); it!=m_rsp_queue.end(); ++it ) {
        if( it->m_type == Response::PROJECT ) {
            project = it->m_project;
            tess_bridge = it->m_project_grid;
            m_rsp_queue.erase( it );
            return true;
        }
    }
    return false;
}

bool
ASyncReader::getSolution( boost::shared_ptr< render::GridFieldBridge >& field_bridge )
{
    // We kill of all but the latest request of correct type
    bool found_any = false;
    std::list<Response> keep;
    std::unique_lock<std::mutex> lock( m_rsp_queue_lock );
    for(auto it = m_rsp_queue.begin(); it!=m_rsp_queue.end(); ++it ) {
        if( it->m_type == Response::SOLUTION ) {
            field_bridge = it->m_solution;
            found_any = true;
        }
        else {
            keep.push_back( *it );
        }
    }
    if( found_any ) {
        m_rsp_queue.swap( keep );
        return true;
    }
    else {
        return false;
    }
}

bool
ASyncReader::getCommand( Command& cmd )
{
    std::unique_lock< std::mutex > lock( m_cmd_queue_lock );
    while( m_cmd_queue.empty() ) {
        m_cmd_queue_wait.wait( lock );
    }
    cmd = m_cmd_queue.front();
    m_cmd_queue.pop_front();
    return true;
}

void
ASyncReader::handleReadProject( const Command& cmd )
{
    Logger log = getLogger( package + ".handleReadProject" );
    m_model->updateElement<bool>( "asyncreader_working", true );
    try {
        m_model->updateElement<std::string>( "asyncreader_what", "Indexing files..." );
        m_model->updateElement<int>( "asyncreader_progress", 0 );

        boost::shared_ptr< dataset::Project<float> > project( new dataset::Project<float>( cmd.m_project_file,
                                                                       cmd.m_refine_i,
                                                                       cmd.m_refine_j,
                                                                       cmd.m_refine_k ) );
        if( project->geometryType() == dataset::Project<float>::GEOMETRY_CORNERPOINT_GRID ) {

            boost::shared_ptr< render::GridTessBridge > tess_bridge( new render::GridTessBridge( cmd.m_triangulate ) );

            m_field_remap = project->fieldRemap();

            cornerpoint::Tessellator< render::GridTessBridge > tess( *tess_bridge );
            tess.tessellate( m_model,
                             "asyncreader_what",
                             "asyncreader_progress",
                             project->nx(),
                             project->ny(),
                             project->nz(),
                             project->nr(),
                             project->cornerPointCoord(),
                             project->cornerPointZCorn(),
                             project->cornerPointActNum() );

            // organize data
            m_model->updateElement<std::string>( "asyncreader_what", "Organizing data..." );
            m_model->updateElement<int>( "asyncreader_progress", 0 );
            tess_bridge->process();

            Response rsp;
            rsp.m_type = Response::PROJECT;
            rsp.m_project = project;
            rsp.m_project_grid = tess_bridge;
            postResponse( cmd, rsp );
        }
        else {
            m_model->updateElement<std::string>( "asyncreader_what", "Unsupported geometry type" );
            sleep(2);
        }
    }
    catch( std::runtime_error& e ) {
        m_model->updateElement<std::string>( "asyncreader_what", e.what() );
        sleep(2);
    }
    m_model->updateElement<bool>( "asyncreader_working", false );
}

void
ASyncReader::handleReadSolution( const Command& cmd )
{
    Logger log = getLogger( package + ".handleReadSolution" );
    m_model->updateElement<std::string>( "asyncreader_what", "Reading solution..." );

    Response rsp;
    rsp.m_type = Response::SOLUTION;
    if( cmd.m_solution_location.m_reader == dataset::Project<float>::READER_UNFORMATTED_ECLIPSE ) {

        if( !m_field_remap.empty() ) {
            rsp.m_solution.reset( new render::GridFieldBridge( m_field_remap.size() ) );

            std::vector<float> tmp( cmd.m_solution_location.m_location.m_unformatted_eclipse.m_size );
            eclipse::Reader reader( cmd.m_solution_location.m_path );
            reader.blockContent( tmp.data(),
                                 rsp.m_solution->minimum(),
                                 rsp.m_solution->maximum(),
                                 cmd.m_solution_location.m_location.m_unformatted_eclipse );
            for(size_t i=0; i<m_field_remap.size(); i++ ) {
                rsp.m_solution->values()[i] = tmp[ m_field_remap[i] ];
            }

        }
        else {
            rsp.m_solution.reset( new render::GridFieldBridge( cmd.m_solution_location.m_location.m_unformatted_eclipse.m_size ) );

            eclipse::Reader reader( cmd.m_solution_location.m_path );
            reader.blockContent( rsp.m_solution->values(),
                                 rsp.m_solution->minimum(),
                                 rsp.m_solution->maximum(),
                                 cmd.m_solution_location.m_location.m_unformatted_eclipse );
        }

    }
    else {
        LOGGER_ERROR( log, "Unsupported solution format" );
    }
    postResponse( cmd, rsp );
}

void
ASyncReader::worker( ASyncReader* that )
{
    Logger log = getLogger( package + ".worker" );

    bool keep_going = true;
    while( keep_going ) {
        Command cmd;
        if( that->getCommand( cmd ) ) {
            switch( cmd.m_type ) {
            case Command::READ_PROJECT:
                that->handleReadProject( cmd );
                break;
            case Command::READ_SOLUTION:
                that->handleReadSolution( cmd );
                break;
            case Command::DIE:
                keep_going = false;
                break;
            }
        }
    }
    LOGGER_DEBUG( log, "weee!" );
}

void
ASyncReader::postCommand( Command& cmd , bool wipe)
{
    Logger log = getLogger( package + ".postCommand" );
    std::unique_lock<std::mutex> lock( m_cmd_queue_lock );
    cmd.m_ticket = m_ticket_counter++;
    if( wipe ) {
        for(auto it=m_cmd_queue.begin(); it!=m_cmd_queue.end(); ++it ) {
            if( it->m_type == cmd.m_type ) {
                LOGGER_DEBUG( log, "Wiped old command" );
                *it = cmd;
                return;
            }
        }
    }
    m_cmd_queue.push_back( cmd );
    m_cmd_queue_wait.notify_one();
}

void
ASyncReader::postResponse( const Command& cmd, const Response& rsp )
{
    std::unique_lock<std::mutex> lock( m_rsp_queue_lock );
    m_rsp_queue.push_back( rsp );
    lock.unlock();

    // Signal that a response is ready
    m_model->updateElement<int>( "asyncreader_ticket", cmd.m_ticket );
}
<commit_msg>Removed unused (and C++11-dependent) include<commit_after>/******************************************************************************
 *
 *  Author(s): Christopher Dyken <christopher.dyken@sintef.no>
 *
 *
 *  Copyright (C) 2012 by SINTEF.  All rights reserved.
 *
 ******************************************************************************/
#include "utils/Logger.hpp"
#include "ASyncReader.hpp"
#include "cornerpoint/Tessellator.hpp"
#include "eclipse/EclipseReader.hpp"
#include "utils/PerfTimer.hpp"

static const std::string package = "ASyncReader";

ASyncReader::ASyncReader( boost::shared_ptr<tinia::model::ExposedModel> model )
    : m_ticket_counter(1),
      m_model( model ),
      m_worker( worker, this )
{
    Logger log = getLogger( package + ".ASyncReader" );
    m_model->addElement<bool>( "asyncreader_working", false, "Loading and preprocessing" );
    m_model->addElement<std::string>( "asyncreader_what", "Idle" );
    m_model->addConstrainedElement<int>( "asyncreader_progress", 0, 0, 100, "Progress" );
    m_model->addElement<int>( "asyncreader_ticket", 0 );
}

bool
ASyncReader::issueReadProject( const std::string& file,
                               const int refine_i,
                               const int refine_j,
                               const int refine_k,
                               const bool triangulate)
{
    Logger log = getLogger( package + ".read" );
    Command cmd;
    cmd.m_type = Command::READ_PROJECT;
    cmd.m_project_file = file;
    cmd.m_refine_i = refine_i;
    cmd.m_refine_j = refine_j;
    cmd.m_refine_k = refine_k;
    cmd.m_triangulate = triangulate;
    postCommand( cmd );
    return true;
}

bool
ASyncReader::issueReadSolution( const dataset::Project<float>::Solution& solution_location )
{
    Command cmd;
    cmd.m_type = Command::READ_SOLUTION;
    cmd.m_solution_location = solution_location;
    postCommand( cmd );
    return true;
}

bool
ASyncReader::getProject( boost::shared_ptr< dataset::Project<float> >& project,
                         boost::shared_ptr< render::GridTessBridge>&  tess_bridge )
{
    std::unique_lock<std::mutex> lock( m_rsp_queue_lock );
    for(auto it = m_rsp_queue.begin(); it!=m_rsp_queue.end(); ++it ) {
        if( it->m_type == Response::PROJECT ) {
            project = it->m_project;
            tess_bridge = it->m_project_grid;
            m_rsp_queue.erase( it );
            return true;
        }
    }
    return false;
}

bool
ASyncReader::getSolution( boost::shared_ptr< render::GridFieldBridge >& field_bridge )
{
    // We kill of all but the latest request of correct type
    bool found_any = false;
    std::list<Response> keep;
    std::unique_lock<std::mutex> lock( m_rsp_queue_lock );
    for(auto it = m_rsp_queue.begin(); it!=m_rsp_queue.end(); ++it ) {
        if( it->m_type == Response::SOLUTION ) {
            field_bridge = it->m_solution;
            found_any = true;
        }
        else {
            keep.push_back( *it );
        }
    }
    if( found_any ) {
        m_rsp_queue.swap( keep );
        return true;
    }
    else {
        return false;
    }
}

bool
ASyncReader::getCommand( Command& cmd )
{
    std::unique_lock< std::mutex > lock( m_cmd_queue_lock );
    while( m_cmd_queue.empty() ) {
        m_cmd_queue_wait.wait( lock );
    }
    cmd = m_cmd_queue.front();
    m_cmd_queue.pop_front();
    return true;
}

void
ASyncReader::handleReadProject( const Command& cmd )
{
    Logger log = getLogger( package + ".handleReadProject" );
    m_model->updateElement<bool>( "asyncreader_working", true );
    try {
        m_model->updateElement<std::string>( "asyncreader_what", "Indexing files..." );
        m_model->updateElement<int>( "asyncreader_progress", 0 );

        boost::shared_ptr< dataset::Project<float> > project( new dataset::Project<float>( cmd.m_project_file,
                                                                       cmd.m_refine_i,
                                                                       cmd.m_refine_j,
                                                                       cmd.m_refine_k ) );
        if( project->geometryType() == dataset::Project<float>::GEOMETRY_CORNERPOINT_GRID ) {

            boost::shared_ptr< render::GridTessBridge > tess_bridge( new render::GridTessBridge( cmd.m_triangulate ) );

            m_field_remap = project->fieldRemap();

            cornerpoint::Tessellator< render::GridTessBridge > tess( *tess_bridge );
            tess.tessellate( m_model,
                             "asyncreader_what",
                             "asyncreader_progress",
                             project->nx(),
                             project->ny(),
                             project->nz(),
                             project->nr(),
                             project->cornerPointCoord(),
                             project->cornerPointZCorn(),
                             project->cornerPointActNum() );

            // organize data
            m_model->updateElement<std::string>( "asyncreader_what", "Organizing data..." );
            m_model->updateElement<int>( "asyncreader_progress", 0 );
            tess_bridge->process();

            Response rsp;
            rsp.m_type = Response::PROJECT;
            rsp.m_project = project;
            rsp.m_project_grid = tess_bridge;
            postResponse( cmd, rsp );
        }
        else {
            m_model->updateElement<std::string>( "asyncreader_what", "Unsupported geometry type" );
            sleep(2);
        }
    }
    catch( std::runtime_error& e ) {
        m_model->updateElement<std::string>( "asyncreader_what", e.what() );
        sleep(2);
    }
    m_model->updateElement<bool>( "asyncreader_working", false );
}

void
ASyncReader::handleReadSolution( const Command& cmd )
{
    Logger log = getLogger( package + ".handleReadSolution" );
    m_model->updateElement<std::string>( "asyncreader_what", "Reading solution..." );

    Response rsp;
    rsp.m_type = Response::SOLUTION;
    if( cmd.m_solution_location.m_reader == dataset::Project<float>::READER_UNFORMATTED_ECLIPSE ) {

        if( !m_field_remap.empty() ) {
            rsp.m_solution.reset( new render::GridFieldBridge( m_field_remap.size() ) );

            std::vector<float> tmp( cmd.m_solution_location.m_location.m_unformatted_eclipse.m_size );
            eclipse::Reader reader( cmd.m_solution_location.m_path );
            reader.blockContent( tmp.data(),
                                 rsp.m_solution->minimum(),
                                 rsp.m_solution->maximum(),
                                 cmd.m_solution_location.m_location.m_unformatted_eclipse );
            for(size_t i=0; i<m_field_remap.size(); i++ ) {
                rsp.m_solution->values()[i] = tmp[ m_field_remap[i] ];
            }

        }
        else {
            rsp.m_solution.reset( new render::GridFieldBridge( cmd.m_solution_location.m_location.m_unformatted_eclipse.m_size ) );

            eclipse::Reader reader( cmd.m_solution_location.m_path );
            reader.blockContent( rsp.m_solution->values(),
                                 rsp.m_solution->minimum(),
                                 rsp.m_solution->maximum(),
                                 cmd.m_solution_location.m_location.m_unformatted_eclipse );
        }

    }
    else {
        LOGGER_ERROR( log, "Unsupported solution format" );
    }
    postResponse( cmd, rsp );
}

void
ASyncReader::worker( ASyncReader* that )
{
    Logger log = getLogger( package + ".worker" );

    bool keep_going = true;
    while( keep_going ) {
        Command cmd;
        if( that->getCommand( cmd ) ) {
            switch( cmd.m_type ) {
            case Command::READ_PROJECT:
                that->handleReadProject( cmd );
                break;
            case Command::READ_SOLUTION:
                that->handleReadSolution( cmd );
                break;
            case Command::DIE:
                keep_going = false;
                break;
            }
        }
    }
    LOGGER_DEBUG( log, "weee!" );
}

void
ASyncReader::postCommand( Command& cmd , bool wipe)
{
    Logger log = getLogger( package + ".postCommand" );
    std::unique_lock<std::mutex> lock( m_cmd_queue_lock );
    cmd.m_ticket = m_ticket_counter++;
    if( wipe ) {
        for(auto it=m_cmd_queue.begin(); it!=m_cmd_queue.end(); ++it ) {
            if( it->m_type == cmd.m_type ) {
                LOGGER_DEBUG( log, "Wiped old command" );
                *it = cmd;
                return;
            }
        }
    }
    m_cmd_queue.push_back( cmd );
    m_cmd_queue_wait.notify_one();
}

void
ASyncReader::postResponse( const Command& cmd, const Response& rsp )
{
    std::unique_lock<std::mutex> lock( m_rsp_queue_lock );
    m_rsp_queue.push_back( rsp );
    lock.unlock();

    // Signal that a response is ready
    m_model->updateElement<int>( "asyncreader_ticket", cmd.m_ticket );
}
<|endoftext|>


<commit_before>#ifndef _SSL_CONNECTION_H
#define _SSL_CONNECTION_H

#include <cstdio>
#include <cstring>
#include <cstdlib>

#include <string>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include "./plain_connection.hpp"

namespace SSLWrapper {

	class SSLConnection : public PlainConnection {

		class _ssl_init_object {
		  public:
			_ssl_init_object() {
				SSL_load_error_strings();
				SSL_library_init();
			}
			~_ssl_init_object() {
				ERR_remove_thread_state(nullptr);
				ERR_free_strings();
				EVP_cleanup();
				CRYPTO_cleanup_all_ex_data();
				sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
			}
		};

		SSL_CTX *ssl_context;
		SSL     *ssl_handle;

	public:

		SSLConnection(const std::string& host , const int& port);
		~SSLConnection();

		bool do_connect(void);
		void disconnect(void);

		std::string receive(void);
		int send(const std::string& msg);

		bool is_connected(void) {
			return PlainConnection::is_connected();
		}

		bool is_secure(void) {
			return true;
		}

		bool operator==(SSLConnection& other) const {
			return false;
		}

	};

};

#endif
<commit_msg>document connections<commit_after>#ifndef _SSL_CONNECTION_H
#define _SSL_CONNECTION_H

#include <cstdio>
#include <cstring>
#include <cstdlib>

#include <string>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include "./plain_connection.hpp"

/*
	If you're reading this, get ready for headaches. This is OpenSSL stuff.
*/

namespace SSLWrapper {

	class SSLConnection : public PlainConnection {

		class _ssl_init_object {
		  public:
			_ssl_init_object() {
				SSL_load_error_strings();
				SSL_library_init();
			}
			~_ssl_init_object() {
				ERR_remove_thread_state(nullptr);
				ERR_free_strings();
				EVP_cleanup();
				CRYPTO_cleanup_all_ex_data();
				sk_SSL_COMP_free(SSL_COMP_get_compression_methods());
			}
		};

		SSL_CTX *ssl_context;
		SSL     *ssl_handle;

	public:

		SSLConnection(const std::string& host , const int& port);
		~SSLConnection();

		bool do_connect(void);
		void disconnect(void);

		std::string receive(void);
		int send(const std::string& msg);

		bool is_connected(void) {
			return PlainConnection::is_connected();
		}

		bool is_secure(void) {
			return true;
		}

		/* since copy-constructors are deleted, symmetry is the only measure of equality. */
		bool operator==(SSLConnection& other) const {
			return this == &other;
		}

	};

};

#endif
<|endoftext|>


<commit_before>//
//  DiskCopy42.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 02/06/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "DiskCopy42.hpp"

#include "../../Track/PCMTrack.hpp"
#include "../../Encodings/AppleGCR/Encoder.hpp"

/*
	File format specifications as referenced below are largely
	sourced from the documentation at
	https://wiki.68kmla.org/DiskCopy_4.2_format_specification
*/

using namespace Storage::Disk;

DiskCopy42::DiskCopy42(const std::string &file_name) :
	file_(file_name) {

	// File format starts with 64 bytes dedicated to the disk name;
	// this is a Pascal-style string though there is apparently a
	// bug in one version of Disk Copy that can cause the length to
	// be one too high.
	//
	// Validate the length, then skip the rest of the string.
	const auto name_length = file_.get8();
	if(name_length > 64)
		throw Error::InvalidFormat;

	// Get the length of the data and tag blocks.
	file_.seek(64, SEEK_SET);
	const auto data_block_length = file_.get32be();
	const auto tag_block_length = file_.get32be();
	const auto data_checksum = file_.get32be();
	const auto tag_checksum = file_.get32be();

	// Don't continue with no data.
	if(!data_block_length)
		throw Error::InvalidFormat;

	// Check that this is a comprehensible disk encoding.
	const auto encoding = file_.get8();
	switch(encoding) {
		default: throw Error::InvalidFormat;

		case 0:	encoding_ = Encoding::GCR400;	break;
		case 1:	encoding_ = Encoding::GCR800;	break;
		case 2:	encoding_ = Encoding::MFM720;	break;
		case 3:	encoding_ = Encoding::MFM1440;	break;
	}
	format_ = file_.get8();

	// Check the magic number.
	const auto magic_number = file_.get16be();
	if(magic_number != 0x0100)
		throw Error::InvalidFormat;

	// Read the data and tags, and verify that enough data
	// was present.
	data_ = file_.read(data_block_length);
	tags_ = file_.read(tag_block_length);

	if(data_.size() != data_block_length || tags_.size() != tag_block_length)
		throw Error::InvalidFormat;

	// Verify the two checksums.
	const auto computed_data_checksum = checksum(data_);
	const auto computed_tag_checksum = checksum(tags_, 12);

	if(computed_tag_checksum != tag_checksum || computed_data_checksum != data_checksum)
		throw Error::InvalidFormat;
}

uint32_t DiskCopy42::checksum(const std::vector<uint8_t> &data, size_t bytes_to_skip) {
	uint32_t result = 0;

	// Checksum algorith is: take each two bytes as a big-endian word; add that to a
	// 32-bit accumulator and then rotate the accumulator right one position.
	for(size_t c = bytes_to_skip; c < data.size(); c += 2) {
		const uint16_t next_word = uint16_t((data[c] << 8) | data[c+1]);
		result += next_word;
		result = (result >> 1) | (result << 31);
	}

	return result;
}

HeadPosition DiskCopy42::get_maximum_head_position() {
	return HeadPosition(80);
}

int DiskCopy42::get_head_count() {
	// Bit 5 in the format field indicates whether this disk is double
	// sided, regardless of whether it is GCR or MFM.
	return 1 + ((format_ & 0x20) >> 5);
}

bool DiskCopy42::get_is_read_only() {
	return true;
}

std::shared_ptr<::Storage::Disk::Track> DiskCopy42::get_track_at_position(::Storage::Disk::Track::Address address) {
	/*
		The format_ byte has the following meanings:

		GCR:
			This byte appears on disk as the GCR format nibble in every sector tag.
			The low five bits are an interleave factor, either:

				'2' for 0 8 1 9 2 10 3 11 4 12 5 13 6 14 7 15; or
				'4' for 0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15.

			Bit 5 indicates double sided or not.

		MFM:
			The low five bits provide sector size as a multiple of 256 bytes.
			Bit 5 indicates double sided or not.
	*/

	if(encoding_ == Encoding::GCR400 || encoding_ == Encoding::GCR800) {
		// Perform a GCR encoding.
		const auto included_sectors = Storage::Encodings::AppleGCR::Macintosh::sectors_in_track(address.position.as_int());
		const size_t start_sector = size_t(included_sectors.start * get_head_count() + included_sectors.length * address.head);

		if(start_sector*512 >= data_.size()) return nullptr;

		uint8_t *sector = &data_[512 * start_sector];
		uint8_t *tags = tags_.size() ? nullptr : &tags_[12 * start_sector];

		Storage::Disk::PCMSegment segment;
		segment += Encodings::AppleGCR::six_and_two_sync(24);

		for(int c = 0; c < included_sectors.length; ++c) {
//			const int interleave_scale = ((format_ & 0x1f) == 4) ? 8 : 4;
			uint8_t sector_id = uint8_t(c);//uint8_t((c == included_sectors.length - 1) ? c : (c * interleave_scale)%included_sectors.length);

			uint8_t sector_plus_tags[524];

			// Copy in the tags, if provided; otherwise generate them.
			if(tags) {
				memcpy(sector_plus_tags, tags, 12);
				tags += 12;
			} else {
				// TODO: fill in tags properly.
				memset(sector_plus_tags, 0, 12);
			}

			// Copy in the sector body.
			memcpy(&sector_plus_tags[12], sector, 512);
			sector += 512;

			// NB: sync lengths below are identical to those for
			// the Apple II, as I have no idea whatsoever what they
			// should be.

			segment += Encodings::AppleGCR::Macintosh::header(
				format_,
				uint8_t(address.position.as_int()),
				sector_id,
				!!address.head
			);
			segment += Encodings::AppleGCR::six_and_two_sync(7);
			segment += Encodings::AppleGCR::Macintosh::data(sector_id, sector_plus_tags);
			segment += Encodings::AppleGCR::six_and_two_sync(20);
		}

		// TODO: is there inter-track skew?

		return std::make_shared<PCMTrack>(segment);
	}

	return nullptr;
}
<commit_msg>Adds support for raw sector dumps.<commit_after>//
//  DiskCopy42.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 02/06/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#include "DiskCopy42.hpp"

#include "../../Track/PCMTrack.hpp"
#include "../../Encodings/AppleGCR/Encoder.hpp"

/*
	File format specifications as referenced below are largely
	sourced from the documentation at
	https://wiki.68kmla.org/DiskCopy_4.2_format_specification
*/

using namespace Storage::Disk;

DiskCopy42::DiskCopy42(const std::string &file_name) :
	file_(file_name) {

	// Test 1: is this a raw secctor dump? If so it'll start with
	// the magic word 0x4C4B6000 (big endian) and be exactly
	// 819,200 bytes long if double sided, or 409,600 bytes if
	// single sided.
	//
	// Luckily, 0x4c is an invalid string length for the proper
	// DiskCopy 4.2 format, so there's no ambiguity here.

	// File format starts with 64 bytes dedicated to the disk name;
	// this is a Pascal-style string though there is apparently a
	// bug in one version of Disk Copy that can cause the length to
	// be one too high.
	//
	// Validate the length, then skip the rest of the string.
	const auto name_length = file_.get8();
	if(name_length == 0x4c) {
		if(file_.stats().st_size != 819200 && file_.stats().st_size != 409600)
			throw Error::InvalidFormat;

		uint32_t magic_word = file_.get24be();
		if(magic_word != 0x4b6000)
			throw Error::InvalidFormat;

		file_.seek(0, SEEK_SET);
		if(file_.stats().st_size == 819200) {
			encoding_ = Encoding::GCR800;
			format_ = 0x22;
			data_ = file_.read(819200);
		} else {
			encoding_ = Encoding::GCR400;
			format_ = 0x2;
			data_ = file_.read(409600);
		}
	} else {
		if(name_length > 64)
			throw Error::InvalidFormat;

		// Get the length of the data and tag blocks.
		file_.seek(64, SEEK_SET);
		const auto data_block_length = file_.get32be();
		const auto tag_block_length = file_.get32be();
		const auto data_checksum = file_.get32be();
		const auto tag_checksum = file_.get32be();

		// Don't continue with no data.
		if(!data_block_length)
			throw Error::InvalidFormat;

		// Check that this is a comprehensible disk encoding.
		const auto encoding = file_.get8();
		switch(encoding) {
			default: throw Error::InvalidFormat;

			case 0:	encoding_ = Encoding::GCR400;	break;
			case 1:	encoding_ = Encoding::GCR800;	break;
			case 2:	encoding_ = Encoding::MFM720;	break;
			case 3:	encoding_ = Encoding::MFM1440;	break;
		}
		format_ = file_.get8();

		// Check the magic number.
		const auto magic_number = file_.get16be();
		if(magic_number != 0x0100)
			throw Error::InvalidFormat;

		// Read the data and tags, and verify that enough data
		// was present.
		data_ = file_.read(data_block_length);
		tags_ = file_.read(tag_block_length);

		if(data_.size() != data_block_length || tags_.size() != tag_block_length)
			throw Error::InvalidFormat;

		// Verify the two checksums.
		const auto computed_data_checksum = checksum(data_);
		const auto computed_tag_checksum = checksum(tags_, 12);

		if(computed_tag_checksum != tag_checksum || computed_data_checksum != data_checksum)
			throw Error::InvalidFormat;
	}
}

uint32_t DiskCopy42::checksum(const std::vector<uint8_t> &data, size_t bytes_to_skip) {
	uint32_t result = 0;

	// Checksum algorith is: take each two bytes as a big-endian word; add that to a
	// 32-bit accumulator and then rotate the accumulator right one position.
	for(size_t c = bytes_to_skip; c < data.size(); c += 2) {
		const uint16_t next_word = uint16_t((data[c] << 8) | data[c+1]);
		result += next_word;
		result = (result >> 1) | (result << 31);
	}

	return result;
}

HeadPosition DiskCopy42::get_maximum_head_position() {
	return HeadPosition(80);
}

int DiskCopy42::get_head_count() {
	// Bit 5 in the format field indicates whether this disk is double
	// sided, regardless of whether it is GCR or MFM.
	return 1 + ((format_ & 0x20) >> 5);
}

bool DiskCopy42::get_is_read_only() {
	return true;
}

std::shared_ptr<::Storage::Disk::Track> DiskCopy42::get_track_at_position(::Storage::Disk::Track::Address address) {
	/*
		The format_ byte has the following meanings:

		GCR:
			This byte appears on disk as the GCR format nibble in every sector tag.
			The low five bits are an interleave factor, either:

				'2' for 0 8 1 9 2 10 3 11 4 12 5 13 6 14 7 15; or
				'4' for 0 4 8 12 1 5 9 13 2 6 10 14 3 7 11 15.

			Bit 5 indicates double sided or not.

		MFM:
			The low five bits provide sector size as a multiple of 256 bytes.
			Bit 5 indicates double sided or not.
	*/

	if(encoding_ == Encoding::GCR400 || encoding_ == Encoding::GCR800) {
		// Perform a GCR encoding.
		const auto included_sectors = Storage::Encodings::AppleGCR::Macintosh::sectors_in_track(address.position.as_int());
		const size_t start_sector = size_t(included_sectors.start * get_head_count() + included_sectors.length * address.head);

		if(start_sector*512 >= data_.size()) return nullptr;

		uint8_t *sector = &data_[512 * start_sector];
		uint8_t *tags = tags_.size() ? &tags_[12 * start_sector] : nullptr;

		Storage::Disk::PCMSegment segment;
		segment += Encodings::AppleGCR::six_and_two_sync(24);

		for(int c = 0; c < included_sectors.length; ++c) {
//			const int interleave_scale = ((format_ & 0x1f) == 4) ? 8 : 4;
			uint8_t sector_id = uint8_t(c);//uint8_t((c == included_sectors.length - 1) ? c : (c * interleave_scale)%included_sectors.length);

			uint8_t sector_plus_tags[524];

			// Copy in the tags, if provided; otherwise generate them.
			if(tags) {
				memcpy(sector_plus_tags, tags, 12);
				tags += 12;
			} else {
				// TODO: fill in tags properly.
				memset(sector_plus_tags, 0, 12);
			}

			// Copy in the sector body.
			memcpy(&sector_plus_tags[12], sector, 512);
			sector += 512;

			// NB: sync lengths below are identical to those for
			// the Apple II, as I have no idea whatsoever what they
			// should be.

			segment += Encodings::AppleGCR::Macintosh::header(
				format_,
				uint8_t(address.position.as_int()),
				sector_id,
				!!address.head
			);
			segment += Encodings::AppleGCR::six_and_two_sync(7);
			segment += Encodings::AppleGCR::Macintosh::data(sector_id, sector_plus_tags);
			segment += Encodings::AppleGCR::six_and_two_sync(20);
		}

		// TODO: is there inter-track skew?

		return std::make_shared<PCMTrack>(segment);
	}

	return nullptr;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
// guaranteed_minimum_withdrawal_benefit.cpp
// -----------------------------------------
//
// Computes the price of a Guaranteed Minimum Withdrawal Benefit (GMWB) using an
// implicit, impulse control formulation.
//
// Author: Parsiad Azimzadeh
////////////////////////////////////////////////////////////////////////////////

#include <QuantPDE/Core>
#include <QuantPDE/Modules/Lambdas>
#include <QuantPDE/Modules/Operators>

////////////////////////////////////////////////////////////////////////////////

#include <algorithm> // max, min
#include <iostream>  // cout
#include <numeric>   // accumulate
#include <tuple>     // get

////////////////////////////////////////////////////////////////////////////////

using namespace QuantPDE;
using namespace QuantPDE::Modules;

using namespace std;

////////////////////////////////////////////////////////////////////////////////

class Withdrawal final : public ControlledLinearSystem2 {

	static constexpr Real epsilon = 1e-12;

	RectilinearGrid2 &grid;
	Noncontrollable2 contractRate, kappa;

	Controllable2 control;

public:

	template <typename G, typename F1, typename F2>
	Withdrawal(G &grid, F1 &&contractRate, F2 &&kappa) noexcept :
		grid(grid),
		contractRate(contractRate),
		kappa(kappa),
		control( Control2(grid) )
	{
		registerControl( control );
	}

	virtual Matrix A(Real t) {
		Matrix M(grid.size(), grid.size());
		M.reserve(IntegerVector::Constant(grid.size(), 4));

		Index i = 0;
		for(auto node : grid) {
			const Real S = node[0]; // Investment
			const Real W = node[1]; // Withdrawal

			const Real lambda = control(t, S, W); // Control

			// Interpolation data
			auto data = interpolationData<2>(
				grid,
				{
					max(S - lambda * W, 0.),
					(1 - lambda) * W
				}
			);

			const Index i0 = get<0>( data[0] );
			const Index i1 = get<0>( data[1] );
			const Real  w0 = get<1>( data[0] );
			const Real  w1 = get<1>( data[1] );

			const Index j = grid.index(i0, i1);

			M.insert(i, j                     ) =    w0  *    w1 ;
			M.insert(i, j     + grid[0].size()) =    w0  * (1-w1);
			M.insert(i, j + 1                 ) = (1-w0) *    w1 ;
			M.insert(i, j + 1 + grid[0].size()) = (1-w0) * (1-w1);

			++i;
		}

		M.makeCompressed();
		return grid.identity() - M;
	}

	virtual Vector b(Real t) {
		Vector b( grid.vector() );
		for(auto node : accessor(grid, b)) {
			const Real S = (&node)[0]; // Investment
			const Real W = (&node)[1]; // Withdrawal

			//std::cout << S << ", " << W << ": ";

			// You have no money :(
			if(W <= epsilon) {
				*node = 0. - epsilon;
				//std::cout << "cashflow=" << *node << std::endl;
				continue;
			}

			// Control
			const Real lambda = control(t, S, W);

			// Contract rate of withdrawal
			const Real Gdt = contractRate(t, S, W);

			// Amount withdrawn, pre-penalty
			const Real lambdaW = lambda * W;

			// Withdrawal at no penalty
			if( lambda < min(Gdt / W, 1.) ) {
				*node = lambdaW - epsilon;
				//std::cout << "cashflow=" << *node << std::endl;
				continue;
			}

			// Withdrawal at a penalty
			*node = lambdaW - kappa(t, S, W) * (lambdaW - Gdt)
					- epsilon;
			//std::cout << "cashflow=" << *node << std::endl;

		}

		return b;
	}

};

////////////////////////////////////////////////////////////////////////////////

int main() {

	int n = 10;  // Optimal control partition size
	int N = 100; // Number of timesteps

	Real T = 10.;
	Real r = .05;
	Real v = .20;

	Real alpha = 0.;  // Hedging fee

	Real G = 10.;     // Contract rate
	Real kappa = 0.1; // Penalty rate

	int refinement = 2;

	////////////////////////////////////////////////////////////////////////
	// Solution grid
	////////////////////////////////////////////////////////////////////////

	RectilinearGrid2 grid(
		Axis {
			0., 5., 10., 15., 20., 25.,
			30., 35., 40., 45.,
			50., 55., 60., 65., 70., 72.5, 75., 77.5, 80., 82., 84.,
			86., 88., 90., 91., 92., 93., 94., 95.,
			96., 97., 98., 99., 100.,
			101., 102., 103., 104., 105., 106.,
			107., 108., 109., 110., 112., 114.,
			116., 118., 120., 123., 126.,
			130., 135., 140., 145., 150., 160., 175., 200., 225.,
			250., 300., 500., 750., 1000.
		},
		Axis::range(0., 2., 200.)
	);

	unsigned pow2l  = 1; // 2^l
	for(int l = 0; l < refinement; ++l) {

		////////////////////////////////////////////////////////////////////////
		// Control grid
		////////////////////////////////////////////////////////////////////////

		// Control partition 0 : 1/n : 1 (MATLAB notation)
		RectilinearGrid1 controls( Axis::range(0, 1. / (n * pow2l), 1) );

		////////////////////////////////////////////////////////////////////////
		// Iteration tree
		////////////////////////////////////////////////////////////////////////

		ReverseConstantStepper stepper(
			0.,              // Initial time
			T,               // Expiry time
			T / (N * pow2l)  // Timestep size
		);
		ToleranceIteration tolerance;
		stepper.setInnerIteration(tolerance);

		////////////////////////////////////////////////////////////////////////
		// Linear system tree
		////////////////////////////////////////////////////////////////////////

		BlackScholes<2, 0> bs(grid, r, v, alpha);
		ReverseLinearBDFTwo bdf(grid, bs);
		bdf.setIteration(stepper);

		Withdrawal impulse(grid, G * T / (N * pow2l), kappa);
		MinPolicyIteration2_1 policy(grid, controls, impulse);

		PenaltyMethod penalty(grid, bdf, policy);

		// TODO: It currently matters what order each linear system is
		//       associated with an iteration; fix this.

		penalty.setIteration(tolerance);
		policy.setIteration(tolerance);

		////////////////////////////////////////////////////////////////////////
		// Payoff
		////////////////////////////////////////////////////////////////////////

		Function2 payoff = [=] (Real S, Real W) {
			return max(S, (1 - kappa) * W);
		};

		////////////////////////////////////////////////////////////////////////
		// Running
		////////////////////////////////////////////////////////////////////////

		BiCGSTABSolver solver;

		auto V = stepper.solve(
			grid,    // Domain
			payoff,  // Initial condition
			penalty, // Root of linear system tree
			solver   // Linear system solver
		);

		////////////////////////////////////////////////////////////////////////
		// Print solution
		////////////////////////////////////////////////////////////////////////

		RectilinearGrid2 printGrid(
			Axis::range(0., 25., 200.),
			Axis::range(0., 25., 200.)
		);
		cout << accessor( printGrid, V );

		cout << endl;

		auto its = tolerance.iterations();
		Real inner = accumulate(its.begin(), its.end(), 0.)/its.size();

		cout << "average number of inner iterations: " << inner << endl;

		cout << endl;

		pow2l *= 2;

		////////////////////////////////////////////////////////////////////////
		// Refine Solution grid
		////////////////////////////////////////////////////////////////////////

		grid.refine( RectilinearGrid2::NewTickBetweenEachPair() );
	}

	return 0;
}

<commit_msg>Control discretization now has the same number of nodes under the contract withdrawal amount and above it.<commit_after>////////////////////////////////////////////////////////////////////////////////
// guaranteed_minimum_withdrawal_benefit.cpp
// -----------------------------------------
//
// Computes the price of a Guaranteed Minimum Withdrawal Benefit (GMWB) using an
// implicit, impulse control formulation.
//
// Author: Parsiad Azimzadeh
////////////////////////////////////////////////////////////////////////////////

#include <QuantPDE/Core>
#include <QuantPDE/Modules/Lambdas>
#include <QuantPDE/Modules/Operators>

////////////////////////////////////////////////////////////////////////////////

#include <algorithm> // max, min
#include <iostream>  // cout
#include <numeric>   // accumulate
#include <tuple>     // get

////////////////////////////////////////////////////////////////////////////////

using namespace QuantPDE;
using namespace QuantPDE::Modules;

using namespace std;

////////////////////////////////////////////////////////////////////////////////

class Withdrawal final : public ControlledLinearSystem2 {

	static constexpr Real epsilon = 1e-12;

	RectilinearGrid2 &grid;
	Noncontrollable2 contractRate, kappa;

	Controllable2 control;

public:

	template <typename G, typename F1, typename F2>
	Withdrawal(G &grid, F1 &&contractRate, F2 &&kappa) noexcept :
		grid(grid),
		contractRate(contractRate),
		kappa(kappa),
		control( Control2(grid) )
	{
		registerControl( control );
	}

	virtual Matrix A(Real t) {
		Matrix M(grid.size(), grid.size());
		M.reserve(IntegerVector::Constant(grid.size(), 4));

		Index i = 0;
		for(auto node : grid) {
			const Real S = node[0]; // Investment
			const Real W = node[1]; // Withdrawal

			// Contract rate of withdrawal
			const Real Gdt = contractRate(t, S, W);

			// Control
			const Real q = control(t, S, W);

			// Amount withdrawn, pre-penalty
			const Real lambdaW = (q<=1.) ? (q*Gdt) : ((q-1.)*(W - Gdt) + Gdt);

			// Interpolation data
			auto data = interpolationData<2>(
				grid,
				{
					max(S - lambdaW, 0.),
					W - lambdaW
				}
			);

			const Index i0 = get<0>( data[0] );
			const Index i1 = get<0>( data[1] );
			const Real  w0 = get<1>( data[0] );
			const Real  w1 = get<1>( data[1] );

			const Index j = grid.index(i0, i1);

			M.insert(i, j                     ) =    w0  *    w1 ;
			M.insert(i, j     + grid[0].size()) =    w0  * (1-w1);
			M.insert(i, j + 1                 ) = (1-w0) *    w1 ;
			M.insert(i, j + 1 + grid[0].size()) = (1-w0) * (1-w1);

			++i;
		}

		M.makeCompressed();
		return grid.identity() - M;
	}

	virtual Vector b(Real t) {
		Vector b( grid.vector() );
		for(auto node : accessor(grid, b)) {
			const Real S = (&node)[0]; // Investment
			const Real W = (&node)[1]; // Withdrawal

			// You have no money :(
			if(W <= epsilon) {
				*node = 0.;
				continue;
			}

			// Contract rate of withdrawal
			const Real Gdt = contractRate(t, S, W);

			// Control
			const Real q = control(t, S, W);

			// Amount withdrawn, pre-penalty
			const Real lambdaW = (q<=1.) ? (q*Gdt) : ((q-1.)*(W - Gdt) + Gdt);

			// Withdrawal at no penalty
			if(lambdaW < Gdt) {
				*node = lambdaW;
				continue;
			}

			// Withdrawal at a penalty
			*node = lambdaW - kappa(t, S, W) * (lambdaW - Gdt);
		}

		return b;
	}

};

////////////////////////////////////////////////////////////////////////////////

int main() {

	int n = 10;  // Optimal control partition size
	int N = 100; // Number of timesteps

	Real T = 10.;
	Real r = .05;
	Real v = .20;

	Real alpha = 0.;  // Hedging fee

	Real G = 10.;     // Contract rate
	Real kappa = 0.1; // Penalty rate

	int refinement = 1;

	////////////////////////////////////////////////////////////////////////
	// Solution grid
	////////////////////////////////////////////////////////////////////////

	RectilinearGrid2 grid(
		Axis {
			0., 5., 10., 15., 20., 25.,
			30., 35., 40., 45.,
			50., 55., 60., 65., 70., 72.5, 75., 77.5, 80., 82., 84.,
			86., 88., 90., 91., 92., 93., 94., 95.,
			96., 97., 98., 99., 100.,
			101., 102., 103., 104., 105., 106.,
			107., 108., 109., 110., 112., 114.,
			116., 118., 120., 123., 126.,
			130., 135., 140., 145., 150., 160., 175., 200., 225.,
			250., 300., 500., 750., 1000.
		},
		Axis::range(0., 2., 200.)
	);

	unsigned pow2l  = 1; // 2^l
	for(int l = 0; l < refinement; ++l) {

		////////////////////////////////////////////////////////////////////////
		// Control grid
		////////////////////////////////////////////////////////////////////////

		// Control partition 0 : 1/n : 1 (MATLAB notation)
		RectilinearGrid1 controls( Axis::range(0., 1. / (n * pow2l), 2.) );

		////////////////////////////////////////////////////////////////////////
		// Iteration tree
		////////////////////////////////////////////////////////////////////////

		ReverseConstantStepper stepper(
			0.,              // Initial time
			T,               // Expiry time
			T / (N * pow2l)  // Timestep size
		);
		ToleranceIteration tolerance;
		stepper.setInnerIteration(tolerance);

		////////////////////////////////////////////////////////////////////////
		// Linear system tree
		////////////////////////////////////////////////////////////////////////

		BlackScholes<2, 0> bs(grid, r, v, alpha);
		ReverseLinearBDFTwo bdf(grid, bs);
		bdf.setIteration(stepper);

		Withdrawal impulse(grid, G * T / (N * pow2l), kappa);
		MinPolicyIteration2_1 policy(grid, controls, impulse);

		PenaltyMethod penalty(grid, bdf, policy);

		// TODO: It currently matters what order each linear system is
		//       associated with an iteration; fix this.

		penalty.setIteration(tolerance);
		policy.setIteration(tolerance);

		////////////////////////////////////////////////////////////////////////
		// Payoff
		////////////////////////////////////////////////////////////////////////

		Function2 payoff = [=] (Real S, Real W) {
			return max(S, (1 - kappa) * W);
		};

		////////////////////////////////////////////////////////////////////////
		// Running
		////////////////////////////////////////////////////////////////////////

		BiCGSTABSolver solver;

		auto V = stepper.solve(
			grid,    // Domain
			payoff,  // Initial condition
			penalty, // Root of linear system tree
			solver   // Linear system solver
		);

		////////////////////////////////////////////////////////////////////////
		// Print solution
		////////////////////////////////////////////////////////////////////////

		RectilinearGrid2 printGrid(
			Axis::range(0., 25., 200.),
			Axis::range(0., 25., 200.)
		);
		cout << accessor( printGrid, V );

		cout << endl;

		auto its = tolerance.iterations();
		Real inner = accumulate(its.begin(), its.end(), 0.)/its.size();

		cout << "average number of inner iterations: " << inner << endl;

		cout << endl;

		pow2l *= 2;

		////////////////////////////////////////////////////////////////////////
		// Refine Solution grid
		////////////////////////////////////////////////////////////////////////

		grid.refine( RectilinearGrid2::NewTickBetweenEachPair() );
	}

	return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_ISATRAITS_HH__
#define __ARCH_X86_ISATRAITS_HH__

#include "arch/x86/intregs.hh"
#include "arch/x86/types.hh"
#include "arch/x86/x86_traits.hh"
#include "sim/host.hh"

class StaticInstPtr;

namespace LittleEndianGuest {}

namespace X86ISA
{
    //This makes sure the little endian version of certain functions
    //are used.
    using namespace LittleEndianGuest;

    // X86 does not have a delay slot
#define ISA_HAS_DELAY_SLOT 0

    // X86 NOP (XCHG rAX, rAX)
    //XXX This needs to be set to an intermediate instruction struct
    //which encodes this instruction

    // These enumerate all the registers for dependence tracking.
    enum DependenceTags {
        //There are 16 microcode registers at the moment. This is an
        //unusually large constant to make sure there isn't overflow.
        FP_Base_DepTag = 128,
        Ctrl_Base_DepTag =
            FP_Base_DepTag +
            //mmx/x87 registers
            8 +
            //xmm registers
            16 * 2 +
            //The microcode fp registers
            8 +
            //The indices that are mapped over the fp stack
            8
    };

    // semantically meaningful register indices
    //There is no such register in X86
    const int ZeroReg = NUM_INTREGS;
    const int StackPointerReg = INTREG_RSP;
    //X86 doesn't seem to have a link register
    const int ReturnAddressReg = 0;
    const int ReturnValueReg = INTREG_RAX;
    const int FramePointerReg = INTREG_RBP;
    const int ArgumentReg[] = {
        INTREG_RDI,
        INTREG_RSI,
        INTREG_RDX,
        //This argument register is r10 for syscalls and rcx for C.
        INTREG_R10W,
        //INTREG_RCX,
        INTREG_R8W,
        INTREG_R9W
    };
    const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);

    // Some OS syscalls use a second register (rdx) to return a second
    // value
    const int SyscallPseudoReturnReg = INTREG_RDX;

    //XXX These numbers are bogus
    const int MaxInstSrcRegs = 10;
    const int MaxInstDestRegs = 10;

    //4k. This value is not constant on x86.
    const int LogVMPageSize = 12;
    const int VMPageSize = (1 << LogVMPageSize);

    const int PageShift = 13;
    const int PageBytes = 1ULL << PageShift;

    const int BranchPredAddrShiftAmt = 0;

    StaticInstPtr decodeInst(ExtMachInst);

    const Addr LoadAddrMask = ULL(0xffffffffff);
};

#endif // __ARCH_X86_ISATRAITS_HH__
<commit_msg>X86: Fix the PageShift constant in isa_traits.hh (I thought I alread did this?)<commit_after>/*
 * Copyright (c) 2007 The Hewlett-Packard Development Company
 * All rights reserved.
 *
 * Redistribution and use of this software in source and binary forms,
 * with or without modification, are permitted provided that the
 * following conditions are met:
 *
 * The software must be used only for Non-Commercial Use which means any
 * use which is NOT directed to receiving any direct monetary
 * compensation for, or commercial advantage from such use.  Illustrative
 * examples of non-commercial use are academic research, personal study,
 * teaching, education and corporate research & development.
 * Illustrative examples of commercial use are distributing products for
 * commercial advantage and providing services using the software for
 * commercial advantage.
 *
 * If you wish to use this software or functionality therein that may be
 * covered by patents for commercial use, please contact:
 *     Director of Intellectual Property Licensing
 *     Office of Strategy and Technology
 *     Hewlett-Packard Company
 *     1501 Page Mill Road
 *     Palo Alto, California  94304
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.  Redistributions
 * in binary form must reproduce the above copyright notice, this list of
 * conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.  Neither the name of
 * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.  No right of
 * sublicense is granted herewith.  Derivatives of the software and
 * output created using the software may be prepared, but only for
 * Non-Commercial Uses.  Derivatives of the software may be shared with
 * others provided: (i) the others agree to abide by the list of
 * conditions herein which includes the Non-Commercial Use restrictions;
 * and (ii) such Derivatives of the software include the above copyright
 * notice to acknowledge the contribution from this software where
 * applicable, this list of conditions and the disclaimer below.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_X86_ISATRAITS_HH__
#define __ARCH_X86_ISATRAITS_HH__

#include "arch/x86/intregs.hh"
#include "arch/x86/types.hh"
#include "arch/x86/x86_traits.hh"
#include "sim/host.hh"

class StaticInstPtr;

namespace LittleEndianGuest {}

namespace X86ISA
{
    //This makes sure the little endian version of certain functions
    //are used.
    using namespace LittleEndianGuest;

    // X86 does not have a delay slot
#define ISA_HAS_DELAY_SLOT 0

    // X86 NOP (XCHG rAX, rAX)
    //XXX This needs to be set to an intermediate instruction struct
    //which encodes this instruction

    // These enumerate all the registers for dependence tracking.
    enum DependenceTags {
        //There are 16 microcode registers at the moment. This is an
        //unusually large constant to make sure there isn't overflow.
        FP_Base_DepTag = 128,
        Ctrl_Base_DepTag =
            FP_Base_DepTag +
            //mmx/x87 registers
            8 +
            //xmm registers
            16 * 2 +
            //The microcode fp registers
            8 +
            //The indices that are mapped over the fp stack
            8
    };

    // semantically meaningful register indices
    //There is no such register in X86
    const int ZeroReg = NUM_INTREGS;
    const int StackPointerReg = INTREG_RSP;
    //X86 doesn't seem to have a link register
    const int ReturnAddressReg = 0;
    const int ReturnValueReg = INTREG_RAX;
    const int FramePointerReg = INTREG_RBP;
    const int ArgumentReg[] = {
        INTREG_RDI,
        INTREG_RSI,
        INTREG_RDX,
        //This argument register is r10 for syscalls and rcx for C.
        INTREG_R10W,
        //INTREG_RCX,
        INTREG_R8W,
        INTREG_R9W
    };
    const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);

    // Some OS syscalls use a second register (rdx) to return a second
    // value
    const int SyscallPseudoReturnReg = INTREG_RDX;

    //XXX These numbers are bogus
    const int MaxInstSrcRegs = 10;
    const int MaxInstDestRegs = 10;

    //4k. This value is not constant on x86.
    const int LogVMPageSize = 12;
    const int VMPageSize = (1 << LogVMPageSize);

    const int PageShift = 12;
    const int PageBytes = 1ULL << PageShift;

    const int BranchPredAddrShiftAmt = 0;

    StaticInstPtr decodeInst(ExtMachInst);

    const Addr LoadAddrMask = ULL(0xffffffffff);
};

#endif // __ARCH_X86_ISATRAITS_HH__
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include <string>

#include "arch/x86/isa_traits.hh"
#include "arch/x86/stacktrace.hh"
#include "arch/x86/vtophys.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "sim/system.hh"

using namespace std;
namespace X86ISA
{
    ProcessInfo::ProcessInfo(ThreadContext *_tc)
        : tc(_tc)
    {
        Addr addr = 0;

        VirtualPort *vp;

        vp = tc->getVirtPort();

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
            panic("thread info not compiled into kernel\n");
        thread_info_size = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
            panic("thread info not compiled into kernel\n");
        task_struct_size = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
            panic("thread info not compiled into kernel\n");
        task_off = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
            panic("thread info not compiled into kernel\n");
        pid_off = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
            panic("thread info not compiled into kernel\n");
        name_off = vp->readGtoH<int32_t>(addr);

        tc->delVirtPort(vp);
    }

    Addr
    ProcessInfo::task(Addr ksp) const
    {
        Addr base = ksp & ~0x3fff;
        if (base == ULL(0xfffffc0000000000))
            return 0;

        Addr tsk;

        VirtualPort *vp;

        vp = tc->getVirtPort();
        tsk = vp->readGtoH<Addr>(base + task_off);
        tc->delVirtPort(vp);

        return tsk;
    }

    int
    ProcessInfo::pid(Addr ksp) const
    {
        Addr task = this->task(ksp);
        if (!task)
            return -1;

        uint16_t pd;

        VirtualPort *vp;

        vp = tc->getVirtPort();
        pd = vp->readGtoH<uint16_t>(task + pid_off);
        tc->delVirtPort(vp);

        return pd;
    }

    string
    ProcessInfo::name(Addr ksp) const
    {
        Addr task = this->task(ksp);
        if (!task)
            return "console";

        char comm[256];
        CopyStringOut(tc, comm, task + name_off, sizeof(comm));
        if (!comm[0])
            return "startup";

        return comm;
    }

    StackTrace::StackTrace()
        : tc(0), stack(64)
    {
    }

    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
        : tc(0), stack(64)
    {
        trace(_tc, inst);
    }

    StackTrace::~StackTrace()
    {
    }

    void
    StackTrace::trace(ThreadContext *_tc, bool is_call)
    {
    }

    bool
    StackTrace::isEntry(Addr addr)
    {
        return false;
    }

    bool
    StackTrace::decodeStack(MachInst inst, int &disp)
    {
        return true;
    }

    bool
    StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
    {
        return true;
    }

    /*
     * Decode the function prologue for the function we're in, and note
     * which registers are stored where, and how large the stack frame is.
     */
    bool
    StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
                               int &size, Addr &ra)
    {
        size = 0;
        ra = 0;

        for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
            MachInst inst;
            CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));

            int reg, disp;
            if (decodeStack(inst, disp)) {
                if (size) {
                    // panic("decoding frame size again");
                    return true;
                }
                size += disp;
            } else if (decodeSave(inst, reg, disp)) {
                if (!ra && reg == ReturnAddressReg) {
                    CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
                    if (!ra) {
                        // panic("no return address value pc=%#x\n", pc);
                        return false;
                    }
                }
            }
        }

        return true;
    }

#if TRACING_ON
    void
    StackTrace::dump()
    {
        StringWrap name(tc->getCpuPtr()->name());
        SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;

        DPRINTFN("------ Stack ------\n");

        string symbol;
        for (int i = 0, size = stack.size(); i < size; ++i) {
            Addr addr = stack[size - i - 1];
            if (addr == user)
                symbol = "user";
            else if (addr == console)
                symbol = "console";
            else if (addr == unknown)
                symbol = "unknown";
            else
                symtab->findSymbol(addr, symbol);

            DPRINTFN("%#x: %s\n", addr, symbol);
        }
    }
#endif
}
<commit_msg>X86: Fix for uninitialized variables in stacktrace code.<commit_after>/*
 * Copyright (c) 2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#include <string>

#include "arch/x86/isa_traits.hh"
#include "arch/x86/stacktrace.hh"
#include "arch/x86/vtophys.hh"
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "sim/system.hh"

using namespace std;
namespace X86ISA
{
    ProcessInfo::ProcessInfo(ThreadContext *_tc)
        : tc(_tc)
    {
        Addr addr = 0;

        VirtualPort *vp;

        vp = tc->getVirtPort();

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
            panic("thread info not compiled into kernel\n");
        thread_info_size = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
            panic("thread info not compiled into kernel\n");
        task_struct_size = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
            panic("thread info not compiled into kernel\n");
        task_off = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
            panic("thread info not compiled into kernel\n");
        pid_off = vp->readGtoH<int32_t>(addr);

        if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
            panic("thread info not compiled into kernel\n");
        name_off = vp->readGtoH<int32_t>(addr);

        tc->delVirtPort(vp);
    }

    Addr
    ProcessInfo::task(Addr ksp) const
    {
        Addr base = ksp & ~0x3fff;
        if (base == ULL(0xfffffc0000000000))
            return 0;

        Addr tsk;

        VirtualPort *vp;

        vp = tc->getVirtPort();
        tsk = vp->readGtoH<Addr>(base + task_off);
        tc->delVirtPort(vp);

        return tsk;
    }

    int
    ProcessInfo::pid(Addr ksp) const
    {
        Addr task = this->task(ksp);
        if (!task)
            return -1;

        uint16_t pd;

        VirtualPort *vp;

        vp = tc->getVirtPort();
        pd = vp->readGtoH<uint16_t>(task + pid_off);
        tc->delVirtPort(vp);

        return pd;
    }

    string
    ProcessInfo::name(Addr ksp) const
    {
        Addr task = this->task(ksp);
        if (!task)
            return "console";

        char comm[256];
        CopyStringOut(tc, comm, task + name_off, sizeof(comm));
        if (!comm[0])
            return "startup";

        return comm;
    }

    StackTrace::StackTrace()
        : tc(0), stack(64)
    {
    }

    StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
        : tc(0), stack(64)
    {
        trace(_tc, inst);
    }

    StackTrace::~StackTrace()
    {
    }

    void
    StackTrace::trace(ThreadContext *_tc, bool is_call)
    {
    }

    bool
    StackTrace::isEntry(Addr addr)
    {
        return false;
    }

    bool
    StackTrace::decodeStack(MachInst inst, int &disp)
    {
        disp = 0;
        return true;
    }

    bool
    StackTrace::decodeSave(MachInst inst, int &reg, int &disp)
    {
        reg = 0;
        disp = 0;
        return true;
    }

    /*
     * Decode the function prologue for the function we're in, and note
     * which registers are stored where, and how large the stack frame is.
     */
    bool
    StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
                               int &size, Addr &ra)
    {
        size = 0;
        ra = 0;

        for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
            MachInst inst;
            CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));

            int reg, disp;
            if (decodeStack(inst, disp)) {
                if (size) {
                    // panic("decoding frame size again");
                    return true;
                }
                size += disp;
            } else if (decodeSave(inst, reg, disp)) {
                if (!ra && reg == ReturnAddressReg) {
                    CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
                    if (!ra) {
                        // panic("no return address value pc=%#x\n", pc);
                        return false;
                    }
                }
            }
        }

        return true;
    }

#if TRACING_ON
    void
    StackTrace::dump()
    {
        StringWrap name(tc->getCpuPtr()->name());
        SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;

        DPRINTFN("------ Stack ------\n");

        string symbol;
        for (int i = 0, size = stack.size(); i < size; ++i) {
            Addr addr = stack[size - i - 1];
            if (addr == user)
                symbol = "user";
            else if (addr == console)
                symbol = "console";
            else if (addr == unknown)
                symbol = "unknown";
            else
                symtab->findSymbol(addr, symbol);

            DPRINTFN("%#x: %s\n", addr, symbol);
        }
    }
#endif
}
<|endoftext|>


<commit_before>#include <iostream>

using namespace std;

#include "mo/SmellFinder.h"
#include "mo/exception/MOException.h"

int main(int argc, char* argv[]) {
  try {
    SmellFinder smellFinder;
    if (smellFinder.hasSmell(argv, argc)) {
      cout << smellFinder.smellToString() << endl;
    }
    else {
      cout << "No Smell Detected!" << endl;
    }
  }
  catch (MOException& ex) {
    cout << "Exception: " << ex.message << endl;
  }
  return 0;
}
<commit_msg>fix the linker warming as what we do right now is syntax only<commit_after>#include <iostream>

using namespace std;

#include "mo/SmellFinder.h"
#include "mo/exception/MOException.h"

int main(int argc, char* argv[]) {
  try {
    SmellFinder smellFinder;
    if (smellFinder.hasSmell(argv + 1, argc - 1)) {
      cout << smellFinder.smellToString() << endl;
    }
    else {
      cout << "No Smell Detected!" << endl;
    }
  }
  catch (MOException& ex) {
    cout << "Exception: " << ex.message << endl;
  }
  return 0;
}
<|endoftext|>