<commit_before>/*
 *	info≈
 *	External object for Max/MSP to get information about TTAudioSignals from a lydbær dsp chain.
 *	Copyright © 2008 by Timothy Place
 *
 *	License: This code is licensed under the terms of the GNU LGPL
 *	http://www.gnu.org/licenses/lgpl.html
 */

#include "maxbaer.h"

// Data Structure for this object
typedef struct LydInfo {
    t_object			obj;
	LydbaerObjectPtr	audioSourceObject;
	TTPtr				outletSampleRate;
	TTPtr				outletVectorSize;
	TTPtr				outletNumChannels;
	long				maxNumChannels;	// the number of inlets or outlets, which is an argument at instantiation
	long				numChannels;	// the actual number of channels to use, set by the dsp method
	long				vectorSize;		// cached by the DSP method
	float				gain;			// gain multiplier
};
typedef LydInfo* LydInfoPtr;

// Prototypes for methods
LydInfoPtr	lydInfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv);
void		lydInfoFree(LydInfoPtr x);
void		lydInfoAssist(LydInfoPtr x, void* b, long msg, long arg, char* dst);
void		lydInfoBang(LydInfoPtr x);
TTErr		lydInfoReset(LydInfoPtr x, long vectorSize);
TTErr		lydInfoObject(LydInfoPtr x, LydbaerObjectPtr audioSourceObject);

// Globals
static ClassPtr sLydInfoClass;

/************************************************************************************/
// Main() Function

int main(void)
{
	t_class *c;

	TTBlueInit();
	common_symbols_init();

	c = class_new("info≈", (method)lydInfoNew, (method)lydInfoFree, sizeof(LydInfo), (method)0L, A_GIMME, 0);

	class_addmethod(c, (method)lydInfoBang,				"bang",				0);
	class_addmethod(c, (method)lydInfoReset,			"lydbaerReset",		A_CANT, 0);
	class_addmethod(c, (method)lydInfoObject,			"lydbaerObject",	A_OBJ,	0);
	class_addmethod(c, (method)lydInfoAssist,			"assist",			A_CANT, 0);
    class_addmethod(c, (method)object_obex_dumpout,		"dumpout",			A_CANT, 0);

	class_register(_sym_box, c);
	sLydInfoClass = c;
	return 0;
}

/************************************************************************************/
// Object Creation Method

LydInfoPtr lydInfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv)
{
    LydInfoPtr	x;

    x = LydInfoPtr(object_alloc(sLydInfoClass));
    if(x){

		attr_args_process(x,argc,argv);				// handle attribute args

    	object_obex_store((void *)x, _sym_dumpout, (object *)outlet_new(x,NULL));	// dumpout
//	    dsp_setup((t_pxobject *)x, 1);
		x->outletNumChannels = outlet_new((t_pxobject *)x, 0L);;
		x->outletVectorSize = outlet_new((t_pxobject *)x, 0L);;
		x->outletSampleRate = outlet_new((t_pxobject *)x, 0L);;
	}
	return x;
}

// Memory Deallocation
void lydInfoFree(LydInfoPtr x)
{
	;
}

/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void lydInfoAssist(LydInfoPtr x, void* b, long msg, long arg, char* dst)
{
	if(msg==1)			// Inlets
		strcpy(dst, "multichannel audio connection and control messages");
	else if(msg==2){	// Outlets
		if(arg == 0)
			strcpy(dst, "sample rate of the input signal");
		else if(arg == 1)
			strcpy(dst, "vector size of the input signal");
		else if(arg == 2)
			strcpy(dst, "number of channels in the input signal");
		else if(arg == 3)
			strcpy(dst, "dumpout");
	}
}

void lydInfoBang(LydInfoPtr x)
{
	if(x->audioSourceObject){
		outlet_int(x->outletNumChannels, x->audioSourceObject->getNumOutputChannels());
		outlet_int(x->outletVectorSize, x->audioSourceObject->getOutputVectorSize());
		outlet_int(x->outletSampleRate, x->audioSourceObject->getSampleRate());
	}
	else{
		object_post(ObjectPtr(x), "No valid audio signals connected.");
	}
}

TTErr lydInfoReset(LydInfoPtr x, long vectorSize)
{
	x->audioSourceObject = NULL;
	return kTTErrNone;
}

TTErr lydInfoObject(LydInfoPtr x, LydbaerObjectPtr newAudioSourceObject)
{
	x->audioSourceObject = newAudioSourceObject;
	lydInfoBang(x);
	return kTTErrNone;
}

<commit_msg>info≈ uses a queue to guarantee correct reporting of signal info when the audio graph is first built.<commit_after>/*
 *	info≈
 *	External object for Max/MSP to get information about TTAudioSignals from a lydbær dsp chain.
 *	Copyright © 2008 by Timothy Place
 *
 *	License: This code is licensed under the terms of the GNU LGPL
 *	http://www.gnu.org/licenses/lgpl.html
 */

#include "maxbaer.h"

// Data Structure for this object
typedef struct LydInfo {
    t_object			obj;
	LydbaerObjectPtr	audioSourceObject;
	TTPtr				outletSampleRate;
	TTPtr				outletVectorSize;
	TTPtr				outletNumChannels;
	long				maxNumChannels;	// the number of inlets or outlets, which is an argument at instantiation
	long				numChannels;	// the actual number of channels to use, set by the dsp method
	long				vectorSize;		// cached by the DSP method
	float				gain;			// gain multiplier
	TTPtr				qelem;			// a queue for deferring 'bang' calls
};
typedef LydInfo* LydInfoPtr;

// Prototypes for methods
LydInfoPtr	lydInfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv);
void		lydInfoFree(LydInfoPtr x);
void		lydInfoAssist(LydInfoPtr x, void* b, long msg, long arg, char* dst);
void		lydInfoBang(LydInfoPtr x);
void		lyInfoQfn(LydInfoPtr x);
TTErr		lydInfoReset(LydInfoPtr x, long vectorSize);
TTErr		lydInfoObject(LydInfoPtr x, LydbaerObjectPtr audioSourceObject);

// Globals
static ClassPtr sLydInfoClass;

/************************************************************************************/
// Main() Function

int main(void)
{
	t_class *c;

	TTBlueInit();
	common_symbols_init();

	c = class_new("info≈", (method)lydInfoNew, (method)lydInfoFree, sizeof(LydInfo), (method)0L, A_GIMME, 0);

	class_addmethod(c, (method)lydInfoBang,				"bang",				0);
	class_addmethod(c, (method)lydInfoReset,			"lydbaerReset",		A_CANT, 0);
	class_addmethod(c, (method)lydInfoObject,			"lydbaerObject",	A_OBJ,	0);
	class_addmethod(c, (method)lydInfoAssist,			"assist",			A_CANT, 0);
    class_addmethod(c, (method)object_obex_dumpout,		"dumpout",			A_CANT, 0);

	class_register(_sym_box, c);
	sLydInfoClass = c;
	return 0;
}

/************************************************************************************/
// Object Creation Method

LydInfoPtr lydInfoNew(SymbolPtr msg, AtomCount argc, AtomPtr argv)
{
    LydInfoPtr	x;

    x = LydInfoPtr(object_alloc(sLydInfoClass));
    if(x){
    	object_obex_store((void *)x, _sym_dumpout, (object *)outlet_new(x,NULL));	// dumpout
		x->outletNumChannels = outlet_new((t_pxobject *)x, 0L);;
		x->outletVectorSize = outlet_new((t_pxobject *)x, 0L);;
		x->outletSampleRate = outlet_new((t_pxobject *)x, 0L);;

		x->qelem = qelem_new(x, (method)lyInfoQfn);

		attr_args_process(x,argc,argv);				// handle attribute args

	}
	return x;
}

// Memory Deallocation
void lydInfoFree(LydInfoPtr x)
{
	qelem_free(x->qelem);
}

/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void lydInfoAssist(LydInfoPtr x, void* b, long msg, long arg, char* dst)
{
	if(msg==1)			// Inlets
		strcpy(dst, "multichannel audio connection and control messages");
	else if(msg==2){	// Outlets
		if(arg == 0)
			strcpy(dst, "sample rate of the input signal");
		else if(arg == 1)
			strcpy(dst, "vector size of the input signal");
		else if(arg == 2)
			strcpy(dst, "number of channels in the input signal");
		else if(arg == 3)
			strcpy(dst, "dumpout");
	}
}

void lydInfoBang(LydInfoPtr x)
{
	qelem_set(x->qelem);
}

void lyInfoQfn(LydInfoPtr x)
{
	if(x->audioSourceObject){
		outlet_int(x->outletNumChannels, x->audioSourceObject->getNumOutputChannels());
		outlet_int(x->outletVectorSize, x->audioSourceObject->getOutputVectorSize());
		outlet_int(x->outletSampleRate, x->audioSourceObject->getSampleRate());
	}
	else{
		object_post(ObjectPtr(x), "No valid audio signals connected.");
	}
}

TTErr lydInfoReset(LydInfoPtr x, long vectorSize)
{
	x->audioSourceObject = NULL;
	return kTTErrNone;
}

TTErr lydInfoObject(LydInfoPtr x, LydbaerObjectPtr newAudioSourceObject)
{
	x->audioSourceObject = newAudioSourceObject;
	lydInfoBang(x);
	return kTTErrNone;
}

<|endoftext|>


