<commit_before>#include <QuantPDE/Core>

// TODO: Change these includes; shouldn't include src directory explicitly
#include <QuantPDE/src/Modules/Payoffs.hpp>
#include <QuantPDE/src/Modules/BlackScholesOperator.hpp>

using namespace QuantPDE;
using namespace QuantPDE::Modules;

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

#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <unistd.h>

using namespace std;

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

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

	// Default options
	Real expiry         = 1.;
	Real interest       = 0.04;
	Real volatility     = 0.2;
	Real dividends      = 0.;
	Real stock          = 100.;
	Real strike         = 100.;
	unsigned refinement = 5;
	unsigned steps      = 25;
	bool call           = true;
	bool variable       = false;
	bool american       = false;

	// Setting options with getopt
	{ char c;
	while((c = getopt(argc, argv, "Ad:hK:pr:R:s:S:T:v:V")) != -1) {
		switch(c) {
			case 'A':
				american = true;
				break;
			case 'd':
				dividends = atof(optarg);
				break;
			case 'h':
				cerr <<
"vanilla_convergence_table [OPTIONS]" << endl << endl <<
"Outputs the rate of convergence for computing the price of a call or put using" << endl <<
"a discretization of the Black-Scholes partial differential equation." << endl <<
endl <<
"-A" << endl <<
endl <<
"    American option (default is European)" << endl <<
endl <<
"-d REAL" << endl <<
endl <<
"    sets the dividend rate (default is 0.)" << endl <<
endl <<
"-K REAL" << endl <<
endl <<
"    sets the strike price (default is 100.)" << endl <<
endl <<
"-p" << endl <<
endl <<
"    computes the price of a European put (default is call)" << endl <<
endl <<
"-r REAL" << endl <<
endl <<
"    sets interest rate (default is 0.04)" << endl <<
endl <<
"-R POSITIVE_INTEGER" << endl <<
endl <<
"    sets the maximum number of refinement steps in the computation (default is" << endl <<
"    5)" << endl <<
endl <<
"-s POSITIVE_INTEGER" << endl <<
endl <<
"    sets the initial number of steps to take in time (default is 25)" << endl <<
endl <<
"-S REAL" << endl <<
endl <<
"    sets the initial stock price (default is 100.)" << endl <<
endl <<
"-T POSITIVE_REAL" << endl <<
endl <<
"    sets the expiry time (default is 1.)" << endl <<
endl <<
"-v REAL" << endl <<
endl <<
"    sets the volatility" << endl <<
endl <<
"-V" << endl <<
"    uses variable-size timestepping" << endl << endl;
				return 0;
			case 'K':
				strike = atof(optarg);
				break;
			case 'p':
				call = false;
				break;
			case 'r':
				interest = atof(optarg);
				break;
			case 'R':
				refinement = atoi(optarg);
				break;
			case 's':
				steps = atoi(optarg);
				if(steps <= 0) {
					cerr <<
"error: the number of steps must be positive" << endl;
					return 1;
				}
				break;
			case 'S':
				stock = atof(optarg);
				break;
			case 'T':
				if((expiry = atof(optarg)) <= 0.) {
					cerr <<
"error: expiry time must be positive" << endl;
					return 1;
				}
				break;
			case 'v':
				volatility = atof(optarg);
				break;
			case 'V':
				variable = true;
				break;
		}
	} }

	// Setting up the table
	const int td = 20;
	cout
		<< setw(td) << "Nodes"                  << "\t"
		<< setw(td) << "Steps"                  << "\t"
		<< setw(td) << "Mean Inner Iterations" << "\t"
		<< setw(td) << "Value"                  << "\t"
		<< setw(td) << "Change"                 << "\t"
		<< setw(td) << "Ratio"
		<< endl
	;
	cout.precision(6);
	Real previousValue = nan(""), previousChange = nan("");

	// Initial discretization
	// TODO: Create grid based on initial stock price and strike price
	RectilinearGrid1 grid(
		Axis {
			0., 10., 20., 30., 40., 50., 60., 70.,
			75., 80.,
			84., 88., 92.,
			94., 96., 98., 100., 102., 104., 106., 108., 110.,
			114., 118.,
			123.,
			130., 140., 150.,
			175.,
			225.,
			300.,
			750.,
			2000.,
			10000.
		}
	);

	// Payoff function
	Function1 payoff = bind(
		call ? callPayoff : putPayoff,
		placeholders::_1,
		strike
	);

	// Alternatively, we could have used...
	//auto payoff = QUANT_PDE_MODULES_CALL_PAYOFF_FIXED_STRIKE(strike);
	//auto payoff = QUANT_PDE_MODULES_PUT_PAYOFF_FIXED_STRIKE(strike);

	Real target = expiry / steps * 10.;
	for(unsigned l = 0; l < refinement; l++, steps *= variable ? 4 : 2) {

		///////////////////////////////////////////////////////////////
		// Build spatial grid
		///////////////////////////////////////////////////////////////

		// Refine the grid
		grid.refine( RectilinearGrid1::NewTickBetweenEachPair() );

		///////////////////////////////////////////////////////////////
		// Solve problem
		///////////////////////////////////////////////////////////////

		unsigned realizedSteps;
		Real averageInnerIterations = nan("");
		Real value;
		{
			// Black-Scholes operator (L in V_t = LV)
			BlackScholesOperator bsOperator(
				grid,
				[interest]   (Real, Real) {return interest;  },
				[volatility] (Real, Real) {return volatility;},
				[dividends]  (Real, Real) {return dividends; }
			);

			// Timestepping method
			Iteration *stepper;
			if(!variable) {
				stepper = new ReverseConstantStepper(
					0., // Initial time
					expiry,
					steps
				);
			} else {
				stepper = new ReverseVariableStepper(
					0., // Initial time
					expiry,
					expiry / steps,
					target
				);
				target /= 2;
			}

			// Time discretization method
			ReverseLinearBDFTwo bdf(grid, bsOperator);
			bdf.setIteration(*stepper);

			// American-specific components; penalty method or not?
			Linearizer *root;
			ToleranceIteration *tolerance = nullptr;
			PenaltyMethodDifference1 *penalty = nullptr;
			if(american) {
				penalty = new PenaltyMethodDifference1(
					grid,
					bdf,
					[&payoff] (Real, Real x) {
						return payoff(x);
					}
				);

				tolerance = new ToleranceIteration();

				penalty->setIteration(*tolerance);
				stepper->setInnerIteration(*tolerance);
				root = penalty;
			} else {
				root = &bdf;
			}

			// Linear system solver
			BiCGSTABSolver solver;

			// Compute solution
			Vector solutionVector = stepper->iterateUntilDone(
				grid.image(payoff),
				*root,
				solver
			);

			// Number of steps taken (outermost iteration)
			realizedSteps = stepper->iterations()[0];

			// Count average number of inner iterations
			if(american) {
				averageInnerIterations =
						tolerance->meanIterations();
			}

			// Solution at S = 100.
			value = grid.accessor(solutionVector)(stock);

			delete penalty;
			delete tolerance;
			delete stepper;
		}

		///////////////////////////////////////////////////////////////
		// Table
		///////////////////////////////////////////////////////////////

		// Change and ratio between successive solutions
		Real
			change = value - previousValue,
			ratio = previousChange / change
		;

		// Print out row of table
		cout
			<< scientific
			<< setw(td) << grid.size()            << "\t"
			<< setw(td) << realizedSteps          << "\t"
			<< setw(td) << averageInnerIterations << "\t"
			<< setw(td) << value                  << "\t"
			<< setw(td) << change                 << "\t"
			<< setw(td) << ratio
			<< endl
		;

		previousChange = change;
		previousValue = value;

	}

	return 0;
}

<commit_msg>Convergence test code is a little easier to read now.<commit_after>#include <QuantPDE/Core>

// TODO: Change these includes; shouldn't include src directory explicitly
#include <QuantPDE/src/Modules/Payoffs.hpp>
#include <QuantPDE/src/Modules/BlackScholesOperator.hpp>

using namespace QuantPDE;
using namespace QuantPDE::Modules;

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

#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <unistd.h>

