<commit_before>// Compare numerically calculated C-V curves with analytic solution

using namespace GeFiCa;
const int n=401;
// get capacitance based on C=2pi*epsilon/ln(radius/boreR), ref. to
// http://hyperphysics.phy-astr.gsu.edu/hbase/electric/capcyl.html
double GetCfromDepletionRadius(double voltage, double radius, double boreR)
{
   TrueCoaxial detector;
   detector.Radius=radius;
   detector.BoreR=boreR;
   detector.Bias[0]=0*volt; // for inner electrode
   detector.Bias[1]=voltage; // for outer electrode
   detector.SetAverageImpurity(-1e10/cm3); // deplete from inside out

   Rho grid(n);
   grid.GetBoundaryConditionFrom(detector);
   grid.RelaxationFactor=1.986;
   grid.SuccessiveOverRelax();

   //search for depletion radius
   double up=radius, down=boreR, depletionR=radius;
   while(up-down>1e-5*mm) {
      depletionR=(down+up)/2;
      if (grid.GetV(depletionR)<voltage) down=depletionR; else up=depletionR;
   }

   cout<<depletionR<<endl;
   double L = 1*cm;
   return L*epsilon*3.14159*2/log(depletionR/boreR);
}
//______________________________________________________________________________
// use GefiCa::X::GetC()
double GetCfromGeFiCa(double voltage, double radius,double boreR)
{
   // calculate fields
   TrueCoaxial detector;
   detector.Radius=radius;
   detector.BoreR=boreR;
   detector.Bias[0]=0*volt; // for bottom electrode
   detector.Bias[1]=voltage; // for top electrode
   detector.SetAverageImpurity(-1e10/cm3);

   Rho grid(n);
   grid.GetBoundaryConditionFrom(detector);
   grid.RelaxationFactor=1.986;
   return grid.GetC();
}
//______________________________________________________________________________
//
double FindR(double voltage,double topr,double downr,double innerr, double rho)
{
   if (topr<downr+1e-5*mm) return topr; // find the required R
   double r=(topr+downr)/2;
   //voltage= -rho*r*r/4 + c1*log(r) + c2, where rho=-1e10/cm3*Qe/epsilon
   //c1=-rho*r^2/2 <= when E(r)=0, the detector is depleted from boreR to r
   //c2=rho*boreR*boreR/4 - c1*log(boreR) <= V(boreR)=0
   double c1=-rho*r*r/2;
   double c2=rho*innerr*innerr/4-c1*log(innerr);
   double V=rho*r*r/4+c1*log(r)+c2;
   if (V>voltage) return FindR(voltage,r,downr,innerr,rho);
   else return FindR(voltage,topr,r,innerr,rho);
}
//______________________________________________________________________________
//
double GetCanalytically(double voltage, double radius,double boreR)
{
   double rho=-1e10/cm3*Qe/epsilon;
   double depth=FindR(voltage,radius,boreR,boreR,rho);
   if (depth>radius) depth=radius;
   cout<<"GetCanalytically, depth: "<<depth<<endl;

   double L = 1*cm;
   return L*epsilon*3.14159*2/log(depth/boreR);
}
//______________________________________________________________________________
//
void verifyCV()
{
   double radius=1*cm;
   double boreR=0.1*cm;
   const int np=10;
   Double_t V[np], Cn[np], Ca[np],Cg[np];
   for (Int_t i=0;i<np;i++) {
      V[i] = (i+2)*50*volt; Printf("voltage: %.0f V", V[i]);
      Cn[i] = GetCfromDepletionRadius(V[i],radius,boreR)/pF;
      Cg[i] = GetCfromGeFiCa(V[i],radius,boreR)/pF;
      Ca[i] = GetCanalytically(V[i],radius,boreR)/pF;
   }

   TGraph *gn = new TGraph(np,V,Cn); gn->SetMarkerStyle(22);
   TGraph *gg = new TGraph(np,V,Cg); gg->SetMarkerStyle(24);
   TGraph *ga = new TGraph(np,V,Ca); ga->SetMarkerStyle(25);

   gStyle->SetPadLeftMargin(0.09);
   gStyle->SetPadRightMargin(0.01);
   gStyle->SetTitleOffset(0.85,"y");
   TMultiGraph *gs = new TMultiGraph; gs->Add(gn); gs->Add(gg); gs->Add(ga);
   gs->SetTitle(";Bias [V];Capacitance per unit length [pF/cm]");
   gs->Draw("pac");

   TLegend *l = new TLegend(0.5,0.6,0.97,0.97);
   l->AddEntry(ga,"#varepsilon A/d, analytically","pl");
   l->AddEntry(gn,"#varepsilon A/d, numerically","pl");
   l->AddEntry(gg,"GeFiCa::X::GetC()","pl");
   l->Draw();
}
<commit_msg>tried different crystal setup<commit_after>// Compare numerically calculated C-V curves with analytic solutions
using namespace GeFiCa;
const int n=401;
// get capacitance based on C=2pi*epsilon/ln(radius/boreR), ref. to
// http://hyperphysics.phy-astr.gsu.edu/hbase/electric/capcyl.html
double GetCfromDepletionRadius(double voltage, double radius, double boreR)
{
   TrueCoaxial detector;
   detector.Radius=radius;
   detector.BoreR=boreR;
   detector.Bias[0]=0*volt; // for inner electrode
   detector.Bias[1]=voltage; // for outer electrode
   detector.SetAverageImpurity(-2e9/cm3); // deplete from inside out

   Rho grid(n);
   grid.GetBoundaryConditionFrom(detector);
   grid.RelaxationFactor=1.986;
   grid.Precision=1e-8;
   grid.SuccessiveOverRelax();

   //search for depletion radius
   double up=radius, down=boreR, depletionR=radius;
   while(up-down>1e-7*mm) {
      depletionR=(down+up)/2;
      if (grid.GetV(depletionR)<voltage) down=depletionR; else up=depletionR;
   }

   return epsilon*3.14159*2/log(depletionR/boreR); // c per unit length in cm
}
//______________________________________________________________________________
// use GefiCa::X::GetC()
double GetCfromGeFiCa(double voltage, double radius,double boreR)
{
   // calculate fields
   TrueCoaxial detector;
   detector.Radius=radius;
   detector.BoreR=boreR;
   detector.Bias[0]=0*volt; // for bottom electrode
   detector.Bias[1]=voltage; // for top electrode
   detector.SetAverageImpurity(-2e9/cm3);

   Rho grid(n);
   grid.GetBoundaryConditionFrom(detector);
   grid.RelaxationFactor=1.986;
   grid.Precision=1e-8;

   return grid.GetC();
}
//______________________________________________________________________________
// search for depleted radius recursively
double FindR(double voltage,double upR,double downR,double boreR,double rho)
{
   if (upR<downR+1e-7*mm) return upR; // find the required R
   double r=(upR+downR)/2;
   //voltage= -rho*r*r/4 + c1*log(r) + c2, where rho=-2e9/cm3*Qe/epsilon
   //c1=-rho*r^2/2 <= when E(r)=0, the detector is depleted from boreR to r
   //c2=rho*boreR*boreR/4 - c1*log(boreR) <= V(boreR)=0
   double c1=-rho*r*r/2;
   double c2=rho*boreR*boreR/4-c1*log(boreR);
   double V=rho*r*r/4+c1*log(r)+c2;
   if (V>voltage) return FindR(voltage,r,downR,boreR,rho);
   else return FindR(voltage,upR,r,boreR,rho);
}
//______________________________________________________________________________
//
double GetCanalytically(double voltage, double radius,double boreR)
{
   double rho=-2e9/cm3*Qe/epsilon;
   double depth=FindR(voltage,radius,boreR,boreR,rho);
   if (depth>radius) depth=radius;
   return epsilon*3.14159*2/log(depth/boreR); // c per unit length in cm
}
//______________________________________________________________________________
//
void verifyCV()
{
   double radius=3.5*cm;
   double boreR=0.5*cm;
   const int np=25;
   Double_t V[np], Cn[np], Ca[np],Cg[np];
   for (Int_t i=0;i<np;i++) {
      V[i] = (i+2)*100*volt; Printf("voltage: %.0f V", V[i]);
      Cn[i] = GetCfromDepletionRadius(V[i],radius,boreR)/pF;
      Cg[i] = GetCfromGeFiCa(V[i],radius,boreR)/pF;
      Ca[i] = GetCanalytically(V[i],radius,boreR)/pF;
   }

   TGraph *gn = new TGraph(np,V,Cn); gn->SetMarkerStyle(22);
   TGraph *gg = new TGraph(np,V,Cg); gg->SetMarkerStyle(24);
   TGraph *ga = new TGraph(np,V,Ca); ga->SetMarkerStyle(25);

   gStyle->SetPadLeftMargin(0.09);
   gStyle->SetPadRightMargin(0.01);
   gStyle->SetTitleOffset(0.85,"y");
   TMultiGraph *gs = new TMultiGraph; gs->Add(gn); gs->Add(gg); gs->Add(ga);
   gs->SetTitle(";Bias [V];Capacitance per unit length [pF/cm]");
   gs->Draw("pac");

   TLegend *l = new TLegend(0.4,0.7,0.97,0.97);
   l->AddEntry(ga,"2#pi#varepsilon/ln(R_{out}/R_{in}), analytically","pl");
   l->AddEntry(gn,"2#pi#varepsilon/ln(R_{out}/R_{in}), numerically","pl");
   l->AddEntry(gg,"GeFiCa::X::GetC()","pl");
   l->Draw();
}
<|endoftext|>


<commit_before>#include "pascinference.h"