<commit_before>/*
Same as parallel.cpp but takes advantage of additional threads via std::async.

Copyright 2013, 2014, 2015 Ilja Honkonen
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of copyright holders nor the names of their contributors
  may be used to endorse or promote products derived from this software
  without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! see ../*/parallel/* for basics

#include "array"
#include "boost/lexical_cast.hpp"
#include "cmath"
#include "cstdlib"
#include "future"
#include "iostream"
#include "mpi.h"

#include "dccrg.hpp"
#include "dccrg_cartesian_geometry.hpp"
#include "gensimcell.hpp"

#include "gol_initialize.hpp"
#include "gol_save.hpp"
#include "gol_solve.hpp"
#include "gol_variables.hpp"
#include "advection_initialize.hpp"
#include "advection_save.hpp"
#include "advection_solve.hpp"
#include "advection_variables.hpp"
#include "particle_initialize.hpp"
#include "particle_save.hpp"
#include "particle_solve.hpp"
#include "particle_variables.hpp"
#include "combined_variables.hpp"

int main(int argc, char* argv[])
{
	// the cell type used by this program
	using Cell = combined::Cell;

	/*
	Set up MPI
	*/
	if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
		std::cerr << "Coudln't initialize MPI." << std::endl;
		abort();
	}

	MPI_Comm comm = MPI_COMM_WORLD;

	int rank = 0, comm_size = 0;
	MPI_Comm_rank(comm, &rank);
	MPI_Comm_size(comm, &comm_size);

	// intialize Zoltan
	float zoltan_version;
	if (Zoltan_Initialize(argc, argv, &zoltan_version) != ZOLTAN_OK) {
		std::cerr << "Zoltan_Initialize failed." << std::endl;
		abort();
	}

	/*
	Set up the grid in which the simulation will run
	*/
	dccrg::Dccrg<Cell, dccrg::Cartesian_Geometry> grid;

	// initialize the grid
	std::array<uint64_t, 3> grid_length = {{20, 20, 1}};
	const unsigned int neighborhood_size = 1;
	if (not grid.initialize(
		grid_length,
		comm,
		"RANDOM",
		neighborhood_size,
		0,
		false, false, false
	)) {
		std::cerr << __FILE__ << ":" << __LINE__
			<< ": Couldn't initialize grid."
			<< std::endl;
		abort();
	}

	// set the grid's geometry
	dccrg::Cartesian_Geometry::Parameters geom_params;
	geom_params.start[0] =
	geom_params.start[1] = -1;
	geom_params.start[2] = -1.0 / grid_length[0];
	geom_params.level_0_cell_length[0] =
	geom_params.level_0_cell_length[1] =
	geom_params.level_0_cell_length[2] = 2.0 / grid_length[0];
	if (not grid.set_geometry(geom_params)) {
		std::cerr << __FILE__ << ":" << __LINE__
			<< ": Couldn't set grid geometry."
			<< std::endl;
		abort();
	}

	grid.balance_load();

	/*
	Simulate
	*/

	gol::initialize<
		Cell,
		gol::Is_Alive,
		gol::Live_Neighbors
	>(grid);

	advection::initialize<
		Cell,
		advection::Density,
		advection::Density_Flux,
		advection::Velocity
	>(grid);

	particle::initialize<
		Cell,
		particle::Number_Of_Internal_Particles,
		particle::Number_Of_External_Particles,
		particle::Velocity,
		particle::Internal_Particles,
		particle::External_Particles
	>(grid);

	const std::vector<uint64_t>
		inner_cells = grid.get_local_cells_not_on_process_boundary(),
		outer_cells = grid.get_local_cells_on_process_boundary();

	const double advection_save_interval = 0.1;
	const double particle_save_interval = 0.1;

	double
		advection_next_save = 0,
		particle_next_save = 0,
		simulation_time = 0,
		time_step = 0;

	/*
	Function templates are not suitable for std::async so make lambdas
	*/

	// game of life
	auto gol_inner_solve = [&](){
		return gol::solve<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(inner_cells, grid);
	};
	auto gol_outer_solve = [&](){
		return gol::solve<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(outer_cells, grid);
	};
	auto gol_inner_apply = [&](){
		return gol::apply_solution<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(inner_cells, grid);
	};
	auto gol_outer_apply = [&](){
		return gol::apply_solution<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(outer_cells, grid);
	};

	// advection
	auto advection_inner_solve = [&](){
		return advection::solve<
			Cell,
			advection::Density,
			advection::Density_Flux,
			advection::Velocity
		>(time_step, inner_cells, grid);
	};
	auto advection_outer_solve = [&](){
		return advection::solve<
			Cell,
			advection::Density,
			advection::Density_Flux,
			advection::Velocity
		>(time_step, outer_cells, grid);
	};
	auto advection_inner_apply = [&](){
		return advection::apply_solution<
			Cell,
			advection::Density,
			advection::Density_Flux
		>(inner_cells, grid);
	};
	auto advection_outer_apply = [&](){
		return advection::apply_solution<
			Cell,
			advection::Density,
			advection::Density_Flux
		>(outer_cells, grid);
	};

	// particle propagation
	auto particle_incorporate_inner = [&](){
		return particle::incorporate_external_particles<
			Cell,
			particle::Number_Of_Internal_Particles,
			particle::Internal_Particles,
			particle::External_Particles
		>(inner_cells, grid);
	};
	auto particle_incorporate_outer = [&](){
		return particle::incorporate_external_particles<
			Cell,
			particle::Number_Of_Internal_Particles,
			particle::Internal_Particles,
			particle::External_Particles
		>(outer_cells, grid);
	};
	auto particle_remove_inner = [&](){
		return particle::remove_external_particles<
			Cell,
			particle::Number_Of_External_Particles,
			particle::External_Particles
		>(inner_cells, grid);
	};
	auto particle_remove_outer = [&](){
		return particle::remove_external_particles<
			Cell,
			particle::Number_Of_External_Particles,
			particle::External_Particles
		>(outer_cells, grid);
	};

	while (simulation_time <= M_PI) {

		double next_time_step = std::numeric_limits<double>::max();

		/*
		Save simulations
		*/

		// saving functions decide what to transfer to disk
		/*Cell::set_transfer_all(
			false,
			gol::Is_Alive(),
			gol::Live_Neighbors()
		);

		Cell::set_transfer_all(
			false,
			advection::Density(),
			advection::Density_Flux(),
			advection::Velocity()
		);

		Cell::set_transfer_all(
			false,
			particle::Number_Of_Internal_Particles(),
			particle::Number_Of_External_Particles(),
			particle::Velocity(),
			particle::Internal_Particles(),
			particle::External_Particles()
		);

		gol::save<Cell, gol::Is_Alive>(grid, simulation_time);

		if (advection_next_save <= simulation_time) {
			advection_next_save += advection_save_interval;

			advection::save<
				Cell,
				advection::Density,
				advection::Velocity
			>(grid, simulation_time);
		}

		if (particle_next_save <= simulation_time) {
			particle_next_save += particle_save_interval;

			particle::save<
				Cell,
				particle::Number_Of_Internal_Particles,
				particle::Velocity,
				particle::Internal_Particles
			>(grid, simulation_time);
		}

		if (simulation_time >= M_PI) {
			break;
		}*/

		/*
		Solve
		*/

		// must finish immediately
		next_time_step
			= std::min(
				next_time_step,
				particle::solve<
					Cell,
					particle::Number_Of_Internal_Particles,
					particle::Number_Of_External_Particles,
					particle::Velocity,
					particle::Internal_Particles,
					particle::External_Particles
				>(time_step, outer_cells, grid)
			);

		Cell::set_transfer_all(true, particle::Number_Of_External_Particles());
		grid.start_remote_neighbor_copy_updates();

		// must finish immediately
		next_time_step
			= std::min(
				next_time_step,
				particle::solve<
					Cell,
					particle::Number_Of_Internal_Particles,
					particle::Number_Of_External_Particles,
					particle::Velocity,
					particle::Internal_Particles,
					particle::External_Particles
				>(time_step, inner_cells, grid)
			);

		grid.wait_remote_neighbor_copy_update_receives();

		// must finish almost immediately
		particle::resize_receiving_containers<
			Cell,
			particle::Number_Of_External_Particles,
			particle::External_Particles
		>(grid);

		grid.wait_remote_neighbor_copy_update_sends();

		Cell::set_transfer_all(true, gol::Is_Alive());
		Cell::set_transfer_all(
			true,
			advection::Density(),
			advection::Velocity()
		);
		Cell::set_transfer_all(false, particle::Number_Of_External_Particles());
		Cell::set_transfer_all(
			true,
			particle::Velocity(),
			particle::External_Particles()
		);
		grid.start_remote_neighbor_copy_updates();

		auto gol_inner_solve_future = std::async(gol_inner_solve);
		auto advection_inner_solve_future = std::async(advection_inner_solve);
		auto particle_incorporate_inner_future = std::async(particle_incorporate_inner);

		gol_inner_solve_future.get();
		next_time_step
			= std::min(
				next_time_step,
				advection_inner_solve_future.get()
			);
		particle_incorporate_inner_future.get();

		grid.wait_remote_neighbor_copy_update_receives();

		auto gol_outer_solve_future = std::async(gol_outer_solve);
		auto gol_inner_apply_future = std::async(gol_inner_apply);
		auto advection_outer_solve_future = std::async(advection_outer_solve);
		auto advection_inner_apply_future = std::async(advection_inner_apply);
		auto particle_incorporate_outer_future = std::async(particle_incorporate_outer);
		auto particle_remove_inner_future = std::async(particle_remove_inner);

		gol_outer_solve_future.get();
		next_time_step
			= std::min(
				next_time_step,
				advection_outer_solve_future.get()
			);
		gol_inner_apply_future.get();
		advection_inner_apply_future.get();
		particle_incorporate_outer_future.get();
		particle_remove_inner_future.get();

		grid.wait_remote_neighbor_copy_update_sends();
		Cell::set_transfer_all(false, gol::Is_Alive());
		Cell::set_transfer_all(
			false,
			advection::Density(),
			advection::Velocity()
		);
		Cell::set_transfer_all(
			false,
			particle::Velocity(),
			particle::External_Particles()
		);

		auto gol_outer_apply_future = std::async(gol_outer_apply);
		auto advection_outer_apply_future = std::async(advection_outer_apply);
		auto particle_remove_outer_future = std::async(particle_remove_outer);

		simulation_time += time_step;

		gol_outer_apply_future.get();
		advection_outer_apply_future.get();
		particle_remove_outer_future.get();

		MPI_Allreduce(&next_time_step, &time_step, 1, MPI_DOUBLE, MPI_MIN, comm);
		const double CFL = 0.5;
		time_step *= CFL;
	}

	MPI_Finalize();

	return EXIT_SUCCESS;
}
<commit_msg>Comment out unused variables from threaded version of combined example program.<commit_after>/*
Same as parallel.cpp but takes advantage of additional threads via std::async.

Copyright 2013, 2014, 2015 Ilja Honkonen
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this
  list of conditions and the following disclaimer in the documentation and/or
  other materials provided with the distribution.

* Neither the name of copyright holders nor the names of their contributors
  may be used to endorse or promote products derived from this software
  without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! see ../*/parallel/* for basics

#include "array"
#include "boost/lexical_cast.hpp"
#include "cmath"
#include "cstdlib"
#include "future"
#include "iostream"
#include "mpi.h"

#include "dccrg.hpp"
#include "dccrg_cartesian_geometry.hpp"
#include "gensimcell.hpp"

#include "gol_initialize.hpp"
#include "gol_save.hpp"
#include "gol_solve.hpp"
#include "gol_variables.hpp"
#include "advection_initialize.hpp"
#include "advection_save.hpp"
#include "advection_solve.hpp"
#include "advection_variables.hpp"
#include "particle_initialize.hpp"
#include "particle_save.hpp"
#include "particle_solve.hpp"
#include "particle_variables.hpp"
#include "combined_variables.hpp"

int main(int argc, char* argv[])
{
	// the cell type used by this program
	using Cell = combined::Cell;

	/*
	Set up MPI
	*/
	if (MPI_Init(&argc, &argv) != MPI_SUCCESS) {
		std::cerr << "Coudln't initialize MPI." << std::endl;
		abort();
	}

	MPI_Comm comm = MPI_COMM_WORLD;

	int rank = 0, comm_size = 0;
	MPI_Comm_rank(comm, &rank);
	MPI_Comm_size(comm, &comm_size);

	// intialize Zoltan
	float zoltan_version;
	if (Zoltan_Initialize(argc, argv, &zoltan_version) != ZOLTAN_OK) {
		std::cerr << "Zoltan_Initialize failed." << std::endl;
		abort();
	}

	/*
	Set up the grid in which the simulation will run
	*/
	dccrg::Dccrg<Cell, dccrg::Cartesian_Geometry> grid;

	// initialize the grid
	std::array<uint64_t, 3> grid_length = {{20, 20, 1}};
	const unsigned int neighborhood_size = 1;
	if (not grid.initialize(
		grid_length,
		comm,
		"RANDOM",
		neighborhood_size,
		0,
		false, false, false
	)) {
		std::cerr << __FILE__ << ":" << __LINE__
			<< ": Couldn't initialize grid."
			<< std::endl;
		abort();
	}

	// set the grid's geometry
	dccrg::Cartesian_Geometry::Parameters geom_params;
	geom_params.start[0] =
	geom_params.start[1] = -1;
	geom_params.start[2] = -1.0 / grid_length[0];
	geom_params.level_0_cell_length[0] =
	geom_params.level_0_cell_length[1] =
	geom_params.level_0_cell_length[2] = 2.0 / grid_length[0];
	if (not grid.set_geometry(geom_params)) {
		std::cerr << __FILE__ << ":" << __LINE__
			<< ": Couldn't set grid geometry."
			<< std::endl;
		abort();
	}

	grid.balance_load();

	/*
	Simulate
	*/

	gol::initialize<
		Cell,
		gol::Is_Alive,
		gol::Live_Neighbors
	>(grid);

	advection::initialize<
		Cell,
		advection::Density,
		advection::Density_Flux,
		advection::Velocity
	>(grid);

	particle::initialize<
		Cell,
		particle::Number_Of_Internal_Particles,
		particle::Number_Of_External_Particles,
		particle::Velocity,
		particle::Internal_Particles,
		particle::External_Particles
	>(grid);

	const std::vector<uint64_t>
		inner_cells = grid.get_local_cells_not_on_process_boundary(),
		outer_cells = grid.get_local_cells_on_process_boundary();

	/*const double advection_save_interval = 0.1;
	const double particle_save_interval = 0.1;*/

	double
		/*advection_next_save = 0,
		particle_next_save = 0,*/
		simulation_time = 0,
		time_step = 0;

	/*
	Function templates are not suitable for std::async so make lambdas
	*/

	// game of life
	auto gol_inner_solve = [&](){
		return gol::solve<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(inner_cells, grid);
	};
	auto gol_outer_solve = [&](){
		return gol::solve<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(outer_cells, grid);
	};
	auto gol_inner_apply = [&](){
		return gol::apply_solution<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(inner_cells, grid);
	};
	auto gol_outer_apply = [&](){
		return gol::apply_solution<
			Cell,
			gol::Is_Alive,
			gol::Live_Neighbors
		>(outer_cells, grid);
	};

	// advection
	auto advection_inner_solve = [&](){
		return advection::solve<
			Cell,
			advection::Density,
			advection::Density_Flux,
			advection::Velocity
		>(time_step, inner_cells, grid);
	};
	auto advection_outer_solve = [&](){
		return advection::solve<
			Cell,
			advection::Density,
			advection::Density_Flux,
			advection::Velocity
		>(time_step, outer_cells, grid);
	};
	auto advection_inner_apply = [&](){
		return advection::apply_solution<
			Cell,
			advection::Density,
			advection::Density_Flux
		>(inner_cells, grid);
	};
	auto advection_outer_apply = [&](){
		return advection::apply_solution<
			Cell,
			advection::Density,
			advection::Density_Flux
		>(outer_cells, grid);
	};

	// particle propagation
	auto particle_incorporate_inner = [&](){
		return particle::incorporate_external_particles<
			Cell,
			particle::Number_Of_Internal_Particles,
			particle::Internal_Particles,
			particle::External_Particles
		>(inner_cells, grid);
	};
	auto particle_incorporate_outer = [&](){
		return particle::incorporate_external_particles<
			Cell,
			particle::Number_Of_Internal_Particles,
			particle::Internal_Particles,
			particle::External_Particles
		>(outer_cells, grid);
	};
	auto particle_remove_inner = [&](){
		return particle::remove_external_particles<
			Cell,
			particle::Number_Of_External_Particles,
			particle::External_Particles
		>(inner_cells, grid);
	};
	auto particle_remove_outer = [&](){
		return particle::remove_external_particles<
			Cell,
			particle::Number_Of_External_Particles,
			particle::External_Particles
		>(outer_cells, grid);
	};

	while (simulation_time <= M_PI) {

		double next_time_step = std::numeric_limits<double>::max();

		/*
		Save simulations
		*/

		// saving functions decide what to transfer to disk
		/*Cell::set_transfer_all(
			false,
			gol::Is_Alive(),
			gol::Live_Neighbors()
		);

		Cell::set_transfer_all(
			false,
			advection::Density(),
			advection::Density_Flux(),
			advection::Velocity()
		);

		Cell::set_transfer_all(
			false,
			particle::Number_Of_Internal_Particles(),
			particle::Number_Of_External_Particles(),
			particle::Velocity(),
			particle::Internal_Particles(),
			particle::External_Particles()
		);

		gol::save<Cell, gol::Is_Alive>(grid, simulation_time);

		if (advection_next_save <= simulation_time) {
			advection_next_save += advection_save_interval;

			advection::save<
				Cell,
				advection::Density,
				advection::Velocity
			>(grid, simulation_time);
		}

		if (particle_next_save <= simulation_time) {
			particle_next_save += particle_save_interval;

			particle::save<
				Cell,
				particle::Number_Of_Internal_Particles,
				particle::Velocity,
				particle::Internal_Particles
			>(grid, simulation_time);
		}

		if (simulation_time >= M_PI) {
			break;
		}*/

		/*
		Solve
		*/

		// must finish immediately
		next_time_step
			= std::min(
				next_time_step,
				particle::solve<
					Cell,
					particle::Number_Of_Internal_Particles,
					particle::Number_Of_External_Particles,
					particle::Velocity,
					particle::Internal_Particles,
					particle::External_Particles
				>(time_step, outer_cells, grid)
			);

		Cell::set_transfer_all(true, particle::Number_Of_External_Particles());
		grid.start_remote_neighbor_copy_updates();

		// must finish immediately
		next_time_step
			= std::min(
				next_time_step,
				particle::solve<
					Cell,
					particle::Number_Of_Internal_Particles,
					particle::Number_Of_External_Particles,
					particle::Velocity,
					particle::Internal_Particles,
					particle::External_Particles
				>(time_step, inner_cells, grid)
			);

		grid.wait_remote_neighbor_copy_update_receives();

		// must finish almost immediately
		particle::resize_receiving_containers<
			Cell,
			particle::Number_Of_External_Particles,
			particle::External_Particles
		>(grid);

		grid.wait_remote_neighbor_copy_update_sends();

		Cell::set_transfer_all(true, gol::Is_Alive());
		Cell::set_transfer_all(
			true,
			advection::Density(),
			advection::Velocity()
		);
		Cell::set_transfer_all(false, particle::Number_Of_External_Particles());
		Cell::set_transfer_all(
			true,
			particle::Velocity(),
			particle::External_Particles()
		);
		grid.start_remote_neighbor_copy_updates();

		auto gol_inner_solve_future = std::async(gol_inner_solve);
		auto advection_inner_solve_future = std::async(advection_inner_solve);
		auto particle_incorporate_inner_future = std::async(particle_incorporate_inner);

		gol_inner_solve_future.get();
		next_time_step
			= std::min(
				next_time_step,
				advection_inner_solve_future.get()
			);
		particle_incorporate_inner_future.get();

		grid.wait_remote_neighbor_copy_update_receives();

		auto gol_outer_solve_future = std::async(gol_outer_solve);
		auto gol_inner_apply_future = std::async(gol_inner_apply);
		auto advection_outer_solve_future = std::async(advection_outer_solve);
		auto advection_inner_apply_future = std::async(advection_inner_apply);
		auto particle_incorporate_outer_future = std::async(particle_incorporate_outer);
		auto particle_remove_inner_future = std::async(particle_remove_inner);

		gol_outer_solve_future.get();
		next_time_step
			= std::min(
				next_time_step,
				advection_outer_solve_future.get()
			);
		gol_inner_apply_future.get();
		advection_inner_apply_future.get();
		particle_incorporate_outer_future.get();
		particle_remove_inner_future.get();

		grid.wait_remote_neighbor_copy_update_sends();
		Cell::set_transfer_all(false, gol::Is_Alive());
		Cell::set_transfer_all(
			false,
			advection::Density(),
			advection::Velocity()
		);
		Cell::set_transfer_all(
			false,
			particle::Velocity(),
			particle::External_Particles()
		);

		auto gol_outer_apply_future = std::async(gol_outer_apply);
		auto advection_outer_apply_future = std::async(advection_outer_apply);
		auto particle_remove_outer_future = std::async(particle_remove_outer);

		simulation_time += time_step;

		gol_outer_apply_future.get();
		advection_outer_apply_future.get();
		particle_remove_outer_future.get();

		MPI_Allreduce(&next_time_step, &time_step, 1, MPI_DOUBLE, MPI_MIN, comm);
		const double CFL = 0.5;
		time_step *= CFL;
	}

	MPI_Finalize();

	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#include "googletest/googletest/include/gtest/gtest.h"