using namespace std;

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

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

	// Default options
	Real expiry         = 1.;
	Real interest       = 0.04;
	Real volatility     = 0.2;
	Real dividends      = 0.;
	Real stock          = 100.;
	Real strike         = 100.;
	unsigned refinement = 5;
	unsigned steps      = 25;
	bool call           = true;
	bool variable       = false;
	bool american       = false;

	// Setting options with getopt
	{ char c;
	while((c = getopt(argc, argv, "Ad:hK:pr:R:s:S:T:v:V")) != -1) {
		switch(c) {
			case 'A':
				american = true;
				break;
			case 'd':
				dividends = atof(optarg);
				break;
			case 'h':
				cerr <<
"vanilla_convergence_table [OPTIONS]" << endl << endl <<
"Outputs the rate of convergence for computing the price of a call or put using" << endl <<
"a discretization of the Black-Scholes partial differential equation." << endl <<
endl <<
"-A" << endl <<
endl <<
"    American option (default is European)" << endl <<
endl <<
"-d REAL" << endl <<
endl <<
"    sets the dividend rate (default is 0.)" << endl <<
endl <<
"-K REAL" << endl <<
endl <<
"    sets the strike price (default is 100.)" << endl <<
endl <<
"-p" << endl <<
endl <<
"    computes the price of a European put (default is call)" << endl <<
endl <<
"-r REAL" << endl <<
endl <<
"    sets interest rate (default is 0.04)" << endl <<
endl <<
"-R POSITIVE_INTEGER" << endl <<
endl <<
"    sets the maximum number of refinement steps in the computation (default is" << endl <<
"    5)" << endl <<
endl <<
"-s POSITIVE_INTEGER" << endl <<
endl <<
"    sets the initial number of steps to take in time (default is 25)" << endl <<
endl <<
"-S REAL" << endl <<
endl <<
"    sets the initial stock price (default is 100.)" << endl <<
endl <<
"-T POSITIVE_REAL" << endl <<
endl <<
"    sets the expiry time (default is 1.)" << endl <<
endl <<
"-v REAL" << endl <<
endl <<
"    sets the volatility" << endl <<
endl <<
"-V" << endl <<
"    uses variable-size timestepping" << endl << endl;
				return 0;
			case 'K':
				strike = atof(optarg);
				break;
			case 'p':
				call = false;
				break;
			case 'r':
				interest = atof(optarg);
				break;
			case 'R':
				refinement = atoi(optarg);
				break;
			case 's':
				steps = atoi(optarg);
				if(steps <= 0) {
					cerr <<
"error: the number of steps must be positive" << endl;
					return 1;
				}
				break;
			case 'S':
				stock = atof(optarg);
				break;
			case 'T':
				if((expiry = atof(optarg)) <= 0.) {
					cerr <<
"error: expiry time must be positive" << endl;
					return 1;
				}
				break;
			case 'v':
				volatility = atof(optarg);
				break;
			case 'V':
				variable = true;
				break;
		}
	} }

	// Setting up the table
	const int td = 20;
	cout
		<< setw(td) << "Nodes"                  << "\t"
		<< setw(td) << "Steps"                  << "\t"
		<< setw(td) << "Mean Inner Iterations" << "\t"
		<< setw(td) << "Value"                  << "\t"
		<< setw(td) << "Change"                 << "\t"
		<< setw(td) << "Ratio"
		<< endl
	;
	cout.precision(6);
	Real previousValue = nan(""), previousChange = nan("");

	// Initial discretization
	// TODO: Create grid based on initial stock price and strike price
	RectilinearGrid1 grid(
		Axis {
			0., 10., 20., 30., 40., 50., 60., 70.,
			75., 80.,
			84., 88., 92.,
			94., 96., 98., 100., 102., 104., 106., 108., 110.,
			114., 118.,
			123.,
			130., 140., 150.,
			175.,
			225.,
			300.,
			750.,
			2000.,
			10000.
		}
	);

	// Payoff function
	Function1 payoff = bind(
		call ? callPayoff : putPayoff,
		placeholders::_1,
		strike
	);

	// Alternatively, we could have used...
	//auto payoff = QUANT_PDE_MODULES_CALL_PAYOFF_FIXED_STRIKE(strike);
	//auto payoff = QUANT_PDE_MODULES_PUT_PAYOFF_FIXED_STRIKE(strike);

	Real target = expiry / steps * 10.;
	for(unsigned l = 0; l < refinement; l++, steps *= variable ? 4 : 2) {

		///////////////////////////////////////////////////////////////
		// Build spatial grid
		///////////////////////////////////////////////////////////////

		// Refine the grid
		grid.refine( RectilinearGrid1::NewTickBetweenEachPair() );

		///////////////////////////////////////////////////////////////
		// Solve problem
		///////////////////////////////////////////////////////////////

		unsigned realizedSteps;
		Real averageInnerIterations = nan("");
		Real value;
		{
			// How to discretize time
			//typedef ReverseImplicitEuler TimeDiscretization;
			typedef ReverseLinearBDFTwo TimeDiscretization;

			// Black-Scholes operator (L in V_t = LV)
			BlackScholesOperator bsOperator(
				grid,
				[interest]   (Real, Real) {return interest;  },
				[volatility] (Real, Real) {return volatility;},
				[dividends]  (Real, Real) {return dividends; }
			);

			// Timestepping method
			Iteration *timeStepper;
			if(!variable) {
				timeStepper = new ReverseConstantStepper(
					0., // Initial time
					expiry,
					steps
				);
			} else {
				timeStepper = new ReverseVariableStepper(
					0., // Initial time
					expiry,
					expiry / steps,
					target
				);
				target /= 2;
			}

			// Time discretization method
			TimeDiscretization timeDiscretization(grid, bsOperator);
			timeDiscretization.setIteration(*timeStepper);

			// American-specific components; penalty method or not?
			Linearizer *root;
			ToleranceIteration *toleranceIteration = nullptr;
			PenaltyMethodDifference1 *penaltyMethod = nullptr;
			if(american) {
				// American case
				penaltyMethod = new PenaltyMethodDifference1(
					grid,
					timeDiscretization,
					[&payoff] (Real, Real x) {
						return payoff(x);
					}
				);

				toleranceIteration = new ToleranceIteration();

				penaltyMethod->setIteration(
						*toleranceIteration);
				timeStepper->setInnerIteration(
						*toleranceIteration);

				root = penaltyMethod;
			} else {
				// European case
				root = &timeDiscretization;
			}

			// Linear system solver
			BiCGSTABSolver solver;

			// Compute solution
			Vector solutionVector = timeStepper->iterateUntilDone(
				grid.image(payoff),
				*root,
				solver
			);

			// Number of steps taken (outermost iteration)
			realizedSteps = timeStepper->iterations()[0];

			// Average number of inner iterations
			if(american) {
				averageInnerIterations = toleranceIteration
						->meanIterations();
			}

			// Solution at S = 100.
			value = grid.accessor(solutionVector)(stock);

			delete penaltyMethod;
			delete toleranceIteration;
			delete timeStepper;
		}

		///////////////////////////////////////////////////////////////
		// Table
		///////////////////////////////////////////////////////////////

		// Change and ratio between successive solutions
		Real
			change = value - previousValue,
			ratio = previousChange / change
		;

		// Print out row of table
		cout
			<< scientific
			<< setw(td) << grid.size()            << "\t"
			<< setw(td) << realizedSteps          << "\t"
			<< setw(td) << averageInnerIterations << "\t"
			<< setw(td) << value                  << "\t"
			<< setw(td) << change                 << "\t"
			<< setw(td) << ratio
			<< endl
		;

		previousChange = change;
		previousValue = value;

	}

	return 0;
}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    Mat4x4.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file or its
contents may be copied, reproduced or altered in any way without the express
written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <stdlib.h>
#include <math.h>

#include "Mat4x4.hh"
#include "vlMath.hh"

// Description:
// Construct identity matrix.
vlMatrix4x4::vlMatrix4x4 ()
{
  int i,j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      if ( i == j ) this->Element[i][j] = 1.0;
      else this->Element[i][j] = 0.0;
      }
    }
}

vlMatrix4x4::vlMatrix4x4(const vlMatrix4x4& m)
{
  int i,j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      this->Element[i][j] = m.Element[i][j];
      }
    }
}

// Description:
// Set all elements of matrix to input value.
void vlMatrix4x4::operator= (float element)
{
  int i,j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      this->Element[i][j] = element;
      }
    }
  this->Modified ();
}

// Description:
// Multiply a point (in homogeneous coordinates) by matrix.
void vlMatrix4x4::PointMultiply(float in[4],float result[4])
{
  int i;
  float v1 = in[0];
  float v2 = in[1];
  float v3 = in[2];
  float v4 = in[3];

  for (i = 0; i < 4; i++)
    {
    result[i] =
      v1 * this->Element[0][i] +
      v2 * this->Element[1][i] +
      v3 * this->Element[2][i] +
      v4 * this->Element[3][i];
    }

}

// Description:
// Matrix Inversion (by Richard Carling from "Graphics Gems",
// Academic Press, 1990).
void vlMatrix4x4::Invert (vlMatrix4x4 in,vlMatrix4x4 & out)
{

#define SMALL_NUMBER	1.e-9

// inverse( original_matrix, inverse_matrix )
// calculate the inverse of a 4x4 matrix

//     -1
//     A  = ___1__ adjoint A
//         det A
//

  int i, j;
  double det;

  // calculate the 4x4 determinent
  // if the determinent is zero,
  // then the inverse matrix is not unique.

  det = in.Determinant(in);
  if ( fabs( det ) < SMALL_NUMBER) {
    vlErrorMacro(<< "Singular matrix, no inverse! Determinant= " << det );
    det = 0.0;
    return;
  }

  // calculate the adjoint matrix

  this->Adjoint( in, out );

  // scale the adjoint matrix to get the inverse

  for (i=0; i<4; i++)
    for(j=0; j<4; j++)
      out.Element[i][j] = out.Element[i][j] / det;
}

// Description:
// Compute the determinant of the matrix.
float vlMatrix4x4::Determinant (vlMatrix4x4 & in)
{
  vlMath math;
  double a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;

  // assign to individual variable names to aid selecting
  //  correct elements

  a1 = in.Element[0][0]; b1 = in.Element[0][1];
  c1 = in.Element[0][2]; d1 = in.Element[0][3];

  a2 = in.Element[1][0]; b2 = in.Element[1][1];
  c2 = in.Element[1][2]; d2 = in.Element[1][3];

  a3 = in.Element[2][0]; b3 = in.Element[2][1];
  c3 = in.Element[2][2]; d3 = in.Element[2][3];

  a4 = in.Element[3][0]; b4 = in.Element[3][1];
  c4 = in.Element[3][2]; d4 = in.Element[3][3];

  return a1 * math.Determinant3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4)
       - b1 * math.Determinant3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4)
       + c1 * math.Determinant3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4)
       - d1 * math.Determinant3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
}

// Description:
// Compute adjoint of matrix.
void vlMatrix4x4::Adjoint (vlMatrix4x4 & in,vlMatrix4x4 & out)
{
//
//   adjoint( original_matrix, inverse_matrix )
//
//     calculate the adjoint of a 4x4 matrix
//
//      Let  a   denote the minor determinant of matrix A obtained by
//           ij
//
//      deleting the ith row and jth column from A.
//
//                    i+j
//     Let  b   = (-1)    a
//          ij            ji
//
//    The matrix B = (b  ) is the adjoint of A
//                     ij
//
  vlMath m;
  double a1, a2, a3, a4, b1, b2, b3, b4;
  double c1, c2, c3, c4, d1, d2, d3, d4;

  // assign to individual variable names to aid
  // selecting correct values

  a1 = in.Element[0][0]; b1 = in.Element[0][1];
  c1 = in.Element[0][2]; d1 = in.Element[0][3];

  a2 = in.Element[1][0]; b2 = in.Element[1][1];
  c2 = in.Element[1][2]; d2 = in.Element[1][3];

  a3 = in.Element[2][0]; b3 = in.Element[2][1];
  c3 = in.Element[2][2]; d3 = in.Element[2][3];

  a4 = in.Element[3][0]; b4 = in.Element[3][1];
  c4 = in.Element[3][2]; d4 = in.Element[3][3];

  // row column labeling reversed since we transpose rows & columns

  out.Element[0][0]  =   m.Determinant3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4);
  out.Element[1][0]  = - m.Determinant3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4);
  out.Element[2][0]  =   m.Determinant3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4);
  out.Element[3][0]  = - m.Determinant3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);

  out.Element[0][1]  = - m.Determinant3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4);
  out.Element[1][1]  =   m.Determinant3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4);
  out.Element[2][1]  = - m.Determinant3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4);
  out.Element[3][1]  =   m.Determinant3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4);

  out.Element[0][2]  =   m.Determinant3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4);
  out.Element[1][2]  = - m.Determinant3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4);
  out.Element[2][2]  =   m.Determinant3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4);
  out.Element[3][2]  = - m.Determinant3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4);

  out.Element[0][3]  = - m.Determinant3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3);
  out.Element[1][3]  =   m.Determinant3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3);
  out.Element[2][3]  = - m.Determinant3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3);
  out.Element[3][3]  =   m.Determinant3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3);
}