#ifndef USE_PETSC
 #error 'this util is for PETSC'
#endif

#ifndef USE_DLIB
 #error 'this util is for DLIB'
#endif

#define ENABLE_ASSERTS

#include <dlib/gui_widgets.h>
#include <sstream>
#include <string>

#define NUMBER_OF_LABELS 9

using namespace dlib;
using namespace pascinference;

class imageplotter : public drawable {
	private:
		Vec *myvector_Vec;
		bool myvector_loaded;

		void draw (const canvas& c) const;
		void plot_vector(const canvas& c) const;

		int image_width;
		int image_height;
		std::string filename;

	public:
		imageplotter(drawable_window& w);
		~imageplotter();

		void set_plotting_area(rectangle area);
		void load_image( const std::string& file_name );
		bool get_myvector_loaded();
		Vec *get_myvector_Vec();

		void set_size(int new_width);

		int get_width() const;
		int get_height() const;

		std::string get_filename() const;
};

class show_image_window : public drawable_window {
private:
    menu_bar mbar; /* gui: menubar */
	imageplotter myimageplotter; /* gui: canvas for drawing */

    label **labels_myvector_properties;
	text_field select_width;
	label label_width;
	text_field select_height;
	label label_height;
	button button_apply_size;

    void load_image( const std::string& file_name );

	/* menu events */
    void on_menu_file_open ();
    void on_menu_file_quit ();
    void on_menu_help_about();

	/* general window events */
	void on_window_resized();

	template<class ValueType>
	void set_label_myvector_properties(int label_idx, const std::string &text, ValueType value);
	std::string cut_filename(const std::string &input);
	void on_button_apply_size();

	void fill_labels();

public:
    show_image_window();
    ~show_image_window();

};

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

int main( int argc, char *argv[] ) {

	/* call initialize */
	if(!Initialize<PetscVector>(argc, argv)){
		return 0;
	}

    // create our window
    show_image_window my_window;

    // wait until the user closes this window before we let the program
    // terminate.
    my_window.wait_until_closed();

	/* finalize the library */
	Finalize<PetscVector>();

    return 0;
}

/* ---------------- implementation -------------- */

show_image_window::show_image_window() : /* All widgets take their parent window as an argument to their constructor. */
        mbar(*this),
        select_width(*this),
		label_width(*this),
        select_height(*this),
		label_height(*this),
        button_apply_size(*this),
        myimageplotter(*this)
{

	/* set the size of window */
    set_size(600,350);

	/* allocate labels */
	labels_myvector_properties = new label*[NUMBER_OF_LABELS];
	for(int i=0; i < NUMBER_OF_LABELS; i++){
		labels_myvector_properties[i] = new label(*this);
	}

    /* prepare position of labels of vector properties */
    labels_myvector_properties[0]->set_pos(10,130);
	for(int i=1; i < 9; i++){
		labels_myvector_properties[i]->set_pos(labels_myvector_properties[i-1]->left(),labels_myvector_properties[i-1]->bottom()+20);
	}

	/* window title */
	set_title("Show PETSc image utility");

	/* create menu bar */
    mbar.set_number_of_menus(2);
    mbar.set_menu_name(0,"File",'F');
    mbar.set_menu_name(1,"Help",'H');

    /* add the entries to the File menu. */
    mbar.menu(0).add_menu_item(menu_item_text("Open",   *this, &show_image_window::on_menu_file_open,    'O'));
    mbar.menu(0).add_menu_item(menu_item_separator());
    mbar.menu(0).add_menu_item(menu_item_text("Quit",   *this, &show_image_window::on_menu_file_quit,    'Q'));

    /* Add the entries to the Help menu. */
    mbar.menu(1).add_menu_item(menu_item_text("About",  *this, &show_image_window::on_menu_help_about,   'A'));

	/* register input for size */
	select_width.set_pos(120,30);
	select_width.set_width(70);
	select_width.set_text("0");
	label_width.set_pos(10,35);
	label_width.set_text("width  :");

	select_height.set_pos(120,60);
	select_height.set_width(70);
	select_height.set_text("0");
	label_height.set_pos(10,65);
	label_height.set_text("height :");
	select_height.disable();

	/* register button for changing the size */
	button_apply_size.set_click_handler(*this, &show_image_window::on_button_apply_size);
	button_apply_size.set_name("apply size");
	button_apply_size.set_pos(120,90);

	/* arrange the window */
	on_window_resized();

	show();
}

show_image_window::~show_image_window(){

	/* destroy labels */
	for(int i=0; i < NUMBER_OF_LABELS; i++){
		free(labels_myvector_properties[i]);
	}
	free(labels_myvector_properties);

	/* close window */
	close_window();
}

void show_image_window::on_menu_help_about(){
     message_box("About","This application is for PETSc vector visualisation\n");
}

void show_image_window::on_menu_file_open(){
    /* display a file chooser window and when the user choses a file */
    open_existing_file_box(*this, &show_image_window::load_image);
}

void show_image_window::on_menu_file_quit(){
	close_window();
}

void show_image_window::on_window_resized() {

	/* set new plotting area */
	unsigned long width,height;
    get_size(width,height);
	myimageplotter.set_plotting_area(rectangle(200,mbar.bottom(),width,height));

	drawable_window::on_window_resized();

}

void show_image_window::load_image( const std::string& file_name ) {
	myimageplotter.load_image(file_name);

	if(myimageplotter.get_myvector_loaded()){
		fill_labels();
	}
}

void show_image_window::fill_labels() {

	Vec *myvector_Vec = myimageplotter.get_myvector_Vec();

	/* compute basic properties of loaded vector */
	int myvector_size;
	double myvector_norm2;
	double myvector_norm1;
	double myvector_normInf;
	double myvector_sum;
	double myvector_max;
	double myvector_min;
	TRYCXX( VecGetSize(*myvector_Vec, &myvector_size) );
	TRYCXX( VecNorm(*myvector_Vec, NORM_2, &myvector_norm2) );
	TRYCXX( VecNorm(*myvector_Vec, NORM_1, &myvector_norm1) );
	TRYCXX( VecNorm(*myvector_Vec, NORM_INFINITY, &myvector_normInf) );
	TRYCXX( VecSum(*myvector_Vec, &myvector_sum) );
	TRYCXX( VecMax(*myvector_Vec, NULL, &myvector_max) );
	TRYCXX( VecMin(*myvector_Vec, NULL, &myvector_min) );

	/* print properties of vectors to labels */
	set_label_myvector_properties(0, "name:    ", cut_filename(myimageplotter.get_filename()));
	set_label_myvector_properties(1, "size:    ", myvector_size);
	set_label_myvector_properties(2, "norm2:   ", myvector_norm2);
	set_label_myvector_properties(3, "norm1:   ", myvector_norm1);
	set_label_myvector_properties(4, "normInf: ", myvector_normInf);
	set_label_myvector_properties(5, "sum:     ", myvector_sum);
	set_label_myvector_properties(6, "max:     ", myvector_max);
	set_label_myvector_properties(7, "min:     ", myvector_min);
	set_label_myvector_properties(8, "mean:    ", myvector_sum/(double)myvector_size);

}

template<class ValueType>
void show_image_window::set_label_myvector_properties(int label_idx, const std::string &text, ValueType value){
	std::ostringstream sout;
	sout << std::setprecision(5);
    sout << text << std::setw(20) << value;
    labels_myvector_properties[label_idx]->set_text(sout.str());
}

std::string show_image_window::cut_filename(const std::string &input){
	std::ostringstream sout;
	boost::filesystem::path p(input);
	sout << p.filename();

	return sout.str();
}

void show_image_window::on_button_apply_size(){
	int new_width = std::stoi(trim(select_width.text()));

	myimageplotter.set_size(new_width);

	/* get recomputed height and set value */
	select_height.set_text(std::to_string(myimageplotter.get_height()));

	if(myimageplotter.get_myvector_loaded()){
		fill_labels();
	}

}

/* ------------------------- graph plotter -------------- */

void imageplotter::draw(const canvas& c) const {
	/* draw background */
	fill_rect(c,rect,rgb_pixel(255,255,255));

	/* plot vector */
	if(myvector_loaded){
		plot_vector(c);
	}

}

imageplotter::imageplotter(drawable_window& w):
			drawable(w)
{
	/* create empty vector */
	myvector_Vec = new Vec();
	TRYCXX( VecCreate(PETSC_COMM_WORLD,myvector_Vec) );
	myvector_loaded = false;

	enable_events();
}

imageplotter::~imageplotter(){
	free(myvector_Vec);

	disable_events();
	parent.invalidate_rectangle(rect);
}

void imageplotter::set_plotting_area(rectangle area){
	rect = area;
}

void imageplotter::load_image( const std::string& file_name ) {
	this->filename = file_name;

	if(myvector_loaded){
		/* destroy existing vector */
		TRYCXX( VecDestroy(myvector_Vec) );
		TRYCXX( VecCreate(PETSC_COMM_WORLD,myvector_Vec) );
	}

	/* load the data from file */
	/* prepare viewer to load from file */
	PetscViewer mviewer;
	TRYCXX( PetscViewerCreate(PETSC_COMM_SELF, &mviewer) );
	TRYCXX( PetscViewerBinaryOpen(PETSC_COMM_SELF ,file_name.c_str(), FILE_MODE_READ, &mviewer) );

	/* load vector from viewer */
	TRYCXX( VecLoad(*myvector_Vec, mviewer) );

	/* destroy the viewer */
	TRYCXX( PetscViewerDestroy(&mviewer) );

	myvector_loaded = true;

	/* the whole rectangle with plotted graph will be repainted */
	parent.invalidate_rectangle(rect);

}