#include <string>
#include <vector>

#include "key.h"
#include "base58.h"
#include "uint256.h"
#include "util.h"

using namespace std;

static const string strSecret1     ("5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj");
static const string strSecret2     ("5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3");
static const string strSecret1C    ("Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw");
static const string strSecret2C    ("L3Hq7a8FEQwJkW1M2GNKDW28546Vp5miewcCzSqUD9kCAXrJdS3g");
static const CBitcoinAddress addr1 ("1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ");
static const CBitcoinAddress addr2 ("1F5y5E5FMc5YzdJtB9hLaUe43GDxEKXENJ");
static const CBitcoinAddress addr1C("1NoJrossxPBKfCHuJXT4HadJrXRE9Fxiqs");
static const CBitcoinAddress addr2C("1CRj2HyM1CXWzHAXLQtiGLyggNT9WQqsDs");

static const string strAddressBad("1HV9Lc3sNHZxwj4Zk6fB38tEmBryq2cBiF");

#ifdef KEY_TESTS_DUMPINFO
void dumpKeyInfo(uint256 privkey)
{
    CSecret secret;
    secret.resize(32);
    memcpy(&secret[0], &privkey, 32);
    vector<unsigned char> sec;
    sec.resize(32);
    memcpy(&sec[0], &secret[0], 32);
    printf("  * secret (hex): %s\n", HexStr(sec).c_str());

    for (int nCompressed=0; nCompressed<2; nCompressed++)
    {
        bool fCompressed = nCompressed == 1;
        printf("  * %s:\n", fCompressed ? "compressed" : "uncompressed");
        CBitcoinSecret bsecret;
        bsecret.SetSecret(secret, fCompressed);
        printf("    * secret (base58): %s\n", bsecret.ToString().c_str());
        CKey key;
        key.SetSecret(secret, fCompressed);
        vector<unsigned char> vchPubKey = key.GetPubKey();
        printf("    * pubkey (hex): %s\n", HexStr(vchPubKey).c_str());
        printf("    * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str());
    }
}
#endif

TEST(key_tests, key_test1)
{
    CBitcoinSecret bsecret1, bsecret2, bsecret1C, bsecret2C, baddress1;
    EXPECT_TRUE( bsecret1.SetString (strSecret1));
    EXPECT_TRUE( bsecret2.SetString (strSecret2));
    EXPECT_TRUE( bsecret1C.SetString(strSecret1C));
    EXPECT_TRUE( bsecret2C.SetString(strSecret2C));
    EXPECT_TRUE(!baddress1.SetString(strAddressBad));

    bool fCompressed;
    CSecret secret1  = bsecret1.GetSecret (fCompressed);
    EXPECT_TRUE(fCompressed == false);
    CSecret secret2  = bsecret2.GetSecret (fCompressed);
    EXPECT_TRUE(fCompressed == false);
    CSecret secret1C = bsecret1C.GetSecret(fCompressed);
    EXPECT_TRUE(fCompressed == true);
    CSecret secret2C = bsecret2C.GetSecret(fCompressed);
    EXPECT_TRUE(fCompressed == true);

    EXPECT_TRUE(secret1 == secret1C);
    EXPECT_TRUE(secret2 == secret2C);

    CKey key1, key2, key1C, key2C;
    key1.SetSecret(secret1, false);
    key2.SetSecret(secret2, false);
    key1C.SetSecret(secret1, true);
    key2C.SetSecret(secret2, true);

    EXPECT_TRUE(addr1.Get()  == CTxDestination(key1.GetPubKey().GetID()));
    EXPECT_TRUE(addr2.Get()  == CTxDestination(key2.GetPubKey().GetID()));
    EXPECT_TRUE(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID()));
    EXPECT_TRUE(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID()));

    for (int n=0; n<16; n++)
    {
        string strMsg = strprintf("Very secret message %i: 11", n);
        uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());

        // normal signatures

        vector<unsigned char> sign1, sign2, sign1C, sign2C;

        EXPECT_TRUE(key1.Sign (hashMsg, sign1));
        EXPECT_TRUE(key2.Sign (hashMsg, sign2));
        EXPECT_TRUE(key1C.Sign(hashMsg, sign1C));
        EXPECT_TRUE(key2C.Sign(hashMsg, sign2C));

        EXPECT_TRUE( key1.Verify(hashMsg, sign1));
        EXPECT_TRUE(!key1.Verify(hashMsg, sign2));
        EXPECT_TRUE( key1.Verify(hashMsg, sign1C));
        EXPECT_TRUE(!key1.Verify(hashMsg, sign2C));

        EXPECT_TRUE(!key2.Verify(hashMsg, sign1));
        EXPECT_TRUE( key2.Verify(hashMsg, sign2));
        EXPECT_TRUE(!key2.Verify(hashMsg, sign1C));
        EXPECT_TRUE( key2.Verify(hashMsg, sign2C));

        EXPECT_TRUE( key1C.Verify(hashMsg, sign1));
        EXPECT_TRUE(!key1C.Verify(hashMsg, sign2));
        EXPECT_TRUE( key1C.Verify(hashMsg, sign1C));
        EXPECT_TRUE(!key1C.Verify(hashMsg, sign2C));

        EXPECT_TRUE(!key2C.Verify(hashMsg, sign1));
        EXPECT_TRUE( key2C.Verify(hashMsg, sign2));
        EXPECT_TRUE(!key2C.Verify(hashMsg, sign1C));
        EXPECT_TRUE( key2C.Verify(hashMsg, sign2C));

        // compact signatures (with key recovery)

        vector<unsigned char> csign1, csign2, csign1C, csign2C;

        EXPECT_TRUE(key1.SignCompact (hashMsg, csign1));
        EXPECT_TRUE(key2.SignCompact (hashMsg, csign2));
        EXPECT_TRUE(key1C.SignCompact(hashMsg, csign1C));
        EXPECT_TRUE(key2C.SignCompact(hashMsg, csign2C));

        CKey rkey1, rkey2, rkey1C, rkey2C;

        EXPECT_TRUE(rkey1.SetCompactSignature (hashMsg, csign1));
        EXPECT_TRUE(rkey2.SetCompactSignature (hashMsg, csign2));
        EXPECT_TRUE(rkey1C.SetCompactSignature(hashMsg, csign1C));
        EXPECT_TRUE(rkey2C.SetCompactSignature(hashMsg, csign2C));

        EXPECT_TRUE(rkey1.GetPubKey()  == key1.GetPubKey());
        EXPECT_TRUE(rkey2.GetPubKey()  == key2.GetPubKey());
        EXPECT_TRUE(rkey1C.GetPubKey() == key1C.GetPubKey());
        EXPECT_TRUE(rkey2C.GetPubKey() == key2C.GetPubKey());
    }
}
<commit_msg>Key tests fixed<commit_after>#include "googletest/googletest/include/gtest/gtest.h"