void vlMatrix4x4::operator= (vlMatrix4x4& source)
{
  int i, j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      this->Element[i][j] = source.Element[i][j];
      }
    }
}

// Description:
//
void vlMatrix4x4::Transpose (vlMatrix4x4 in,vlMatrix4x4 & out)
{
  int i, j;
  float temp;

  for (i=0; i<4; i++)
    for(j=i; j<4; j++)
      {
      temp = in.Element[i][j];
      out.Element[i][j] = in.Element[j][i];
      out.Element[j][i] = temp;
      }
}

void vlMatrix4x4::PrintSelf (ostream& os, vlIndent indent)
{
  int i, j;

        vlObject::PrintSelf(os, indent);

        os << indent << "Elements:\n";
        for (i = 0; i < 4; i++) {
          cout << indent << indent;
          for (j = 0; j < 4; j++) {
            cout << this->Element[i][j] << " ";
	    cout << "\n";
          }
    }
}

<commit_msg>*** empty log message ***<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    Mat4x4.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file or its
contents may be copied, reproduced or altered in any way without the express
written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <stdlib.h>
#include <math.h>

#include "Mat4x4.hh"
#include "vlMath.hh"

// Description:
// Construct identity matrix.
vlMatrix4x4::vlMatrix4x4 ()
{
  int i,j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      if ( i == j ) this->Element[i][j] = 1.0;
      else this->Element[i][j] = 0.0;
      }
    }
}

vlMatrix4x4::vlMatrix4x4(const vlMatrix4x4& m)
{
  int i,j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      this->Element[i][j] = m.Element[i][j];
      }
    }
}

// Description:
// Set all elements of matrix to input value.
void vlMatrix4x4::operator= (float element)
{
  int i,j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      this->Element[i][j] = element;
      }
    }
  this->Modified ();
}

// Description:
// Multiply a point (in homogeneous coordinates) by matrix. The in[4] and
// result[4] arrays can be the same array.
void vlMatrix4x4::PointMultiply(float in[4],float result[4])
{
  int i;
  float v1 = in[0];
  float v2 = in[1];
  float v3 = in[2];
  float v4 = in[3];

  for (i = 0; i < 4; i++)
    {
    result[i] =
      v1 * this->Element[0][i] +
      v2 * this->Element[1][i] +
      v3 * this->Element[2][i] +
      v4 * this->Element[3][i];
    }

}

// Description:
// Matrix Inversion (by Richard Carling from "Graphics Gems",
// Academic Press, 1990).
void vlMatrix4x4::Invert (vlMatrix4x4 in,vlMatrix4x4 & out)
{

#define SMALL_NUMBER	1.e-9

// inverse( original_matrix, inverse_matrix )
// calculate the inverse of a 4x4 matrix

//     -1
//     A  = ___1__ adjoint A
//         det A
//

  int i, j;
  double det;

  // calculate the 4x4 determinent
  // if the determinent is zero,
  // then the inverse matrix is not unique.

  det = in.Determinant(in);
  if ( fabs( det ) < SMALL_NUMBER) {
    vlErrorMacro(<< "Singular matrix, no inverse! Determinant= " << det );
    det = 0.0;
    return;
  }

  // calculate the adjoint matrix

  this->Adjoint( in, out );

  // scale the adjoint matrix to get the inverse

  for (i=0; i<4; i++)
    for(j=0; j<4; j++)
      out.Element[i][j] = out.Element[i][j] / det;
}

// Description:
// Compute the determinant of the matrix.
float vlMatrix4x4::Determinant (vlMatrix4x4 & in)
{
  vlMath math;
  double a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4;

  // assign to individual variable names to aid selecting
  //  correct elements

  a1 = in.Element[0][0]; b1 = in.Element[0][1];
  c1 = in.Element[0][2]; d1 = in.Element[0][3];

  a2 = in.Element[1][0]; b2 = in.Element[1][1];
  c2 = in.Element[1][2]; d2 = in.Element[1][3];

  a3 = in.Element[2][0]; b3 = in.Element[2][1];
  c3 = in.Element[2][2]; d3 = in.Element[2][3];

  a4 = in.Element[3][0]; b4 = in.Element[3][1];
  c4 = in.Element[3][2]; d4 = in.Element[3][3];

  return a1 * math.Determinant3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4)
       - b1 * math.Determinant3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4)
       + c1 * math.Determinant3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4)
       - d1 * math.Determinant3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);
}

// Description:
// Compute adjoint of matrix.
void vlMatrix4x4::Adjoint (vlMatrix4x4 & in,vlMatrix4x4 & out)
{
//
//   adjoint( original_matrix, inverse_matrix )
//
//     calculate the adjoint of a 4x4 matrix
//
//      Let  a   denote the minor determinant of matrix A obtained by
//           ij
//
//      deleting the ith row and jth column from A.
//
//                    i+j
//     Let  b   = (-1)    a
//          ij            ji
//
//    The matrix B = (b  ) is the adjoint of A
//                     ij
//
  vlMath m;
  double a1, a2, a3, a4, b1, b2, b3, b4;
  double c1, c2, c3, c4, d1, d2, d3, d4;

  // assign to individual variable names to aid
  // selecting correct values

  a1 = in.Element[0][0]; b1 = in.Element[0][1];
  c1 = in.Element[0][2]; d1 = in.Element[0][3];

  a2 = in.Element[1][0]; b2 = in.Element[1][1];
  c2 = in.Element[1][2]; d2 = in.Element[1][3];

  a3 = in.Element[2][0]; b3 = in.Element[2][1];
  c3 = in.Element[2][2]; d3 = in.Element[2][3];

  a4 = in.Element[3][0]; b4 = in.Element[3][1];
  c4 = in.Element[3][2]; d4 = in.Element[3][3];

  // row column labeling reversed since we transpose rows & columns

  out.Element[0][0]  =   m.Determinant3x3( b2, b3, b4, c2, c3, c4, d2, d3, d4);
  out.Element[1][0]  = - m.Determinant3x3( a2, a3, a4, c2, c3, c4, d2, d3, d4);
  out.Element[2][0]  =   m.Determinant3x3( a2, a3, a4, b2, b3, b4, d2, d3, d4);
  out.Element[3][0]  = - m.Determinant3x3( a2, a3, a4, b2, b3, b4, c2, c3, c4);

  out.Element[0][1]  = - m.Determinant3x3( b1, b3, b4, c1, c3, c4, d1, d3, d4);
  out.Element[1][1]  =   m.Determinant3x3( a1, a3, a4, c1, c3, c4, d1, d3, d4);
  out.Element[2][1]  = - m.Determinant3x3( a1, a3, a4, b1, b3, b4, d1, d3, d4);
  out.Element[3][1]  =   m.Determinant3x3( a1, a3, a4, b1, b3, b4, c1, c3, c4);

  out.Element[0][2]  =   m.Determinant3x3( b1, b2, b4, c1, c2, c4, d1, d2, d4);
  out.Element[1][2]  = - m.Determinant3x3( a1, a2, a4, c1, c2, c4, d1, d2, d4);
  out.Element[2][2]  =   m.Determinant3x3( a1, a2, a4, b1, b2, b4, d1, d2, d4);
  out.Element[3][2]  = - m.Determinant3x3( a1, a2, a4, b1, b2, b4, c1, c2, c4);

  out.Element[0][3]  = - m.Determinant3x3( b1, b2, b3, c1, c2, c3, d1, d2, d3);
  out.Element[1][3]  =   m.Determinant3x3( a1, a2, a3, c1, c2, c3, d1, d2, d3);
  out.Element[2][3]  = - m.Determinant3x3( a1, a2, a3, b1, b2, b3, d1, d2, d3);
  out.Element[3][3]  =   m.Determinant3x3( a1, a2, a3, b1, b2, b3, c1, c2, c3);
}

void vlMatrix4x4::operator= (vlMatrix4x4& source)
{
  int i, j;

  for (i = 0; i < 4; i++)
    {
    for (j = 0; j < 4; j++)
      {
      this->Element[i][j] = source.Element[i][j];
      }
    }
}

// Description:
//
void vlMatrix4x4::Transpose (vlMatrix4x4 in,vlMatrix4x4 & out)
{
  int i, j;
  float temp;

  for (i=0; i<4; i++)
    for(j=i; j<4; j++)
      {
      temp = in.Element[i][j];
      out.Element[i][j] = in.Element[j][i];
      out.Element[j][i] = temp;
      }
}

void vlMatrix4x4::PrintSelf (ostream& os, vlIndent indent)
{
  int i, j;

        vlObject::PrintSelf(os, indent);

        os << indent << "Elements:\n";
        for (i = 0; i < 4; i++) {
          cout << indent << indent;
          for (j = 0; j < 4; j++) {
            cout << this->Element[i][j] << " ";
	    cout << "\n";
          }
    }
}

<|endoftext|>


<commit_before>#include "Model.h"
#include "EffectNode.h"
#include "main.h"

Model::Model() {
}

Model::~Model() {
}

void Model::addVideoNode(VideoNode *videoNode) {
    if (!m_vertices.contains(videoNode)) {
        {
            QMutexLocker locker(&m_graphLock);
            m_vertices.append(videoNode);
            m_verticesSortedForRendering = topoSort();
        }
        emit videoNodeAdded(videoNode);
    }
}