Vec * imageplotter::get_myvector_Vec(){
	return myvector_Vec;
}

bool imageplotter::get_myvector_loaded(){
	return myvector_loaded;
}

void imageplotter::plot_vector(const canvas& c) const{
	unsigned long x_begin = this->left();
	unsigned long y_begin = this->top();

	unsigned long x_size = this->width();
	unsigned long y_size = this->height();

	/* get the length of the signal */
	int    myvector_size;
	double myvector_max;
	double myvector_min;
	TRYCXX( VecGetSize(*myvector_Vec, &myvector_size) );
	TRYCXX( VecMax(*myvector_Vec, NULL, &myvector_max) );
	TRYCXX( VecMin(*myvector_Vec, NULL, &myvector_min) );

	/* free space parameters */
	double px_min = 0.01*x_size;
	double px_max = 0.99*x_size;
	double py_min = 0.1*y_size;
	double py_max = 0.9*y_size;

	/* coefficients of mapping t to x */
	double ax = (px_max - px_min)/(double)(myvector_size - 1);
	double bx = px_max - ax*myvector_size;

	/* coefficients of mapping value to y */
	double ay = (py_max - py_min)/(double)(myvector_max - myvector_min);
	double by = py_max - ay*myvector_max;

	/* I will use these points */
	point mypoint1;
	point mypoint2;

	double *values;
	TRYCXX( VecGetArray(*myvector_Vec,&values) );
	for(int t=1;t<myvector_size;t++){
		mypoint1(0) = x_begin + ax*(t-1) + bx;
		mypoint1(1) = y_begin + (y_size - (ay*values[t-1] + by));

		mypoint2(0) = x_begin + ax*t + bx;
		mypoint2(1) = y_begin + (y_size - (ay*values[t] + by));

		draw_line(c,mypoint1,mypoint2, rgb_pixel(0,0,255));

	}
	TRYCXX( VecRestoreArray(*myvector_Vec,&values) );

	/* plot a line */

}

void imageplotter::set_size(int new_width){
	this->image_width = new_width;

	/* compute height */
	if(new_width > 0 && myvector_loaded){
		int    myvector_size;
		TRYCXX( VecGetSize(*myvector_Vec, &myvector_size) );

		this->image_height = (int)(myvector_size/(double)new_width);

	} else {
		this->image_height = 0;
	}

	/* repaint ! */
	parent.invalidate_rectangle(rect);
}

int imageplotter::get_width() const {
	return image_width;
}

int imageplotter::get_height() const {
	return image_height;
}

std::string imageplotter::get_filename() const{
	return this->filename;
}
<commit_msg>still not working<commit_after>#include "pascinference.h"

#ifndef USE_PETSC
 #error 'this util is for PETSC'
#endif

#ifndef USE_DLIB
 #error 'this util is for DLIB'
#endif

#define ENABLE_ASSERTS

#include <dlib/gui_widgets.h>
#include <sstream>
#include <string>

#define NUMBER_OF_LABELS 9

using namespace dlib;
using namespace pascinference;

class imageplotter : public drawable {
	private:
		Vec *myvector_Vec;
		bool myvector_loaded;

		void draw (const canvas& c) const;
		void plot_image(const canvas& c) const;

		int image_width;
		int image_height;
		double image_scale;
		std::string filename;

	public:
		imageplotter(drawable_window& w);
		~imageplotter();

		void set_plotting_area(rectangle area);
		void load_image( const std::string& file_name );
		bool get_myvector_loaded();
		Vec *get_myvector_Vec();

		void set_size(int new_width, double new_scale);

		int get_width() const;
		int get_height() const;
		double get_scale() const;

		std::string get_filename() const;
};

class show_image_window : public drawable_window {
private:
    menu_bar mbar; /* gui: menubar */
	imageplotter myimageplotter; /* gui: canvas for drawing */

    label **labels_myvector_properties;
	text_field select_width;
	label label_width;
	text_field select_height;
	label label_height;
	text_field select_scale;
	label label_scale;
	button button_apply_size;

    void load_image( const std::string& file_name );

	/* menu events */
    void on_menu_file_open ();
    void on_menu_file_quit ();
    void on_menu_help_about();

	/* general window events */
	void on_window_resized();

	template<class ValueType>
	void set_label_myvector_properties(int label_idx, const std::string &text, ValueType value);
	std::string cut_filename(const std::string &input);
	void on_button_apply_size();

	void fill_labels();

public:
    show_image_window();
    ~show_image_window();

};

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

int main( int argc, char *argv[] ) {

	/* call initialize */
	if(!Initialize<PetscVector>(argc, argv)){
		return 0;
	}

    // create our window
    show_image_window my_window;

    // wait until the user closes this window before we let the program
    // terminate.
    my_window.wait_until_closed();

	/* finalize the library */
	Finalize<PetscVector>();

    return 0;
}

/* ---------------- implementation -------------- */

show_image_window::show_image_window() : /* All widgets take their parent window as an argument to their constructor. */
        mbar(*this),
        select_width(*this),
		label_width(*this),
        select_height(*this),
		label_height(*this),
        select_scale(*this),
		label_scale(*this),
        button_apply_size(*this),
        myimageplotter(*this)
{

	/* set the size of window */
    set_size(600,350);

	/* allocate labels */
	labels_myvector_properties = new label*[NUMBER_OF_LABELS];
	for(int i=0; i < NUMBER_OF_LABELS; i++){
		labels_myvector_properties[i] = new label(*this);
	}

    /* prepare position of labels of vector properties */
    labels_myvector_properties[0]->set_pos(10,160);
	for(int i=1; i < 9; i++){
		labels_myvector_properties[i]->set_pos(labels_myvector_properties[i-1]->left(),labels_myvector_properties[i-1]->bottom()+20);
	}

	/* window title */
	set_title("Show PETSc image utility");

	/* create menu bar */
    mbar.set_number_of_menus(2);
    mbar.set_menu_name(0,"File",'F');
    mbar.set_menu_name(1,"Help",'H');

    /* add the entries to the File menu. */
    mbar.menu(0).add_menu_item(menu_item_text("Open",   *this, &show_image_window::on_menu_file_open,    'O'));
    mbar.menu(0).add_menu_item(menu_item_separator());
    mbar.menu(0).add_menu_item(menu_item_text("Quit",   *this, &show_image_window::on_menu_file_quit,    'Q'));

    /* Add the entries to the Help menu. */
    mbar.menu(1).add_menu_item(menu_item_text("About",  *this, &show_image_window::on_menu_help_about,   'A'));

	/* register input for size */
	select_width.set_pos(120,30);
	select_width.set_width(70);
	select_width.set_text("0");
	label_width.set_pos(10,35);
	label_width.set_text("width  :");

	select_height.set_pos(120,60);
	select_height.set_width(70);
	select_height.set_text("0");
	label_height.set_pos(10,65);
	label_height.set_text("height :");
	select_height.disable();

	select_scale.set_pos(120,90);
	select_scale.set_width(70);
	select_scale.set_text("1.0");
	label_scale.set_pos(10,95);
	label_scale.set_text("scale  :");

	/* register button for changing the size */
	button_apply_size.set_click_handler(*this, &show_image_window::on_button_apply_size);
	button_apply_size.set_name("apply size");
	button_apply_size.set_pos(120,120);

	/* arrange the window */
	on_window_resized();

	show();
}

show_image_window::~show_image_window(){

	/* destroy labels */
	for(int i=0; i < NUMBER_OF_LABELS; i++){
		free(labels_myvector_properties[i]);
	}
	free(labels_myvector_properties);

	/* close window */
	close_window();
}

void show_image_window::on_menu_help_about(){
     message_box("About","This application is for PETSc vector visualisation\n");
}

void show_image_window::on_menu_file_open(){
    /* display a file chooser window and when the user choses a file */
    open_existing_file_box(*this, &show_image_window::load_image);
}

void show_image_window::on_menu_file_quit(){
	close_window();
}

void show_image_window::on_window_resized() {

	/* set new plotting area */
	unsigned long width,height;
    get_size(width,height);
	myimageplotter.set_plotting_area(rectangle(200,mbar.bottom(),width,height));

	drawable_window::on_window_resized();

}

void show_image_window::load_image( const std::string& file_name ) {
	myimageplotter.load_image(file_name);

	if(myimageplotter.get_myvector_loaded()){
		fill_labels();
	}
}

void show_image_window::fill_labels() {

	Vec *myvector_Vec = myimageplotter.get_myvector_Vec();

	/* compute basic properties of loaded vector */
	int myvector_size;
	double myvector_norm2;
	double myvector_norm1;
	double myvector_normInf;
	double myvector_sum;
	double myvector_max;
	double myvector_min;
	TRYCXX( VecGetSize(*myvector_Vec, &myvector_size) );
	TRYCXX( VecNorm(*myvector_Vec, NORM_2, &myvector_norm2) );
	TRYCXX( VecNorm(*myvector_Vec, NORM_1, &myvector_norm1) );
	TRYCXX( VecNorm(*myvector_Vec, NORM_INFINITY, &myvector_normInf) );
	TRYCXX( VecSum(*myvector_Vec, &myvector_sum) );
	TRYCXX( VecMax(*myvector_Vec, NULL, &myvector_max) );
	TRYCXX( VecMin(*myvector_Vec, NULL, &myvector_min) );

	/* print properties of vectors to labels */
	set_label_myvector_properties(0, "name:    ", cut_filename(myimageplotter.get_filename()));
	set_label_myvector_properties(1, "size:    ", myvector_size);
	set_label_myvector_properties(2, "norm2:   ", myvector_norm2);
	set_label_myvector_properties(3, "norm1:   ", myvector_norm1);
	set_label_myvector_properties(4, "normInf: ", myvector_normInf);
	set_label_myvector_properties(5, "sum:     ", myvector_sum);
	set_label_myvector_properties(6, "max:     ", myvector_max);
	set_label_myvector_properties(7, "min:     ", myvector_min);
	set_label_myvector_properties(8, "mean:    ", myvector_sum/(double)myvector_size);

}