#include <string>
#include <vector>

#include "key.h"
#include "base58.h"
#include "uint256.h"
#include "util.h"

using namespace std;

static const string strSecret1C    ("TtnutkcnaPcu3zmjWcrJazf42fp1YAKRpm8grKRRuYjtiykmGuM7");
static const string strSecret2C    ("TnNwg92Wpw8iuBRwaeJydzw2c6MMqTe2c6cA5hn3NBBdqFWvpViF");
static const CBitcoinAddress addr1C("NVFdK9ik6mBCG6syVw2gD1gBwJzKF5me5i");
static const CBitcoinAddress addr2C("NSTdV7BgFeYXR61ywiMyAoof2ihwUPDPpj");

static const string strAddressBad("NSTdV7BgFeYXR61ywiMyAoof2ihwUPDPp");

#ifdef KEY_TESTS_DUMPINFO
void dumpKeyInfo(uint256 privkey)
{
    CSecret secret;
    secret.resize(32);
    memcpy(&secret[0], &privkey, 32);
    vector<unsigned char> sec;
    sec.resize(32);
    memcpy(&sec[0], &secret[0], 32);
    printf("  * secret (hex): %s\n", HexStr(sec).c_str());

    for (int nCompressed=0; nCompressed<2; nCompressed++)
    {
        bool fCompressed = nCompressed == 1;
        printf("  * %s:\n", fCompressed ? "compressed" : "uncompressed");
        CBitcoinSecret bsecret;
        bsecret.SetSecret(secret, fCompressed);
        printf("    * secret (base58): %s\n", bsecret.ToString().c_str());
        CKey key;
        key.SetSecret(secret, fCompressed);
        vector<unsigned char> vchPubKey = key.GetPubKey();
        printf("    * pubkey (hex): %s\n", HexStr(vchPubKey).c_str());
        printf("    * address (base58): %s\n", CBitcoinAddress(vchPubKey).ToString().c_str());
    }
}
#endif

TEST(key_tests, key_test1)
{
    CBitcoinSecret bsecret1C, bsecret2C, baddress1;
    EXPECT_TRUE( bsecret1C.SetString(strSecret1C));
    EXPECT_TRUE( bsecret2C.SetString(strSecret2C));
    EXPECT_TRUE(!baddress1.SetString(strAddressBad));

    bool fCompressed;
    CSecret secret1C = bsecret1C.GetSecret(fCompressed);
    EXPECT_TRUE(fCompressed == true);
    CSecret secret2C = bsecret2C.GetSecret(fCompressed);
    EXPECT_TRUE(fCompressed == true);

    CKey key1C, key2C;
    key1C.SetSecret(secret1C, true);
    key2C.SetSecret(secret2C, true);

    EXPECT_TRUE(addr1C.Get() == CTxDestination(key1C.GetPubKey().GetID()));
    EXPECT_TRUE(addr2C.Get() == CTxDestination(key2C.GetPubKey().GetID()));

    for (int n=0; n<16; n++)
    {
        string strMsg = strprintf("Very secret message %i: 11", n);
        uint256 hashMsg = Hash(strMsg.begin(), strMsg.end());

        // normal signatures

        vector<unsigned char> sign1C, sign2C;

        EXPECT_TRUE(key1C.Sign(hashMsg, sign1C));
        EXPECT_TRUE(key2C.Sign(hashMsg, sign2C));

        EXPECT_TRUE( key1C.Verify(hashMsg, sign1C));
        EXPECT_TRUE(!key1C.Verify(hashMsg, sign2C));

        EXPECT_TRUE(!key2C.Verify(hashMsg, sign1C));
        EXPECT_TRUE( key2C.Verify(hashMsg, sign2C));

        EXPECT_TRUE( key1C.Verify(hashMsg, sign1C));
        EXPECT_TRUE(!key1C.Verify(hashMsg, sign2C));

        EXPECT_TRUE(!key2C.Verify(hashMsg, sign1C));
        EXPECT_TRUE( key2C.Verify(hashMsg, sign2C));

        // compact signatures (with key recovery)

        vector<unsigned char> csign1C, csign2C;

        EXPECT_TRUE(key1C.SignCompact(hashMsg, csign1C));
        EXPECT_TRUE(key2C.SignCompact(hashMsg, csign2C));

        CKey rkey1C, rkey2C;

        EXPECT_TRUE(rkey1C.SetCompactSignature(hashMsg, csign1C));
        EXPECT_TRUE(rkey2C.SetCompactSignature(hashMsg, csign2C));

        EXPECT_TRUE(rkey1C.GetPubKey() == key1C.GetPubKey());
        EXPECT_TRUE(rkey2C.GetPubKey() == key2C.GetPubKey());
    }
}
<|endoftext|>


<commit_before>

#include <arrayfire.h>
#include <gtest/gtest.h>
#include <testHelpers.hpp>

using af::allTrue;
using af::array;
using af::constant;
using af::dtype;
using af::dtype_traits;
using af::randomEngine;
using af::randomEngineType;
using af::sum;

template<typename T>
class RandomEngine : public ::testing::Test {
   public:
    virtual void SetUp() {}
};

// create a list of types to be tested
typedef ::testing::Types<float, double> TestTypesEngine;
// register the type list
TYPED_TEST_CASE(RandomEngine, TestTypesEngine);

template<typename T>
void testRandomEnginePeriod(randomEngineType type) {
    SUPPORTED_TYPE_CHECK(T);
    dtype ty = (dtype)dtype_traits<T>::af_type;

    int elem  = 1024 * 1024;
    int steps = 4 * 1024;
    randomEngine r(type, 0);

    array first = randu(elem, ty, r);

    for (int i = 0; i < steps; ++i) {
        array step     = randu(elem, ty, r);
        bool different = !allTrue<bool>(first == step);
        ASSERT_TRUE(different);
    }
}

TYPED_TEST(RandomEngine, philoxRandomEnginePeriod) {
    testRandomEnginePeriod<TypeParam>(AF_RANDOM_ENGINE_PHILOX_4X32_10);
}

TYPED_TEST(RandomEngine, threefryRandomEnginePeriod) {
    testRandomEnginePeriod<TypeParam>(AF_RANDOM_ENGINE_THREEFRY_2X32_16);
}

TYPED_TEST(RandomEngine, mersenneRandomEnginePeriod) {
    testRandomEnginePeriod<TypeParam>(AF_RANDOM_ENGINE_MERSENNE_GP11213);
}

template<typename T>
double chi2_statistic(array input, array expected, bool print = false) {
    expected *= sum<T>(input) / sum<T>(expected);
    array diff = input - expected;

    double chi2 = sum<T>((diff * diff) / expected);
    if (print) {
        array legend = af::seq(input.elements());
        legend -= (input.elements() / 2.);
        legend *= (14. / input.elements());

        af_print(
            join(1, legend, expected.as(f32), input.as(f32), diff.as(f32)));
    }

    return chi2;
}

template<>
double chi2_statistic<half_float::half>(array input, array expected,
                                        bool print) {
    expected *= convert<float>(sum<float>(input)) /
                convert<float>(sum<float>(expected));
    array diff  = input - expected;
    double chi2 = convert<float>(sum<float>((diff * diff) / expected));
    return chi2;
}