void Model::removeVideoNode(VideoNode *videoNode) {
    QList<Edge> removed;

    int count;
    {
        QMutexLocker locker(&m_graphLock);

        QMutableListIterator<Edge> i(m_edges);
        while (i.hasNext()) {
            auto edgeCopy = i.next();
            if (edgeCopy.fromVertex == videoNode || edgeCopy.toVertex == videoNode) {
                i.remove();
                removed.append(edgeCopy);
            }
        }

        count = m_vertices.removeAll(videoNode);
    }

    if (removed.count() > 0 || count > 0) {
        m_verticesSortedForRendering = topoSort();
        for (auto edge = removed.begin(); edge != removed.end(); edge++) {
            emit edgeRemoved(edge->fromVertex, edge->toVertex, edge->toInput);
        }
        if (count > 0) {
            emit videoNodeRemoved(videoNode);
        }
    }
}

void Model::addEdge(VideoNode *fromVertex, VideoNode *toVertex, int toInput) {
    Q_ASSERT(fromVertex != nullptr);
    Q_ASSERT(toVertex != nullptr);
    Q_ASSERT(toInput >= 0);
    Q_ASSERT(m_vertices.contains(fromVertex));
    Q_ASSERT(m_vertices.contains(toVertex));

    QList<Edge> removed;

    QList<Edge> edgesOld;

    Edge newEdge = {
        .fromVertex = fromVertex,
        .toVertex = toVertex,
        .toInput = toInput,
    };
    {
        QMutexLocker locker(&m_graphLock);

        for (auto edge = m_edges.begin(); edge != m_edges.end(); edge++) {
            if (edge->toVertex == toVertex && edge->toInput == toInput) {
                if (edge->fromVertex == fromVertex)
                    return;
                auto edgeCopy = *edge;
                m_edges.erase(edge);
                removed.append(edgeCopy);
            }
        }

        m_edges.append(newEdge);
        QVector<VideoNode *> sortedVertices = topoSort();
        if(sortedVertices.count() < m_vertices.count()) {
            // Roll back changes if a cycle was detected
            m_edges = edgesOld;
            return;
        }
        m_verticesSortedForRendering = sortedVertices;
    }
    for (auto edge = removed.begin(); edge != removed.end(); edge++) {
        emit edgeRemoved(edge->fromVertex, edge->toVertex, edge->toInput);
    }
    emit edgeAdded(newEdge.fromVertex, newEdge.toVertex, newEdge.toInput);
}

void Model::removeEdge(VideoNode *fromVertex, VideoNode *toVertex, int toInput) {
    Q_ASSERT(fromVertex != nullptr);
    Q_ASSERT(toVertex != nullptr);
    Q_ASSERT(toInput >= 0);
    Q_ASSERT(m_vertices.contains(fromVertex));
    Q_ASSERT(m_vertices.contains(toVertex));

    Edge edgeCopy;
    bool removed = false;
    {
        QMutexLocker locker(&m_graphLock);
        QMutableListIterator<Edge> i(m_edges);
        while (i.hasNext()) {
            edgeCopy = i.next();
            if (edgeCopy.fromVertex == fromVertex
             && edgeCopy.toVertex == toVertex
             && edgeCopy.toInput == toInput) {
                i.remove();
                removed = true;
                break;
            }
        }
        if (removed) {
            m_verticesSortedForRendering = topoSort();
        }
    }
    if (removed) {
        emit edgeRemoved(edgeCopy.fromVertex, edgeCopy.toVertex, edgeCopy.toInput);
    }
}

ModelCopyForRendering Model::createCopyForRendering() {
    QMutexLocker locker(&m_graphLock);
    ModelCopyForRendering out;

    // Create a map from VideoNodes to indices
    QMap<VideoNode *, int> map;
    for (int i=0; i<m_vertices.count(); i++) {
        map.insert(m_vertices.at(i), i);
    }

    for(int i=0; i<m_edges.count(); i++) {
        out.fromVertex.append(map.value(m_edges.at(i).fromVertex, -1));
        out.toVertex.append(map.value(m_edges.at(i).toVertex, -1));
        out.toInput.append(m_edges.at(i).toInput);
    }

    out.origVertices = m_verticesSortedForRendering;
    QVector<QSharedPointer<VideoNode>> vertices;
    for(int i=0; i<out.origVertices.count(); i++) {
        vertices.append(out.origVertices.at(i)->createCopyForRendering());
    }
    out.vertices = vertices;
    return out;
}

void Model::copyBackRenderStates(int chain, QVector<VideoNode *> origVertices, QVector<QSharedPointer<VideoNode>> renderedVertices) {
    Q_ASSERT(origVertices.count() == renderedVertices.count());
    {
        QMutexLocker locker(&m_graphLock);
        for(int i=0; i<origVertices.count(); i++) {
            // If the VideoNode is still in the DAG,
            // Javascript shouldn't have deleted it
            if(m_vertices.contains(origVertices.at(i))) {
                origVertices[i]->copyBackRenderState(chain, renderedVertices.at(i));
            } else {
                //qDebug() << "Node was deleted during rendering";
            }
        }
    }
}

QVector<VideoNode *> Model::topoSort() {
    // Kahn's algorithm from Wikipedia

    auto edges = m_edges;

    QVector<VideoNode *> l;
    QList<VideoNode *> s;
    {
        QSet<VideoNode *> sSet;
        // Populate s, the start nodes
        for (auto v = m_vertices.begin(); v != m_vertices.end(); v++) {
            sSet.insert(*v);
        }
        for (auto e = edges.begin(); e != edges.end(); e++) {
            sSet.remove(e->toVertex);
        }
        s = sSet.values();
    }

    while(!s.empty()) {
        // Put a start node into the sorted list
        auto n = s.takeFirst();
        l.append(n);

        QSet<VideoNode *> newStartNodes; // Potential new start nodes
        for (auto e = edges.begin(); e != edges.end(); e++) {
            // Remove edges originating from the node we just took
            if (e->fromVertex == n) {
                newStartNodes.insert(e->toVertex);
                edges.erase(e);
                // Any node pointed to by one of these deleted edges
                // is a potential new start node
            }
        }
        // Prune the potential new start nodes down to just the ones
        // with no edges
        for (auto e = edges.begin(); e != edges.end(); e++) {
            newStartNodes.remove(e->toVertex);
        }
        // Add them to s
        for (auto newStartNode = newStartNodes.begin(); newStartNode != newStartNodes.end(); newStartNode++) {
            s.append(*newStartNode);
        }
    }

    // If there are edges left, they are part of cycles
    if(!edges.empty()) {
        qDebug() << "Cycle detected!";
    }
    return l;
}

// ModelGraph methods

/*
ModelGraph::ModelGraph() {
}

ModelGraph::ModelGraph(QVector<VideoNode *> vertices, QList<Edge> edges)
    : m_vertices(vertices) {
    QMap<VideoNode *, int> map;
    int i = 0;
    for (int i=0; i<m_vertices.count(); i++) {
        map.insert(m_vertices.at(i), i);
    }
    for (auto edge = edges.begin(); edge != edges.end(); edge++) {
        ModelGraphEdge mge {
            .fromVertex = map.value(edge->fromVertex, -1),
            .toVertex = map.value(edge->toVertex, -1),
            .toInput = edge->toInput,
        };
        m_edges.append(mge);
    }
}

ModelGraph::ModelGraph(const ModelGraph &other)
    : m_vertices(other.m_vertices)
    , m_edges(other.m_edges) {
}

ModelGraph::~ModelGraph() {
}
*/

QList<VideoNode *> Model::vertices() const {
    return m_vertices;
}

QList<Edge> Model::edges() const {
    return m_edges;
}

QQmlListProperty<VideoNode> Model::qmlVertices() {
    return QQmlListProperty<VideoNode>(this, this, &Model::vertexCount, &Model::vertexAt);
}

int Model::vertexCount() const {
    return m_vertices.count();
}

VideoNode *Model::vertexAt(int index) const {
    return m_vertices.at(index);
}

QVariantList Model::qmlEdges() const {
    QVariantList edges;

    QMap<VideoNode *, int> map;
    int i = 0;
    for (int i=0; i<m_vertices.count(); i++) {
        map.insert(m_vertices.at(i), i);
    }

    for (auto edge = m_edges.begin(); edge != m_edges.end(); edge++) {
        QVariantMap vedge;
        vedge.insert("fromVertex", map.value(edge->fromVertex, -1));
        vedge.insert("toVertex", map.value(edge->toVertex, -1));
        vedge.insert("toInput", edge->toInput);
        edges.append(vedge);
    }
    return edges;
}

int Model::vertexCount(QQmlListProperty<VideoNode>* list) {
    return reinterpret_cast< Model* >(list->data)->vertexCount();
}

VideoNode* Model::vertexAt(QQmlListProperty<VideoNode>* list, int i) {
    return reinterpret_cast< Model* >(list->data)->vertexAt(i);
}
<commit_msg>fix connectionbug<commit_after>#include "Model.h"
#include "EffectNode.h"
#include "main.h"

Model::Model() {
}

Model::~Model() {
}

void Model::addVideoNode(VideoNode *videoNode) {
    if (!m_vertices.contains(videoNode)) {
        {
            QMutexLocker locker(&m_graphLock);
            m_vertices.append(videoNode);
            m_verticesSortedForRendering = topoSort();
        }
        emit videoNodeAdded(videoNode);
    }
}

void Model::removeVideoNode(VideoNode *videoNode) {
    QList<Edge> removed;

    int count;
    {
        QMutexLocker locker(&m_graphLock);

        QMutableListIterator<Edge> i(m_edges);
        while (i.hasNext()) {
            auto edgeCopy = i.next();
            if (edgeCopy.fromVertex == videoNode || edgeCopy.toVertex == videoNode) {
                i.remove();
                removed.append(edgeCopy);
            }
        }

        count = m_vertices.removeAll(videoNode);
    }

    if (removed.count() > 0 || count > 0) {
        m_verticesSortedForRendering = topoSort();
        for (auto edge = removed.begin(); edge != removed.end(); edge++) {
            emit edgeRemoved(edge->fromVertex, edge->toVertex, edge->toInput);
        }
        if (count > 0) {
            emit videoNodeRemoved(videoNode);
        }
    }
}