template<class ValueType>
void show_image_window::set_label_myvector_properties(int label_idx, const std::string &text, ValueType value){
	std::ostringstream sout;
	sout << std::setprecision(5);
    sout << text << std::setw(20) << value;
    labels_myvector_properties[label_idx]->set_text(sout.str());
}

std::string show_image_window::cut_filename(const std::string &input){
	std::ostringstream sout;
	boost::filesystem::path p(input);
	sout << p.filename();

	return sout.str();
}

void show_image_window::on_button_apply_size(){
	int new_width = std::stoi(trim(select_width.text()));
	double new_scale = std::stod(trim(select_scale.text()));

	myimageplotter.set_size(new_width,new_scale);

	/* get recomputed height and set value */
	select_height.set_text(std::to_string(myimageplotter.get_height()));

	if(myimageplotter.get_myvector_loaded()){
		fill_labels();
	}

}

/* ------------------------- graph plotter -------------- */

void imageplotter::draw(const canvas& c) const {
	/* draw background */
	fill_rect(c,rect,rgb_pixel(255,255,255));

	/* plot vector */
	if(myvector_loaded){
		plot_image(c);
	}

}

imageplotter::imageplotter(drawable_window& w):
			drawable(w)
{
	/* create empty vector */
	myvector_Vec = new Vec();
	TRYCXX( VecCreate(PETSC_COMM_WORLD,myvector_Vec) );
	myvector_loaded = false;

	image_width = 0;
	image_height = 0;
	image_scale = 1.0;

	enable_events();
}

imageplotter::~imageplotter(){
	free(myvector_Vec);

	disable_events();
	parent.invalidate_rectangle(rect);
}

void imageplotter::set_plotting_area(rectangle area){
	rect = area;
}

void imageplotter::load_image( const std::string& file_name ) {
	this->filename = file_name;

	if(myvector_loaded){
		/* destroy existing vector */
		TRYCXX( VecDestroy(myvector_Vec) );
		TRYCXX( VecCreate(PETSC_COMM_WORLD,myvector_Vec) );
	}

	/* load the data from file */
	/* prepare viewer to load from file */
	PetscViewer mviewer;
	TRYCXX( PetscViewerCreate(PETSC_COMM_SELF, &mviewer) );
	TRYCXX( PetscViewerBinaryOpen(PETSC_COMM_SELF ,file_name.c_str(), FILE_MODE_READ, &mviewer) );

	/* load vector from viewer */
	TRYCXX( VecLoad(*myvector_Vec, mviewer) );

	/* destroy the viewer */
	TRYCXX( PetscViewerDestroy(&mviewer) );

	myvector_loaded = true;

	/* the whole rectangle with plotted graph will be repainted */
	parent.invalidate_rectangle(rect);

}

Vec * imageplotter::get_myvector_Vec(){
	return myvector_Vec;
}

bool imageplotter::get_myvector_loaded(){
	return myvector_loaded;
}

void imageplotter::plot_image(const canvas& c) const{
	unsigned long x_begin = this->left();
	unsigned long y_begin = this->top();

	unsigned long x_size = this->width();
	unsigned long y_size = this->height();

	/* get the length of the signal */
	int    myvector_size;
	double myvector_max;
	double myvector_min;
	TRYCXX( VecGetSize(*myvector_Vec, &myvector_size) );
	TRYCXX( VecMax(*myvector_Vec, NULL, &myvector_max) );
	TRYCXX( VecMin(*myvector_Vec, NULL, &myvector_min) );

	/* free space parameters */
	double px_min = 0.01*x_size;
	double px_max = 0.99*x_size;
	double py_min = 0.1*y_size;
	double py_max = 0.9*y_size;

	/* coefficients of mapping t to x */
	double ax = (px_max - px_min)/(double)(myvector_size - 1);
	double bx = px_max - ax*myvector_size;

	/* coefficients of mapping value to y */
	double ay = (py_max - py_min)/(double)(myvector_max - myvector_min);
	double by = py_max - ay*myvector_max;

	/* I will use these points */
	point mypoint1;
	point mypoint2;

	double *values;
	TRYCXX( VecGetArray(*myvector_Vec,&values) );
	for(int t=1;t<myvector_size;t++){
		mypoint1(0) = x_begin + ax*(t-1) + bx;
		mypoint1(1) = y_begin + (y_size - (ay*values[t-1] + by));

		mypoint2(0) = x_begin + ax*t + bx;
		mypoint2(1) = y_begin + (y_size - (ay*values[t] + by));

		draw_line(c,mypoint1,mypoint2, rgb_pixel(0,0,255));

	}
	TRYCXX( VecRestoreArray(*myvector_Vec,&values) );

	/* plot a line */

}

void imageplotter::set_size(int new_width, double new_scale){
	this->image_width = new_width;
	this->image_scale = new_scale;

	/* compute height */
	if(new_width > 0 && myvector_loaded){
		int    myvector_size;
		TRYCXX( VecGetSize(*myvector_Vec, &myvector_size) );

		this->image_height = (int)(myvector_size/(double)new_width);

	} else {
		this->image_height = 0;
	}

	/* repaint ! */
	parent.invalidate_rectangle(rect);
}

int imageplotter::get_width() const {
	return image_width;
}

int imageplotter::get_height() const {
	return image_height;
}

double imageplotter::get_scale() const {
	return image_scale;
}

std::string imageplotter::get_filename() const{
	return this->filename;
}
<|endoftext|>


<commit_before>/*  Sirikata
 *  StressTestBase.hpp
 *
 *  Copyright (c) 2011, Stanford University
 *  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 Sirikata 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.
 */

#ifndef __SIRIKATA_STRESS_TEST_BASE_HPP__
#define __SIRIKATA_STRESS_TEST_BASE_HPP__

#include <sys/time.h>
#include <cxxtest/TestSuite.h>
#include <sirikata/oh/Storage.hpp>
#include "DataFiles.hpp"

class StressTestBase
{
protected:
    typedef OH::Storage::ReadSet ReadSet;

    DataFiles _data;
    static const OH::Storage::Bucket _buckets[100];
    static const String _dataIndex[20];

    int _initialized;

    String _plugin;
    String _type;
    String _args;

    PluginManager _pmgr;
    OH::Storage* _storage;

    // Helpers for getting event loop setup/torn down
    Trace::Trace* _trace;
    ODPSST::ConnectionManager* _sstConnMgr;
    OHDPSST::ConnectionManager* _ohSstConnMgr;
    Network::IOService* _ios;
    Network::IOStrand* _mainStrand;
    Network::IOWork* _work;
    ObjectHostContext* _ctx;

    // Processing happens in another thread, but the main test thread
    // needs to wait for the test to complete before proceeding. This
    // CV notifies the main thread as each callback finishes.
    boost::mutex _mutex;
    boost::condition_variable _cond;

public:
    StressTestBase(String plugin, String type, String args)
     : _initialized(0),
       _plugin(plugin),
       _type(type),
       _args(args),
       _data(),
       _storage(NULL),
       _trace(NULL),
       _sstConnMgr(NULL),
       _ohSstConnMgr(NULL),
       _mainStrand(NULL),
       _work(NULL),
       _ctx(NULL)
    {}

    void setUp() {
        if (!_initialized) {
            _initialized = 1;
            _pmgr.load(_plugin);
        }

        // Storage is tied to the main event loop, which requires quite a bit of setup
        ObjectHostID oh_id(1);
        _trace = new Trace::Trace("dummy.trace");
        _ios = new Network::IOService("StressTestBase IOService");
        _mainStrand = _ios->createStrand("StressTestBase IOStrand");
        _work = new Network::IOWork(*_ios, "StressTest");
        Time start_time = Timer::now(); // Just for stats in ObjectHostContext.
        Duration duration = Duration::zero(); // Indicates to run forever.
        _sstConnMgr = new ODPSST::ConnectionManager();
        _ohSstConnMgr = new OHDPSST::ConnectionManager();

        _ctx = new ObjectHostContext("test", oh_id, _sstConnMgr, _ohSstConnMgr, _ios, _mainStrand, _trace, start_time, duration);

        _storage = OH::StorageFactory::getSingleton().getConstructor(_type)(_ctx, _args);

        _ctx->add(_ctx);
        _ctx->add(_storage);

        // Run the context, but we need to make sure it only lives in other
        // threads, otherwise we'd block up this one.  We include 4 threads to
        // exercise support for multiple threads.
        _ctx->run(4, Context::AllNew);
    }

    void tearDown() {
        delete _work;
        _work = NULL;

        _ctx->shutdown();

        _trace->prepareShutdown();

        delete _storage;
        _storage = NULL;

        delete _ctx;
        _ctx = NULL;

        _trace->shutdown();
        delete _trace;
        _trace = NULL;

        delete _mainStrand;
        _mainStrand = NULL;
        delete _ios;
        _ios = NULL;
    }