template<typename T>
void testRandomEngineUniformChi2(randomEngineType type) {
    SUPPORTED_TYPE_CHECK(T);
    dtype ty = (dtype)dtype_traits<T>::af_type;

    int elem  = 256 * 1024 * 1024;
    int steps = 256;
    int bins  = 100;

    array total_hist = constant(0.0, bins, f32);
    array expected   = constant(1.0 / bins, bins, f32);

    randomEngine r(type, 0);

    // R> qchisq(c(5e-6, 1 - 5e-6), 99)
    // [1]  48.68125 173.87456
    float lower(48.68125);
    float upper(173.87456);

    bool prev_step  = true;
    bool prev_total = true;
    for (int i = 0; i < steps; ++i) {
        array rn_numbers = randu(elem, ty, r);
        array step_hist  = histogram(rn_numbers, bins, 0.0, 1.0);
        step_hist        = step_hist.as(f32);
        float step_chi2  = chi2_statistic<float>(step_hist, expected);
        if (!prev_step) {
            EXPECT_GT(step_chi2, lower) << "at step: " << i;
            EXPECT_LT(step_chi2, upper) << "at step: " << i;
        }
        prev_step = step_chi2 > lower && step_chi2 < upper;

        total_hist += step_hist;
        float total_chi2 = chi2_statistic<float>(total_hist, expected);
        if (!prev_total) {
            EXPECT_GT(total_chi2, lower) << "at step: " << i;
            EXPECT_LT(total_chi2, upper) << "at step: " << i;
        }
        prev_total = total_chi2 > lower && total_chi2 < upper;
    }
}

TYPED_TEST(RandomEngine, philoxRandomEngineUniformChi2) {
    testRandomEngineUniformChi2<TypeParam>(AF_RANDOM_ENGINE_PHILOX_4X32_10);
}

TYPED_TEST(RandomEngine, threefryRandomEngineUniformChi2) {
    testRandomEngineUniformChi2<TypeParam>(AF_RANDOM_ENGINE_THREEFRY_2X32_16);
}

TYPED_TEST(RandomEngine, mersenneRandomEngineUniformChi2) {
    testRandomEngineUniformChi2<TypeParam>(AF_RANDOM_ENGINE_MERSENNE_GP11213);
}

// should be used only for x <= 5 (roughly)
array cnd(array x) { return 0.5 * erfc(-x * sqrt(0.5)); }

template<typename T>
bool testRandomEngineNormalChi2(randomEngineType type)

{
    af::dtype ty = (af::dtype)af::dtype_traits<T>::af_type;

    int elem  = 256 * 1024 * 1024;
    int steps = 64;  // 256 * 32;
    int bins  = 100;

    T lower_edge(-7.0);
    T upper_edge(7.0);

    array total_hist = af::constant(0.0, 2 * bins, f32);
    array edges      = af::seq(bins + 1) / bins * lower_edge;
    array expected   = -af::diff1(cnd(edges));

    expected =
        af::join(0, expected(af::seq(bins - 1, 0, -1)), expected).as(f32);

    af::randomEngine r(type, 0);

    // NOTE(@rstub): In the chi^2 test one computes the test statistic and
    // compares the value with the chi^2 distribution with appropriate number of
    // degrees of freedom. For the uniform distribution one has "number of bins
    // minus 1" degrees of freedom. For the normal distribution it is "number of
    // bins minus 3", since there are two parameters mu and sigma. Here I used
    // the qchisq() function from R to compute "suitable" values from the chi^2
    // distribution.
    //
    // R> qchisq(c(5e-6, 1 - 5e-6), 197)
    // [1] 121.3197 297.2989
    float lower(121.3197);
    float upper(297.2989);

    bool prev_step  = true;
    bool prev_total = true;

    af::setSeed(0x76fa214467690e3c);

    // std::cout << std::setw(4) << "step" << std::setw(7) << "chi2_i"
    //           << std::setw(7) << "chi2_t" << std::setprecision(2) <<
    //           std::fixed
    //           << std::endl;

    for (int i = 0; i < steps; ++i) {
        array rn_numbers = randn(elem, ty, r);
        array step_hist =
            af::histogram(rn_numbers, 2 * bins, lower_edge, upper_edge);
        step_hist = step_hist.as(f32);

        float step_chi2 = chi2_statistic<float>(step_hist, expected);

        // if (step_chi2 > 10000) af_print(rn_numbers);
        // std::cout << std::setprecision(2) << std::fixed << std::setw(4) << i
        //           << std::setw(9) << step_chi2;

        bool step = step_chi2 > lower && step_chi2 < upper;

        if (!prev_step) {
            EXPECT_GT(step_chi2, lower) << "at step " << i;
            EXPECT_LT(step_chi2, upper) << "at step: " << i;
            if (step_chi2 < lower || step_chi2 > upper) {
                bool print = true;
                chi2_statistic<float>(step_hist, expected, print);
            }
        }

        // if (!(step || prev_step)) break;

        prev_step = step;
        total_hist += step_hist;

        float total_chi2 = chi2_statistic<float>(total_hist, expected);

        // std::cout << std::setw(9) << total_chi2 << std::endl;

        bool total = total_chi2 > lower && total_chi2 < upper;
        if (!prev_total) {
            EXPECT_GT(total_chi2, lower) << "at step " << i;
            EXPECT_LT(total_chi2, upper) << "at step " << i;
            if (total_chi2 < lower || total_chi2 > upper) {
                bool print = true;
                chi2_statistic<float>(total_hist, expected, print);
            }
        }

        prev_total = total;
    }

    return true;
}

TYPED_TEST(RandomEngine, philoxRandomEngineNormalChi2) {
    testRandomEngineNormalChi2<TypeParam>(AF_RANDOM_ENGINE_PHILOX_4X32_10);
}

TYPED_TEST(RandomEngine, threefryRandomEngineNormalChi2) {
    testRandomEngineNormalChi2<TypeParam>(AF_RANDOM_ENGINE_THREEFRY_2X32_16);
}