void Model::addEdge(VideoNode *fromVertex, VideoNode *toVertex, int toInput) {
    Q_ASSERT(fromVertex != nullptr);
    Q_ASSERT(toVertex != nullptr);
    Q_ASSERT(toInput >= 0);
    Q_ASSERT(m_vertices.contains(fromVertex));
    Q_ASSERT(m_vertices.contains(toVertex));

    QList<Edge> removed;

    QList<Edge> edgesOld;

    Edge newEdge = {
        .fromVertex = fromVertex,
        .toVertex = toVertex,
        .toInput = toInput,
    };
    {
        QMutexLocker locker(&m_graphLock);

        for (auto edge = m_edges.begin(); edge != m_edges.end(); edge++) {
            if (edge->toVertex == toVertex && edge->toInput == toInput) {
                if (edge->fromVertex == fromVertex)
                    return;
                auto edgeCopy = *edge;
                m_edges.erase(edge);
                removed.append(edgeCopy);
            }
        }

        m_edges.append(newEdge);
        QVector<VideoNode *> sortedVertices = topoSort();
        if(sortedVertices.count() < m_vertices.count()) {
            // Roll back changes if a cycle was detected
            m_edges = edgesOld;
            return;
        }
        m_verticesSortedForRendering = sortedVertices;
    }
    for (auto edge = removed.begin(); edge != removed.end(); edge++) {
        emit edgeRemoved(edge->fromVertex, edge->toVertex, edge->toInput);
    }
    emit edgeAdded(newEdge.fromVertex, newEdge.toVertex, newEdge.toInput);
}

void Model::removeEdge(VideoNode *fromVertex, VideoNode *toVertex, int toInput) {
    Q_ASSERT(fromVertex != nullptr);
    Q_ASSERT(toVertex != nullptr);
    Q_ASSERT(toInput >= 0);
    Q_ASSERT(m_vertices.contains(fromVertex));
    Q_ASSERT(m_vertices.contains(toVertex));

    Edge edgeCopy;
    bool removed = false;
    {
        QMutexLocker locker(&m_graphLock);
        QMutableListIterator<Edge> i(m_edges);
        while (i.hasNext()) {
            edgeCopy = i.next();
            if (edgeCopy.fromVertex == fromVertex
             && edgeCopy.toVertex == toVertex
             && edgeCopy.toInput == toInput) {
                i.remove();
                removed = true;
                break;
            }
        }
        if (removed) {
            m_verticesSortedForRendering = topoSort();
        }
    }
    if (removed) {
        emit edgeRemoved(edgeCopy.fromVertex, edgeCopy.toVertex, edgeCopy.toInput);
    }
}

ModelCopyForRendering Model::createCopyForRendering() {
    QMutexLocker locker(&m_graphLock);
    ModelCopyForRendering out;

    // Create a map from VideoNodes to indices
    QMap<VideoNode *, int> map;
    for (int i=0; i<m_verticesSortedForRendering.count(); i++) {
        map.insert(m_verticesSortedForRendering.at(i), i);
    }

    for(int i=0; i<m_edges.count(); i++) {
        out.fromVertex.append(map.value(m_edges.at(i).fromVertex, -1));
        out.toVertex.append(map.value(m_edges.at(i).toVertex, -1));
        out.toInput.append(m_edges.at(i).toInput);
    }

    out.origVertices = m_verticesSortedForRendering;
    QVector<QSharedPointer<VideoNode>> vertices;
    for(int i=0; i<out.origVertices.count(); i++) {
        vertices.append(out.origVertices.at(i)->createCopyForRendering());
    }
    out.vertices = vertices;
    return out;
}

void Model::copyBackRenderStates(int chain, QVector<VideoNode *> origVertices, QVector<QSharedPointer<VideoNode>> renderedVertices) {
    Q_ASSERT(origVertices.count() == renderedVertices.count());
    {
        QMutexLocker locker(&m_graphLock);
        for(int i=0; i<origVertices.count(); i++) {
            // If the VideoNode is still in the DAG,
            // Javascript shouldn't have deleted it
            if(m_vertices.contains(origVertices.at(i))) {
                origVertices[i]->copyBackRenderState(chain, renderedVertices.at(i));
            } else {
                //qDebug() << "Node was deleted during rendering";
            }
        }
    }
}

QVector<VideoNode *> Model::topoSort() {
    // Kahn's algorithm from Wikipedia

    auto edges = m_edges;

    QVector<VideoNode *> l;
    QList<VideoNode *> s;
    {
        QSet<VideoNode *> sSet;
        // Populate s, the start nodes
        for (auto v = m_vertices.begin(); v != m_vertices.end(); v++) {
            sSet.insert(*v);
        }
        for (auto e = edges.begin(); e != edges.end(); e++) {
            sSet.remove(e->toVertex);
        }
        s = sSet.values();
    }

    while(!s.empty()) {
        // Put a start node into the sorted list
        auto n = s.takeFirst();
        l.append(n);

        QSet<VideoNode *> newStartNodes; // Potential new start nodes
        for (auto e = edges.begin(); e != edges.end(); e++) {
            // Remove edges originating from the node we just took
            if (e->fromVertex == n) {
                newStartNodes.insert(e->toVertex);
                edges.erase(e);
                // Any node pointed to by one of these deleted edges
                // is a potential new start node
            }
        }
        // Prune the potential new start nodes down to just the ones
        // with no edges
        for (auto e = edges.begin(); e != edges.end(); e++) {
            newStartNodes.remove(e->toVertex);
        }
        // Add them to s
        for (auto newStartNode = newStartNodes.begin(); newStartNode != newStartNodes.end(); newStartNode++) {
            s.append(*newStartNode);
        }
    }

    // If there are edges left, they are part of cycles
    if(!edges.empty()) {
        qDebug() << "Cycle detected!";
    }
    return l;
}

// ModelGraph methods

/*
ModelGraph::ModelGraph() {
}

ModelGraph::ModelGraph(QVector<VideoNode *> vertices, QList<Edge> edges)
    : m_vertices(vertices) {
    QMap<VideoNode *, int> map;
    int i = 0;
    for (int i=0; i<m_vertices.count(); i++) {
        map.insert(m_vertices.at(i), i);
    }
    for (auto edge = edges.begin(); edge != edges.end(); edge++) {
        ModelGraphEdge mge {
            .fromVertex = map.value(edge->fromVertex, -1),
            .toVertex = map.value(edge->toVertex, -1),
            .toInput = edge->toInput,
        };
        m_edges.append(mge);
    }
}

ModelGraph::ModelGraph(const ModelGraph &other)
    : m_vertices(other.m_vertices)
    , m_edges(other.m_edges) {
}

ModelGraph::~ModelGraph() {
}
*/

QList<VideoNode *> Model::vertices() const {
    return m_vertices;
}

QList<Edge> Model::edges() const {
    return m_edges;
}

QQmlListProperty<VideoNode> Model::qmlVertices() {
    return QQmlListProperty<VideoNode>(this, this, &Model::vertexCount, &Model::vertexAt);
}

int Model::vertexCount() const {
    return m_vertices.count();
}

VideoNode *Model::vertexAt(int index) const {
    return m_vertices.at(index);
}

QVariantList Model::qmlEdges() const {
    QVariantList edges;

    QMap<VideoNode *, int> map;
    int i = 0;
    for (int i=0; i<m_vertices.count(); i++) {
        map.insert(m_vertices.at(i), i);
    }

    for (auto edge = m_edges.begin(); edge != m_edges.end(); edge++) {
        QVariantMap vedge;
        vedge.insert("fromVertex", map.value(edge->fromVertex, -1));
        vedge.insert("toVertex", map.value(edge->toVertex, -1));
        vedge.insert("toInput", edge->toInput);
        edges.append(vedge);
    }
    return edges;
}

int Model::vertexCount(QQmlListProperty<VideoNode>* list) {
    return reinterpret_cast< Model* >(list->data)->vertexCount();
}

VideoNode* Model::vertexAt(QQmlListProperty<VideoNode>* list, int i) {
    return reinterpret_cast< Model* >(list->data)->vertexAt(i);
}
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <unordered_map>
#include "constants.hpp"

// map for determining model symmetries
const std::unordered_map<std::string, std::vector<int>> MODEL_MAP(
  {
    {"JC69", {0,0,0,0,0,0}},
    {"K80", {0,1,0,0,1,0}},
    {"GTR", {0,1,2,3,4,5}}
  }
);

/* Encapsulates the evolutionary model parameters
  TODO possible basepoint of model class hierarchy */
class Model {
public:
  Model() = default;
  Model(std::string model_id);
  ~Model() = default;

  // getters
  const std::vector<double>& base_frequencies() const {return base_frequencies_;};
  std::vector<int>& symmetries()  {return subs_symmetries_;};
  const std::vector<double>& substitution_rates() const {return substitution_rates_;};
  double alpha() const {return alpha_;};

  // setters
  void base_frequencies(double* source, unsigned int length);
  void substitution_rates(double* source, unsigned int length);
  void symmetries(int* source, unsigned int length);
  void alpha(double a) {alpha_ = a;};

private:
  double alpha_;
  std::vector<double> base_frequencies_;
  std::vector<double> substitution_rates_;
  /* six integer code defining the symmetries in the subsitution matrix
    examples:
    JC/F81:   000000
    HKY/K80:  010010
    */
  std::vector<int> subs_symmetries_;
};
<commit_msg>set default model symmetry to GTR<commit_after>#pragma once

#include <vector>
#include <unordered_map>
#include "constants.hpp"

// map for determining model symmetries
const std::unordered_map<std::string, std::vector<int>> MODEL_MAP(
  {
    {"JC69", {0,0,0,0,0,0}},
    {"K80", {0,1,0,0,1,0}},
    {"GTR", {0,1,2,3,4,5}}
  }
);

/* Encapsulates the evolutionary model parameters
  TODO possible basepoint of model class hierarchy */
class Model {
public:
  Model() : Model("GTR") { }
  Model(std::string model_id);
  ~Model() = default;