    void checkReadValuesImpl(bool expected_success, ReadSet expected, bool success, ReadSet* rs) {
        TS_ASSERT_EQUALS(expected_success, success);
        if (!success || !expected_success) return;

        if (!rs) {
            TS_ASSERT_EQUALS(expected.size(), 0);
            return;
        }

        TS_ASSERT_EQUALS(expected.size(), rs->size());
        for(ReadSet::iterator it = expected.begin(); it != expected.end(); it++) {
            String key = it->first; String value = it->second;
            TS_ASSERT(rs->find(key) != rs->end());
            TS_ASSERT_EQUALS((*rs)[key], value);
        }
    }

    void checkReadValues(bool expected_success, ReadSet expected, bool success, ReadSet* rs) {
        boost::unique_lock<boost::mutex> lock(_mutex);
        checkReadValuesImpl(expected_success, expected, success, rs);
        delete rs;
        _cond.notify_one();
    }

    void checkSuccessImpl(bool expected_success, ReadSet expected, bool success, ReadSet* rs){
        TS_ASSERT_EQUALS(expected_success, success);
    }

    void checkSuccess(bool expected_success, ReadSet expected, bool success, ReadSet* rs){
        boost::unique_lock<boost::mutex> lock(_mutex);
        checkSuccessImpl(expected_success, expected, success, rs);
        _cond.notify_one();
    }

    void waitForTransaction() {
        boost::unique_lock<boost::mutex> lock(_mutex);
        _cond.wait(lock);
    }

    void testSetupTeardown() {
        TS_ASSERT(_storage);
    }

    void testSingleWrites(String length, int keyNum, int bucketNum) {
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        timeval ts;
        gettimeofday(&ts,NULL);
        long int time1_s = ts.tv_sec;
        int time1_us=ts.tv_usec;

        String key;
        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->write(_buckets[i], key, _data.dataSet[key],
	                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
	                       );
                waitForTransaction();
            }
        }

        gettimeofday(&ts,NULL);
        long int time2_s = ts.tv_sec;
        int time2_us=ts.tv_usec;
        long int diff_s=time2_s - time1_s;
        int diff_us=time2_us - time1_us;
        double diff_t=diff_s*1000+diff_us/(double)1000;
        std::cout<<"Write time: "<<diff_t<<std::endl;
    }

    void testSingleReads(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        ReadSet rs=_data.dataSet;

        timeval ts;
        gettimeofday(&ts,NULL);
        long int time1_s = ts.tv_sec;
        int time1_us=ts.tv_usec;

        String key;
        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key,
                               std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                              );
                waitForTransaction();
            }
        }

        gettimeofday(&ts,NULL);
        long int time2_s = ts.tv_sec;
        int time2_us=ts.tv_usec;
        long int diff_s=time2_s - time1_s;
        int diff_us=time2_us - time1_us;
        double diff_t=diff_s*1000+diff_us/(double)1000;
        std::cout<<"Read time:  "<<diff_t<<std::endl;

    }

    void testSingleErases(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        timeval ts;
        gettimeofday(&ts,NULL);
        long int time1_s = ts.tv_sec;
        int time1_us=ts.tv_usec;

        String key;
        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->erase(_buckets[i], key,
                                std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                               );
                waitForTransaction();
            }
        }

        gettimeofday(&ts,NULL);
        long int time2_s = ts.tv_sec;
        int time2_us=ts.tv_usec;
        long int diff_s=time2_s - time1_s;
        int diff_us=time2_us - time1_us;
        double diff_t=diff_s*1000+diff_us/(double)1000;
        std::cout<<"Erase time: "<<diff_t<<std::endl;

        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key,
                               std::tr1::bind(&StressTestBase::checkSuccess, this, false, ReadSet(), _1, _2)
                              );
                waitForTransaction();
            }
        }

    }

    void testBatchWrites(String length, int keyNum, int bucketNum) {
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        timeval ts;
        gettimeofday(&ts,NULL);
        long int time1_s = ts.tv_sec;
        int time1_us=ts.tv_usec;

        String key;
        for (int i=0; i<bucketNum; i++){
            _storage->beginTransaction(_buckets[i]);
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->write(_buckets[i], key, _data.dataSet[key]);
            }
            _storage->commitTransaction(_buckets[i],
                                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                                       );
            waitForTransaction();
        }

        gettimeofday(&ts,NULL);
        long int time2_s = ts.tv_sec;
        int time2_us=ts.tv_usec;
        long int diff_s=time2_s - time1_s;
        int diff_us=time2_us - time1_us;
        double diff_t=diff_s*1000+diff_us/(double)1000;
        std::cout<<"Write time: "<<diff_t<<std::endl;
    }

    void testBatchReads(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        ReadSet rs=_data.dataSet;

        timeval ts;
        gettimeofday(&ts,NULL);
        long int time1_s = ts.tv_sec;
        int time1_us=ts.tv_usec;

        String key;
        for (int i=0; i<bucketNum; i++){
            _storage->beginTransaction(_buckets[i]);
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key);
            }
            _storage->commitTransaction(_buckets[i],
                                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                                       );
            waitForTransaction();
        }

        gettimeofday(&ts,NULL);
        long int time2_s = ts.tv_sec;
        int time2_us=ts.tv_usec;
        long int diff_s=time2_s - time1_s;
        int diff_us=time2_us - time1_us;
        double diff_t=diff_s*1000+diff_us/(double)1000;
        std::cout<<"Read time:  "<<diff_t<<std::endl;

    }

    void testBatchErases(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        timeval ts;
        gettimeofday(&ts,NULL);
        long int time1_s = ts.tv_sec;
        int time1_us=ts.tv_usec;

        String key;
        for (int i=0; i<bucketNum; i++){
            _storage->beginTransaction(_buckets[i]);
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->erase(_buckets[i], key);
            }
            _storage->commitTransaction(_buckets[i],
                                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                                       );
            waitForTransaction();
        }

        gettimeofday(&ts,NULL);
        long int time2_s = ts.tv_sec;
        int time2_us=ts.tv_usec;
        long int diff_s=time2_s - time1_s;
        int diff_us=time2_us - time1_us;
        double diff_t=diff_s*1000+diff_us/(double)1000;
        std::cout<<"Erase time: "<<diff_t<<std::endl;

        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key,
                               std::tr1::bind(&StressTestBase::checkSuccess, this, false, ReadSet(), _1, _2)
                              );
                waitForTransaction();
            }
        }
    }

  void testMultiRounds(String length, int keyNum, int bucketNum, int times){

    std::cout<<"dataLength: "<<length<<", keyNum: "<<keyNum<<", bucketNum: "<<bucketNum<<", rounds: "<<times<<"\n\n";
    for (int i=0; i<times; i++){
      std::cout<<"Round "<<i+1<<std::endl;
      std::cout<<"testSingleWrites -- ";
      testSingleWrites(length, keyNum, bucketNum);
      std::cout<<"testSingleReads  -- ";
      testSingleReads(length, keyNum, bucketNum);
      std::cout<<"testSingleErases -- ";
      testSingleErases(length, keyNum, bucketNum);
      std::cout<<"testBatchWrites  -- ";
      testBatchWrites(length, keyNum, bucketNum);
      std::cout<<"testBatchReads   -- ";
      testBatchReads(length, keyNum, bucketNum);
      std::cout<<"testBatchErases  -- ";
      testBatchErases(length, keyNum, bucketNum);
      std::cout<<std::endl;
    }
  }

};

const OH::Storage::Bucket StressTestBase::_buckets[100] = DataFiles::buckets;
const String StressTestBase::_dataIndex[20]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"};

#endif //__SIRIKATA_STRESS_TEST_BASE_HPP__
<commit_msg>Use Sirikata's timing code to make stress tests cross platform and simpler.<commit_after>/*  Sirikata
 *  StressTestBase.hpp
 *
 *  Copyright (c) 2011, Stanford University
 *  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 Sirikata 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.
 */

#ifndef __SIRIKATA_STRESS_TEST_BASE_HPP__
#define __SIRIKATA_STRESS_TEST_BASE_HPP__

#include <sys/time.h>
#include <cxxtest/TestSuite.h>
#include <sirikata/oh/Storage.hpp>
#include "DataFiles.hpp"

class StressTestBase
{
protected:
    typedef OH::Storage::ReadSet ReadSet;

    DataFiles _data;
    static const OH::Storage::Bucket _buckets[100];
    static const String _dataIndex[20];

    int _initialized;

    String _plugin;
    String _type;
    String _args;

    PluginManager _pmgr;
    OH::Storage* _storage;

    // Helpers for getting event loop setup/torn down
    Trace::Trace* _trace;
    ODPSST::ConnectionManager* _sstConnMgr;
    OHDPSST::ConnectionManager* _ohSstConnMgr;
    Network::IOService* _ios;
    Network::IOStrand* _mainStrand;
    Network::IOWork* _work;
    ObjectHostContext* _ctx;

    // Processing happens in another thread, but the main test thread
    // needs to wait for the test to complete before proceeding. This
    // CV notifies the main thread as each callback finishes.
    boost::mutex _mutex;
    boost::condition_variable _cond;

public:
    StressTestBase(String plugin, String type, String args)
     : _initialized(0),
       _plugin(plugin),
       _type(type),
       _args(args),
       _data(),
       _storage(NULL),
       _trace(NULL),
       _sstConnMgr(NULL),
       _ohSstConnMgr(NULL),
       _mainStrand(NULL),
       _work(NULL),
       _ctx(NULL)
    {}