TYPED_TEST(RandomEngine, DISABLED_mersenneRandomEngineNormalChi2) {
    testRandomEngineNormalChi2<TypeParam>(AF_RANDOM_ENGINE_MERSENNE_GP11213);
}
<commit_msg>Free unlocked buffers before tests run in rng quality tests (#3151)<commit_after>

#include <arrayfire.h>
#include <gtest/gtest.h>
#include <testHelpers.hpp>

using af::allTrue;
using af::array;
using af::constant;
using af::deviceGC;
using af::dtype;
using af::dtype_traits;
using af::randomEngine;
using af::randomEngineType;
using af::sum;

template<typename T>
class RandomEngine : public ::testing::Test {
   public:
    virtual void SetUp() {
        // Ensure all unlocked buffers are freed
        deviceGC();
    }
};

// create a list of types to be tested
typedef ::testing::Types<float, double> TestTypesEngine;
// register the type list
TYPED_TEST_CASE(RandomEngine, TestTypesEngine);

template<typename T>
void testRandomEnginePeriod(randomEngineType type) {
    SUPPORTED_TYPE_CHECK(T);
    dtype ty = (dtype)dtype_traits<T>::af_type;

    int elem  = 1024 * 1024;
    int steps = 4 * 1024;
    randomEngine r(type, 0);

    array first = randu(elem, ty, r);

    for (int i = 0; i < steps; ++i) {
        array step     = randu(elem, ty, r);
        bool different = !allTrue<bool>(first == step);
        ASSERT_TRUE(different);
    }
}

TYPED_TEST(RandomEngine, philoxRandomEnginePeriod) {
    testRandomEnginePeriod<TypeParam>(AF_RANDOM_ENGINE_PHILOX_4X32_10);
}

TYPED_TEST(RandomEngine, threefryRandomEnginePeriod) {
    testRandomEnginePeriod<TypeParam>(AF_RANDOM_ENGINE_THREEFRY_2X32_16);
}

TYPED_TEST(RandomEngine, mersenneRandomEnginePeriod) {
    testRandomEnginePeriod<TypeParam>(AF_RANDOM_ENGINE_MERSENNE_GP11213);
}

template<typename T>
double chi2_statistic(array input, array expected, bool print = false) {
    expected *= sum<T>(input) / sum<T>(expected);
    array diff = input - expected;

    double chi2 = sum<T>((diff * diff) / expected);
    if (print) {
        array legend = af::seq(input.elements());
        legend -= (input.elements() / 2.);
        legend *= (14. / input.elements());

        af_print(
            join(1, legend, expected.as(f32), input.as(f32), diff.as(f32)));
    }

    return chi2;
}

template<>
double chi2_statistic<half_float::half>(array input, array expected,
                                        bool print) {
    expected *= convert<float>(sum<float>(input)) /
                convert<float>(sum<float>(expected));
    array diff  = input - expected;
    double chi2 = convert<float>(sum<float>((diff * diff) / expected));
    return chi2;
}

template<typename T>
void testRandomEngineUniformChi2(randomEngineType type) {
    SUPPORTED_TYPE_CHECK(T);
    dtype ty = (dtype)dtype_traits<T>::af_type;

    int elem  = 256 * 1024 * 1024;
    int steps = 256;
    int bins  = 100;

    array total_hist = constant(0.0, bins, f32);
    array expected   = constant(1.0 / bins, bins, f32);

    randomEngine r(type, 0);

    // R> qchisq(c(5e-6, 1 - 5e-6), 99)
    // [1]  48.68125 173.87456
    float lower(48.68125);
    float upper(173.87456);

    bool prev_step  = true;
    bool prev_total = true;
    for (int i = 0; i < steps; ++i) {
        array rn_numbers = randu(elem, ty, r);
        array step_hist  = histogram(rn_numbers, bins, 0.0, 1.0);
        step_hist        = step_hist.as(f32);
        float step_chi2  = chi2_statistic<float>(step_hist, expected);
        if (!prev_step) {
            EXPECT_GT(step_chi2, lower) << "at step: " << i;
            EXPECT_LT(step_chi2, upper) << "at step: " << i;
        }
        prev_step = step_chi2 > lower && step_chi2 < upper;

        total_hist += step_hist;
        float total_chi2 = chi2_statistic<float>(total_hist, expected);
        if (!prev_total) {
            EXPECT_GT(total_chi2, lower) << "at step: " << i;
            EXPECT_LT(total_chi2, upper) << "at step: " << i;
        }
        prev_total = total_chi2 > lower && total_chi2 < upper;
    }
}

TYPED_TEST(RandomEngine, philoxRandomEngineUniformChi2) {
    testRandomEngineUniformChi2<TypeParam>(AF_RANDOM_ENGINE_PHILOX_4X32_10);
}

TYPED_TEST(RandomEngine, threefryRandomEngineUniformChi2) {
    testRandomEngineUniformChi2<TypeParam>(AF_RANDOM_ENGINE_THREEFRY_2X32_16);
}

TYPED_TEST(RandomEngine, mersenneRandomEngineUniformChi2) {
    testRandomEngineUniformChi2<TypeParam>(AF_RANDOM_ENGINE_MERSENNE_GP11213);
}

// should be used only for x <= 5 (roughly)
array cnd(array x) { return 0.5 * erfc(-x * sqrt(0.5)); }

template<typename T>
bool testRandomEngineNormalChi2(randomEngineType type)

{
    af::dtype ty = (af::dtype)af::dtype_traits<T>::af_type;

    int elem  = 256 * 1024 * 1024;
    int steps = 64;  // 256 * 32;
    int bins  = 100;

    T lower_edge(-7.0);
    T upper_edge(7.0);

    array total_hist = af::constant(0.0, 2 * bins, f32);
    array edges      = af::seq(bins + 1) / bins * lower_edge;
    array expected   = -af::diff1(cnd(edges));

    expected =
        af::join(0, expected(af::seq(bins - 1, 0, -1)), expected).as(f32);

    af::randomEngine r(type, 0);

    // NOTE(@rstub): In the chi^2 test one computes the test statistic and
    // compares the value with the chi^2 distribution with appropriate number of
    // degrees of freedom. For the uniform distribution one has "number of bins
    // minus 1" degrees of freedom. For the normal distribution it is "number of
    // bins minus 3", since there are two parameters mu and sigma. Here I used
    // the qchisq() function from R to compute "suitable" values from the chi^2
    // distribution.
    //
    // R> qchisq(c(5e-6, 1 - 5e-6), 197)
    // [1] 121.3197 297.2989
    float lower(121.3197);
    float upper(297.2989);

    bool prev_step  = true;
    bool prev_total = true;

    af::setSeed(0x76fa214467690e3c);

    // std::cout << std::setw(4) << "step" << std::setw(7) << "chi2_i"
    //           << std::setw(7) << "chi2_t" << std::setprecision(2) <<
    //           std::fixed
    //           << std::endl;

    for (int i = 0; i < steps; ++i) {
        array rn_numbers = randn(elem, ty, r);
        array step_hist =
            af::histogram(rn_numbers, 2 * bins, lower_edge, upper_edge);
        step_hist = step_hist.as(f32);

        float step_chi2 = chi2_statistic<float>(step_hist, expected);

        // if (step_chi2 > 10000) af_print(rn_numbers);
        // std::cout << std::setprecision(2) << std::fixed << std::setw(4) << i
        //           << std::setw(9) << step_chi2;

        bool step = step_chi2 > lower && step_chi2 < upper;

        if (!prev_step) {
            EXPECT_GT(step_chi2, lower) << "at step " << i;
            EXPECT_LT(step_chi2, upper) << "at step: " << i;
            if (step_chi2 < lower || step_chi2 > upper) {
                bool print = true;
                chi2_statistic<float>(step_hist, expected, print);
            }
        }

        // if (!(step || prev_step)) break;

        prev_step = step;
        total_hist += step_hist;

        float total_chi2 = chi2_statistic<float>(total_hist, expected);

        // std::cout << std::setw(9) << total_chi2 << std::endl;

        bool total = total_chi2 > lower && total_chi2 < upper;
        if (!prev_total) {
            EXPECT_GT(total_chi2, lower) << "at step " << i;
            EXPECT_LT(total_chi2, upper) << "at step " << i;
            if (total_chi2 < lower || total_chi2 > upper) {
                bool print = true;
                chi2_statistic<float>(total_hist, expected, print);
            }
        }

        prev_total = total;
    }

    return true;
}

TYPED_TEST(RandomEngine, philoxRandomEngineNormalChi2) {
    testRandomEngineNormalChi2<TypeParam>(AF_RANDOM_ENGINE_PHILOX_4X32_10);
}

TYPED_TEST(RandomEngine, threefryRandomEngineNormalChi2) {
    testRandomEngineNormalChi2<TypeParam>(AF_RANDOM_ENGINE_THREEFRY_2X32_16);
}

TYPED_TEST(RandomEngine, DISABLED_mersenneRandomEngineNormalChi2) {
    testRandomEngineNormalChi2<TypeParam>(AF_RANDOM_ENGINE_MERSENNE_GP11213);
}
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE TestFileio
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(SANITY){
  BOOST_ASSERT(true);
}
<commit_msg>test catch<commit_after>#define CATCH_CONFIG_MAIN
#include "catch.hpp"

int add(int a, int b){
  return a + b;
}

SCENARIO("sanity", "[santest]"){
  GIVEN("nothing that matters"){
    WHEN( "adding two numbers"){
      THEN("The result should be the sum of both"){
        REQUIRE(add(10, 10) == 20);
      }
    }
  }
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "test.hpp"

TEST_CASE("shuffle/0", "[shuffle]") {
    const size_t N = 137;

    float* a_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = i;
    }

    float* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    egblas_shuffle(N, a_gpu, sizeof(float));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/1", "[shuffle]") {
    const size_t N = 129;

    double* a_cpu = new double[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle(N, a_gpu, sizeof(double));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(double), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/2", "[shuffle]") {
    const size_t N = 129;

    double* a_cpu = new double[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, sizeof(double), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(double), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/3", "[shuffle]") {
    const size_t N = 129;
    const size_t S = 16;

    double* a_cpu = new double[N * S];

    for (size_t i = 0; i < N * S; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * S * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * S * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, S * sizeof(double), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * S * sizeof(double), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        for(size_t j = 1; j < S; ++j){
            REQUIRE(a_cpu[(i * S) + j] == 1 + a_cpu[(i * S) + j - 1]);
        }
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/4", "[shuffle]") {
    const size_t N = 129;
    const size_t S = 23;

    double* a_cpu = new double[N * S];

    for (size_t i = 0; i < N * S; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * S * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * S * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, S * sizeof(double), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * S * sizeof(double), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        for(size_t j = 1; j < S; ++j){
            REQUIRE(a_cpu[(i * S) + j] == 1 + a_cpu[(i * S) + j - 1]);
        }
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("par_shuffle/0", "[shuffle]") {
    const size_t N = 137;

    float* a_cpu = new float[N];
    float* b_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = float(i);
        b_cpu[i] = float(i) + 1.0f;
    }

    float* a_gpu;
    float* b_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&b_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(b_gpu, b_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    egblas_par_shuffle(N, a_gpu, sizeof(float), b_gpu, sizeof(float));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(b_cpu, b_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        REQUIRE(a_cpu[i] + 1.0f == b_cpu[i]);

        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
            REQUIRE(b_cpu[i] != b_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));
    cuda_check(cudaFree(b_gpu));

    delete[] a_cpu;
    delete[] b_cpu;
}

TEST_CASE("par_shuffle/1", "[shuffle]") {
    const size_t N = 137;

    float* a_cpu = new float[N];
    double* b_cpu = new double[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = float(i);
        b_cpu[i] = double(i) + 1.0;
    }

    float* a_gpu;
    double* b_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&b_gpu, N * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(b_gpu, b_cpu, N * sizeof(double), cudaMemcpyHostToDevice));

    egblas_par_shuffle(N, a_gpu, sizeof(float), b_gpu, sizeof(double));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(b_cpu, b_gpu, N * sizeof(double), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        REQUIRE(double(a_cpu[i] + 1.0) == b_cpu[i]);

        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
            REQUIRE(b_cpu[i] != b_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));
    cuda_check(cudaFree(b_gpu));

    delete[] a_cpu;
    delete[] b_cpu;
}
<commit_msg>Stronger tests<commit_after>//=======================================================================
// Copyright (c) 2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include "test.hpp"

TEST_CASE("shuffle/0", "[shuffle]") {
    const size_t N = 137;

    float* a_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = i;
    }

    float* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    egblas_shuffle(N, a_gpu, sizeof(float));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    // Make sure we find each number in [0,N[
    for (size_t i = 0; i < N; ++i) {
        REQUIRE(std::count(a_cpu, a_cpu + N, float(i)) == 1);
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/1", "[shuffle]") {
    const size_t N = 129;

    double* a_cpu = new double[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle(N, a_gpu, sizeof(double));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(double), cudaMemcpyDeviceToHost));

    // Make sure we find each number in [0,N[
    for (size_t i = 0; i < N; ++i) {
        REQUIRE(std::count(a_cpu, a_cpu + N, double(i)) == 1);
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/2", "[shuffle]") {
    const size_t N = 129;

    double* a_cpu = new double[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, sizeof(double), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(double), cudaMemcpyDeviceToHost));

    // Make sure we find each number in [0,N[
    for (size_t i = 0; i < N; ++i) {
        REQUIRE(std::count(a_cpu, a_cpu + N, double(i)) == 1);
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/3", "[shuffle]") {
    const size_t N = 129;
    const size_t S = 16;

    double* a_cpu = new double[N * S];

    for (size_t i = 0; i < N * S; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * S * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * S * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, S * sizeof(double), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * S * sizeof(double), cudaMemcpyDeviceToHost));

    // Make sure the sub order is correct
    for (size_t i = 0; i < N; ++i) {
        for(size_t j = 1; j < S; ++j){
            REQUIRE(a_cpu[(i * S) + j] == 1 + a_cpu[(i * S) + j - 1]);
        }
    }

    // Make sure we find each number in [0,N[
    for (size_t i = 0; i < N * S; ++i) {
        REQUIRE(std::count(a_cpu, a_cpu + N * S, double(i)) == 1);
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/4", "[shuffle]") {
    const size_t N = 129;
    const size_t S = 23;

    double* a_cpu = new double[N * S];

    for (size_t i = 0; i < N * S; ++i) {
        a_cpu[i] = i;
    }

    double* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * S * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * S * sizeof(double), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, S * sizeof(double), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * S * sizeof(double), cudaMemcpyDeviceToHost));

    // Make sure the sub order is correct
    for (size_t i = 0; i < N; ++i) {
        for(size_t j = 1; j < S; ++j){
            REQUIRE(a_cpu[(i * S) + j] == 1 + a_cpu[(i * S) + j - 1]);
        }
    }

    // Make sure we find each number in [0,N[
    for (size_t i = 0; i < N * S; ++i) {
        REQUIRE(std::count(a_cpu, a_cpu + N * S, double(i)) == 1);
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("shuffle/5", "[shuffle]") {
    const size_t N = 129;
    const size_t S = 23;

    float* a_cpu = new float[N * S];

    for (size_t i = 0; i < N * S; ++i) {
        a_cpu[i] = i;
    }

    float* a_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * S * sizeof(float)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * S * sizeof(float), cudaMemcpyHostToDevice));

    egblas_shuffle_seed(N, a_gpu, S * sizeof(float), 123);

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * S * sizeof(float), cudaMemcpyDeviceToHost));

    // Make sure the sub order is correct
    for (size_t i = 0; i < N; ++i) {
        for(size_t j = 1; j < S; ++j){
            REQUIRE(a_cpu[(i * S) + j] == 1 + a_cpu[(i * S) + j - 1]);
        }
    }

    // Make sure we find each number in [0,N[
    for (size_t i = 0; i < N * S; ++i) {
        REQUIRE(std::count(a_cpu, a_cpu + N * S, double(i)) == 1);
    }

    cuda_check(cudaFree(a_gpu));

    delete[] a_cpu;
}

TEST_CASE("par_shuffle/0", "[shuffle]") {
    const size_t N = 137;

    float* a_cpu = new float[N];
    float* b_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = float(i);
        b_cpu[i] = float(i) + 1.0f;
    }

    float* a_gpu;
    float* b_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&b_gpu, N * sizeof(float)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(b_gpu, b_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    egblas_par_shuffle(N, a_gpu, sizeof(float), b_gpu, sizeof(float));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(b_cpu, b_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        REQUIRE(a_cpu[i] + 1.0f == b_cpu[i]);

        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
            REQUIRE(b_cpu[i] != b_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));
    cuda_check(cudaFree(b_gpu));

    delete[] a_cpu;
    delete[] b_cpu;
}

TEST_CASE("par_shuffle/1", "[shuffle]") {
    const size_t N = 137;

    float* a_cpu = new float[N];
    double* b_cpu = new double[N];

    for (size_t i = 0; i < N; ++i) {
        a_cpu[i] = float(i);
        b_cpu[i] = double(i) + 1.0;
    }

    float* a_gpu;
    double* b_gpu;
    cuda_check(cudaMalloc((void**)&a_gpu, N * sizeof(float)));
    cuda_check(cudaMalloc((void**)&b_gpu, N * sizeof(double)));

    cuda_check(cudaMemcpy(a_gpu, a_cpu, N * sizeof(float), cudaMemcpyHostToDevice));
    cuda_check(cudaMemcpy(b_gpu, b_cpu, N * sizeof(double), cudaMemcpyHostToDevice));

    egblas_par_shuffle(N, a_gpu, sizeof(float), b_gpu, sizeof(double));

    cuda_check(cudaMemcpy(a_cpu, a_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(b_cpu, b_gpu, N * sizeof(double), cudaMemcpyDeviceToHost));

    for (size_t i = 0; i < N; ++i) {
        REQUIRE(double(a_cpu[i] + 1.0) == b_cpu[i]);

        for (size_t j = i + 1; j < N; ++j) {
            REQUIRE(a_cpu[i] != a_cpu[j]);
            REQUIRE(b_cpu[i] != b_cpu[j]);
        }
    }

    cuda_check(cudaFree(a_gpu));
    cuda_check(cudaFree(b_gpu));

    delete[] a_cpu;
    delete[] b_cpu;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2015 - 2017)
//   Rene Milk       (2016 - 2017)

#ifndef DUNE_GDT_LOCAL_FUNCTIONALS_INTEGRALS_HH
#define DUNE_GDT_LOCAL_FUNCTIONALS_INTEGRALS_HH

#include <dune/gdt/local/integrands/interfaces.hh>
#include <dune/gdt/type_traits.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {

template <class UnaryEvaluationType, class TestBase, class Field = typename TestBase::RangeFieldType>
class LocalVolumeIntegralFunctional : public LocalVolumeFunctionalInterface<TestBase, Field>
{
  static_assert(is_unary_volume_integrand<UnaryEvaluationType>::value, "");
  typedef LocalVolumeIntegralFunctional<UnaryEvaluationType, TestBase, Field> ThisType;
  typedef LocalVolumeFunctionalInterface<TestBase, Field> BaseType;

  typedef typename TestBase::DomainFieldType D;
  static const size_t d = TestBase::dimDomain;

public:
  using typename BaseType::TestBaseType;
  using typename BaseType::FieldType;

  template <class... Args>
  explicit LocalVolumeIntegralFunctional(Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(0)
  {
  }

  template <class... Args>
  explicit LocalVolumeIntegralFunctional(const int over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(boost::numeric_cast<size_t>(over_integrate))
  {
  }

  template <class... Args>
  explicit LocalVolumeIntegralFunctional(const size_t over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(over_integrate)
  {
  }

  LocalVolumeIntegralFunctional(const ThisType& other) = default;
  LocalVolumeIntegralFunctional(ThisType&& source) = default;

  using BaseType::apply;

  void apply(const TestBaseType& test_base, DynamicVector<FieldType>& ret) const override final
  {
    const auto& entity = test_base.entity();
    const auto local_functions = integrand_.localFunctions(entity);
    // create quadrature
    const size_t integrand_order = integrand_.order(local_functions, test_base) + over_integrate_;
    const auto& quadrature = QuadratureRules<D, d>::rule(entity.type(), boost::numeric_cast<int>(integrand_order));
    // prepare storage
    const size_t size = test_base.size();
    ret *= 0.0;
    assert(ret.size() >= size);
    DynamicVector<FieldType> evaluation_result(size, 0.); // \todo: make mutable member, after SMP refactor
    // loop over all quadrature points
    for (const auto& quadrature_point : quadrature) {
      const auto xx = quadrature_point.position();
      // integration factors
      const auto integration_factor = entity.geometry().integrationElement(xx);
      const auto quadrature_weight = quadrature_point.weight();
      // evaluate the integrand
      integrand_.evaluate(local_functions, test_base, xx, evaluation_result);
      // compute integral
      for (size_t ii = 0; ii < size; ++ii)
        ret[ii] += evaluation_result[ii] * integration_factor * quadrature_weight;
    } // loop over all quadrature points
  } // ... apply(...)

private:
  const UnaryEvaluationType integrand_;
  const size_t over_integrate_;
}; // class LocalVolumeIntegralFunctional

template <class UnaryEvaluationType,
          class TestBase,
          class Intersection,
          class Field = typename TestBase::RangeFieldType>
class LocalFaceIntegralFunctional : public LocalFaceFunctionalInterface<TestBase, Intersection, Field>
{
  static_assert(is_unary_face_integrand<UnaryEvaluationType>::value, "");
  typedef LocalFaceIntegralFunctional<UnaryEvaluationType, TestBase, Intersection, Field> ThisType;
  typedef LocalFaceFunctionalInterface<TestBase, Intersection, Field> BaseType;

  typedef typename TestBase::DomainFieldType D;
  static const size_t d = TestBase::dimDomain;

public:
  using typename BaseType::TestBaseType;
  using typename BaseType::IntersectionType;
  using typename BaseType::FieldType;

  template <class... Args>
  explicit LocalFaceIntegralFunctional(Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(0)
  {
  }

  template <class... Args>
  explicit LocalFaceIntegralFunctional(const int over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(boost::numeric_cast<size_t>(over_integrate))
  {
  }

  template <class... Args>
  explicit LocalFaceIntegralFunctional(const size_t over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(over_integrate)
  {
  }

  LocalFaceIntegralFunctional(const ThisType& other) = default;
  LocalFaceIntegralFunctional(ThisType&& source) = default;

  using BaseType::apply;

  void apply(const TestBaseType& test_base,
             const IntersectionType& intersection,
             DynamicVector<FieldType>& ret) const override final
  {
    const auto& entity = test_base.entity();
    const auto local_functions = integrand_.localFunctions(entity);
    // create quadrature
    const size_t integrand_order = integrand_.order(local_functions, test_base) + over_integrate_;
    const auto& quadrature =
        QuadratureRules<D, d - 1>::rule(intersection.type(), boost::numeric_cast<int>(integrand_order));
    // prepare storage
    const size_t size = test_base.size();
    ret *= 0.0;
    assert(ret.size() >= size);
    DynamicVector<FieldType> evaluation_result(size, 0.); // \todo: make mutable member, after SMP refactor
    // loop over all quadrature points
    for (const auto& quadrature_point : quadrature) {
      const auto xx = quadrature_point.position();
      // integration factors
      const auto integration_factor = intersection.geometry().integrationElement(xx);
      const auto quadrature_weight = quadrature_point.weight();
      // evaluate the integrand
      integrand_.evaluate(local_functions, test_base, intersection, xx, evaluation_result);
      // compute integral
      for (size_t ii = 0; ii < size; ++ii)
        ret[ii] += evaluation_result[ii] * integration_factor * quadrature_weight;
    } // loop over all quadrature points
  } // ... apply(...)

private:
  const UnaryEvaluationType integrand_;
  const size_t over_integrate_;
}; // class LocalFaceIntegralFunctional

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_FUNCTIONALS_INTEGRALS_HH
<commit_msg>[WIP|local.functionals.integrals] disable all that is not yet rewritten<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2015 - 2017)
//   Rene Milk       (2016 - 2017)

#ifndef DUNE_GDT_LOCAL_FUNCTIONALS_INTEGRALS_HH
#define DUNE_GDT_LOCAL_FUNCTIONALS_INTEGRALS_HH

#include <dune/gdt/local/integrands/interfaces.hh>
#include <dune/gdt/type_traits.hh>

#include "interfaces.hh"

namespace Dune {
namespace GDT {

template <class UnaryEvaluationType, class TestBase, class Field = typename TestBase::RangeFieldType>
class LocalVolumeIntegralFunctional : public LocalVolumeFunctionalInterface<TestBase, Field>
{
  static_assert(is_unary_volume_integrand<UnaryEvaluationType>::value, "");
  typedef LocalVolumeIntegralFunctional<UnaryEvaluationType, TestBase, Field> ThisType;
  typedef LocalVolumeFunctionalInterface<TestBase, Field> BaseType;

  typedef typename TestBase::DomainFieldType D;
  static const size_t d = TestBase::dimDomain;

public:
  using typename BaseType::TestBaseType;
  using typename BaseType::FieldType;

  template <class... Args>
  explicit LocalVolumeIntegralFunctional(Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(0)
  {
  }

  template <class... Args>
  explicit LocalVolumeIntegralFunctional(const int over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(boost::numeric_cast<size_t>(over_integrate))
  {
  }

  template <class... Args>
  explicit LocalVolumeIntegralFunctional(const size_t over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(over_integrate)
  {
  }

  LocalVolumeIntegralFunctional(const ThisType& other) = default;
  LocalVolumeIntegralFunctional(ThisType&& source) = default;

  using BaseType::apply;

  void apply(const TestBaseType& test_base, DynamicVector<FieldType>& ret) const override final
  {
    const auto& entity = test_base.entity();
    const auto local_functions = integrand_.localFunctions(entity);
    // create quadrature
    const size_t integrand_order = integrand_.order(local_functions, test_base) + over_integrate_;
    const auto& quadrature = QuadratureRules<D, d>::rule(entity.type(), boost::numeric_cast<int>(integrand_order));
    // prepare storage
    const size_t size = test_base.size();
    ret *= 0.0;
    assert(ret.size() >= size);
    DynamicVector<FieldType> evaluation_result(size, 0.); // \todo: make mutable member, after SMP refactor
    // loop over all quadrature points
    for (const auto& quadrature_point : quadrature) {
      const auto xx = quadrature_point.position();
      // integration factors
      const auto integration_factor = entity.geometry().integrationElement(xx);
      const auto quadrature_weight = quadrature_point.weight();
      // evaluate the integrand
      integrand_.evaluate(local_functions, test_base, xx, evaluation_result);
      // compute integral
      for (size_t ii = 0; ii < size; ++ii)
        ret[ii] += evaluation_result[ii] * integration_factor * quadrature_weight;
    } // loop over all quadrature points
  } // ... apply(...)

private:
  const UnaryEvaluationType integrand_;
  const size_t over_integrate_;
}; // class LocalVolumeIntegralFunctional

#if 0
template <class UnaryEvaluationType,
          class TestBase,
          class Intersection,
          class Field = typename TestBase::RangeFieldType>
class LocalFaceIntegralFunctional : public LocalFaceFunctionalInterface<TestBase, Intersection, Field>
{
  static_assert(is_unary_face_integrand<UnaryEvaluationType>::value, "");
  typedef LocalFaceIntegralFunctional<UnaryEvaluationType, TestBase, Intersection, Field> ThisType;
  typedef LocalFaceFunctionalInterface<TestBase, Intersection, Field> BaseType;

  typedef typename TestBase::DomainFieldType D;
  static const size_t d = TestBase::dimDomain;

public:
  using typename BaseType::TestBaseType;
  using typename BaseType::IntersectionType;
  using typename BaseType::FieldType;

  template <class... Args>
  explicit LocalFaceIntegralFunctional(Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(0)
  {
  }

  template <class... Args>
  explicit LocalFaceIntegralFunctional(const int over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(boost::numeric_cast<size_t>(over_integrate))
  {
  }

  template <class... Args>
  explicit LocalFaceIntegralFunctional(const size_t over_integrate, Args&&... args)
    : integrand_(std::forward<Args>(args)...)
    , over_integrate_(over_integrate)
  {
  }

  LocalFaceIntegralFunctional(const ThisType& other) = default;
  LocalFaceIntegralFunctional(ThisType&& source) = default;

  using BaseType::apply;

  void apply(const TestBaseType& test_base,
             const IntersectionType& intersection,
             DynamicVector<FieldType>& ret) const override final
  {
    const auto& entity = test_base.entity();
    const auto local_functions = integrand_.localFunctions(entity);
    // create quadrature
    const size_t integrand_order = integrand_.order(local_functions, test_base) + over_integrate_;
    const auto& quadrature =
        QuadratureRules<D, d - 1>::rule(intersection.type(), boost::numeric_cast<int>(integrand_order));
    // prepare storage
    const size_t size = test_base.size();
    ret *= 0.0;
    assert(ret.size() >= size);
    DynamicVector<FieldType> evaluation_result(size, 0.); // \todo: make mutable member, after SMP refactor
    // loop over all quadrature points
    for (const auto& quadrature_point : quadrature) {
      const auto xx = quadrature_point.position();
      // integration factors
      const auto integration_factor = intersection.geometry().integrationElement(xx);
      const auto quadrature_weight = quadrature_point.weight();
      // evaluate the integrand
      integrand_.evaluate(local_functions, test_base, intersection, xx, evaluation_result);
      // compute integral
      for (size_t ii = 0; ii < size; ++ii)
        ret[ii] += evaluation_result[ii] * integration_factor * quadrature_weight;
    } // loop over all quadrature points
  } // ... apply(...)

private:
  const UnaryEvaluationType integrand_;
  const size_t over_integrate_;
}; // class LocalFaceIntegralFunctional
#endif // 0

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_LOCAL_FUNCTIONALS_INTEGRALS_HH
<|endoftext|>


<commit_before>#include "tokenizer.h"

#include <algorithm>
#include <iostream>
#include <iomanip>

// Utility functions
namespace
{

bool idx_valid(const std::string& input, std::size_t idx)
{
    return idx >= 0 && idx < input.size();
}

bool is_digit(char c)
{
    return c == '_' || (c >= '0' && c <= '9');
}

} // namespace

// Tokenizer
void Tokenizer::tokenize(const std::string& input)
{
    tokens_.clear();

    // Tokenize in greedy manner
    std::size_t idx = 0;

    while (idx_valid(input, idx)) {
        // Number, read it and continue
        if (is_digit(input[idx])) {
            idx = read_number(input, idx);
            continue;
        }

        // Operator, check for characters
        const Token* best_token = nullptr;
        for (const auto& token : Token::checkable_tokens()) {
            const auto len = token.symbol().size();
            const auto remaining_len = input.size() - idx;

            if (remaining_len < len) {
                continue;
            }

            if (input.substr(idx, len) == token.symbol() &&
                (best_token == nullptr || best_token->precedence() < token.precedence())) {
                best_token = &token;
            }
        }

        if (best_token != nullptr) {
            std::cout << "found " << best_token->symbol() << "\n";
        }

        if (best_token != nullptr) {
            // Symbol was identified, add it
            tokens_.push_back(*best_token);
            idx += best_token->symbol().size();
        }
        else {
            // Prevent infinite loop on unrecognized values
            ++idx;
        }
    }
}

const std::vector<Token>& Tokenizer::tokens() const
{
    return tokens_;
}

std::size_t Tokenizer::read_number(const std::string& input, std::size_t idx)
{
    // Valid number format:
    // [0-9]*(\.[0-9]*)? with underscores as separators
    std::size_t end_idx = idx;
    double value = 0;

    // Read value until period
    while (idx_valid(input, end_idx) && is_digit(input[end_idx])) {
        ++end_idx;
    }

    // Check for decimal component
    if (idx_valid(input, end_idx) && input[end_idx] == '.') {
        ++end_idx;

        // Get remaining numbers
        while (idx_valid(input, end_idx) && is_digit(input[end_idx])) {
            ++end_idx;
        }
    }

    // Tokenize and finish using std::stod
    std::string num_string{input.substr(idx, end_idx - idx)};
    num_string.erase(std::remove_if(num_string.begin(),
                                    num_string.end(),
                                    [](char c) { return c == '_'; }),
                     num_string.end());

    Token token{TokenType::NUMBER, num_string, Token::NULL_PRECEDENCE};

    token.set_value(std::stod(num_string));
    tokens_.push_back(token);

    return end_idx;
}

std::ostream& operator<<(std::ostream& out, const Tokenizer& tokenizer)
{
    out << "Total " << tokenizer.tokens_.size() << " tokens\n";
    for (const auto& token : tokenizer.tokens_) {
        out << "  " << token.name();

        // Print the value if it is a number
        if (token.type() == TokenType::NUMBER) {
            out << " " << std::setprecision(12) << token.value();
        }

        out << "\n";
    }

    return out;
}<commit_msg>Remove debug output<commit_after>#include "tokenizer.h"

#include <algorithm>
#include <iostream>
#include <iomanip>

// Utility functions
namespace
{

bool idx_valid(const std::string& input, std::size_t idx)
{
    return idx >= 0 && idx < input.size();
}

bool is_digit(char c)
{
    return c == '_' || (c >= '0' && c <= '9');
}

} // namespace

// Tokenizer
void Tokenizer::tokenize(const std::string& input)
{
    tokens_.clear();

    // Tokenize in greedy manner
    std::size_t idx = 0;

    while (idx_valid(input, idx)) {
        // Number, read it and continue
        if (is_digit(input[idx])) {
            idx = read_number(input, idx);
            continue;
        }

        // Operator, check for characters
        const Token* best_token = nullptr;
        for (const auto& token : Token::checkable_tokens()) {
            const auto len = token.symbol().size();
            const auto remaining_len = input.size() - idx;

            if (remaining_len < len) {
                continue;
            }

            if (input.substr(idx, len) == token.symbol() &&
                (best_token == nullptr || best_token->precedence() < token.precedence())) {
                best_token = &token;
            }
        }

        if (best_token != nullptr) {
            // Symbol was identified, add it
            tokens_.push_back(*best_token);
            idx += best_token->symbol().size();
        }
        else {
            // Prevent infinite loop on unrecognized values
            ++idx;
        }
    }
}

const std::vector<Token>& Tokenizer::tokens() const
{
    return tokens_;
}

std::size_t Tokenizer::read_number(const std::string& input, std::size_t idx)
{
    // Valid number format:
    // [0-9]*(\.[0-9]*)? with underscores as separators
    std::size_t end_idx = idx;
    double value = 0;

    // Read value until period
    while (idx_valid(input, end_idx) && is_digit(input[end_idx])) {
        ++end_idx;
    }

    // Check for decimal component
    if (idx_valid(input, end_idx) && input[end_idx] == '.') {
        ++end_idx;

        // Get remaining numbers
        while (idx_valid(input, end_idx) && is_digit(input[end_idx])) {
            ++end_idx;
        }
    }

    // Tokenize and finish using std::stod
    std::string num_string{input.substr(idx, end_idx - idx)};
    num_string.erase(std::remove_if(num_string.begin(),
                                    num_string.end(),
                                    [](char c) { return c == '_'; }),
                     num_string.end());

    Token token{TokenType::NUMBER, num_string, Token::NULL_PRECEDENCE};

    token.set_value(std::stod(num_string));
    tokens_.push_back(token);

    return end_idx;
}

std::ostream& operator<<(std::ostream& out, const Tokenizer& tokenizer)
{
    out << "Total " << tokenizer.tokens_.size() << " tokens\n";
    for (const auto& token : tokenizer.tokens_) {
        out << "  " << token.name();

        // Print the value if it is a number
        if (token.type() == TokenType::NUMBER) {
            out << " " << std::setprecision(12) << token.value();
        }

        out << "\n";
    }

    return out;
}<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 Klaus Reimer <k@ailis.de>
 * See COPYING file for copying conditions
 */

#include <fstream>
#include <sstream>
#include <wasteland/exceptions.h>
#include <wasteland/end_anim.h>
#include "gdutils.h"
#include "fileutils.h"
#include "unpackcpa.h"

using namespace std;
using namespace wasteland;

namespace tools
{

unpackcpa::unpackcpa() : program()
{
    set_arg_range(2, 2);
    set_syntax("[OPTION]... CPAFILE OUTPUTDIR");
    set_description("Unpacks CPA animation file into PNG images.");
};

void unpackcpa::exec(int argc, char *argv[])
{
    char *source = argv[0];
    char *dest = argv[1];

    mkdir(dest);

    ifstream file(source);
    if (!source) throw io_error(string("Unable to open ") + source);
    end_anim anim;
    file >> anim;
    if (!file) throw io_error("Unable to read end animation");

    end_anim_frame frame;
    ostringstream filename;
    filename << dest << DIR_SEPARATOR << 0 << ".png";
    frame = anim.get_base_frame();
    image_to_png(frame, filename.str().c_str());

    int index = 1;
    for(vector<end_anim_update>::const_iterator update = anim.get_frame_updates().begin(),
        end = anim.get_frame_updates().end(); update != end; ++update)
    {
        update->apply(frame);
        ostringstream filename;
        filename << dest << DIR_SEPARATOR << index << ".png";
        image_to_png(frame, filename.str().c_str());
        index += 1;
    }

    file.close();
}

}

int main(int argc, char *argv[])
{
    return tools::unpackcpa().run(argc, argv);
}
<commit_msg>Add dump of delays.txt<commit_after>/*
 * Copyright (C) 2013 Klaus Reimer <k@ailis.de>
 * See COPYING file for copying conditions
 */

#include <fstream>
#include <sstream>
#include <wasteland/exceptions.h>
#include <wasteland/end_anim.h>
#include "gdutils.h"
#include "fileutils.h"
#include "unpackcpa.h"

using namespace std;
using namespace wasteland;

namespace tools
{

unpackcpa::unpackcpa() : program()
{
    set_arg_range(2, 2);
    set_syntax("[OPTION]... CPAFILE OUTPUTDIR");
    set_description("Unpacks CPA animation file into PNG images.");
};

void unpackcpa::exec(int argc, char *argv[])
{
    char *source = argv[0];
    char *dest = argv[1];

    mkdir(dest);

    ifstream file(source);
    if (!source) throw io_error(string("Unable to open ") + source);
    end_anim anim;
    file >> anim;
    if (!file) throw io_error("Unable to read end animation");

    end_anim_frame frame;
    ostringstream filename;
    filename << dest << DIR_SEPARATOR << 0 << ".png";
    frame = anim.get_base_frame();
    image_to_png(frame, filename.str().c_str());

    ostringstream delay_filename;
    delay_filename << dest << DIR_SEPARATOR << "delays.txt";
    fstream delay_file(delay_filename.str().c_str(), ios_base::out);

    int index = 1;
    for(vector<end_anim_update>::const_iterator update = anim.get_frame_updates().begin(),
        end = anim.get_frame_updates().end(); update != end; ++update)
    {
        update->apply(frame);
        ostringstream filename;
        filename << dest << DIR_SEPARATOR << index << ".png";
        delay_file << update->get_delay() << endl;
        image_to_png(frame, filename.str().c_str());
        index += 1;
    }

    delay_file.close();
    file.close();
}

}

int main(int argc, char *argv[])
{
    return tools::unpackcpa().run(argc, argv);
}
<|endoftext|>