  // getters
  const std::vector<double>& base_frequencies() const {return base_frequencies_;};
  std::vector<int>& symmetries()  {return subs_symmetries_;};
  const std::vector<double>& substitution_rates() const {return substitution_rates_;};
  double alpha() const {return alpha_;};

  // setters
  void base_frequencies(double* source, unsigned int length);
  void substitution_rates(double* source, unsigned int length);
  void symmetries(int* source, unsigned int length);
  void alpha(double a) {alpha_ = a;};

private:
  double alpha_;
  std::vector<double> base_frequencies_;
  std::vector<double> substitution_rates_;
  /* six integer code defining the symmetries in the subsitution matrix
    examples:
    JC/F81:   000000
    HKY/K80:  010010
    */
  std::vector<int> subs_symmetries_;
};
<|endoftext|>


<commit_before>/* Robot.cpp -- Implementation of Robot class

   Copyright (C) 2014 Tushar Pankaj

   This file is part of San Diego Robotics 101 Robosub.

   San Diego Robotics 101 Robosub is free software: you can redistribute it
   and/or modify it under the terms of the GNU General Public License as
   published by he Free Software Foundation, either version 3 of the License,
   or (at your option) any later version.

   San Diego Robotics 101 Robosub is distributed in the hope that it will be
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
   Public License for more details.

   You should have received a copy of the GNU General Public License
   along with San Diego Robotics 101 Robosub.  If not, see
   <http://www.gnu.org/licenses/>. */

#include <iostream>
#include <thread>
#include <chrono>
#include "Robot.hpp"
#include "Serial.hpp"
#include "TXPacket.hpp"