    void setUp() {
        if (!_initialized) {
            _initialized = 1;
            _pmgr.load(_plugin);
        }

        // Storage is tied to the main event loop, which requires quite a bit of setup
        ObjectHostID oh_id(1);
        _trace = new Trace::Trace("dummy.trace");
        _ios = new Network::IOService("StressTestBase IOService");
        _mainStrand = _ios->createStrand("StressTestBase IOStrand");
        _work = new Network::IOWork(*_ios, "StressTest");
        Time start_time = Timer::now(); // Just for stats in ObjectHostContext.
        Duration duration = Duration::zero(); // Indicates to run forever.
        _sstConnMgr = new ODPSST::ConnectionManager();
        _ohSstConnMgr = new OHDPSST::ConnectionManager();

        _ctx = new ObjectHostContext("test", oh_id, _sstConnMgr, _ohSstConnMgr, _ios, _mainStrand, _trace, start_time, duration);

        _storage = OH::StorageFactory::getSingleton().getConstructor(_type)(_ctx, _args);

        _ctx->add(_ctx);
        _ctx->add(_storage);

        // Run the context, but we need to make sure it only lives in other
        // threads, otherwise we'd block up this one.  We include 4 threads to
        // exercise support for multiple threads.
        _ctx->run(4, Context::AllNew);
    }

    void tearDown() {
        delete _work;
        _work = NULL;

        _ctx->shutdown();

        _trace->prepareShutdown();

        delete _storage;
        _storage = NULL;

        delete _ctx;
        _ctx = NULL;

        _trace->shutdown();
        delete _trace;
        _trace = NULL;

        delete _mainStrand;
        _mainStrand = NULL;
        delete _ios;
        _ios = NULL;
    }

    void checkReadValuesImpl(bool expected_success, ReadSet expected, bool success, ReadSet* rs) {
        TS_ASSERT_EQUALS(expected_success, success);
        if (!success || !expected_success) return;

        if (!rs) {
            TS_ASSERT_EQUALS(expected.size(), 0);
            return;
        }

        TS_ASSERT_EQUALS(expected.size(), rs->size());
        for(ReadSet::iterator it = expected.begin(); it != expected.end(); it++) {
            String key = it->first; String value = it->second;
            TS_ASSERT(rs->find(key) != rs->end());
            TS_ASSERT_EQUALS((*rs)[key], value);
        }
    }

    void checkReadValues(bool expected_success, ReadSet expected, bool success, ReadSet* rs) {
        boost::unique_lock<boost::mutex> lock(_mutex);
        checkReadValuesImpl(expected_success, expected, success, rs);
        delete rs;
        _cond.notify_one();
    }

    void checkSuccessImpl(bool expected_success, ReadSet expected, bool success, ReadSet* rs){
        TS_ASSERT_EQUALS(expected_success, success);
    }

    void checkSuccess(bool expected_success, ReadSet expected, bool success, ReadSet* rs){
        boost::unique_lock<boost::mutex> lock(_mutex);
        checkSuccessImpl(expected_success, expected, success, rs);
        _cond.notify_one();
    }

    void waitForTransaction() {
        boost::unique_lock<boost::mutex> lock(_mutex);
        _cond.wait(lock);
    }

    void testSetupTeardown() {
        TS_ASSERT(_storage);
    }

    void testSingleWrites(String length, int keyNum, int bucketNum) {
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        Time start = Timer::now();

        String key;
        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->write(_buckets[i], key, _data.dataSet[key],
	                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
	                       );
                waitForTransaction();
            }
        }

        Time end = Timer::now();
        std::cout << "Write time " << (end-start) << std::endl;
    }

    void testSingleReads(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        ReadSet rs=_data.dataSet;

        Time start = Timer::now();

        String key;
        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key,
                               std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                              );
                waitForTransaction();
            }
        }

        Time end = Timer::now();
        std::cout << "Read time " << (end-start) << std::endl;
    }

    void testSingleErases(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        Time start = Timer::now();

        String key;
        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->erase(_buckets[i], key,
                                std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                               );
                waitForTransaction();
            }
        }

        Time end = Timer::now();
        std::cout << "Erase time " << (end-start) << std::endl;

        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key,
                               std::tr1::bind(&StressTestBase::checkSuccess, this, false, ReadSet(), _1, _2)
                              );
                waitForTransaction();
            }
        }

    }

    void testBatchWrites(String length, int keyNum, int bucketNum) {
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        Time start = Timer::now();

        String key;
        for (int i=0; i<bucketNum; i++){
            _storage->beginTransaction(_buckets[i]);
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->write(_buckets[i], key, _data.dataSet[key]);
            }
            _storage->commitTransaction(_buckets[i],
                                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                                       );
            waitForTransaction();
        }

        Time end = Timer::now();
        std::cout << "Batch write time " << (end-start) << std::endl;
    }

    void testBatchReads(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        ReadSet rs=_data.dataSet;

        Time start = Timer::now();

        String key;
        for (int i=0; i<bucketNum; i++){
            _storage->beginTransaction(_buckets[i]);
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key);
            }
            _storage->commitTransaction(_buckets[i],
                                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                                       );
            waitForTransaction();
        }

        Time end = Timer::now();
        std::cout << "Batch read time " << (end-start) << std::endl;
    }

    void testBatchErases(String length, int keyNum, int bucketNum) {
        // NOTE: Depends on above write
        using std::tr1::placeholders::_1;
        using std::tr1::placeholders::_2;

        Time start = Timer::now();

        String key;
        for (int i=0; i<bucketNum; i++){
            _storage->beginTransaction(_buckets[i]);
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->erase(_buckets[i], key);
            }
            _storage->commitTransaction(_buckets[i],
                                        std::tr1::bind(&StressTestBase::checkSuccess, this, true, ReadSet(), _1, _2)
                                       );
            waitForTransaction();
        }

        Time end = Timer::now();
        std::cout << "Batch erase time " << (end-start) << std::endl;

        for (int i=0; i<bucketNum; i++){
            for(int j=0; j<keyNum; j++){
                key=_dataIndex[j]+"-"+length;
                _storage->read(_buckets[i], key,
                               std::tr1::bind(&StressTestBase::checkSuccess, this, false, ReadSet(), _1, _2)
                              );
                waitForTransaction();
            }
        }
    }

  void testMultiRounds(String length, int keyNum, int bucketNum, int times){

    std::cout<<"dataLength: "<<length<<", keyNum: "<<keyNum<<", bucketNum: "<<bucketNum<<", rounds: "<<times<<"\n\n";
    for (int i=0; i<times; i++){
      std::cout<<"Round "<<i+1<<std::endl;
      std::cout<<"testSingleWrites -- ";
      testSingleWrites(length, keyNum, bucketNum);
      std::cout<<"testSingleReads  -- ";
      testSingleReads(length, keyNum, bucketNum);
      std::cout<<"testSingleErases -- ";
      testSingleErases(length, keyNum, bucketNum);
      std::cout<<"testBatchWrites  -- ";
      testBatchWrites(length, keyNum, bucketNum);
      std::cout<<"testBatchReads   -- ";
      testBatchReads(length, keyNum, bucketNum);
      std::cout<<"testBatchErases  -- ";
      testBatchErases(length, keyNum, bucketNum);
      std::cout<<std::endl;
    }
  }

};

const OH::Storage::Bucket StressTestBase::_buckets[100] = DataFiles::buckets;
const String StressTestBase::_dataIndex[20]={"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"};

#endif //__SIRIKATA_STRESS_TEST_BASE_HPP__
<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#include "libtorrent/assert.hpp"

#include "zlib.h"

#include <vector>
#include <string>

namespace
{
	enum
	{
		FTEXT = 0x01,
		FHCRC = 0x02,
		FEXTRA = 0x04,
		FNAME = 0x08,
		FCOMMENT = 0x10,
		FRESERVED = 0xe0,

		GZIP_MAGIC0 = 0x1f,
		GZIP_MAGIC1 = 0x8b
	};

}

namespace libtorrent
{
	// returns -1 if gzip header is invalid or the header size in bytes
	int gzip_header(const char* buf, int size)
	{
		TORRENT_ASSERT(buf != 0);
		TORRENT_ASSERT(size > 0);

		const unsigned char* buffer = reinterpret_cast<const unsigned char*>(buf);
		const int total_size = size;

		// The zip header cannot be shorter than 10 bytes
		if (size < 10) return -1;

		// check the magic header of gzip
		if ((buffer[0] != GZIP_MAGIC0) || (buffer[1] != GZIP_MAGIC1)) return -1;

		int method = buffer[2];
		int flags = buffer[3];

		// check for reserved flag and make sure it's compressed with the correct metod
		if (method != Z_DEFLATED || (flags & FRESERVED) != 0) return -1;

		// skip time, xflags, OS code
		size -= 10;
		buffer += 10;

		if (flags & FEXTRA)
		{
			int extra_len;

			if (size < 2) return -1;

			extra_len = (buffer[1] << 8) | buffer[0];

			if (size < (extra_len+2)) return -1;
			size -= (extra_len + 2);
			buffer += (extra_len + 2);
		}

		if (flags & FNAME)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FCOMMENT)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FHCRC)
		{
			if (size < 2) return -1;

			size -= 2;
			buffer += 2;
		}

		return total_size - size;
	}

	bool inflate_gzip(
		char const* in
		, int size
		, std::vector<char>& buffer
		, int maximum_size
		, std::string& error)
	{
		TORRENT_ASSERT(maximum_size > 0);

		int header_len = gzip_header(in, size);
		if (header_len < 0)
		{
			error = "invalid gzip header in tracker response";
			return true;
		}

		// start off with one kilobyte and grow
		// if needed
		buffer.resize(1024);

		// initialize the zlib-stream
		z_stream str;

		// subtract 8 from the end of the buffer since that's CRC32 and input size
		// and those belong to the gzip file
		str.avail_in = (int)size - header_len - 8;
		str.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in + header_len));
		str.next_out = reinterpret_cast<Bytef*>(&buffer[0]);
		str.avail_out = (int)buffer.size();
		str.zalloc = Z_NULL;
		str.zfree = Z_NULL;
		str.opaque = 0;
		// -15 is really important. It will make inflate() not look for a zlib header
		// and just deflate the buffer
		if (inflateInit2(&str, -15) != Z_OK)
		{
			error = "gzip out of memory";
			return true;
		}

		// inflate and grow inflate_buffer as needed
		int ret = inflate(&str, Z_SYNC_FLUSH);
		while (ret == Z_OK)
		{
			if (str.avail_out == 0)
			{
				if (buffer.size() >= (unsigned)maximum_size)
				{
					inflateEnd(&str);
					error = "response too large";
					return true;
				}
				int new_size = (int)buffer.size() * 2;
				if (new_size > maximum_size)
					new_size = maximum_size;
				int old_size = (int)buffer.size();

				buffer.resize(new_size);
				str.next_out = reinterpret_cast<Bytef*>(&buffer[old_size]);
				str.avail_out = new_size - old_size;
			}

			ret = inflate(&str, Z_SYNC_FLUSH);
		}

		buffer.resize(buffer.size() - str.avail_out);
		inflateEnd(&str);

		if (ret != Z_STREAM_END)
		{
			error = "gzip error";
			return true;
		}

		// commit the resulting buffer
		return false;
	}

}

