<commit_before>#include "../MDFILU_test.h"

int
main(int argc, char *argv[])
{
  // #ifdef VERBOSE_OUTPUT
  //   debugStream.open("debug.out");
  // #endif

  Utilities::MPI::MPI_InitFinalize mpi_initialization(
    argc, argv, ::numbers::invalid_unsigned_int);
  const global_index_type degree(10);
  const unsigned int      estimated_row_length(10);
  SourceMatrix            system_matrix(degree,
                             degree,
                             /*max_entries_per_row*/ estimated_row_length);

  // Set value for system_matrix
  const bool use_sparse_matrix(true);
  if (use_sparse_matrix)
    {
      std::ifstream fin("sparse_matrix.dat");
      while (true)
        {
          global_index_type i, j;
          data_type         value;
          fin >> i >> j >> value;
          if (fin.eof())
            {
              break;
            }
          system_matrix.set(i, j, value);
        }
      fin.close();
    }
  else
    {
      std::ifstream fin("matrix.dat");
      for (global_index_type i = 0; i < degree; ++i)
        for (global_index_type j = 0; j < degree; ++j)
          {
            data_type value;
            fin >> value;
            system_matrix.set(i, j, value);
          }
      fin.close();
    }

  system_matrix.compress(VectorOperation::insert);
  {
    // Out put system_matrix
    std::ofstream fout("matrix.out");
    system_matrix.print(fout);
    fout.close();
  }
  MDFILU mdfilu(system_matrix, estimated_row_length, 20);

  // Out put LU
  {
    std::ofstream fout("LU.out");
    mdfilu.get_LU().print(fout);
    fout.close();
  }

  // Test the MDFILU class by multiplying LU back
  // For now the sparsity pattern is ignored.
  {
    const data_type tolerance(1e-12);
    DynamicMatrix   A(degree, degree, estimated_row_length);
    // Compute LD*U
    for (global_index_type i = 0; i < degree; ++i)
      {
        const global_index_type i_row = mdfilu.get_permutation()[i];
        for (global_index_type j = 0; j < degree; ++j)
          {
            const global_index_type j_col = mdfilu.get_permutation()[j];
            data_type               value = 0;
            global_index_type       vmult_max_index = 0;
            // Diagonal values of L is always 1 thus not been stored.
            // Recover its effect manually.
            if (j >= i)
              {
                value           = mdfilu.get_LU().el(i_row, j_col);
                vmult_max_index = i;
              }
            else
              {
                vmult_max_index = j + 1;
              }
            for (global_index_type k = 0; k < vmult_max_index; ++k)
              {
                const global_index_type k_permuted =
                  mdfilu.get_permutation()[k];
                value += mdfilu.get_LU().el(i_row, k_permuted) *
                         mdfilu.get_LU().el(k_permuted, j_col);
              }
            if (std::abs(value) > tolerance)
              {
                A.set(i_row, j_col, value);
              }
          }
      }
    std::ofstream fout("A.out");
    A.print(fout);
    fout.close();
  }

  // Report number of new fill-ins
  {
    std::ofstream fout("apply.out");
    fout << "\nNumber of new fill-ins: " << mdfilu.number_of_new_fill_ins()
         << std::endl
         << std::endl;
    fout.close();
  }

  // Apply LU and (LU)^-1 to a vector
  MDFVector v(degree);
  {
    const data_type a[degree] = {6, 10, 9, 5, 2, 5, 7, 3, 6, 3};

    for (global_index_type i = 0; i < degree; ++i)
      {
        v[i] = a[i];
      }
  }

  // Cache initial transpose status
  const bool use_tranpose_init_stats = mdfilu.UseTranspose();
  //--------- Deal.II native Vector ---------//
  mdfilu.SetUseTranspose(false);
  {
    MDFVector o(v);
    mdfilu.apply(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector (LU)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }
  {
    MDFVector o(v);
    mdfilu.apply_inverse(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector ((LU)^-1)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }

  mdfilu.SetUseTranspose(true);
  {
    MDFVector o(v);
    mdfilu.apply(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector ((LU)^T)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }
  {
    MDFVector o(v);
    mdfilu.apply_inverse(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector (((LU)^-1)^T)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }
  // Set flags
  mdfilu.SetUseTranspose(use_tranpose_init_stats);
  //[END]// //--------- Deal.II native Vector ---------//
  //--------- Deal.II wrapped Trilinos Vector ---------//
  mdfilu.SetUseTranspose(false);
  {
    NSVector o;
    o = v;
    mdfilu.apply(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout << "Vector v:" << std::endl;
    fout << v;
    fout << "NSVector (LU)*v:" << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  {
    NSVector o;
    o = v;
    mdfilu.apply_inverse(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout << "Vector v:" << std::endl;
    fout << v;
    fout << "NSVector ((LU)^-1)*v:" << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }

  mdfilu.SetUseTranspose(true);
  {
    NSVector o;
    o = v;
    mdfilu.apply(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout << "Vector v:" << std::endl;
    fout << v;
    fout << "NSVector ((LU)^T)*v:" << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  {
    NSVector o;
    o = v;
    mdfilu.apply_inverse(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout << "Vector v:" << std::endl;
    fout << v;
    fout << "NSVector (((LU)^-1)^T)*v:" << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  mdfilu.SetUseTranspose(use_tranpose_init_stats);
  //[END]// //--------- Deal.II wrapped Trilinos Vector ---------//

  //--------- Finally, Preconditioner test ---------//
  {
    // No preconditioner first
    Epetra_Vector o(system_matrix.trilinos_matrix().DomainMap());
    Epetra_Vector b(View,
                    system_matrix.trilinos_matrix().RangeMap(),
                    v.begin());
    AztecOO       solver;
    solver.SetAztecOption(AZ_output, AZ_none);
    solver.SetAztecOption(AZ_solver, AZ_gmres);
    solver.SetLHS(&o);
    solver.SetRHS(&b);

    solver.SetAztecOption(AZ_precond, AZ_none);
    solver.SetUserMatrix(
      const_cast<Epetra_CrsMatrix *>(&system_matrix.trilinos_matrix()));

    const unsigned int max_iterations  = 1000;
    const double       linear_residual = 1e-8;
    solver.Iterate(max_iterations, linear_residual);

    std::ofstream fout("apply.out", std::fstream::app);
    fout << "GMRES Solved Ax=v without preconditioner:" << std::endl;
    fout << "NumIters: " << solver.NumIters() << std::endl;
    fout << "TrueResidual: " << solver.TrueResidual() << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  {
    // No preconditioner first
    Epetra_Vector o(system_matrix.trilinos_matrix().DomainMap());
    Epetra_Vector b(View,
                    system_matrix.trilinos_matrix().RangeMap(),
                    v.begin());
    AztecOO       solver;
    solver.SetAztecOption(AZ_output, AZ_none);
    solver.SetAztecOption(AZ_solver, AZ_gmres);
    solver.SetLHS(&o);
    solver.SetRHS(&b);

    solver.SetUserMatrix(
      const_cast<Epetra_CrsMatrix *>(&system_matrix.trilinos_matrix()));

    mdfilu.SetUseTranspose(false);
    solver.SetPrecOperator(&mdfilu);

    const unsigned int max_iterations  = 1000;
    const double       linear_residual = 1e-8;
    solver.Iterate(max_iterations, linear_residual);

    std::ofstream fout("apply.out", std::fstream::app);
    fout << "GMRES Solved Ax=v with MDFILU preconditioner:" << std::endl;
    fout << "NumIters: " << solver.NumIters() << std::endl;
    fout << "TrueResidual: " << solver.TrueResidual() << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  mdfilu.SetUseTranspose(use_tranpose_init_stats);
  //[END]// //--------- Finally, Preconditioner test ---------//

  // #ifdef VERBOSE_OUTPUT
  //   debugStream.close();
  // #endif
  return (system("cat  A.out  apply.out  LU.out  matrix.out  > output.out"));
}
<commit_msg>fix regTests module_MDFILU case002000 due to trilinos vector interface change<commit_after>#include "../MDFILU_test.h"

int
main(int argc, char *argv[])
{
  // #ifdef VERBOSE_OUTPUT
  //   debugStream.open("debug.out");
  // #endif

  Utilities::MPI::MPI_InitFinalize mpi_initialization(
    argc, argv, ::numbers::invalid_unsigned_int);
  const global_index_type degree(10);
  const unsigned int      estimated_row_length(10);
  SourceMatrix            system_matrix(degree,
                             degree,
                             /*max_entries_per_row*/ estimated_row_length);

  // Set value for system_matrix
  const bool use_sparse_matrix(true);
  if (use_sparse_matrix)
    {
      std::ifstream fin("sparse_matrix.dat");
      while (true)
        {
          global_index_type i, j;
          data_type         value;
          fin >> i >> j >> value;
          if (fin.eof())
            {
              break;
            }
          system_matrix.set(i, j, value);
        }
      fin.close();
    }
  else
    {
      std::ifstream fin("matrix.dat");
      for (global_index_type i = 0; i < degree; ++i)
        for (global_index_type j = 0; j < degree; ++j)
          {
            data_type value;
            fin >> value;
            system_matrix.set(i, j, value);
          }
      fin.close();
    }

  system_matrix.compress(VectorOperation::insert);
  {
    // Out put system_matrix
    std::ofstream fout("matrix.out");
    system_matrix.print(fout);
    fout.close();
  }
  MDFILU mdfilu(system_matrix, estimated_row_length, 20);

  // Out put LU
  {
    std::ofstream fout("LU.out");
    mdfilu.get_LU().print(fout);
    fout.close();
  }

  // Test the MDFILU class by multiplying LU back
  // For now the sparsity pattern is ignored.
  {
    const data_type tolerance(1e-12);
    DynamicMatrix   A(degree, degree, estimated_row_length);
    // Compute LD*U
    for (global_index_type i = 0; i < degree; ++i)
      {
        const global_index_type i_row = mdfilu.get_permutation()[i];
        for (global_index_type j = 0; j < degree; ++j)
          {
            const global_index_type j_col = mdfilu.get_permutation()[j];
            data_type               value = 0;
            global_index_type       vmult_max_index = 0;
            // Diagonal values of L is always 1 thus not been stored.
            // Recover its effect manually.
            if (j >= i)
              {
                value           = mdfilu.get_LU().el(i_row, j_col);
                vmult_max_index = i;
              }
            else
              {
                vmult_max_index = j + 1;
              }
            for (global_index_type k = 0; k < vmult_max_index; ++k)
              {
                const global_index_type k_permuted =
                  mdfilu.get_permutation()[k];
                value += mdfilu.get_LU().el(i_row, k_permuted) *
                         mdfilu.get_LU().el(k_permuted, j_col);
              }
            if (std::abs(value) > tolerance)
              {
                A.set(i_row, j_col, value);
              }
          }
      }
    std::ofstream fout("A.out");
    A.print(fout);
    fout.close();
  }

  // Report number of new fill-ins
  {
    std::ofstream fout("apply.out");
    fout << "\nNumber of new fill-ins: " << mdfilu.number_of_new_fill_ins()
         << std::endl
         << std::endl;
    fout.close();
  }

  // Apply LU and (LU)^-1 to a vector
  MDFVector v(degree);
  {
    const data_type a[degree] = {6, 10, 9, 5, 2, 5, 7, 3, 6, 3};

    for (global_index_type i = 0; i < degree; ++i)
      {
        v[i] = a[i];
      }
  }

  // Cache initial transpose status
  const bool use_tranpose_init_stats = mdfilu.UseTranspose();
  //--------- Deal.II native Vector ---------//
  mdfilu.SetUseTranspose(false);
  {
    MDFVector o(v);
    mdfilu.apply(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector (LU)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }
  {
    MDFVector o(v);
    mdfilu.apply_inverse(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector ((LU)^-1)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }

  mdfilu.SetUseTranspose(true);
  {
    MDFVector o(v);
    mdfilu.apply(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector ((LU)^T)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }
  {
    MDFVector o(v);
    mdfilu.apply_inverse(o, o);
    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "Vector (((LU)^-1)^T)*v:" << std::endl;
    fout << o << std::endl << std::endl;
    fout.close();
  }
  // Set flags
  mdfilu.SetUseTranspose(use_tranpose_init_stats);
  //[END]// //--------- Deal.II native Vector ---------//
  //--------- Deal.II wrapped Trilinos Vector ---------//
  {
    mdfilu.SetUseTranspose(false);

    std::ofstream fout("apply.out", std::fstream::app);
    fout.precision(3);
    fout << std::scientific;

    IndexSet idxset(degree);
    idxset.add_range(0, degree);
    NSVector o(idxset);

    o = v;
    mdfilu.apply(o, o);
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "NSVector (LU)*v:" << std::endl;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;

    o = v;
    mdfilu.apply_inverse(o, o);
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "NSVector ((LU)^-1)*v:" << std::endl;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;

    // Begain transplose
    mdfilu.SetUseTranspose(true);

    o = v;
    mdfilu.apply(o, o);
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "NSVector ((LU)^T)*v:" << std::endl;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;

    o = v;
    mdfilu.apply_inverse(o, o);
    fout << "Vector v:" << std::endl;
    fout << v << std::endl;
    fout << "NSVector (((LU)^-1)^T)*v:" << std::endl;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;

    fout.close();
  }
  mdfilu.SetUseTranspose(use_tranpose_init_stats);
  //[END]// //--------- Deal.II wrapped Trilinos Vector ---------//

  //--------- Finally, Preconditioner test ---------//
  {
    // No preconditioner first
    Epetra_Vector o(system_matrix.trilinos_matrix().DomainMap());
    Epetra_Vector b(View,
                    system_matrix.trilinos_matrix().RangeMap(),
                    v.begin());
    AztecOO       solver;
    solver.SetAztecOption(AZ_output, AZ_none);
    solver.SetAztecOption(AZ_solver, AZ_gmres);
    solver.SetLHS(&o);
    solver.SetRHS(&b);

    solver.SetAztecOption(AZ_precond, AZ_none);
    solver.SetUserMatrix(
      const_cast<Epetra_CrsMatrix *>(&system_matrix.trilinos_matrix()));

    const unsigned int max_iterations  = 1000;
    const double       linear_residual = 1e-8;
    solver.Iterate(max_iterations, linear_residual);

    std::ofstream fout("apply.out", std::fstream::app);
    fout << "GMRES Solved Ax=v without preconditioner:" << std::endl;
    fout << "NumIters: " << solver.NumIters() << std::endl;
    fout << "TrueResidual: " << solver.TrueResidual() << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  {
    // No preconditioner first
    Epetra_Vector o(system_matrix.trilinos_matrix().DomainMap());
    Epetra_Vector b(View,
                    system_matrix.trilinos_matrix().RangeMap(),
                    v.begin());
    AztecOO       solver;
    solver.SetAztecOption(AZ_output, AZ_none);
    solver.SetAztecOption(AZ_solver, AZ_gmres);
    solver.SetLHS(&o);
    solver.SetRHS(&b);

    solver.SetUserMatrix(
      const_cast<Epetra_CrsMatrix *>(&system_matrix.trilinos_matrix()));

    mdfilu.SetUseTranspose(false);
    solver.SetPrecOperator(&mdfilu);

    const unsigned int max_iterations  = 1000;
    const double       linear_residual = 1e-8;
    solver.Iterate(max_iterations, linear_residual);

    std::ofstream fout("apply.out", std::fstream::app);
    fout << "GMRES Solved Ax=v with MDFILU preconditioner:" << std::endl;
    fout << "NumIters: " << solver.NumIters() << std::endl;
    fout << "TrueResidual: " << solver.TrueResidual() << std::endl;
    fout.precision(3);
    fout << std::scientific;
    for (global_index_type i = 0; i < degree; ++i)
      {
        fout << o[i] << ' ';
      }
    fout << std::endl << std::endl;
    fout.close();
  }
  mdfilu.SetUseTranspose(use_tranpose_init_stats);
  //[END]// //--------- Finally, Preconditioner test ---------//

  // #ifdef VERBOSE_OUTPUT
  //   debugStream.close();
  // #endif
  return (system("cat  A.out  apply.out  LU.out  matrix.out  > output.out"));
}
<|endoftext|>


<commit_before>#include<iostream>
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
#include"opencv2/core/core.hpp"
#include <fstream>

using namespace cv;
using namespace std;

//Input Mat, and Scalar bounds for thresholding.
Mat src;
Scalar upperBound;
Scalar lowerBound;

//Mode variables. Defaulted at -1 for checking.
int colorMode=-1; //0 for HSV, 1 for RGB.
int inputMode=-1; //0 FOr webcam, 1 for video file.

//File path variables
int videoFilePath;

//capture variables;
bool capture = false;
int captureNum= 0;
ofstream outCenter;
ofstream outMoment;
ofstream outMouse;

int mouseX;
int mouseY;

void onMove(int, void *);
void onClickOriginal(int, int, int, int, void *);
void saveFrame(Mat, Mat, int);
void centerMoment(Mat, int &, int &);
void centerFind(Mat, int &, int &);

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

	//Input parsing to select color mode, input mode and anything else needed.
	if(argc > 1){
		int num=1;

		while(num < argc){

			string input= argv[num];

			//Help text.
			if(input == "-help" || input == "-h" || input == "-H"){
		                cout<<"Available options for v5:"<<endl;
		                cout<<"-w       Use a webcam input"<<endl;
		                cout<<"-f       Use a video file (Follow with a valid file path)"<<endl;
        		        cout<<"-HSV     Use HSV images and values to preform thresholding"<<endl;
		                cout<<"-RGB     Use RGB images and values to preofrm thresholding"<<endl;

			}
			else if(input == "-w" || input == "-W"){
				inputMode=0;
			}
			else if(input == "-v" || input == "-V"){
				if((num+1) <argc){
					inputMode=1;
					videoFilePath=num+1;
					num++;
				}
				else
					cout<<"Please follow -v with a path to a video file.";
			}
			else if(input== "-HSV" || input == "-hsv"){
				colorMode=0;
			}
			else if(input== "-RGB" || input == "-rgb"){
				colorMode=1;
			}
			else{
				cout<<"Unrecognized option"<<endl;
			}

			num++;
		}

	}
	//If there is no input, simply use defaults: webcam input and HSV color mode.
	else{
		colorMode= 0;
		inputMode= 0;
	}

	if(colorMode ==-1)
		colorMode=0;
	if(inputMode == -1)
		inputMode = 0;

	//Input completed, now we move to the real stuff.

	//Open the selected input.
	VideoCapture cap;

	if(inputMode ==0)
		cap.open(0);
	else if(inputMode ==1)
		cap.open(argv[videoFilePath]);

	//If some error happens with video input, show an error message.
	if(!cap.isOpened()){
		cerr<< "Was unable to open video input."<<endl;
		if(inputMode ==1)
			cerr<<"Filepath inputed ="<<argv[videoFilePath]<<endl<<"Please input a valid filepath."<<endl;
		else
			cerr<<"Please check your input method."<<endl;

		return -1;
	}

	//Create our three windows for control of the threshold, display of the original image, and the display of the thresholded image.

	namedWindow("Control", CV_WINDOW_AUTOSIZE);
	namedWindow("Thresholded", CV_WINDOW_AUTOSIZE);
	namedWindow("Original", CV_WINDOW_AUTOSIZE);

	//Variables for holding the trackbar values.  We need 6, whether we're using HSV or RGB, though the max values for the hiA variable are different.
	int lowA =0;
	int hiA;
	if(colorMode == 0)
		hiA = 179;
	else if(colorMode ==1)
		hiA = 255;
	int lowB= 0;
	int hiB = 255;
	int lowC = 0;
	int hiC = 255;

	//Initial values for the threshold ranges.
	lowerBound = Scalar(lowA, lowB, lowC);
	upperBound = Scalar(hiA, hiB, hiC);

	//Create relevent trackbars based on colorMode.
	if(colorMode == 0){
		createTrackbar("Low H", "Control", &lowA, 179, onMove, (void*) (0));
		createTrackbar("High H", "Control", &hiA, 179, onMove, (void*) (1));
	        createTrackbar("Low S", "Control", &lowB, 255, onMove, (void*) (2));
	        createTrackbar("High S", "Control", &hiB, 255, onMove, (void*) (3));
	        createTrackbar("Low V", "Control", &lowC, 255, onMove, (void*) (4));
	        createTrackbar("High V", "Control", &hiC, 255, onMove, (void*) (5));

	}
	else if(colorMode == 1){
		createTrackbar("Low R", "Control", &lowA, 255, onMove, (void*) (0));
                createTrackbar("High R", "Control", &hiA, 255, onMove, (void*) (1));
	        createTrackbar("Low G", "Control", &lowB, 255, onMove, (void*) (2));
	        createTrackbar("High G", "Control", &hiB, 255, onMove, (void*) (3));
       		createTrackbar("Low B", "Control", &lowC, 255, onMove, (void*) (4));
	        createTrackbar("High B", "Control", &hiC, 255, onMove, (void*) (5));

	}

	setMouseCallback("Original", onClickOriginal, NULL);

	int frameNum = 0;
	int blobX=-1;
	int blobY=-1;
	//Loop runs until you can't get another frame from the video source, or a user presses escape.

	while(true){

		bool success = cap.read(src);
		if(!success){
			cerr<<"Cannot read frame from video stream"<<endl;
			break;
		}

		//Do color conversion based on colorMOde
		Mat colorImg;
		if(colorMode == 0)
			cvtColor(src, colorImg, COLOR_BGR2HSV);
		else if(colorMode == 1)
			colorImg=src;

		Mat thresholdedImg;

  		inRange(colorImg, lowerBound, upperBound, thresholdedImg);

	        //morphological opening
       		erode(thresholdedImg,thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
	       	dilate(thresholdedImg, thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );

	        //morphological closing
        	dilate(thresholdedImg, thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
	        erode(thresholdedImg, thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );

		centerMoment(thresholdedImg,blobX, blobY);
		//centerFind(thresholdedImg,0, 0);

		rectangle(src, Point(blobX +50, blobY+50), Point(blobX-50, blobY-50),Scalar(93, 240, 76),  CV_FILLED, 8,0);

		//Show images.
		imshow("Original", src);
		imshow("Thresholded", thresholdedImg);

		//Set trackbar variables to reflect any changes that may have happened to the thresholder values.
		if(colorMode ==0){
			setTrackbarPos("Low H", "Control", lowerBound[0]);
			setTrackbarPos("High H", "Control", upperBound[0]);
			setTrackbarPos("Low S", "Control", lowerBound[1]);
			setTrackbarPos("High S", "Control", upperBound[1]);
			setTrackbarPos("Low V", "Control", lowerBound[2]);
			setTrackbarPos("High V", "Control", upperBound[2]);
		}
		else if(colorMode == 1){
			setTrackbarPos("Low R", "Control", lowerBound[0]);
			setTrackbarPos("High R", "Control", upperBound[0]);
			setTrackbarPos("Low G", "Control", lowerBound[1]);
			setTrackbarPos("High G", "Control", upperBound[1]);
			setTrackbarPos("Low B", "Control", lowerBound[2]);
			setTrackbarPos("High B", "Control", upperBound[2]);
		}

		//If user presses ESC, quit stream.
		if(waitKey(5) ==27){
			cerr<<"Video Stream Ended"<<endl;
			break;
		}
		//Begin data capture if user presses C.
		else if(waitKey(5) == 99){
			cout<<"BEGINING DATA CAPTURE. PLEASE MOUSEOVER CENTER LINE"<<endl;
			capture = true;

			outCenter.open("./data/captures/center.dat");
			outMoment.open("./data/captures/moment.dat");
			outMouse.open("./data/captures/mouse.dat");
		}
		//End data capture if user presses E.
		else if(waitKey(5) == 101){
			cout<<"ENDING DATA CAPTURE.  ANALYSIS WILL BE COMPLETE AT PROGRAM END"<<endl;
			capture = false;
			captureNum = 0;

			outCenter.close();
			outMoment.close();
			outMouse.close();
		}

		//Set threshold values to defaults if user presses Enter
		else if(waitKey(5) == 13){
			cout<<"RESETING THRESHOLDS TO DEFAULTS"<<endl;
			lowerBound = Scalar(0,0,0);
			if(colorMode ==0)
				upperBound = Scalar(179, 255, 255);
			else if(colorMode ==1)
				upperBound = Scalar(255, 255, 255);
		}
		//Save frames if user presses s.
		else if(waitKey(5) ==115){
			cout<<"SAVING FRAMES "<<frameNum<<endl;
			saveFrame(src, thresholdedImg, frameNum);
			frameNum++;
		}

		if(capture)
			outMouse<<captureNum<<" "<<mouseX<<" "<<mouseY<<endl;
			captureNum++;
	}
	return 0;
}

//handler for the control trackbars.
void onMove(int val, void * userdata){
	int num	= *((int*)&userdata);

	//Userdata holds the index that we want tos set, so just set the scalar accordingly.
	if(num ==0)
		lowerBound = Scalar(val, lowerBound[1], lowerBound[2]);
	else if(num ==1)
		upperBound = Scalar(val, upperBound[1], upperBound[2]);
        else if(num ==2)
		lowerBound = Scalar(lowerBound[0], val, lowerBound[2]);
        else if(num ==3)
		upperBound = Scalar(upperBound[0], val, upperBound[2]);
        else if(num ==4)
		lowerBound = Scalar(lowerBound[0], lowerBound[1], val);
        else if(num ==5)
		upperBound = Scalar(upperBound[0], upperBound[1], val);

}

//Handles onclick events for the "original" window.
void onClickOriginal(int event, int x, int y, int flags, void * userdata){
	//If the left mouse is clicked,get the average HSV or RGB values from the area and use them for a new set of threshold ranges.
	mouseX = x;
	mouseY = y;
	if(event == EVENT_LBUTTONDOWN){
		Mat COLORimg;
		if(colorMode == 0)
			cvtColor(src, COLORimg, COLOR_BGR2HSV);
		else
			COLORimg=src;
	        Mat ROI= COLORimg (Rect ((x-5), (y-5), 10, 10));

        	Scalar ROImean= mean(ROI);

		//For HSV, use ranges H(14), S(60), V(80).
		if(colorMode ==0){
			lowerBound = Scalar(ROImean[0] - 7, ROImean[1] - 30, ROImean[2] -40);
			upperBound = Scalar(ROImean[0] +7, ROImean[1] +30, ROImean[2] +40);
		}

		//For RGB, use ranges R(20), G(20), B(20). (NEEDS REVISION)
		else if(colorMode ==1){
			lowerBound = Scalar(ROImean[0] -10, ROImean[1] -10, ROImean[2] -10);
			upperBound = Scalar(ROImean[0] +10, ROImean[1] +10, ROImean[2] +10);
		}
	}
}

/*
Save the orignal and thresholded frames after generating a unique filename.
*/
void saveFrame(Mat imgOriginal, Mat imgThresholded, int frameNum){
        String path= "./data/images/";
        String ext= ".png";

        String number;
        ostringstream convert;
        convert << frameNum;
        number= convert.str();

        String original= path+"original";
        String threshed= path+"thresholed";
        original=original+number;
        threshed=threshed+number;
        original=original+ext;
        threshed=threshed+ext;

        vector<int> params;
        params.push_back(CV_IMWRITE_PNG_COMPRESSION);
        params.push_back(9);

        if(!imwrite(original, imgOriginal, params))
                cerr<<"Failed to write original"<<endl;

        if(!imwrite(threshed, imgThresholded, params))
                cerr<<"Failed to write thresholded"<<endl;
}

void centerMoment(Mat img, int & x, int & y){
	Moments oMoments=moments(img);

        double dM01= oMoments.m01;
        double dM10= oMoments.m10;
        double area= oMoments.m00;
        if(area > 10000){
  	      x =dM10/area;
              y= dM01/area;
	}
	if(capture)
		outMoment<<captureNum<<" "<<x<<" "<<y<<endl;

}

void centerFind(Mat img, int & x, int & y){

	uchar a, b, c;
	int firstX, lastX;
	int firstY, lastY;
	firstY= -1;
	lastY=-1;

	for(int i =0; i<img.rows; i++){
		Vec3b * pixel = img.ptr<Vec3b>(i);
		firstX= -1;
		lastX = -1;

		for(int j = 0; j<img.cols; j++){
			a=pixel[j][0];
			b=pixel[j][1];
			c=pixel[j][2];

			int A= (int) a;
			int B = (int) b;
			int C= (int) c;

			if((a >0 || b>0 || c>0)  && capture){
				if(firstX == -1)
					firstX =j;
				else
					lastX = j;

				if(firstY == -1)
					firstY= i;
				else
					lastY=i;
			}
		}

	}
	x = (lastX-firstX)/2 +firstX;
	y = (lastY - firstY)/2 +firstY;
}
<commit_msg>transparent rectangle..which crashes if it cant track.<commit_after>#include<iostream>
#include"opencv2/highgui/highgui.hpp"
#include"opencv2/imgproc/imgproc.hpp"
#include"opencv2/core/core.hpp"
#include <fstream>

using namespace cv;
using namespace std;

//Input Mat, and Scalar bounds for thresholding.
Mat src;
Scalar upperBound;
Scalar lowerBound;

//Mode variables. Defaulted at -1 for checking.
int colorMode=-1; //0 for HSV, 1 for RGB.
int inputMode=-1; //0 FOr webcam, 1 for video file.

//File path variables
int videoFilePath;

//capture variables;
bool capture = false;
int captureNum= 0;
ofstream outCenter;
ofstream outMoment;
ofstream outMouse;

int mouseX;
int mouseY;
bool thresholdSet = false;

void onMove(int, void *);
void onClickOriginal(int, int, int, int, void *);
void saveFrame(Mat, Mat, int);
void centerMoment(Mat, int &, int &);
void centerFind(Mat, int &, int &);

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

	//Input parsing to select color mode, input mode and anything else needed.
	if(argc > 1){
		int num=1;

		while(num < argc){

			string input= argv[num];

			//Help text.
			if(input == "-help" || input == "-h" || input == "-H"){
		                cout<<"Available options for v5:"<<endl;
		                cout<<"-w       Use a webcam input"<<endl;
		                cout<<"-f       Use a video file (Follow with a valid file path)"<<endl;
        		        cout<<"-HSV     Use HSV images and values to preform thresholding"<<endl;
		                cout<<"-RGB     Use RGB images and values to preofrm thresholding"<<endl;

			}
			else if(input == "-w" || input == "-W"){
				inputMode=0;
			}
			else if(input == "-v" || input == "-V"){
				if((num+1) <argc){
					inputMode=1;
					videoFilePath=num+1;
					num++;
				}
				else
					cout<<"Please follow -v with a path to a video file.";
			}
			else if(input== "-HSV" || input == "-hsv"){
				colorMode=0;
			}
			else if(input== "-RGB" || input == "-rgb"){
				colorMode=1;
			}
			else{
				cout<<"Unrecognized option"<<endl;
			}

			num++;
		}

	}
	//If there is no input, simply use defaults: webcam input and HSV color mode.
	else{
		colorMode= 0;
		inputMode= 0;
	}

	if(colorMode ==-1)
		colorMode=0;
	if(inputMode == -1)
		inputMode = 0;

	//Input completed, now we move to the real stuff.

	//Open the selected input.
	VideoCapture cap;

	if(inputMode ==0)
		cap.open(0);
	else if(inputMode ==1)
		cap.open(argv[videoFilePath]);

	//If some error happens with video input, show an error message.
	if(!cap.isOpened()){
		cerr<< "Was unable to open video input."<<endl;
		if(inputMode ==1)
			cerr<<"Filepath inputed ="<<argv[videoFilePath]<<endl<<"Please input a valid filepath."<<endl;
		else
			cerr<<"Please check your input method."<<endl;

		return -1;
	}

	//Create our three windows for control of the threshold, display of the original image, and the display of the thresholded image.

	namedWindow("Control", CV_WINDOW_AUTOSIZE);
	namedWindow("Thresholded", CV_WINDOW_AUTOSIZE);
	namedWindow("Original", CV_WINDOW_AUTOSIZE);

	//Variables for holding the trackbar values.  We need 6, whether we're using HSV or RGB, though the max values for the hiA variable are different.
	int lowA =0;
	int hiA;
	if(colorMode == 0)
		hiA = 179;
	else if(colorMode ==1)
		hiA = 255;
	int lowB= 0;
	int hiB = 255;
	int lowC = 0;
	int hiC = 255;

	//Initial values for the threshold ranges.
	lowerBound = Scalar(lowA, lowB, lowC);
	upperBound = Scalar(hiA, hiB, hiC);

	//Create relevent trackbars based on colorMode.
	if(colorMode == 0){
		createTrackbar("Low H", "Control", &lowA, 179, onMove, (void*) (0));
		createTrackbar("High H", "Control", &hiA, 179, onMove, (void*) (1));
	        createTrackbar("Low S", "Control", &lowB, 255, onMove, (void*) (2));
	        createTrackbar("High S", "Control", &hiB, 255, onMove, (void*) (3));
	        createTrackbar("Low V", "Control", &lowC, 255, onMove, (void*) (4));
	        createTrackbar("High V", "Control", &hiC, 255, onMove, (void*) (5));

	}
	else if(colorMode == 1){
		createTrackbar("Low R", "Control", &lowA, 255, onMove, (void*) (0));
                createTrackbar("High R", "Control", &hiA, 255, onMove, (void*) (1));
	        createTrackbar("Low G", "Control", &lowB, 255, onMove, (void*) (2));
	        createTrackbar("High G", "Control", &hiB, 255, onMove, (void*) (3));
       		createTrackbar("Low B", "Control", &lowC, 255, onMove, (void*) (4));
	        createTrackbar("High B", "Control", &hiC, 255, onMove, (void*) (5));

	}

	setMouseCallback("Original", onClickOriginal, NULL);

	int frameNum = 0;
	int blobX=-1;
	int blobY=-1;
	//Loop runs until you can't get another frame from the video source, or a user presses escape.

	while(true){

		bool success = cap.read(src);
		if(!success){
			cerr<<"Cannot read frame from video stream"<<endl;
			break;
		}

		//Do color conversion based on colorMOde
		Mat colorImg;
		if(colorMode == 0)
			cvtColor(src, colorImg, COLOR_BGR2HSV);
		else if(colorMode == 1)
			colorImg=src;

		Mat thresholdedImg;

  		inRange(colorImg, lowerBound, upperBound, thresholdedImg);

	        //morphological opening
       		erode(thresholdedImg,thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
	       	dilate(thresholdedImg, thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );

	        //morphological closing
        	dilate(thresholdedImg, thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );
	        erode(thresholdedImg, thresholdedImg, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)) );

		centerMoment(thresholdedImg,blobX, blobY);
		//centerFind(thresholdedImg,0, 0);

		if(thresholdSet ){
			Mat roi = src(Rect(Point(blobX -50, blobY-50), Point(blobX+50, blobY+50)));
			Mat color(roi.size(), CV_8UC3, Scalar(0, 255, 43));
	    		double alpha = 0.3;
			addWeighted(color, alpha, roi, 1.0 - alpha , 0.0, roi);
		}

		//Show images.
		imshow("Original", src);
		imshow("Thresholded", thresholdedImg);

		//Set trackbar variables to reflect any changes that may have happened to the thresholder values.
		if(colorMode ==0){
			setTrackbarPos("Low H", "Control", lowerBound[0]);
			setTrackbarPos("High H", "Control", upperBound[0]);
			setTrackbarPos("Low S", "Control", lowerBound[1]);
			setTrackbarPos("High S", "Control", upperBound[1]);
			setTrackbarPos("Low V", "Control", lowerBound[2]);
			setTrackbarPos("High V", "Control", upperBound[2]);
		}
		else if(colorMode == 1){
			setTrackbarPos("Low R", "Control", lowerBound[0]);
			setTrackbarPos("High R", "Control", upperBound[0]);
			setTrackbarPos("Low G", "Control", lowerBound[1]);
			setTrackbarPos("High G", "Control", upperBound[1]);
			setTrackbarPos("Low B", "Control", lowerBound[2]);
			setTrackbarPos("High B", "Control", upperBound[2]);
		}

		//If user presses ESC, quit stream.
		if(waitKey(5) ==27){
			cerr<<"Video Stream Ended"<<endl;
			break;
		}
		//Begin data capture if user presses C.
		else if(waitKey(5) == 99){
			cout<<"BEGINING DATA CAPTURE. PLEASE MOUSEOVER CENTER LINE"<<endl;
			capture = true;

			outCenter.open("./data/captures/center.dat");
			outMoment.open("./data/captures/moment.dat");
			outMouse.open("./data/captures/mouse.dat");
		}
		//End data capture if user presses E.
		else if(waitKey(5) == 101){
			cout<<"ENDING DATA CAPTURE.  ANALYSIS WILL BE COMPLETE AT PROGRAM END"<<endl;
			capture = false;
			captureNum = 0;

			outCenter.close();
			outMoment.close();
			outMouse.close();
		}

		//Set threshold values to defaults if user presses Enter
		else if(waitKey(5) == 13){
			cout<<"RESETING THRESHOLDS TO DEFAULTS"<<endl;
			lowerBound = Scalar(0,0,0);
			if(colorMode ==0)
				upperBound = Scalar(179, 255, 255);
			else if(colorMode ==1)
				upperBound = Scalar(255, 255, 255);
			thresholdSet =false;
		}
		//Save frames if user presses s.
		else if(waitKey(5) ==115){
			cout<<"SAVING FRAMES "<<frameNum<<endl;
			saveFrame(src, thresholdedImg, frameNum);
			frameNum++;
		}

		if(capture)
			outMouse<<captureNum<<" "<<mouseX<<" "<<mouseY<<endl;
			captureNum++;
	}
	return 0;
}

//handler for the control trackbars.
void onMove(int val, void * userdata){
	int num	= *((int*)&userdata);
	//Userdata holds the index that we want tos set, so just set the scalar accordingly.
	if(num ==0)
		lowerBound = Scalar(val, lowerBound[1], lowerBound[2]);
	else if(num ==1)
		upperBound = Scalar(val, upperBound[1], upperBound[2]);
        else if(num ==2)
		lowerBound = Scalar(lowerBound[0], val, lowerBound[2]);
        else if(num ==3)
		upperBound = Scalar(upperBound[0], val, upperBound[2]);
        else if(num ==4)
		lowerBound = Scalar(lowerBound[0], lowerBound[1], val);
        else if(num ==5)
		upperBound = Scalar(upperBound[0], upperBound[1], val);

}

//Handles onclick events for the "original" window.
void onClickOriginal(int event, int x, int y, int flags, void * userdata){
	//If the left mouse is clicked,get the average HSV or RGB values from the area and use them for a new set of threshold ranges.
	mouseX = x;
	mouseY = y;
	if(event == EVENT_LBUTTONDOWN){
		Mat COLORimg;
		if(colorMode == 0)
			cvtColor(src, COLORimg, COLOR_BGR2HSV);
		else
			COLORimg=src;
	        Mat ROI= COLORimg (Rect ((x-5), (y-5), 10, 10));

        	Scalar ROImean= mean(ROI);

		//For HSV, use ranges H(14), S(60), V(80).
		if(colorMode ==0){
			lowerBound = Scalar(ROImean[0] - 7, ROImean[1] - 30, ROImean[2] -40);
			upperBound = Scalar(ROImean[0] +7, ROImean[1] +30, ROImean[2] +40);
		}

		//For RGB, use ranges R(20), G(20), B(20). (NEEDS REVISION)
		else if(colorMode ==1){
			lowerBound = Scalar(ROImean[0] -10, ROImean[1] -10, ROImean[2] -10);
			upperBound = Scalar(ROImean[0] +10, ROImean[1] +10, ROImean[2] +10);
		}

		thresholdSet=true;
	}
}

/*
Save the orignal and thresholded frames after generating a unique filename.
*/
void saveFrame(Mat imgOriginal, Mat imgThresholded, int frameNum){
        String path= "./data/images/";
        String ext= ".png";

        String number;
        ostringstream convert;
        convert << frameNum;
        number= convert.str();

        String original= path+"original";
        String threshed= path+"thresholed";
        original=original+number;
        threshed=threshed+number;
        original=original+ext;
        threshed=threshed+ext;

        vector<int> params;
        params.push_back(CV_IMWRITE_PNG_COMPRESSION);
        params.push_back(9);

        if(!imwrite(original, imgOriginal, params))
                cerr<<"Failed to write original"<<endl;

        if(!imwrite(threshed, imgThresholded, params))
                cerr<<"Failed to write thresholded"<<endl;
}

void centerMoment(Mat img, int & x, int & y){
	Moments oMoments=moments(img);

        double dM01= oMoments.m01;
        double dM10= oMoments.m10;
        double area= oMoments.m00;
        if(area > 10000){
  	      x =dM10/area;
              y= dM01/area;
	}
	if(capture)
		outMoment<<captureNum<<" "<<x<<" "<<y<<endl;

}

void centerFind(Mat img, int & x, int & y){

	uchar a, b, c;
	int firstX, lastX;
	int firstY, lastY;
	firstY= -1;
	lastY=-1;

	for(int i =0; i<img.rows; i++){
		Vec3b * pixel = img.ptr<Vec3b>(i);
		firstX= -1;
		lastX = -1;

		for(int j = 0; j<img.cols; j++){
			a=pixel[j][0];
			b=pixel[j][1];
			c=pixel[j][2];

			int A= (int) a;
			int B = (int) b;
			int C= (int) c;

			if((a >0 || b>0 || c>0)  && capture){
				if(firstX == -1)
					firstX =j;
				else
					lastX = j;

				if(firstY == -1)
					firstY= i;
				else
					lastY=i;
			}
		}

	}
	x = (lastX-firstX)/2 +firstX;
	y = (lastY - firstY)/2 +firstY;
}
<|endoftext|>


<commit_before>#ifndef ALGO_HPP
#define ALGO_HPP

#include "ptree.hpp"
#include "equivalence.hpp"
#include "ztree.hpp"
#include "khash.hh"

namespace tree {
////////////////////////////////////////////////////////////////////////////////
// Central algorithm and stuff
////////////////////////////////////////////////////////////////////////////////

// porta il sottolbero radicato in x in una catena sinistra o destra a seconda di type
// (algoritmi LEFT e RIGHT). Restituisce -1 in caso di errore, oppure 0 se l'albero e' nullo
template<class T>
T list ( ptree<T>& a, T i, equivalence_info<T>& eqinfo, rotation_type type = LEFT ) {
  if ( i == EMPTY ) return 0;

  a.get_structure( eqinfo );

  T total = 0;
  while ( i != EMPTY ) {
    T next = i;

    T j = i;
    while ( ( type == RIGHT && ( a[j].left() && eqinfo[a[j].left()] == EMPTY ) ) ||
            ( type == LEFT && ( a[j].right() && eqinfo[a[j].right()] == EMPTY ) ) ) {
      next = ( type == LEFT ) ? a[j].right() : a[j].left();

      a.rotate( j, type );
      ++total;

      j = next;
    }

    // l'ultimo nodo che ho ruotato (oppure i invariato) e' quello da cui devo scendere
    i = ( type == LEFT ) ? a.base()[next].left() : a.base()[next].right();
  }

  return total;
}

// processing basato sull'algoritmo CENTRAL
template<class T>
T central ( ptree<T>& a, ptree<T>& b ) {

  assert( a.size() == b.size() );
  equivalence_info<T> eqinfo( a.size() );
  T total = 0;

  // cerco il nodo con c(x) massimo
  T cmax = 0, rx = 2 * a.size() + 1;
  T selected = a.best_c( b, eqinfo, cmax, rx, greater<T>() );

  if ( cmax == 0 )
    return total;

  // porto il nodo selezionato alla radice in entrambi gli alberi
  total += a.to_root( selected );
  total += b.to_root( selected );

  // applico gli algoritmi left e right ai sottoalberi
  total += list( a, a.base()[selected].right(), eqinfo, LEFT );
  total += list( b, b.base()[selected].right(), eqinfo.inverse(), LEFT );
  total += list( a, a.base()[selected].left(), eqinfo, RIGHT );
  total += list( b, b.base()[selected].left(), eqinfo.inverse(), RIGHT );

  return total;
}

template<class T>
T centralfirststep ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {
  //cout << "centralfirststep()" << endl;
  assert( a.size() == b.size() );

  T total = 0;

  // cerco il nodo con c(x) massimo
  T cmax = 0, rx = 2 * a.size() + 1;
  T selected = a.best_c( b, eqinfo, cmax, rx, greater<T>() );

  if ( cmax == 0 || selected == EMPTY )
    return total;

  //cout << "selected node " << selected << " with cmax = " << cmax << endl;

  // porto il nodo selezionato alla radice in entrambi gli alberi
  total += a.to_root( selected );
  total += b.to_root( selected );

  return total;
}

template<class T>
T movebestr ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {

  assert( a.size() == b.size() );
  T total = 0;

  // cerco il nodo con r(x) minimo
  T rx = 2 * a.size() + 1;
  T selected = a.best_r( b, eqinfo, rx, less<T>() );

  if ( rx == 0 || selected == EMPTY )
    return total;

  //cout << "selected node " << selected << " with rx = " << rx << endl;

  // porto il nodo selezionato alla radice in entrambi gli alberi
  total += a.to_root( selected );
  total += b.to_root( selected );

  return total;
}

////////////////////////////////////////////////////////////////////////////////
// New algorithm and stuff
////////////////////////////////////////////////////////////////////////////////

template<class T>
bool has_equivalent ( ptree<T>& a, ptree<T>& b ) {
  assert( a.size() == b.size() );

  equivalence_info<T> eqinfo( a.size() );
  return a.equal_subtrees( b, eqinfo ) != 0;
}

template<class T>
T newalgo_r ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {
  assert( a.size() == b.size() );

  //printf( "a.root() = %d, b.root() = %d, size = %d\n", a.root(), b.root(), a.size() );
  if ( a.size() == 0 || a.size() == 1 )
    return 0;

  T total = 0;
  a.equal_subtrees( b, eqinfo );              // aggiorno gli intervalli
  total += k_equivalent(a, b, 1, eqinfo);        // stacco nodi k-equivalenti
  a.equal_subtrees( b, eqinfo );              // riaggiorno

  total += centralfirststep( a, b, eqinfo );  // porto un nodo a radice
  a.equal_subtrees( b, eqinfo );              // riaggiorno (in particolare i figli)

  ptree<T> al = a.left();
  ptree<T> bl = b.left();
  ptree<T> ar = a.right();
  ptree<T> br = b.right();
  return total + newalgo_r( al, bl, eqinfo ) + newalgo_r( ar, br, eqinfo );
}

template<class T>
T newalgo ( ptree<T>& a, ptree<T>& b ) {
  //cout << "newalgo()\n";
  equivalence_info<T> eqinfo( a.size() );
  return newalgo_r( a, b, eqinfo );
}

template<class T>
T mix_r ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {
  assert( a.size() == b.size() );

  if ( a.size() == 0 || a.size() == 1 )
    return 0;

  T total = 0;
  a.equal_subtrees( b, eqinfo );              // aggiorno gli intervalli
  //print<T>(a,b);
  //cout << eqinfo << endl;
  total += k_equivalent(a, b, 1, eqinfo);     // stacco nodi k-equivalenti
  a.equal_subtrees( b, eqinfo );              // riaggiorno

  total += movebestr( a, b, eqinfo );         // porto un nodo a radice
  a.equal_subtrees( b, eqinfo );              // riaggiorno (in particolare i figli)

  ptree<T> al = a.left();
  ptree<T> bl = b.left();
  ptree<T> ar = a.right();
  ptree<T> br = b.right();
  return total + mix_r( al, bl, eqinfo ) + mix_r( ar, br, eqinfo );
}

template<class T>
T mix ( ptree<T>& a, ptree<T>& b ) {
  //cout << "mix()\n";
  equivalence_info<T> eqinfo( a.size() );
  return mix_r( a, b, eqinfo );
}

template<class T>
bool k_equivalent_r ( ptree<T>& a, ptree<T>& b, T k, equivalence_info<T>& eqinfo, T before ) {
  if ( k == 0 ) {
    T after = a.equal_subtrees( b, eqinfo );

    T threshold = 1;
    if ( after - before >= threshold )
      return true; // keep
    else
      return false;
  }

  for ( T i = a.minimum(); i <= a.maximum(); ++i ) {
    if ( i == a.root() ) continue;

    /*if( a.equal_subtrees( b, eqinfo ) != before ) {
      print<T>(a,b,eqinfo);
      printf( "now is %d, was %d\n", a.equal_subtrees( b, eqinfo ), before );
      cout << eqinfo << endl;
      exit(1);
    }*/
    if ( eqinfo[i] != EMPTY ) continue;

    T father = a[i].father();

    a.up( i );
    bool keep = k_equivalent_r( a, b, k-1, eqinfo, before );

    if ( keep ) {
      //cout << "kept rotation up of " << i << endl;
      //print<T>(a,b,eqinfo);
      return true; // keep
    }
    a.rotate( father, i );
    //printf( "restored rotation up of %d [%d, %d, %d]\n", i, a.minimum(), a.root(), a.maximum() );
  }

  return false;
}

template<class T>
T k_equivalent ( ptree<T>& a, ptree<T>& b, T k, equivalence_info<T>& eqinfo ) {
  //cout << "k_equivalent()" << endl;
  T total = 0;

  for ( T t = 1; t <= k; ) {
    T before = a.equal_subtrees( b, eqinfo );
    /*cout << eqinfo << endl;
    a.debug();
    b.debug();
    print<T>(a,b,eqinfo);*/

    bool something = k_equivalent_r( a, b, t, eqinfo, before );
    if ( !something )
      assert ( a.equal_subtrees(b, eqinfo) == before );

    if ( !something )
      something = k_equivalent_r( b, a, t, eqinfo.inverse(), before );

    if ( !something ) // increase t
      ++t;
    else {
      total += t; // t remain the same (try to search again)
    }
  }

  return total;
}

template<class T>
class unordered_set : public khset_t<T> {};

size_t distance ( const ztree<N>& a, const ztree<N>& b, size_t& visited ) {
  visited = 0;

  if ( a == b ) return 0;
  unordered_set<unsigned long> queued;
  deque<ztree<N> > q;
  q.push_back( a );
  queued.insert( (int) a.to_ulong() );

  // During BFS I scan sequentially all nodes at distance d, exploring the next level d+1.
  // I set two extremes for two sets:
  //   [0,left)       contains the nodes at distance d, d-1, d-2.. 0 from the source node a
  //   [left,right)   contains the nodes at distance d+1 from a
  // When [0,left) = [0,0) means that I have exhausted all the nodes at distance d, d-1..
  // that means I generated all the nodes on the next level, so I can increase the distance
  // from the source.
  int left = 1;      // Initially I have node a at distance 0 from a, so [0,left) must contain only node 0
  int right = 1;     // The right limit is the left limit: I have no known node at distance 1
  size_t d = 0;      // distance from a in the current level
  bool found = false;

  while( q.size() != 0 ) {
   size_t occupied = q.size() * sizeof( ztree<N> ) + queued.size() * sizeof( unsigned long );
   if ( occupied > visited ) visited = occupied;
    // select first node in the deque and generates its outcoming star
    for ( unsigned int i = 1; i <= N; ++i ) {
      ztree<N> newone = q.front();
      newone ^ i;

      // if I already queued (or visited) this node I simply skip it
      if ( queued.find( newone.to_ulong() ) != queued.end() )
        continue;

      // if I found it, exit from the loops
      if ( newone == b ) {
        found = true;
        break;
      }

      // otherwise put the new node in the deque and to the hashtable
      q.push_back( newone );
      queued.insert( newone.to_ulong() );
      right++;
    }

    if ( found ) break;

    // effectively pop the first element, after visiting him
    q.pop_front();
    --right;
    // start processing elements at the next level?
    if ( --left == 0 ) {
      left = right;
      ++d;
    }
  }

  if (!found) {
      cerr << "Fatal error.\n";
      //cout << queued.count( a.to_ulong() ) << " " << queued.count( b.to_ulong() ) << endl;
      exit( 1 );
  }

  //visited = queued.size();
  return d + 1;
}

} // namespace tree

#endif // ALGO_HPP
<commit_msg>removed debug lines<commit_after>#ifndef ALGO_HPP
#define ALGO_HPP

#include "ptree.hpp"
#include "equivalence.hpp"
#include "ztree.hpp"
#include "khash.hh"

namespace tree {
////////////////////////////////////////////////////////////////////////////////
// Central algorithm and stuff
////////////////////////////////////////////////////////////////////////////////

// porta il sottolbero radicato in x in una catena sinistra o destra a seconda di type
// (algoritmi LEFT e RIGHT). Restituisce -1 in caso di errore, oppure 0 se l'albero e' nullo
template<class T>
T list ( ptree<T>& a, T i, equivalence_info<T>& eqinfo, rotation_type type = LEFT ) {
  if ( i == EMPTY ) return 0;

  a.get_structure( eqinfo );

  T total = 0;
  while ( i != EMPTY ) {
    T next = i;

    T j = i;
    while ( ( type == RIGHT && ( a[j].left() && eqinfo[a[j].left()] == EMPTY ) ) ||
            ( type == LEFT && ( a[j].right() && eqinfo[a[j].right()] == EMPTY ) ) ) {
      next = ( type == LEFT ) ? a[j].right() : a[j].left();

      a.rotate( j, type );
      ++total;

      j = next;
    }

    // l'ultimo nodo che ho ruotato (oppure i invariato) e' quello da cui devo scendere
    i = ( type == LEFT ) ? a.base()[next].left() : a.base()[next].right();
  }

  return total;
}

// processing basato sull'algoritmo CENTRAL
template<class T>
T central ( ptree<T>& a, ptree<T>& b ) {

  assert( a.size() == b.size() );
  equivalence_info<T> eqinfo( a.size() );
  T total = 0;

  // cerco il nodo con c(x) massimo
  T cmax = 0, rx = 2 * a.size() + 1;
  T selected = a.best_c( b, eqinfo, cmax, rx, greater<T>() );

  if ( cmax == 0 )
    return total;

  // porto il nodo selezionato alla radice in entrambi gli alberi
  total += a.to_root( selected );
  total += b.to_root( selected );

  // applico gli algoritmi left e right ai sottoalberi
  total += list( a, a.base()[selected].right(), eqinfo, LEFT );
  total += list( b, b.base()[selected].right(), eqinfo.inverse(), LEFT );
  total += list( a, a.base()[selected].left(), eqinfo, RIGHT );
  total += list( b, b.base()[selected].left(), eqinfo.inverse(), RIGHT );

  return total;
}

template<class T>
T centralfirststep ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {
  //cout << "centralfirststep()" << endl;
  assert( a.size() == b.size() );

  T total = 0;

  // cerco il nodo con c(x) massimo
  T cmax = 0, rx = 2 * a.size() + 1;
  T selected = a.best_c( b, eqinfo, cmax, rx, greater<T>() );

  if ( cmax == 0 || selected == EMPTY )
    return total;

  //cout << "selected node " << selected << " with cmax = " << cmax << endl;

  // porto il nodo selezionato alla radice in entrambi gli alberi
  total += a.to_root( selected );
  total += b.to_root( selected );

  return total;
}

template<class T>
T movebestr ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {

  assert( a.size() == b.size() );
  T total = 0;

  // cerco il nodo con r(x) minimo
  T rx = 2 * a.size() + 1;
  T selected = a.best_r( b, eqinfo, rx, less<T>() );

  if ( rx == 0 || selected == EMPTY )
    return total;

  //cout << "selected node " << selected << " with rx = " << rx << endl;

  // porto il nodo selezionato alla radice in entrambi gli alberi
  total += a.to_root( selected );
  total += b.to_root( selected );

  return total;
}

////////////////////////////////////////////////////////////////////////////////
// New algorithm and stuff
////////////////////////////////////////////////////////////////////////////////

template<class T>
bool has_equivalent ( ptree<T>& a, ptree<T>& b ) {
  assert( a.size() == b.size() );

  equivalence_info<T> eqinfo( a.size() );
  return a.equal_subtrees( b, eqinfo ) != 0;
}

template<class T>
T newalgo_r ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {
  assert( a.size() == b.size() );

  if ( a.size() == 0 || a.size() == 1 )
    return 0;

  T total = 0;
  a.equal_subtrees( b, eqinfo );              // aggiorno gli intervalli
  total += k_equivalent(a, b, 1, eqinfo);        // stacco nodi k-equivalenti
  a.equal_subtrees( b, eqinfo );              // riaggiorno

  total += centralfirststep( a, b, eqinfo );  // porto un nodo a radice
  a.equal_subtrees( b, eqinfo );              // riaggiorno (in particolare i figli)

  ptree<T> al = a.left();
  ptree<T> bl = b.left();
  ptree<T> ar = a.right();
  ptree<T> br = b.right();
  return total + newalgo_r( al, bl, eqinfo ) + newalgo_r( ar, br, eqinfo );
}

template<class T>
T newalgo ( ptree<T>& a, ptree<T>& b ) {
  //cout << "newalgo()\n";
  equivalence_info<T> eqinfo( a.size() );
  return newalgo_r( a, b, eqinfo );
}

template<class T>
T mix_r ( ptree<T>& a, ptree<T>& b, equivalence_info<T>& eqinfo ) {
  assert( a.size() == b.size() );

  if ( a.size() == 0 || a.size() == 1 )
    return 0;

  T total = 0;
  a.equal_subtrees( b, eqinfo );              // aggiorno gli intervalli
  total += k_equivalent(a, b, 1, eqinfo);     // stacco nodi k-equivalenti
  a.equal_subtrees( b, eqinfo );              // riaggiorno

  total += movebestr( a, b, eqinfo );         // porto un nodo a radice
  a.equal_subtrees( b, eqinfo );              // riaggiorno (in particolare i figli)

  ptree<T> al = a.left();
  ptree<T> bl = b.left();
  ptree<T> ar = a.right();
  ptree<T> br = b.right();
  return total + mix_r( al, bl, eqinfo ) + mix_r( ar, br, eqinfo );
}

template<class T>
T mix ( ptree<T>& a, ptree<T>& b ) {
  equivalence_info<T> eqinfo( a.size() );
  return mix_r( a, b, eqinfo );
}

template<class T>
bool k_equivalent_r ( ptree<T>& a, ptree<T>& b, T k, equivalence_info<T>& eqinfo, T before ) {
  if ( k == 0 ) {
    T after = a.equal_subtrees( b, eqinfo );

    T threshold = 1;
    if ( after - before >= threshold )
      return true; // keep
    else
      return false;
  }

  for ( T i = a.minimum(); i <= a.maximum(); ++i ) {
    if ( i == a.root() ) continue;

    if ( eqinfo[i] != EMPTY ) continue;

    T father = a[i].father();

    a.up( i );
    bool keep = k_equivalent_r( a, b, k-1, eqinfo, before );

    if ( keep )
      return true; // keep
    a.rotate( father, i );
  }

  return false;
}

template<class T>
T k_equivalent ( ptree<T>& a, ptree<T>& b, T k, equivalence_info<T>& eqinfo ) {
  T total = 0;

  for ( T t = 1; t <= k; ) {
    T before = a.equal_subtrees( b, eqinfo );

    bool something = k_equivalent_r( a, b, t, eqinfo, before );
    if ( !something )
      assert ( a.equal_subtrees(b, eqinfo) == before );

    if ( !something )
      something = k_equivalent_r( b, a, t, eqinfo.inverse(), before );

    if ( !something ) // increase t
      ++t;
    else {
      total += t; // t remain the same (try to search again)
    }
  }

  return total;
}

template<class T>
class unordered_set : public khset_t<T> {};

size_t distance ( const ztree<N>& a, const ztree<N>& b, size_t& visited ) {
  visited = 0;

  if ( a == b ) return 0;
  unordered_set<unsigned long> queued;
  deque<ztree<N> > q;
  q.push_back( a );
  queued.insert( (int) a.to_ulong() );

  // During BFS I scan sequentially all nodes at distance d, exploring the next level d+1.
  // I set two extremes for two sets:
  //   [0,left)       contains the nodes at distance d, d-1, d-2.. 0 from the source node a
  //   [left,right)   contains the nodes at distance d+1 from a
  // When [0,left) = [0,0) means that I have exhausted all the nodes at distance d, d-1..
  // that means I generated all the nodes on the next level, so I can increase the distance
  // from the source.
  int left = 1;      // Initially I have node a at distance 0 from a, so [0,left) must contain only node 0
  int right = 1;     // The right limit is the left limit: I have no known node at distance 1
  size_t d = 0;      // distance from a in the current level
  bool found = false;

  while( q.size() != 0 ) {
   size_t occupied = q.size() * sizeof( ztree<N> ) + queued.size() * sizeof( unsigned long );
   if ( occupied > visited ) visited = occupied;
    // select first node in the deque and generates its outcoming star
    for ( unsigned int i = 1; i <= N; ++i ) {
      ztree<N> newone = q.front();
      newone ^ i;

      // if I already queued (or visited) this node I simply skip it
      if ( queued.find( newone.to_ulong() ) != queued.end() )
        continue;

      // if I found it, exit from the loops
      if ( newone == b ) {
        found = true;
        break;
      }

      // otherwise put the new node in the deque and to the hashtable
      q.push_back( newone );
      queued.insert( newone.to_ulong() );
      right++;
    }

    if ( found ) break;

    // effectively pop the first element, after visiting him
    q.pop_front();
    --right;
    // start processing elements at the next level?
    if ( --left == 0 ) {
      left = right;
      ++d;
    }
  }

  if (!found) {
      cerr << "Fatal error.\n";
      //cout << queued.count( a.to_ulong() ) << " " << queued.count( b.to_ulong() ) << endl;
      exit( 1 );
  }

  //visited = queued.size();
  return d + 1;
}

} // namespace tree

#endif // ALGO_HPP
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "kudu/clock/hybrid_clock.h"

#include <algorithm>
#include <cstdint>
#include <string>
#include <vector>

#include <gflags/gflags.h>
#include <gflags/gflags_declare.h>
#include <glog/logging.h>
#include <gtest/gtest.h>

#include "kudu/clock/mock_ntp.h"
#include "kudu/clock/time_service.h"
#include "kudu/common/timestamp.h"
#include "kudu/gutil/casts.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/strings/join.h"
#include "kudu/util/atomic.h"
#include "kudu/util/monotime.h"
#include "kudu/util/random.h"
#include "kudu/util/random_util.h"
#include "kudu/util/scoped_cleanup.h"
#include "kudu/util/status.h"
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"
#include "kudu/util/thread.h"

DECLARE_bool(inject_unsync_time_errors);
DECLARE_string(time_source);

using std::string;
using std::vector;

namespace kudu {
namespace clock {

class HybridClockTest : public KuduTest {
 public:
  HybridClockTest()
      : clock_(new HybridClock) {
  }

  void SetUp() override {
    KuduTest::SetUp();
    ASSERT_OK(clock_->Init());
  }

 protected:
  scoped_refptr<HybridClock> clock_;
};

clock::MockNtp* mock_ntp(HybridClock* clock) {
  return down_cast<clock::MockNtp*>(clock->time_service());
}

TEST(MockHybridClockTest, TestMockedSystemClock) {
  google::FlagSaver saver;
  FLAGS_time_source = "mock";
  scoped_refptr<HybridClock> clock(new HybridClock);
  ASSERT_OK(clock->Init());
  Timestamp timestamp;
  uint64_t max_error_usec;
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(), 0);
  ASSERT_EQ(max_error_usec, 0);
  // If we read the clock again we should see the logical component be incremented.
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(), 1);
  // Now set an arbitrary time and check that is the time returned by the clock.
  uint64_t time = 1234 * 1000;
  uint64_t error = 100 * 1000;
  mock_ntp(clock.get())->SetMockClockWallTimeForTests(time);
  mock_ntp(clock.get())->SetMockMaxClockErrorForTests(error);
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(),
            HybridClock::TimestampFromMicrosecondsAndLogicalValue(time, 0).ToUint64());
  ASSERT_EQ(max_error_usec, error);
  // Perform another read, we should observe the logical component increment, again.
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(),
            HybridClock::TimestampFromMicrosecondsAndLogicalValue(time, 1).ToUint64());
}

// Test that, if the rate at which the clock is read is greater than the maximum
// resolution of the logical counter (12 bits in our implementation), it properly
// "overflows" into the physical portion of the clock, and maintains all ordering
// guarantees even as the physical clock continues to increase.
//
// This is a regression test for KUDU-1345.
TEST(MockHybridClockTest, TestClockDealsWithWrapping) {
  google::FlagSaver saver;
  FLAGS_time_source = "mock";
  scoped_refptr<HybridClock> clock(new HybridClock);
  ASSERT_OK(clock->Init());
  mock_ntp(clock.get())->SetMockClockWallTimeForTests(1000);

  Timestamp prev = clock->Now();

  // Update the clock from 10us in the future
  ASSERT_OK(clock->Update(HybridClock::TimestampFromMicroseconds(1010)));

  // Now read the clock value enough times so that the logical value wraps
  // over, and should increment the _physical_ portion of the clock.
  for (int i = 0; i < 10000; i++) {
    Timestamp now = clock->Now();
    ASSERT_GT(now.value(), prev.value());
    prev = now;
  }
  ASSERT_EQ(1012, HybridClock::GetPhysicalValueMicros(prev));

  // Advance the time microsecond by microsecond, and ensure the clock never
  // goes backwards.
  for (int time = 1001; time < 1020; time++) {
    mock_ntp(clock.get())->SetMockClockWallTimeForTests(time);
    Timestamp now = clock->Now();

    // Clock should run strictly forwards.
    ASSERT_GT(now.value(), prev.value());

    // Additionally, once the physical time surpasses the logical time, we should
    // be running on the physical clock. Otherwise, we should stick with the physical
    // time we had rolled forward to above.
    if (time > 1012) {
      ASSERT_EQ(time, HybridClock::GetPhysicalValueMicros(now));
    } else {
      ASSERT_EQ(1012, HybridClock::GetPhysicalValueMicros(now));
    }

    prev = now;
  }
}

// Test that two subsequent time reads are monotonically increasing.
TEST_F(HybridClockTest, TestNow_ValuesIncreaseMonotonically) {
  const Timestamp now1 = clock_->Now();
  const Timestamp now2 = clock_->Now();
  ASSERT_LT(now1.value(), now2.value());
}

// Tests the clock updates with the incoming value if it is higher.
TEST_F(HybridClockTest, TestUpdate_LogicalValueIncreasesByAmount) {
  Timestamp now = clock_->Now();
  uint64_t now_micros = HybridClock::GetPhysicalValueMicros(now);

  // increase the logical value
  uint64_t logical = HybridClock::GetLogicalValue(now);
  logical += 10;

  // increase the physical value so that we're sure the clock will take this
  // one, 200 msecs should be more than enough.
  now_micros += 200000;

  Timestamp now_increased = HybridClock::TimestampFromMicrosecondsAndLogicalValue(now_micros,
                                                                                logical);

  ASSERT_OK(clock_->Update(now_increased));

  Timestamp now2 = clock_->Now();
  ASSERT_EQ(logical + 1, HybridClock::GetLogicalValue(now2));
  ASSERT_EQ(HybridClock::GetPhysicalValueMicros(now) + 200000,
            HybridClock::GetPhysicalValueMicros(now2));
}

// Test that the incoming event is in the past, i.e. less than now - max_error
TEST_F(HybridClockTest, TestWaitUntilAfter_TestCase1) {
  MonoTime no_deadline;
  MonoTime before = MonoTime::Now();

  Timestamp past_ts;
  uint64_t max_error;
  clock_->NowWithError(&past_ts, &max_error);

  // make the event 3 * the max. possible error in the past
  Timestamp past_ts_changed = HybridClock::AddPhysicalTimeToTimestamp(
      past_ts,
      MonoDelta::FromMicroseconds(-3 * static_cast<int64_t>(max_error)));
  ASSERT_OK(clock_->WaitUntilAfter(past_ts_changed, no_deadline));

  MonoTime after = MonoTime::Now();
  MonoDelta delta = after - before;
  // The delta should be close to 0, but it takes some time for the hybrid
  // logical clock to decide that it doesn't need to wait.
  ASSERT_LT(delta.ToMicroseconds(), 25000);
}

// The normal case for transactions. Obtain a timestamp and then wait until
// we're sure that tx_latest < now_earliest.
TEST_F(HybridClockTest, TestWaitUntilAfter_TestCase2) {
  MonoTime before = MonoTime::Now();

  // we do no time adjustment, this event should fall right within the possible
  // error interval
  Timestamp past_ts;
  uint64_t past_max_error;
  clock_->NowWithError(&past_ts, &past_max_error);
  // Make sure the error is at least a small number of microseconds, to ensure
  // that we always have to wait.
  past_max_error = std::max(past_max_error, static_cast<uint64_t>(20));
  Timestamp wait_until = HybridClock::AddPhysicalTimeToTimestamp(
      past_ts,
      MonoDelta::FromMicroseconds(past_max_error));

  Timestamp current_ts;
  uint64_t current_max_error;
  clock_->NowWithError(&current_ts, &current_max_error);

  // Check waiting with a deadline which already expired.
  {
    MonoTime deadline = before;
    Status s = clock_->WaitUntilAfter(wait_until, deadline);
    ASSERT_TRUE(s.IsTimedOut()) << s.ToString();
  }

  // Wait with a deadline well in the future. This should succeed.
  {
    MonoTime deadline = before + MonoDelta::FromSeconds(60);
    ASSERT_OK(clock_->WaitUntilAfter(wait_until, deadline));
  }

  MonoTime after = MonoTime::Now();
  MonoDelta delta = after - before;

  // In the common case current_max_error >= past_max_error and we should have waited
  // 2 * past_max_error, but if the clock's error is reset between the two reads we might
  // have waited less time, but always more than 'past_max_error'.
  if (current_max_error >= past_max_error) {
    ASSERT_GE(delta.ToMicroseconds(), 2 * past_max_error);
  } else {
    ASSERT_GE(delta.ToMicroseconds(), past_max_error);
  }
}

TEST_F(HybridClockTest, TestIsAfter) {
  Timestamp ts1 = clock_->Now();
  ASSERT_TRUE(clock_->IsAfter(ts1));

  // Update the clock in the future, make sure it still
  // handles "IsAfter" properly even when it's running in
  // "logical" mode.
  Timestamp now_increased = HybridClock::TimestampFromMicroseconds(
    HybridClock::GetPhysicalValueMicros(ts1) + 1 * 1000 * 1000);
  ASSERT_OK(clock_->Update(now_increased));
  Timestamp ts2 = clock_->Now();

  ASSERT_TRUE(clock_->IsAfter(ts1));
  ASSERT_TRUE(clock_->IsAfter(ts2));
}

// Thread which loops polling the clock and updating it slightly
// into the future.
void StresserThread(HybridClock* clock, AtomicBool* stop) {
  Random rng(GetRandomSeed32());
  Timestamp prev(0);
  while (!stop->Load()) {
    Timestamp t = clock->Now();
    CHECK_GT(t.value(), prev.value());
    prev = t;

    // Add a random bit of offset to the clock, and perform an update.
    Timestamp new_ts = HybridClock::AddPhysicalTimeToTimestamp(
        t, MonoDelta::FromMicroseconds(rng.Uniform(10000)));
    CHECK_OK(clock->Update(new_ts));
  }
}

// Regression test for KUDU-953: if threads are updating and polling the
// clock concurrently, the clock should still never run backwards.
TEST_F(HybridClockTest, TestClockDoesntGoBackwardsWithUpdates) {
  vector<scoped_refptr<kudu::Thread>> threads;
  AtomicBool stop(false);

  SCOPED_CLEANUP({
    stop.Store(true);
    for (const auto& t : threads) {
      t->Join();
    }
  });

  for (int i = 0; i < 4; i++) {
    scoped_refptr<Thread> thread;
    ASSERT_OK(Thread::Create("test", "stresser",
                             &StresserThread, clock_.get(), &stop,
                             &thread));
    threads.push_back(thread);
  }

  SleepFor(MonoDelta::FromSeconds(1));
}

TEST_F(HybridClockTest, TestGetPhysicalComponentDifference) {
  Timestamp now1 = HybridClock::TimestampFromMicrosecondsAndLogicalValue(100, 100);
  SleepFor(MonoDelta::FromMilliseconds(1));
  Timestamp now2 = HybridClock::TimestampFromMicrosecondsAndLogicalValue(200, 0);
  MonoDelta delta = clock_->GetPhysicalComponentDifference(now2, now1);
  MonoDelta negative_delta = clock_->GetPhysicalComponentDifference(now1, now2);
  ASSERT_EQ(100, delta.ToMicroseconds());
  ASSERT_EQ(-100, negative_delta.ToMicroseconds());
}

TEST_F(HybridClockTest, TestRideOverNtpInterruption) {
  Timestamp timestamps[3];
  uint64_t max_error_usec[3];

  // Get the clock once, with a working NTP.
  clock_->NowWithError(&timestamps[0], &max_error_usec[0]);

  // Try to read the clock again a second later, but with an error
  // injected. It should extrapolate from the first read.
  SleepFor(MonoDelta::FromSeconds(1));
  FLAGS_inject_unsync_time_errors = true;
  clock_->NowWithError(&timestamps[1], &max_error_usec[1]);

  // The new clock reading should be a second or longer from the
  // first one, since SleepFor guarantees sleeping at least as long
  // as specified.
  MonoDelta phys_diff = clock_->GetPhysicalComponentDifference(
      timestamps[1], timestamps[0]);
  ASSERT_GE(phys_diff.ToSeconds(), 1);

  // The new clock reading should have higher error than the first.
  // The error should have increased based on the clock skew.
  int64_t error_diff = max_error_usec[1] - max_error_usec[0];
  ASSERT_NEAR(error_diff, clock_->time_service()->skew_ppm() * phys_diff.ToSeconds(),
              10);

  // Now restore the ability to read the system clock, and
  // read it again.
  FLAGS_inject_unsync_time_errors = false;
  clock_->NowWithError(&timestamps[2], &max_error_usec[2]);

  ASSERT_LT(timestamps[0].ToUint64(), timestamps[1].ToUint64());
  ASSERT_LT(timestamps[1].ToUint64(), timestamps[2].ToUint64());
}

#ifndef __APPLE__
TEST_F(HybridClockTest, TestNtpDiagnostics) {
  vector<string> log;
  clock_->time_service()->DumpDiagnostics(&log);
  string s = JoinStrings(log, "\n");
  SCOPED_TRACE(s);
  ASSERT_STR_MATCHES(s, "(ntp_gettime\\(\\) returns code |chronyc -n tracking)");
  ASSERT_STR_MATCHES(s, "(ntpq -n |chronyc -n sources)");
}
#endif

}  // namespace clock
}  // namespace kudu
<commit_msg>[test] fix HybridClockTest.TestWaitUntilAfter_TestCase2<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "kudu/clock/hybrid_clock.h"

#include <algorithm>
#include <cstdint>
#include <string>
#include <vector>

#include <gflags/gflags.h>
#include <gflags/gflags_declare.h>
#include <glog/logging.h>
#include <gtest/gtest.h>

#include "kudu/clock/mock_ntp.h"
#include "kudu/clock/time_service.h"
#include "kudu/common/timestamp.h"
#include "kudu/gutil/casts.h"
#include "kudu/gutil/ref_counted.h"
#include "kudu/gutil/strings/join.h"
#include "kudu/util/atomic.h"
#include "kudu/util/monotime.h"
#include "kudu/util/random.h"
#include "kudu/util/random_util.h"
#include "kudu/util/scoped_cleanup.h"
#include "kudu/util/status.h"
#include "kudu/util/test_macros.h"
#include "kudu/util/test_util.h"
#include "kudu/util/thread.h"

DECLARE_bool(inject_unsync_time_errors);
DECLARE_string(time_source);

using std::string;
using std::vector;

namespace kudu {
namespace clock {

class HybridClockTest : public KuduTest {
 public:
  HybridClockTest()
      : clock_(new HybridClock) {
  }

  void SetUp() override {
    KuduTest::SetUp();
    ASSERT_OK(clock_->Init());
  }

 protected:
  scoped_refptr<HybridClock> clock_;
};

clock::MockNtp* mock_ntp(HybridClock* clock) {
  return down_cast<clock::MockNtp*>(clock->time_service());
}

TEST(MockHybridClockTest, TestMockedSystemClock) {
  google::FlagSaver saver;
  FLAGS_time_source = "mock";
  scoped_refptr<HybridClock> clock(new HybridClock);
  ASSERT_OK(clock->Init());
  Timestamp timestamp;
  uint64_t max_error_usec;
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(), 0);
  ASSERT_EQ(max_error_usec, 0);
  // If we read the clock again we should see the logical component be incremented.
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(), 1);
  // Now set an arbitrary time and check that is the time returned by the clock.
  uint64_t time = 1234 * 1000;
  uint64_t error = 100 * 1000;
  mock_ntp(clock.get())->SetMockClockWallTimeForTests(time);
  mock_ntp(clock.get())->SetMockMaxClockErrorForTests(error);
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(),
            HybridClock::TimestampFromMicrosecondsAndLogicalValue(time, 0).ToUint64());
  ASSERT_EQ(max_error_usec, error);
  // Perform another read, we should observe the logical component increment, again.
  clock->NowWithError(&timestamp, &max_error_usec);
  ASSERT_EQ(timestamp.ToUint64(),
            HybridClock::TimestampFromMicrosecondsAndLogicalValue(time, 1).ToUint64());
}

// Test that, if the rate at which the clock is read is greater than the maximum
// resolution of the logical counter (12 bits in our implementation), it properly
// "overflows" into the physical portion of the clock, and maintains all ordering
// guarantees even as the physical clock continues to increase.
//
// This is a regression test for KUDU-1345.
TEST(MockHybridClockTest, TestClockDealsWithWrapping) {
  google::FlagSaver saver;
  FLAGS_time_source = "mock";
  scoped_refptr<HybridClock> clock(new HybridClock);
  ASSERT_OK(clock->Init());
  mock_ntp(clock.get())->SetMockClockWallTimeForTests(1000);

  Timestamp prev = clock->Now();

  // Update the clock from 10us in the future
  ASSERT_OK(clock->Update(HybridClock::TimestampFromMicroseconds(1010)));

  // Now read the clock value enough times so that the logical value wraps
  // over, and should increment the _physical_ portion of the clock.
  for (int i = 0; i < 10000; i++) {
    Timestamp now = clock->Now();
    ASSERT_GT(now.value(), prev.value());
    prev = now;
  }
  ASSERT_EQ(1012, HybridClock::GetPhysicalValueMicros(prev));

  // Advance the time microsecond by microsecond, and ensure the clock never
  // goes backwards.
  for (int time = 1001; time < 1020; time++) {
    mock_ntp(clock.get())->SetMockClockWallTimeForTests(time);
    Timestamp now = clock->Now();

    // Clock should run strictly forwards.
    ASSERT_GT(now.value(), prev.value());

    // Additionally, once the physical time surpasses the logical time, we should
    // be running on the physical clock. Otherwise, we should stick with the physical
    // time we had rolled forward to above.
    if (time > 1012) {
      ASSERT_EQ(time, HybridClock::GetPhysicalValueMicros(now));
    } else {
      ASSERT_EQ(1012, HybridClock::GetPhysicalValueMicros(now));
    }

    prev = now;
  }
}

// Test that two subsequent time reads are monotonically increasing.
TEST_F(HybridClockTest, TestNow_ValuesIncreaseMonotonically) {
  const Timestamp now1 = clock_->Now();
  const Timestamp now2 = clock_->Now();
  ASSERT_LT(now1.value(), now2.value());
}

// Tests the clock updates with the incoming value if it is higher.
TEST_F(HybridClockTest, TestUpdate_LogicalValueIncreasesByAmount) {
  Timestamp now = clock_->Now();
  uint64_t now_micros = HybridClock::GetPhysicalValueMicros(now);

  // increase the logical value
  uint64_t logical = HybridClock::GetLogicalValue(now);
  logical += 10;

  // increase the physical value so that we're sure the clock will take this
  // one, 200 msecs should be more than enough.
  now_micros += 200000;

  Timestamp now_increased = HybridClock::TimestampFromMicrosecondsAndLogicalValue(now_micros,
                                                                                logical);

  ASSERT_OK(clock_->Update(now_increased));

  Timestamp now2 = clock_->Now();
  ASSERT_EQ(logical + 1, HybridClock::GetLogicalValue(now2));
  ASSERT_EQ(HybridClock::GetPhysicalValueMicros(now) + 200000,
            HybridClock::GetPhysicalValueMicros(now2));
}

// Test that the incoming event is in the past, i.e. less than now - max_error
TEST_F(HybridClockTest, TestWaitUntilAfter_TestCase1) {
  MonoTime no_deadline;
  MonoTime before = MonoTime::Now();

  Timestamp past_ts;
  uint64_t max_error;
  clock_->NowWithError(&past_ts, &max_error);

  // make the event 3 * the max. possible error in the past
  Timestamp past_ts_changed = HybridClock::AddPhysicalTimeToTimestamp(
      past_ts,
      MonoDelta::FromMicroseconds(-3 * static_cast<int64_t>(max_error)));
  ASSERT_OK(clock_->WaitUntilAfter(past_ts_changed, no_deadline));

  MonoTime after = MonoTime::Now();
  MonoDelta delta = after - before;
  // The delta should be close to 0, but it takes some time for the hybrid
  // logical clock to decide that it doesn't need to wait.
  ASSERT_LT(delta.ToMicroseconds(), 25000);
}

// The normal case for transactions. Obtain a timestamp and then wait until
// we're sure that tx_latest < now_earliest.
TEST_F(HybridClockTest, TestWaitUntilAfter_TestCase2) {
  const MonoTime before = MonoTime::Now();

  // we do no time adjustment, this event should fall right within the possible
  // error interval
  Timestamp past_ts;
  uint64_t past_max_error;
  clock_->NowWithError(&past_ts, &past_max_error);
  // Make sure the error is at least a small number of microseconds, to ensure
  // that we always have to wait.
  past_max_error = std::max(past_max_error, static_cast<uint64_t>(2000));
  Timestamp wait_until = HybridClock::AddPhysicalTimeToTimestamp(
      past_ts,
      MonoDelta::FromMicroseconds(past_max_error));

  Timestamp current_ts;
  uint64_t current_max_error;
  clock_->NowWithError(&current_ts, &current_max_error);

  // Check waiting with a deadline which already expired.
  {
    MonoTime deadline = before;
    Status s = clock_->WaitUntilAfter(wait_until, deadline);
    ASSERT_TRUE(s.IsTimedOut()) << s.ToString();
  }

  // Wait with a deadline well in the future. This should succeed.
  {
    MonoTime deadline = before + MonoDelta::FromSeconds(60);
    ASSERT_OK(clock_->WaitUntilAfter(wait_until, deadline));
  }

  MonoTime after = MonoTime::Now();
  MonoDelta delta = after - before;

  // In the common case current_max_error >= past_max_error and we should have waited
  // 2 * past_max_error, but if the clock's error is reset between the two reads we might
  // have waited less time, but always more than 'past_max_error'.
  if (current_max_error >= past_max_error) {
    ASSERT_GE(delta.ToMicroseconds(), 2 * past_max_error);
  } else {
    ASSERT_GE(delta.ToMicroseconds(), past_max_error);
  }
}

TEST_F(HybridClockTest, TestIsAfter) {
  Timestamp ts1 = clock_->Now();
  ASSERT_TRUE(clock_->IsAfter(ts1));

  // Update the clock in the future, make sure it still
  // handles "IsAfter" properly even when it's running in
  // "logical" mode.
  Timestamp now_increased = HybridClock::TimestampFromMicroseconds(
    HybridClock::GetPhysicalValueMicros(ts1) + 1 * 1000 * 1000);
  ASSERT_OK(clock_->Update(now_increased));
  Timestamp ts2 = clock_->Now();

  ASSERT_TRUE(clock_->IsAfter(ts1));
  ASSERT_TRUE(clock_->IsAfter(ts2));
}

// Thread which loops polling the clock and updating it slightly
// into the future.
void StresserThread(HybridClock* clock, AtomicBool* stop) {
  Random rng(GetRandomSeed32());
  Timestamp prev(0);
  while (!stop->Load()) {
    Timestamp t = clock->Now();
    CHECK_GT(t.value(), prev.value());
    prev = t;

    // Add a random bit of offset to the clock, and perform an update.
    Timestamp new_ts = HybridClock::AddPhysicalTimeToTimestamp(
        t, MonoDelta::FromMicroseconds(rng.Uniform(10000)));
    CHECK_OK(clock->Update(new_ts));
  }
}

// Regression test for KUDU-953: if threads are updating and polling the
// clock concurrently, the clock should still never run backwards.
TEST_F(HybridClockTest, TestClockDoesntGoBackwardsWithUpdates) {
  vector<scoped_refptr<kudu::Thread>> threads;
  AtomicBool stop(false);

  SCOPED_CLEANUP({
    stop.Store(true);
    for (const auto& t : threads) {
      t->Join();
    }
  });

  for (int i = 0; i < 4; i++) {
    scoped_refptr<Thread> thread;
    ASSERT_OK(Thread::Create("test", "stresser",
                             &StresserThread, clock_.get(), &stop,
                             &thread));
    threads.push_back(thread);
  }

  SleepFor(MonoDelta::FromSeconds(1));
}

TEST_F(HybridClockTest, TestGetPhysicalComponentDifference) {
  Timestamp now1 = HybridClock::TimestampFromMicrosecondsAndLogicalValue(100, 100);
  SleepFor(MonoDelta::FromMilliseconds(1));
  Timestamp now2 = HybridClock::TimestampFromMicrosecondsAndLogicalValue(200, 0);
  MonoDelta delta = clock_->GetPhysicalComponentDifference(now2, now1);
  MonoDelta negative_delta = clock_->GetPhysicalComponentDifference(now1, now2);
  ASSERT_EQ(100, delta.ToMicroseconds());
  ASSERT_EQ(-100, negative_delta.ToMicroseconds());
}

TEST_F(HybridClockTest, TestRideOverNtpInterruption) {
  Timestamp timestamps[3];
  uint64_t max_error_usec[3];

  // Get the clock once, with a working NTP.
  clock_->NowWithError(&timestamps[0], &max_error_usec[0]);

  // Try to read the clock again a second later, but with an error
  // injected. It should extrapolate from the first read.
  SleepFor(MonoDelta::FromSeconds(1));
  FLAGS_inject_unsync_time_errors = true;
  clock_->NowWithError(&timestamps[1], &max_error_usec[1]);

  // The new clock reading should be a second or longer from the
  // first one, since SleepFor guarantees sleeping at least as long
  // as specified.
  MonoDelta phys_diff = clock_->GetPhysicalComponentDifference(
      timestamps[1], timestamps[0]);
  ASSERT_GE(phys_diff.ToSeconds(), 1);

  // The new clock reading should have higher error than the first.
  // The error should have increased based on the clock skew.
  int64_t error_diff = max_error_usec[1] - max_error_usec[0];
  ASSERT_NEAR(error_diff, clock_->time_service()->skew_ppm() * phys_diff.ToSeconds(),
              10);

  // Now restore the ability to read the system clock, and
  // read it again.
  FLAGS_inject_unsync_time_errors = false;
  clock_->NowWithError(&timestamps[2], &max_error_usec[2]);

  ASSERT_LT(timestamps[0].ToUint64(), timestamps[1].ToUint64());
  ASSERT_LT(timestamps[1].ToUint64(), timestamps[2].ToUint64());
}

#ifndef __APPLE__
TEST_F(HybridClockTest, TestNtpDiagnostics) {
  vector<string> log;
  clock_->time_service()->DumpDiagnostics(&log);
  string s = JoinStrings(log, "\n");
  SCOPED_TRACE(s);
  ASSERT_STR_MATCHES(s, "(ntp_gettime\\(\\) returns code |chronyc -n tracking)");
  ASSERT_STR_MATCHES(s, "(ntpq -n |chronyc -n sources)");
}
#endif

}  // namespace clock
}  // namespace kudu
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include "Myexception.h"
#include "chain.h"

using namespace std;

void chain :: readAndStoreFromFile(char* fileName)
{
	//This function reads integers from the file given by fileName then store them in the chain

	ifstream in;
	in.open(filename.c_str());
	if (!in) return; // file doesn't exist

	int line;
	while(in >> line) {
		insert(listSize, line);
	}

	/*int line;

	while(std::getline(data, line))
		std::stringstream str(line);
		std::string text;

		std::getline(str,text,'=');

		double value;
		str >> value;
	}*/

}

void chain :: eraseModuloValue(int theInt)
{
	//This function erases all the entries from the list which are multiple of theInt

	for(int i=0; i<listSize; i++) {
		int value = *this->get(i);
        	if (value/theInt > 0 && value != theInt) remove(i);
	}

}

void chain :: oddAndEvenOrdering()
{
	//This function reorders the list such a way that all odd numbers precede all even numbers.
	//Note that for two odd (even) numbers i and j, the ordering between i and j should be intact after reordering.

}

void chain :: reverse()
{
	//Reverses the list

}

chain :: chain(int initialCapacity)
{
	//Constructor
	if(initialCapacity < 1)
	{
		ostringstream s;
		s << "Initial capacity = " << initialCapacity << " Must be > 0";
		throw illegalParameterValue(s.str());
	}

	firstNode = NULL;
	listSize = 0;

}

chain :: ~chain()
{
	//Destructor. Delete all nodes in chain

	while(firstNode != NULL)
	{
		//delete firstNode
		chainNode* nextNode = firstNode->next;
		delete firstNode;
		firstNode = nextNode;

	}

}

int* chain :: get(int theIndex) const
{
	//Return element whose index is theIndex.
	//Throw illegalIndex exception if no such element.
	try{
		checkIndex(theIndex);
	}
	catch(illegalIndex &e){
		e.outputMessage();
		return NULL;
	}

	chainNode* currentNode = firstNode;
	for(int i=0;i<theIndex;i++)
		currentNode = currentNode->next;

	return &currentNode->element;

}

int chain :: indexOf(const int& theElement) const
{
	//Return index of first occurrence of theElement.
	//Return -1 of theElement not in list.

	chainNode* currentNode = firstNode;
	int index = 0;
	while(currentNode != NULL && currentNode->element != theElement)
	{
		//move to the next node
		currentNode = currentNode->next;
		index++;

	}

	//make sure we found matching element
	if(currentNode == NULL)
		return -1;

	else
		return index;

}

void chain :: erase(int theIndex)
{
	//Delete the element whose index is theIndex.
	//Throw illegalIndex exception if no such element.

	try{
		checkIndex(theIndex);
	}
	catch(illegalIndex &e){
		e.outputMessage();
		return;
	}

	chainNode* deleteNode;
	if(theIndex == 0)
	{
		//remove first node from chain
		deleteNode = firstNode;
		firstNode = firstNode->next;

	}
	else
	{
		//use p to get to predecessor of desired node
		chainNode* p = firstNode;
		for(int i=0;i<theIndex-1;i++)
			p = p->next;

		deleteNode = p->next;
		p->next = p->next->next; //remove deleteNode from chain

	}

	listSize--;
	delete deleteNode;

}

void chain :: insert(int theIndex, const int& theElement)
{
	//Insert theElement so that its index is theIndex.
	try{
   		if (theIndex < 0 || theIndex > listSize)
   		{// invalid index

			ostringstream s;
    			s << "index = " << theIndex << " size = " << listSize;
    			throw illegalIndex(s.str());
		}
	}
	catch(illegalIndex &e){
		e.outputMessage();
		return;
	}

	if(theIndex == 0)
		//insert at front
		firstNode = new chainNode(theElement, firstNode);
	else
	{
		chainNode *p = firstNode;
		for(int i=0;i<theIndex-1;i++)
			p = p->next;

		//insert after p
		p->next = new chainNode(theElement, p->next);

	}

	listSize++;

}

void chain :: output() const
{
	//Put the list into the output.

	for(int i=0;i<listSize;i++)
		cout << *this->get(i) << " ";
	cout<<endl;

}

void chain::checkIndex(int theIndex) const
{
// Verify that theIndex is between 0 and
 // listSize - 1.

   	if (theIndex < 0 || theIndex >= listSize){
		ostringstream s;
    		s << "index = " << theIndex << " size = "
                    << listSize<<", the input index is invalid";
    		throw illegalIndex(s.str());
	}

}
<commit_msg>Update chain.cpp<commit_after>#include <iostream>
#include <sstream>
#include "Myexception.h"
#include "chain.h"

using namespace std;

void chain :: readAndStoreFromFile(char* fileName)
{
	//This function reads integers from the file given by fileName then store them in the chain

	/*ifstream in;
	ifstream infile("input.txt");
	stringstream
	in.open(filename.c_str());
	if (!in) return; // file doesn't exist

	int line;
	while(in >> line) {
		insert(listSize, line);
	}*/

	ifstream infile(fileName.c_str()) ;
	string line;

	while(getline(infile, line)) {
		istringstream iss(line);
		int n;
		iss > n;
	}

	/*int line;

	while(std::getline(data, line))
		std::stringstream str(line);
		std::string text;

		std::getline(str,text,'=');

		double value;
		str >> value;
	}*/

}

void chain :: eraseModuloValue(int theInt)
{
	//This function erases all the entries from the list which are multiple of theInt

	for(int i=0; i<listSize; i++) {
		int value = *this->get(i);
        	if (value/theInt > 0 && value != theInt) remove(i);
	}

}

void chain :: oddAndEvenOrdering()
{
	//This function reorders the list such a way that all odd numbers precede all even numbers.
	//Note that for two odd (even) numbers i and j, the ordering between i and j should be intact after reordering.

}

void chain :: reverse()
{
	//Reverses the list

}

chain :: chain(int initialCapacity)
{
	//Constructor
	if(initialCapacity < 1)
	{
		ostringstream s;
		s << "Initial capacity = " << initialCapacity << " Must be > 0";
		throw illegalParameterValue(s.str());
	}

	firstNode = NULL;
	listSize = 0;

}

chain :: ~chain()
{
	//Destructor. Delete all nodes in chain

	while(firstNode != NULL)
	{
		//delete firstNode
		chainNode* nextNode = firstNode->next;
		delete firstNode;
		firstNode = nextNode;

	}

}

int* chain :: get(int theIndex) const
{
	//Return element whose index is theIndex.
	//Throw illegalIndex exception if no such element.
	try{
		checkIndex(theIndex);
	}
	catch(illegalIndex &e){
		e.outputMessage();
		return NULL;
	}

	chainNode* currentNode = firstNode;
	for(int i=0;i<theIndex;i++)
		currentNode = currentNode->next;

	return &currentNode->element;

}

int chain :: indexOf(const int& theElement) const
{
	//Return index of first occurrence of theElement.
	//Return -1 of theElement not in list.

	chainNode* currentNode = firstNode;
	int index = 0;
	while(currentNode != NULL && currentNode->element != theElement)
	{
		//move to the next node
		currentNode = currentNode->next;
		index++;

	}

	//make sure we found matching element
	if(currentNode == NULL)
		return -1;

	else
		return index;

}

void chain :: erase(int theIndex)
{
	//Delete the element whose index is theIndex.
	//Throw illegalIndex exception if no such element.

	try{
		checkIndex(theIndex);
	}
	catch(illegalIndex &e){
		e.outputMessage();
		return;
	}

	chainNode* deleteNode;
	if(theIndex == 0)
	{
		//remove first node from chain
		deleteNode = firstNode;
		firstNode = firstNode->next;

	}
	else
	{
		//use p to get to predecessor of desired node
		chainNode* p = firstNode;
		for(int i=0;i<theIndex-1;i++)
			p = p->next;

		deleteNode = p->next;
		p->next = p->next->next; //remove deleteNode from chain

	}

	listSize--;
	delete deleteNode;

}

void chain :: insert(int theIndex, const int& theElement)
{
	//Insert theElement so that its index is theIndex.
	try{
   		if (theIndex < 0 || theIndex > listSize)
   		{// invalid index

			ostringstream s;
    			s << "index = " << theIndex << " size = " << listSize;
    			throw illegalIndex(s.str());
		}
	}
	catch(illegalIndex &e){
		e.outputMessage();
		return;
	}

	if(theIndex == 0)
		//insert at front
		firstNode = new chainNode(theElement, firstNode);
	else
	{
		chainNode *p = firstNode;
		for(int i=0;i<theIndex-1;i++)
			p = p->next;

		//insert after p
		p->next = new chainNode(theElement, p->next);

	}

	listSize++;

}

void chain :: output() const
{
	//Put the list into the output.

	for(int i=0;i<listSize;i++)
		cout << *this->get(i) << " ";
	cout<<endl;

}

void chain::checkIndex(int theIndex) const
{
// Verify that theIndex is between 0 and
 // listSize - 1.

   	if (theIndex < 0 || theIndex >= listSize){
		ostringstream s;
    		s << "index = " << theIndex << " size = "
                    << listSize<<", the input index is invalid";
    		throw illegalIndex(s.str());
	}

}
<|endoftext|>