void Robot::start()
{
	serial.open_serial();
	serial.start();
	std::cout << "Moving forward at full speed...";
	serial.get_tx_packet()->set_vel_x(127);
	std::this_thread::sleep_for(std::chrono::seconds(5));
	std::cout << "done" << std::endl;
	std::cout << "Moving backward at full speed...";
	serial.get_tx_packet()->set_vel_x(-127);
	std::this_thread::sleep_for(std::chrono::seconds(5));
	serial.get_tx_packet()->set_vel_x(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving left at full speed...";
	serial.get_tx_packet()->set_vel_y(127);
	std::this_thread::sleep_for(std::chrono::seconds(5));
	std::cout << "done" << std::endl;
	std::cout << "Moving right at full speed...";
	serial.get_tx_packet()->set_vel_y(-127);
	std::this_thread::sleep_for(std::chrono::seconds(5));
	serial.get_tx_packet()->set_vel_y(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving up at full speed...";
	serial.get_tx_packet()->set_vel_z(127);
	std::this_thread::sleep_for(std::chrono::seconds(5));
	std::cout << "done" << std::endl;
	std::cout << "Moving down at full speed...";
	serial.get_tx_packet()->set_vel_z(-127);
	std::this_thread::sleep_for(std::chrono::seconds(5));
	serial.get_tx_packet()->set_vel_z(0);
	std::cout << "done" << std::endl;
}
<commit_msg>Edited robot code to ramp up each axis individually<commit_after>/* Robot.cpp -- Implementation of Robot class

   Copyright (C) 2014 Tushar Pankaj

   This file is part of San Diego Robotics 101 Robosub.

   San Diego Robotics 101 Robosub is free software: you can redistribute it
   and/or modify it under the terms of the GNU General Public License as
   published by he Free Software Foundation, either version 3 of the License,
   or (at your option) any later version.

   San Diego Robotics 101 Robosub is distributed in the hope that it will be
   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
   Public License for more details.

   You should have received a copy of the GNU General Public License
   along with San Diego Robotics 101 Robosub.  If not, see
   <http://www.gnu.org/licenses/>. */

#include <iostream>
#include <thread>
#include <chrono>
#include "Robot.hpp"
#include "Serial.hpp"
#include "TXPacket.hpp"

void Robot::start()
{
	serial.open_serial();
	serial.start();
	std::chrono::milliseconds ramp_itr_time = std::chrono::milliseconds(30);
	std::chrono::milliseconds run_time = std::chrono::milliseconds(5000);

	std::cout << "Moving in +x direction..." << std::flush;
	for (int i = 0; i <= 127; i++) {
		serial.get_tx_packet()->set_vel_x(i);
		std::this_thread::sleep_for(ramp_itr_time);
	}
	std::this_thread::sleep_for(run_time);
	serial.get_tx_packet()->set_vel_x(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving in -x direction..." << std::flush;
	for (int i = 0; i >= -128; i--) {
		serial.get_tx_packet()->set_vel_x(i);
		std::this_thread::sleep_for(ramp_itr_time);
	}
	std::this_thread::sleep_for(run_time);
	serial.get_tx_packet()->set_vel_x(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving in +y direction..." << std::flush;
	for (int i = 0; i <= 127; i++) {
		serial.get_tx_packet()->set_vel_y(i);
		std::this_thread::sleep_for(ramp_itr_time);
	}
	std::this_thread::sleep_for(run_time);
	serial.get_tx_packet()->set_vel_y(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving in -y direction..." << std::flush;
	for (int i = 0; i >= -128; i--) {
		serial.get_tx_packet()->set_vel_y(i);
		std::this_thread::sleep_for(ramp_itr_time);
	}
	std::this_thread::sleep_for(run_time);
	serial.get_tx_packet()->set_vel_y(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving in +z direction..." << std::flush;
	for (int i = 0; i <= 127; i++) {
		serial.get_tx_packet()->set_vel_z(i);
		std::this_thread::sleep_for(ramp_itr_time);
	}
	std::this_thread::sleep_for(run_time);
	serial.get_tx_packet()->set_vel_z(0);
	std::cout << "done" << std::endl;
	std::cout << "Moving in -z direction..." << std::flush;
	for (int i = 0; i >= -128; i--) {
		serial.get_tx_packet()->set_vel_z(i);
		std::this_thread::sleep_for(ramp_itr_time);
	}
	std::this_thread::sleep_for(run_time);
	serial.get_tx_packet()->set_vel_z(0);
	std::cout << "done" << std::endl;
	while (1) ;
}
<|endoftext|>


<commit_before>#pragma once

#include "sqlite.hh"

#include "pathlocks.hh"
#include "store-api.hh"
#include "sync.hh"
#include "util.hh"

#include <chrono>
#include <future>
#include <string>
#include <unordered_set>

namespace nix {

/* Nix store and database schema version.  Version 1 (or 0) was Nix <=
   0.7.  Version 2 was Nix 0.8 and 0.9.  Version 3 is Nix 0.10.
   Version 4 is Nix 0.11.  Version 5 is Nix 0.12-0.16.  Version 6 is
   Nix 1.0.  Version 7 is Nix 1.3. Version 10 is 2.0. */
const int nixSchemaVersion = 10;

struct Derivation;

struct OptimiseStats
{
    unsigned long filesLinked = 0;
    unsigned long long bytesFreed = 0;
    unsigned long long blocksFreed = 0;
};

class LocalStore : public LocalFSStore
{
private:

    /* Lock file used for upgrading. */
    AutoCloseFD globalLock;

    struct State
    {
        /* The SQLite database object. */
        SQLite db;

        /* Some precompiled SQLite statements. */
        SQLiteStmt stmtRegisterValidPath;
        SQLiteStmt stmtUpdatePathInfo;
        SQLiteStmt stmtAddReference;
        SQLiteStmt stmtQueryPathInfo;
        SQLiteStmt stmtQueryReferences;
        SQLiteStmt stmtQueryReferrers;
        SQLiteStmt stmtInvalidatePath;
        SQLiteStmt stmtAddDerivationOutput;
        SQLiteStmt stmtQueryValidDerivers;
        SQLiteStmt stmtQueryDerivationOutputs;
        SQLiteStmt stmtQueryPathFromHashPart;
        SQLiteStmt stmtQueryValidPaths;

        /* The file to which we write our temporary roots. */
        AutoCloseFD fdTempRoots;

        /* The last time we checked whether to do an auto-GC, or an
           auto-GC finished. */
        std::chrono::time_point<std::chrono::steady_clock> lastGCCheck;

        /* Whether auto-GC is running. If so, get gcFuture to wait for
           the GC to finish. */
        bool gcRunning = false;
        std::shared_future<void> gcFuture;

        /* How much disk space was available after the previous
           auto-GC. If the current available disk space is below
           minFree but not much below availAfterGC, then there is no
           point in starting a new GC. */
        uint64_t availAfterGC = std::numeric_limits<uint64_t>::max();

        std::unique_ptr<PublicKeys> publicKeys;
    };

    Sync<State, std::recursive_mutex> _state;

public:

    PathSetting realStoreDir_;

    const Path realStoreDir;
    const Path dbDir;
    const Path linksDir;
    const Path reservedPath;
    const Path schemaPath;
    const Path trashDir;
    const Path tempRootsDir;
    const Path fnTempRoots;

private:

    Setting<bool> requireSigs{(Store*) this,
        settings.requireSigs,
        "require-sigs", "whether store paths should have a trusted signature on import"};

    const PublicKeys & getPublicKeys();

public:

    // Hack for build-remote.cc.
    PathSet locksHeld;

    /* Initialise the local store, upgrading the schema if
       necessary. */
    LocalStore(const Params & params);

    ~LocalStore();

    /* Implementations of abstract store API methods. */

    std::string getUri() override;

    bool isValidPathUncached(const StorePath & path) override;

    StorePathSet queryValidPaths(const StorePathSet & paths,
        SubstituteFlag maybeSubstitute = NoSubstitute) override;

    StorePathSet queryAllValidPaths() override;

    void queryPathInfoUncached(const StorePath & path,
        Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;

    void queryReferrers(const StorePath & path, StorePathSet & referrers) override;

    StorePathSet queryValidDerivers(const StorePath & path) override;

    StorePathSet queryDerivationOutputs(const StorePath & path) override;

    std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;

    StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;

    void querySubstitutablePathInfos(const StorePathSet & paths,
        SubstitutablePathInfos & infos) override;

    void addToStore(const ValidPathInfo & info, Source & source,
        RepairFlag repair, CheckSigsFlag checkSigs,
        std::shared_ptr<FSAccessor> accessor) override;

    StorePath addToStore(const string & name, const Path & srcPath,
        FileIngestionMethod method, HashType hashAlgo,
        PathFilter & filter, RepairFlag repair) override;

    /* Like addToStore(), but the contents of the path are contained
       in `dump', which is either a NAR serialisation (if recursive ==
       true) or simply the contents of a regular file (if recursive ==
       false). */
    StorePath addToStoreFromDump(const string & dump, const string & name,
        FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) override;

    StorePath addTextToStore(const string & name, const string & s,
        const StorePathSet & references, RepairFlag repair) override;

    void buildPaths(
        const std::vector<StorePathWithOutputs> & paths,
        BuildMode buildMode) override;

    BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
        BuildMode buildMode) override;

    void ensurePath(const StorePath & path) override;

    void addTempRoot(const StorePath & path) override;

    void addIndirectRoot(const Path & path) override;

    void syncWithGC() override;

private:

    typedef std::shared_ptr<AutoCloseFD> FDPtr;
    typedef list<FDPtr> FDs;

    void findTempRoots(FDs & fds, Roots & roots, bool censor);

public:

    Roots findRoots(bool censor) override;

    void collectGarbage(const GCOptions & options, GCResults & results) override;

    /* Optimise the disk space usage of the Nix store by hard-linking
       files with the same contents. */
    void optimiseStore(OptimiseStats & stats);

    void optimiseStore() override;

    /* Optimise a single store path. */
    void optimisePath(const Path & path);

    bool verifyStore(bool checkContents, RepairFlag repair) override;

    /* Register the validity of a path, i.e., that `path' exists, that
       the paths referenced by it exists, and in the case of an output
       path of a derivation, that it has been produced by a successful
       execution of the derivation (or something equivalent).  Also
       register the hash of the file system contents of the path.  The
       hash must be a SHA-256 hash. */
    void registerValidPath(const ValidPathInfo & info);

    void registerValidPaths(const ValidPathInfos & infos);

    unsigned int getProtocol() override;

    void vacuumDB();

    /* Repair the contents of the given path by redownloading it using
       a substituter (if available). */
    void repairPath(const StorePath & path);

    void addSignatures(const StorePath & storePath, const StringSet & sigs) override;

    /* If free disk space in /nix/store if below minFree, delete
       garbage until it exceeds maxFree. */
    void autoGC(bool sync = true);

private:

    int getSchema();

    void openDB(State & state, bool create);

    void makeStoreWritable();

    uint64_t queryValidPathId(State & state, const StorePath & path);

    uint64_t addValidPath(State & state, const ValidPathInfo & info, bool checkOutputs = true);

    void invalidatePath(State & state, const StorePath & path);

    /* Delete a path from the Nix store. */
    void invalidatePathChecked(const StorePath & path);

    void verifyPath(const Path & path, const StringSet & store,
        PathSet & done, StorePathSet & validPaths, RepairFlag repair, bool & errors);

    void updatePathInfo(State & state, const ValidPathInfo & info);

    void upgradeStore6();
    void upgradeStore7();
    PathSet queryValidPathsOld();
    ValidPathInfo queryPathInfoOld(const Path & path);

    struct GCState;

    void deleteGarbage(GCState & state, const Path & path);

    void tryToDelete(GCState & state, const Path & path);

    bool canReachRoot(GCState & state, StorePathSet & visited, const StorePath & path);

    void deletePathRecursive(GCState & state, const Path & path);

    bool isActiveTempFile(const GCState & state,
        const Path & path, const string & suffix);

    AutoCloseFD openGCLock(LockType lockType);

    void findRoots(const Path & path, unsigned char type, Roots & roots);

    void findRootsNoTemp(Roots & roots, bool censor);

    void findRuntimeRoots(Roots & roots, bool censor);

    void removeUnusedLinks(const GCState & state);

    Path createTempDirInStore();

    void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);

    typedef std::unordered_set<ino_t> InodeHash;

    InodeHash loadInodeHash();
    Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash);
    void optimisePath_(Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash);

    // Internal versions that are not wrapped in retry_sqlite.
    bool isValidPath_(State & state, const StorePath & path);
    void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers);

    /* Add signatures to a ValidPathInfo using the secret keys
       specified by the ‘secret-key-files’ option. */
    void signPathInfo(ValidPathInfo & info);

    Path getRealStoreDir() override { return realStoreDir; }

    void createUser(const std::string & userName, uid_t userId) override;

    friend class DerivationGoal;
    friend class SubstitutionGoal;
};

typedef std::pair<dev_t, ino_t> Inode;
typedef set<Inode> InodesSeen;

/* "Fix", or canonicalise, the meta-data of the files in a store path
   after it has been built.  In particular:
   - the last modification date on each file is set to 1 (i.e.,
     00:00:01 1/1/1970 UTC)
   - the permissions are set of 444 or 555 (i.e., read-only with or
     without execute permission; setuid bits etc. are cleared)
   - the owner and group are set to the Nix user and group, if we're
     running as root. */
void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & inodesSeen);
void canonicalisePathMetaData(const Path & path, uid_t fromUid);

void canonicaliseTimestampAndPermissions(const Path & path);

MakeError(PathInUse, Error);

}
<commit_msg>Don't need abstract `struct Derivation` in local-store<commit_after>#pragma once

#include "sqlite.hh"

#include "pathlocks.hh"
#include "store-api.hh"
#include "sync.hh"
#include "util.hh"

#include <chrono>
#include <future>
#include <string>
#include <unordered_set>

namespace nix {

/* Nix store and database schema version.  Version 1 (or 0) was Nix <=
   0.7.  Version 2 was Nix 0.8 and 0.9.  Version 3 is Nix 0.10.
   Version 4 is Nix 0.11.  Version 5 is Nix 0.12-0.16.  Version 6 is
   Nix 1.0.  Version 7 is Nix 1.3. Version 10 is 2.0. */
const int nixSchemaVersion = 10;

struct OptimiseStats
{
    unsigned long filesLinked = 0;
    unsigned long long bytesFreed = 0;
    unsigned long long blocksFreed = 0;
};

class LocalStore : public LocalFSStore
{
private:

    /* Lock file used for upgrading. */
    AutoCloseFD globalLock;

    struct State
    {
        /* The SQLite database object. */
        SQLite db;

        /* Some precompiled SQLite statements. */
        SQLiteStmt stmtRegisterValidPath;
        SQLiteStmt stmtUpdatePathInfo;
        SQLiteStmt stmtAddReference;
        SQLiteStmt stmtQueryPathInfo;
        SQLiteStmt stmtQueryReferences;
        SQLiteStmt stmtQueryReferrers;
        SQLiteStmt stmtInvalidatePath;
        SQLiteStmt stmtAddDerivationOutput;
        SQLiteStmt stmtQueryValidDerivers;
        SQLiteStmt stmtQueryDerivationOutputs;
        SQLiteStmt stmtQueryPathFromHashPart;
        SQLiteStmt stmtQueryValidPaths;

        /* The file to which we write our temporary roots. */
        AutoCloseFD fdTempRoots;

        /* The last time we checked whether to do an auto-GC, or an
           auto-GC finished. */
        std::chrono::time_point<std::chrono::steady_clock> lastGCCheck;

        /* Whether auto-GC is running. If so, get gcFuture to wait for
           the GC to finish. */
        bool gcRunning = false;
        std::shared_future<void> gcFuture;

        /* How much disk space was available after the previous
           auto-GC. If the current available disk space is below
           minFree but not much below availAfterGC, then there is no
           point in starting a new GC. */
        uint64_t availAfterGC = std::numeric_limits<uint64_t>::max();

        std::unique_ptr<PublicKeys> publicKeys;
    };

    Sync<State, std::recursive_mutex> _state;

public:

    PathSetting realStoreDir_;

    const Path realStoreDir;
    const Path dbDir;
    const Path linksDir;
    const Path reservedPath;
    const Path schemaPath;
    const Path trashDir;
    const Path tempRootsDir;
    const Path fnTempRoots;

private:

    Setting<bool> requireSigs{(Store*) this,
        settings.requireSigs,
        "require-sigs", "whether store paths should have a trusted signature on import"};

    const PublicKeys & getPublicKeys();

public:

    // Hack for build-remote.cc.
    PathSet locksHeld;

    /* Initialise the local store, upgrading the schema if
       necessary. */
    LocalStore(const Params & params);

    ~LocalStore();

    /* Implementations of abstract store API methods. */

    std::string getUri() override;

    bool isValidPathUncached(const StorePath & path) override;

    StorePathSet queryValidPaths(const StorePathSet & paths,
        SubstituteFlag maybeSubstitute = NoSubstitute) override;

    StorePathSet queryAllValidPaths() override;

    void queryPathInfoUncached(const StorePath & path,
        Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept override;

    void queryReferrers(const StorePath & path, StorePathSet & referrers) override;

    StorePathSet queryValidDerivers(const StorePath & path) override;

    StorePathSet queryDerivationOutputs(const StorePath & path) override;

    std::optional<StorePath> queryPathFromHashPart(const std::string & hashPart) override;

    StorePathSet querySubstitutablePaths(const StorePathSet & paths) override;

    void querySubstitutablePathInfos(const StorePathSet & paths,
        SubstitutablePathInfos & infos) override;

    void addToStore(const ValidPathInfo & info, Source & source,
        RepairFlag repair, CheckSigsFlag checkSigs,
        std::shared_ptr<FSAccessor> accessor) override;

    StorePath addToStore(const string & name, const Path & srcPath,
        FileIngestionMethod method, HashType hashAlgo,
        PathFilter & filter, RepairFlag repair) override;

    /* Like addToStore(), but the contents of the path are contained
       in `dump', which is either a NAR serialisation (if recursive ==
       true) or simply the contents of a regular file (if recursive ==
       false). */
    StorePath addToStoreFromDump(const string & dump, const string & name,
        FileIngestionMethod method = FileIngestionMethod::Recursive, HashType hashAlgo = htSHA256, RepairFlag repair = NoRepair) override;

    StorePath addTextToStore(const string & name, const string & s,
        const StorePathSet & references, RepairFlag repair) override;

    void buildPaths(
        const std::vector<StorePathWithOutputs> & paths,
        BuildMode buildMode) override;

    BuildResult buildDerivation(const StorePath & drvPath, const BasicDerivation & drv,
        BuildMode buildMode) override;

    void ensurePath(const StorePath & path) override;

    void addTempRoot(const StorePath & path) override;

    void addIndirectRoot(const Path & path) override;

    void syncWithGC() override;

private:

    typedef std::shared_ptr<AutoCloseFD> FDPtr;
    typedef list<FDPtr> FDs;

    void findTempRoots(FDs & fds, Roots & roots, bool censor);

public:

    Roots findRoots(bool censor) override;

    void collectGarbage(const GCOptions & options, GCResults & results) override;

    /* Optimise the disk space usage of the Nix store by hard-linking
       files with the same contents. */
    void optimiseStore(OptimiseStats & stats);

    void optimiseStore() override;

    /* Optimise a single store path. */
    void optimisePath(const Path & path);

    bool verifyStore(bool checkContents, RepairFlag repair) override;

    /* Register the validity of a path, i.e., that `path' exists, that
       the paths referenced by it exists, and in the case of an output
       path of a derivation, that it has been produced by a successful
       execution of the derivation (or something equivalent).  Also
       register the hash of the file system contents of the path.  The
       hash must be a SHA-256 hash. */
    void registerValidPath(const ValidPathInfo & info);

    void registerValidPaths(const ValidPathInfos & infos);

    unsigned int getProtocol() override;

    void vacuumDB();

    /* Repair the contents of the given path by redownloading it using
       a substituter (if available). */
    void repairPath(const StorePath & path);

    void addSignatures(const StorePath & storePath, const StringSet & sigs) override;

    /* If free disk space in /nix/store if below minFree, delete
       garbage until it exceeds maxFree. */
    void autoGC(bool sync = true);

private:

    int getSchema();

    void openDB(State & state, bool create);

    void makeStoreWritable();

    uint64_t queryValidPathId(State & state, const StorePath & path);

    uint64_t addValidPath(State & state, const ValidPathInfo & info, bool checkOutputs = true);

    void invalidatePath(State & state, const StorePath & path);

    /* Delete a path from the Nix store. */
    void invalidatePathChecked(const StorePath & path);

    void verifyPath(const Path & path, const StringSet & store,
        PathSet & done, StorePathSet & validPaths, RepairFlag repair, bool & errors);

    void updatePathInfo(State & state, const ValidPathInfo & info);

    void upgradeStore6();
    void upgradeStore7();
    PathSet queryValidPathsOld();
    ValidPathInfo queryPathInfoOld(const Path & path);

    struct GCState;

    void deleteGarbage(GCState & state, const Path & path);

    void tryToDelete(GCState & state, const Path & path);

    bool canReachRoot(GCState & state, StorePathSet & visited, const StorePath & path);

    void deletePathRecursive(GCState & state, const Path & path);

    bool isActiveTempFile(const GCState & state,
        const Path & path, const string & suffix);

    AutoCloseFD openGCLock(LockType lockType);

    void findRoots(const Path & path, unsigned char type, Roots & roots);

    void findRootsNoTemp(Roots & roots, bool censor);

    void findRuntimeRoots(Roots & roots, bool censor);

    void removeUnusedLinks(const GCState & state);

    Path createTempDirInStore();

    void checkDerivationOutputs(const StorePath & drvPath, const Derivation & drv);

    typedef std::unordered_set<ino_t> InodeHash;

    InodeHash loadInodeHash();
    Strings readDirectoryIgnoringInodes(const Path & path, const InodeHash & inodeHash);
    void optimisePath_(Activity * act, OptimiseStats & stats, const Path & path, InodeHash & inodeHash);

    // Internal versions that are not wrapped in retry_sqlite.
    bool isValidPath_(State & state, const StorePath & path);
    void queryReferrers(State & state, const StorePath & path, StorePathSet & referrers);

    /* Add signatures to a ValidPathInfo using the secret keys
       specified by the ‘secret-key-files’ option. */
    void signPathInfo(ValidPathInfo & info);

    Path getRealStoreDir() override { return realStoreDir; }

    void createUser(const std::string & userName, uid_t userId) override;

    friend class DerivationGoal;
    friend class SubstitutionGoal;
};

typedef std::pair<dev_t, ino_t> Inode;
typedef set<Inode> InodesSeen;

/* "Fix", or canonicalise, the meta-data of the files in a store path
   after it has been built.  In particular:
   - the last modification date on each file is set to 1 (i.e.,
     00:00:01 1/1/1970 UTC)
   - the permissions are set of 444 or 555 (i.e., read-only with or
     without execute permission; setuid bits etc. are cleared)
   - the owner and group are set to the Nix user and group, if we're
     running as root. */
void canonicalisePathMetaData(const Path & path, uid_t fromUid, InodesSeen & inodesSeen);
void canonicalisePathMetaData(const Path & path, uid_t fromUid);

void canonicaliseTimestampAndPermissions(const Path & path);

MakeError(PathInUse, Error);

}
<|endoftext|>


<commit_before>#include "test_pal.h"

#include "pal.h"
//#include <cppunit/config/SourcePrefix.h>

namespace Microsoft {

    CPPUNIT_TEST_SUITE_REGISTRATION(PalTestSuite);

    void PalTestSuite::testDatatypes() {

        // windows datatypes
        CPPUNIT_ASSERT_EQUAL(sizeof(WORD),(std::size_t)2);
        CPPUNIT_ASSERT_EQUAL(sizeof(DWORD),(std::size_t)4);

        // windows integer datatypes
        CPPUNIT_ASSERT_EQUAL(sizeof(INT),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT8),(std::size_t)1);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT16),(std::size_t)2);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT32),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT64),(std::size_t)8);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT8),(std::size_t)1);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT16),(std::size_t)2);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT32),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT64),(std::size_t)8);

        // windows integer max and min size constants
        CPPUNIT_ASSERT_EQUAL(CHAR_BIT,8);
        CPPUNIT_ASSERT_EQUAL(SCHAR_MIN,-127-1);
        CPPUNIT_ASSERT_EQUAL(SCHAR_MAX,127);
        CPPUNIT_ASSERT_EQUAL(UCHAR_MAX,0xff);
        CPPUNIT_ASSERT_EQUAL(SHRT_MIN,-32767-1);
        CPPUNIT_ASSERT_EQUAL(SHRT_MAX,32767);
        CPPUNIT_ASSERT_EQUAL(USHRT_MAX,0xffff);
        CPPUNIT_ASSERT_EQUAL(INT_MIN,-2147483647-1);
        CPPUNIT_ASSERT_EQUAL(INT_MAX,2147483647);
        CPPUNIT_ASSERT_EQUAL(UINT_MAX,0xffffffff);
        CPPUNIT_ASSERT_EQUAL(LONG_MIN,-2147483647L-1);
        CPPUNIT_ASSERT_EQUAL(LONG_MAX,2147483647L);
        CPPUNIT_ASSERT_EQUAL(ULONG_MAX,0xffffffff);

    }

}<commit_msg>added some more checks for basic windows data types<commit_after>#include "test_pal.h"