<commit_msg>removed invalid assert<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#include "libtorrent/assert.hpp"

#include "zlib.h"

#include <vector>
#include <string>

namespace
{
	enum
	{
		FTEXT = 0x01,
		FHCRC = 0x02,
		FEXTRA = 0x04,
		FNAME = 0x08,
		FCOMMENT = 0x10,
		FRESERVED = 0xe0,

		GZIP_MAGIC0 = 0x1f,
		GZIP_MAGIC1 = 0x8b
	};

}

namespace libtorrent
{
	// returns -1 if gzip header is invalid or the header size in bytes
	int gzip_header(const char* buf, int size)
	{
		TORRENT_ASSERT(buf != 0);

		const unsigned char* buffer = reinterpret_cast<const unsigned char*>(buf);
		const int total_size = size;

		// The zip header cannot be shorter than 10 bytes
		if (size < 10) return -1;

		// check the magic header of gzip
		if ((buffer[0] != GZIP_MAGIC0) || (buffer[1] != GZIP_MAGIC1)) return -1;

		int method = buffer[2];
		int flags = buffer[3];

		// check for reserved flag and make sure it's compressed with the correct metod
		if (method != Z_DEFLATED || (flags & FRESERVED) != 0) return -1;

		// skip time, xflags, OS code
		size -= 10;
		buffer += 10;

		if (flags & FEXTRA)
		{
			int extra_len;

			if (size < 2) return -1;

			extra_len = (buffer[1] << 8) | buffer[0];

			if (size < (extra_len+2)) return -1;
			size -= (extra_len + 2);
			buffer += (extra_len + 2);
		}

		if (flags & FNAME)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FCOMMENT)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FHCRC)
		{
			if (size < 2) return -1;

			size -= 2;
			buffer += 2;
		}

		return total_size - size;
	}

	bool inflate_gzip(
		char const* in
		, int size
		, std::vector<char>& buffer
		, int maximum_size
		, std::string& error)
	{
		TORRENT_ASSERT(maximum_size > 0);

		int header_len = gzip_header(in, size);
		if (header_len < 0)
		{
			error = "invalid gzip header in tracker response";
			return true;
		}

		// start off with one kilobyte and grow
		// if needed
		buffer.resize(1024);

		// initialize the zlib-stream
		z_stream str;

		// subtract 8 from the end of the buffer since that's CRC32 and input size
		// and those belong to the gzip file
		str.avail_in = (int)size - header_len - 8;
		str.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(in + header_len));
		str.next_out = reinterpret_cast<Bytef*>(&buffer[0]);
		str.avail_out = (int)buffer.size();
		str.zalloc = Z_NULL;
		str.zfree = Z_NULL;
		str.opaque = 0;
		// -15 is really important. It will make inflate() not look for a zlib header
		// and just deflate the buffer
		if (inflateInit2(&str, -15) != Z_OK)
		{
			error = "gzip out of memory";
			return true;
		}

		// inflate and grow inflate_buffer as needed
		int ret = inflate(&str, Z_SYNC_FLUSH);
		while (ret == Z_OK)
		{
			if (str.avail_out == 0)
			{
				if (buffer.size() >= (unsigned)maximum_size)
				{
					inflateEnd(&str);
					error = "response too large";
					return true;
				}
				int new_size = (int)buffer.size() * 2;
				if (new_size > maximum_size)
					new_size = maximum_size;
				int old_size = (int)buffer.size();

				buffer.resize(new_size);
				str.next_out = reinterpret_cast<Bytef*>(&buffer[old_size]);
				str.avail_out = new_size - old_size;
			}

			ret = inflate(&str, Z_SYNC_FLUSH);
		}

		buffer.resize(buffer.size() - str.avail_out);
		inflateEnd(&str);

		if (ret != Z_STREAM_END)
		{
			error = "gzip error";
			return true;
		}

		// commit the resulting buffer
		return false;
	}

}

<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : A.cpp
 * Author  : Kazune Takahashi
 * Created : 11/2/2019, 1:43:18 PM
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

constexpr int MOD{40};

using Point = tuple<int, int>;
Point operator+(Point const &lhs, Point const &rhs)
{
  return Point((get<0>(lhs) + get<0>(rhs) + MOD) % MOD, (get<1>(lhs) + get<1>(rhs) + MOD) % MOD);
}

constexpr int dx[4] = {-1, 1, 0, 0};
constexpr int dy[4] = {0, 0, -1, 1};
constexpr char direction[4] = {'U', 'D', 'L', 'R'};
constexpr int reverse_direction[4] = {1, 0, 3, 2};

enum class State
{
  Empty,
  Robot,
  Block,
  Goal,
  Invalid
};

class Field
{
public:
  static int N;
  int M, B;
  static vector<Point> V;
  static vector<vector<Point>> P;
  vector<vector<int>> D;
  vector<vector<State>> S;

  Field();
  void solve()
  {
    good_place();
    other_place();
    fill_empty();
  }
  void flush();

  State get_state(Point const &p) const
  {
    return S[get<0>(p)][get<1>(p)];
  }

  State &set_state(Point const &p, State s)
  {
    return S[get<0>(p)][get<1>(p)] = s;
  }

  int get_direction(Point const &p) const
  {
    return D[get<0>(p)][get<1>(p)];
  }

  int &set_direction(Point const &p, int d)
  {
    return D[get<0>(p)][get<1>(p)] = d;
  }

private:
  void good_place();
  void other_place();
  void fill_empty();
};

int Field::N;
vector<Point> Field::V;
vector<vector<Point>> Field::P;

Field::Field()
{
  cin >> M >> B;
  D = vector<vector<int>>(N, vector<int>(N, -1));
  S = vector<vector<State>>(N, vector<State>(N, State::Empty));
  int gx, gy;
  cin >> gx >> gy;
  int x, y;
  char c;
  for (auto i = 0; i < M; i++)
  {
    cin >> x >> y >> c;
    S[x][y] = State::Robot;
  }
  for (auto i = 0; i < B; i++)
  {
    cin >> x >> y;
    S[x][y] = State::Block;
  }
  S[gx][gy] = State::Goal;
}

void Field::good_place()
{
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      if (S[i][j] == State::Robot)
      {
        for (auto k = 0; k < 4; k++)
        {
          Point p{P[i][j] + V[k]};
          State s{get_state(p)};
          if (s == State::Block || s == State::Robot)
          {
            D[i][j] = k;
            break;
          }
        }
      }
    }
  }
}

void Field::other_place()
{
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      if (S[i][j] == State::Robot && D[i][j] == -1)
      {
        for (auto k = 0; k < 4; k++)
        {
          Point p{P[i][j] + V[k]};
          int d{get_direction(p)};
          // State s{get_state(p)};
          if (d != -1)
          {
            D[i][j] = k;
            break;
          }
        }
        if (D[i][j] != -1)
        {
          continue;
        }
        for (auto k = 0; k < 4; k++)
        {
          Point p{P[i][j] + V[k]};
          // int d{get_direction(p)};
          State s{get_state(p)};
          if (s == State::Empty)
          {
            D[i][j] = k;
            if (get_direction(p) == -1)
            {
              set_direction(p, reverse_direction[k]);
            }
            break;
          }
        }
        assert(D[i][j] != -1);
      }
    }
  }
}

void Field::fill_empty()
{
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      if (D[i][j] == -1)
      {
        D[i][j] = 0;
      }
    }
  }
}

void Field::flush()
{
  int K{N * N};
  cout << K << endl;
  for (auto x = 0; x < N; x++)
  {
    for (auto y = 0; y < N; y++)
    {
      assert(0 <= D[x][y] && D[x][y] < 4);
      cout << x << " " << y << " " << direction[D[x][y]] << endl;
    }
  }
}