#include "pal.h"
//#include <cppunit/config/SourcePrefix.h>

namespace Microsoft {

    CPPUNIT_TEST_SUITE_REGISTRATION(PalTestSuite);

    void PalTestSuite::testDatatypes() {

        // check basic pointer lengths
        CPPUNIT_ASSERT_EQUAL(sizeof(void*), sizeof(PVOID));

        // windows datatypes
        CPPUNIT_ASSERT_EQUAL(sizeof(WORD),(std::size_t)2);
        CPPUNIT_ASSERT_EQUAL(sizeof(DWORD),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(HANDLE),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HWND),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HMODULE),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HINSTANCE),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HGLOBAL),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HLOCAL),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HRSRC),sizeof(void*));
        CPPUNIT_ASSERT_EQUAL(sizeof(HRESULT),sizeof(LONG));
        CPPUNIT_ASSERT_EQUAL(sizeof(NTSTATUS),sizeof(LONG));

        // windows integer datatypes
        CPPUNIT_ASSERT_EQUAL(sizeof(INT),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT8),(std::size_t)1);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT16),(std::size_t)2);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT32),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(INT64),(std::size_t)8);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT8),(std::size_t)1);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT16),(std::size_t)2);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT32),(std::size_t)4);
        CPPUNIT_ASSERT_EQUAL(sizeof(UINT64),(std::size_t)8);

        // windows integer max and min size constants
        CPPUNIT_ASSERT_EQUAL(CHAR_BIT,8);
        CPPUNIT_ASSERT_EQUAL(SCHAR_MIN,-127-1);
        CPPUNIT_ASSERT_EQUAL(SCHAR_MAX,127);
        CPPUNIT_ASSERT_EQUAL(UCHAR_MAX,0xff);
        CPPUNIT_ASSERT_EQUAL(SHRT_MIN,-32767-1);
        CPPUNIT_ASSERT_EQUAL(SHRT_MAX,32767);
        CPPUNIT_ASSERT_EQUAL(USHRT_MAX,0xffff);
        CPPUNIT_ASSERT_EQUAL(INT_MIN,-2147483647-1);
        CPPUNIT_ASSERT_EQUAL(INT_MAX,2147483647);
        CPPUNIT_ASSERT_EQUAL(UINT_MAX,0xffffffff);
        CPPUNIT_ASSERT_EQUAL(LONG_MIN,-2147483647L-1);
        CPPUNIT_ASSERT_EQUAL(LONG_MAX,2147483647L);
        CPPUNIT_ASSERT_EQUAL(ULONG_MAX,0xffffffff);

        CPPUNIT_ASSERT_EQUAL(MAXSHORT,0x7fff);
        CPPUNIT_ASSERT_EQUAL(MAXLONG,0x7fffffff);
        CPPUNIT_ASSERT_EQUAL(MAXCHAR,0x7f);
        CPPUNIT_ASSERT_EQUAL(MAXDWORD,0xffffffff);

        // character data types
        CPPUNIT_ASSERT_EQUAL(sizeof(CHAR),(std::size_t)1);
        CPPUNIT_ASSERT_EQUAL(sizeof(TCHAR),(std::size_t)1);

    }

}<|endoftext|>