int main()
{
  cin >> Field::N;
  for (auto i = 0; i < 4; i++)
  {
    Field::V.push_back(Point{dy[i], dx[i]});
  }
  Field::P = vector<vector<Point>>(Field::N, vector<Point>(Field::N));
  for (auto i = 0; i < Field::N; i++)
  {
    for (auto j = 0; j < Field::N; j++)
    {
      Field::P[i][j] = Point{i, j};
    }
  }
  Field f;
  f.solve();
  f.flush();
}<commit_msg>submit A.cpp to 'A - ロボットの誘導' (future-contest-2020-qual) [C++14 (GCC 5.4.1)]<commit_after>#define DEBUG 1
/**
 * File    : A.cpp
 * Author  : Kazune Takahashi
 * Created : 11/2/2019, 1:43:18 PM
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

constexpr int MOD{40};

using Point = tuple<int, int>;
Point operator+(Point const &lhs, Point const &rhs)
{
  return Point((get<0>(lhs) + get<0>(rhs) + MOD) % MOD, (get<1>(lhs) + get<1>(rhs) + MOD) % MOD);
}

constexpr int dx[4] = {-1, 1, 0, 0};
constexpr int dy[4] = {0, 0, -1, 1};
constexpr char direction[4] = {'U', 'D', 'L', 'R'};
constexpr int reverse_direction[4] = {1, 0, 3, 2};

enum class State
{
  Empty,
  Robot,
  Block,
  Goal,
  Invalid
};

class Field
{
public:
  static int N;
  int M, B;
  static vector<Point> V;
  static vector<vector<Point>> P;
  vector<vector<int>> D;
  vector<vector<State>> S;

  Field();
  void solve()
  {
    good_place();
    other_place();
    // fill_empty();
  }
  void flush();

  State get_state(Point const &p) const
  {
    return S[get<0>(p)][get<1>(p)];
  }

  State &set_state(Point const &p, State s)
  {
    return S[get<0>(p)][get<1>(p)] = s;
  }

  int get_direction(Point const &p) const
  {
    return D[get<0>(p)][get<1>(p)];
  }

  int &set_direction(Point const &p, int d)
  {
    return D[get<0>(p)][get<1>(p)] = d;
  }

private:
  void good_place();
  void other_place();
  void fill_empty();
};

int Field::N;
vector<Point> Field::V;
vector<vector<Point>> Field::P;

Field::Field()
{
  cin >> M >> B;
  D = vector<vector<int>>(N, vector<int>(N, -1));
  S = vector<vector<State>>(N, vector<State>(N, State::Empty));
  int gx, gy;
  cin >> gx >> gy;
  int x, y;
  char c;
  for (auto i = 0; i < M; i++)
  {
    cin >> x >> y >> c;
    S[x][y] = State::Robot;
  }
  for (auto i = 0; i < B; i++)
  {
    cin >> x >> y;
    S[x][y] = State::Block;
  }
  S[gx][gy] = State::Goal;
}

void Field::good_place()
{
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      if (S[i][j] == State::Robot)
      {
        for (auto k = 0; k < 4; k++)
        {
          Point p{P[i][j] + V[k]};
          State s{get_state(p)};
          if (s == State::Block || s == State::Robot)
          {
            D[i][j] = k;
            break;
          }
        }
      }
    }
  }
}

void Field::other_place()
{
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      if (S[i][j] == State::Robot && D[i][j] == -1)
      {
        for (auto k = 0; k < 4; k++)
        {
          Point p{P[i][j] + V[k]};
          int d{get_direction(p)};
          // State s{get_state(p)};
          if (d != -1)
          {
            D[i][j] = k;
            break;
          }
        }
        if (D[i][j] != -1)
        {
          continue;
        }
        for (auto k = 0; k < 4; k++)
        {
          Point p{P[i][j] + V[k]};
          // int d{get_direction(p)};
          State s{get_state(p)};
          if (s == State::Empty)
          {
            D[i][j] = k;
            if (get_direction(p) == -1)
            {
              set_direction(p, reverse_direction[k]);
            }
            break;
          }
        }
        assert(D[i][j] != -1);
      }
    }
  }
}

void Field::fill_empty()
{
  for (auto i = 0; i < N; i++)
  {
    for (auto j = 0; j < N; j++)
    {
      if (D[i][j] == -1)
      {
        D[i][j] = 0;
      }
    }
  }
}

void Field::flush()
{
  int K{0};
  for (auto x = 0; x < N; x++)
  {
    for (auto y = 0; y < N; y++)
    {
      if (0 <= D[x][y] && D[x][y] < 4)
      {
        ++K;
      }
    }
  }
  cout << K << endl;
  for (auto x = 0; x < N; x++)
  {
    for (auto y = 0; y < N; y++)
    {
      if (0 <= D[x][y] && D[x][y] < 4)
      {
        cout << x << " " << y << " " << direction[D[x][y]] << endl;
      }
    }
  }
}

int main()
{
  cin >> Field::N;
  for (auto i = 0; i < 4; i++)
  {
    Field::V.push_back(Point{dy[i], dx[i]});
  }
  Field::P = vector<vector<Point>>(Field::N, vector<Point>(Field::N));
  for (auto i = 0; i < Field::N; i++)
  {
    for (auto j = 0; j < Field::N; j++)
    {
      Field::P[i][j] = Point{i, j};
    }
  }
  Field f;
  f.solve();
  f.flush();
}<|endoftext|>


<commit_before>//
// Copyright (C) 2015 Red Hat, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Authors: Daniel Kopecek <dkopecek@redhat.com>
//
#include "Logger.hpp"
#include "Exceptions.hpp"
#include <sys/types.h>
#include <unistd.h>

namespace pgl
{
  /* Instantiate the logger */
  Logger G_logger;

  LogStream::LogStream(Logger& logger, const std::string& file, int line,
      const std::string& function)
    : _logger(logger), _file(file), _line(line), _function(function)
  {
  }

  LogStream::LogStream(const LogStream& rhs)
    : _logger(rhs._logger), _file(rhs._file), _line(rhs._line),
    _function(rhs._function)
  {
  }

  LogStream::~LogStream()
  {
    _logger.write(_file, _line, _function, str());
  }

  Logger::Logger()
  {
    const char * const envval = getenv("PGL_DEBUG");
    _enabled = false;
    /*
     * If PGL_DEBUG=1 is set in the current environment, then
     * open the log file stream and mark the logger as active.
     */
    if (envval != nullptr && strcmp(envval, "1") == 0) {
      _path = "pgl-debug.";
      _path += std::to_string(getpid());
      _path += ".log";
      _stream.open(_path);
      _enabled = true;
    }
  }

  Logger::~Logger()
  {
    if (isEnabled()) {
      _stream.close();
      _enabled = false;
    }
  }

  bool Logger::isEnabled() const
  {
    return _enabled;
  }

  LogStream Logger::operator()(const std::string& file, const int line,
      const std::string& function)
  {
    return LogStream(*this, file, line, function);
  }

  void Logger::write(const std::string& file, int line, const std::string& func,
      const std::string& message)
  {
    std::unique_lock<std::mutex> lock(_mutex);

    _stream << timestamp() << " "
      << file << " "
      << line << " "
      << func << " "
      << ": " << message << std::endl;

    return;
  }

  /*
   * Generate a timestamp string in the form:
   * <seconds>.<microseconds>
   */
  const std::string Logger::timestamp()
  {
    struct timeval tv_now = { 0, 0 };

    if (gettimeofday(&tv_now, nullptr) != 0) {
      throw SyscallError("gettimeofday", errno, /*nolog=*/true);
    }

    return std::to_string(tv_now.tv_sec) \
      + "." + std::to_string(tv_now.tv_usec);
  }

} /* namespace pgl */

<commit_msg>Added missing include<commit_after>//
// Copyright (C) 2015 Red Hat, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Authors: Daniel Kopecek <dkopecek@redhat.com>
//
#include "Logger.hpp"
#include "Exceptions.hpp"
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

namespace pgl
{
  /* Instantiate the logger */
  Logger G_logger;

  LogStream::LogStream(Logger& logger, const std::string& file, int line,
      const std::string& function)
    : _logger(logger), _file(file), _line(line), _function(function)
  {
  }

  LogStream::LogStream(const LogStream& rhs)
    : _logger(rhs._logger), _file(rhs._file), _line(rhs._line),
    _function(rhs._function)
  {
  }

  LogStream::~LogStream()
  {
    _logger.write(_file, _line, _function, str());
  }

  Logger::Logger()
  {
    const char * const envval = getenv("PGL_DEBUG");
    _enabled = false;
    /*
     * If PGL_DEBUG=1 is set in the current environment, then
     * open the log file stream and mark the logger as active.
     */
    if (envval != nullptr && strcmp(envval, "1") == 0) {
      _path = "pgl-debug.";
      _path += std::to_string(getpid());
      _path += ".log";
      _stream.open(_path);
      _enabled = true;
    }
  }

  Logger::~Logger()
  {
    if (isEnabled()) {
      _stream.close();
      _enabled = false;
    }
  }

  bool Logger::isEnabled() const
  {
    return _enabled;
  }

  LogStream Logger::operator()(const std::string& file, const int line,
      const std::string& function)
  {
    return LogStream(*this, file, line, function);
  }

  void Logger::write(const std::string& file, int line, const std::string& func,
      const std::string& message)
  {
    std::unique_lock<std::mutex> lock(_mutex);

    _stream << timestamp() << " "
      << file << " "
      << line << " "
      << func << " "
      << ": " << message << std::endl;

    return;
  }

  /*
   * Generate a timestamp string in the form:
   * <seconds>.<microseconds>
   */
  const std::string Logger::timestamp()
  {
    struct timeval tv_now = { 0, 0 };

    if (gettimeofday(&tv_now, nullptr) != 0) {
      throw SyscallError("gettimeofday", errno, /*nolog=*/true);
    }

    return std::to_string(tv_now.tv_sec) \
      + "." + std::to_string(tv_now.tv_usec);
  }

} /* namespace pgl */

<|endoftext|>