<commit_before>// Project: Parallel Collaborative Ranking with Alt-rankSVM and SGD
// Collaborative work by Dohyung Park and Jin Zhang
// Date: 11/26/2014
//
// The script will:
// [1]  convert preference data into item-based graph (adjacency matrix format)
// [2]  partition graph with Graclus
// [3a] solve the problem with alternative rankSVM via liblineaer
// [3b] solve the problem with stochasitic gradient descent in hogwild style
// [3c] solve the problem with stochastic gradient descent in nomad style
//
// Compile: g++ -std=C++11 -O3 -g -fopenmp collaborative_ranking.cpp
// Run: ./a.out [rating_file] [rating_format] [graph_output] [num_partitions]

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include "collaborative_ranking.h"
#include "linear.h"

using namespace std;

class Problem {
	bool is_allocated, is_clustered;
	int n_users, n_items, n_train_comps, n_test_comps; 	// number of users/items in training sample, number of samples in traing and testing data set
	int rank, lambda, nparts;				// parameters
	double *U, *V;						// low rank U, V
	double alpha, beta;					// parameter for sgd
	Graph g;						// Graph used for clustering training data
	vector<int> n_comps_by_user, n_comps_by_item;	// number of comparisons for each user and item
	vector<comparison> comparisons_test;			// vector stores testing comparison data

	void de_allocate();					// check if U, V has been allocated
	bool sgd_step(const comparison &comp, const double step_size);

	public:
		Problem(int, int);					// default constructor
	void read_data(char* train_file, char* test_file);	// read function
	void alt_rankSVM();
	void run_sgd_random();
	void run_sgd_nomad();
	// two different sgd function
	double compute_ndcg();
	double compute_testerror();
};

// may be more parameters can be specified here
Problem::Problem (int r, int np): g(np) {
	this->rank = r;
	this->is_allocated = false;
	this->nparts = np;
}

void Problem::read_data (char* train_file, char* test_file) {
	this->g.read_data(train_file);	// training file will be feed to graph for clustering
	this->n_users = this->g.n;
	this->n_items = this->g.m;
	this->n_train_comps = this->g.omega;

	n_comps_by_user.clear(); n_comps_by_user.resize(this->n_users);
	n_comps_by_item.clear(); n_comps_by_item.resize(this->n_items);
	for(int i=0; i<this->n_users; i++) n_comps_by_user[i] = 0;
	for(int i=0; i<this->n_items; i++) n_comps_by_item[i] = 0;

	for(int i=0; i<this->n_train_comps; i++) {
		++n_comps_by_user[g.ucmp[i].user_id];
		++n_comps_by_item[g.ucmp[i].item1_id];
		++n_comps_by_item[g.ucmp[i].item2_id];
	}

	ifstream f(test_file);
	if (f) {
		int u, i, j;
		while (f >> u >> i >> j) {
			this->n_users = max(u, this->n_users);
			this->n_items = max(i, max(j, this->n_items));
			this->comparisons_test.push_back(comparison(u - 1, i - 1, j - 1) );
		}
		this->n_test_comps = this->comparisons_test.size();
	} else {
		printf("Error in opening the testing file\n");
		exit(EXIT_FAILURE);
	}
	f.close();
}

void Problem::alt_rankSVM () {
	if (!is_clustered) {
		this->g.cluster();		// call graph clustering prior to the computation
	}

	if (this->is_allocated) {
		this->de_allocate();
	}
	this->is_allocated = true;

	this->U = new double (this->n_users * this->rank);
	this->V = new double (this->n_items * this->rank);

	srand(time(NULL));
	for (int i = 0; i < this->n_users; ++i) {
		U[i] = ((double) rand() / RAND_MAX);
	}
	for (int i = 0; i < this->n_users; ++i) {
		V[i] = ((double) rand() / RAND_MAX);
	}

	// Alternating RankSVM
	struct feature_node **A, **B;
	A = new struct feature_node*[this->n_train_comps];
	for (int i = 0; i < this->n_train_comps; ++i) {
		A[i] = new struct feature_node[this->rank + 1];
		for (int j = 0; j < this->rank; j++) {
			A[i][j].index = j;
		}
		A[i][this->rank].index = -1;
	}

	B = new struct feature_node*[this->n_train_comps];
	for (int i = 0; i < this->n_train_comps; ++i) {
		B[i] = new struct feature_node[this->rank * 2 + 1];
		for (int j = 0; j < 2 * this->rank; ++j) {
			B[i][j].index = j;
		}
		B[i][this->rank * 2].index = -1;
	}

	for (int iter = 0; iter < 20; ++iter) {
		// Learning U
		// #pragma omp parallel for
		for (int i = 0; i < this->n_users; ++i) {
			for (int j = this->g.uidx[i]; j < this->g.uidx[i + 1]; ++j) {
				double *V1 = &V[this->g.ucmp[j].item1_id * this->rank];
				double *V2 = &V[this->g.ucmp[j].item2_id * this->rank];
				for (int s = 0; s < this->rank; ++s) {
					A[j][s].value = V1[s] - V2[s];
				}
			}

			// call LIBLINEAR with U[i * rank]
			struct problem P;
			P.l = this->g.uidx[i + 1] - this->g.uidx[i];
			P.n = this->rank;
			double *y = new double[P.l];
			for (int j = 0; j < P.l; ++j) {
				y[j] = 1.;
			}
			P.y = y;
			P.x = &A[this->g.uidx[i]];
			P.bias = -1.;

			struct parameter param;
			param.solver_type = L2R_L2LOSS_SVC_DUAL;
			param.C = 1.;
			struct model *M;
			if (!check_parameter(&P, &param) ) {
				// run SVM
				M = train(&P, &param);
				// store the result
				for (int j = 0; j < rank; ++j) {
					U[i * rank + j] = M->w[j];
				}
				//free_and_destory_model(&M);
			}
		}

		// Learning V
		// #pragma omp parallel for
		for (int i = 0; i < this->nparts; ++i) {
			// solve the SVM problem sequentially for each sample in the partition
			for (int j = this->g.pidx[i]; j < this->g.pidx[i + 1]; ++j) {
				// generate the training set for V using U
				for (int s = 0; s < this->rank; ++s) {
					B[j][s].value = U[this->g.pcmp[j].user_id * this->rank + s];		// U_i
					B[j][s + rank].value = -U[this->g.pcmp[j].user_id * this->rank + s];	// -U_i
				}

				// call LIBLINEAR with U[i*rank], B[j]
				struct problem P;
				P.l = 1;
				P.n = rank * 2;
				double y = 1.;
				P.y = &y;
				P.x = &B[j];
				P.bias = -1;

				struct parameter param;
				param.solver_type = L2R_L2LOSS_SVC_DUAL;
				param.C = 1.;

				struct model *M;
				if (!check_parameter(&P, &param) ) {
					// run SVM
					M = train(&P, &param);

					// store the result
					for (int s = 0; s < rank; ++s) {
						V[this->g.pcmp[j].item1_id * this->rank + s] = M->w[s];			// other threads might be doing the same thing
						V[this->g.pcmp[j].item2_id * this->rank + s] = M->w[s + this->rank];		// so add lock to the two steps is another option.
					}
					//free_and_destroy_model(&M);
				}
			}
		}
	}
}

bool Problem::sgd_step(const comparison &comp, const double step_size) {
	double *user_vec  = &U[comp.user_id * rank];
	double *item1_vec = &V[comp.item1_id * rank];
	double *item2_vec = &V[comp.item2_id * rank];

    int n_comps_user  = n_comps_by_user[comp.user_id];
    int n_comps_item1 = n_comps_by_item[comp.item1_id];
    int n_comps_item2 = n_comps_by_item[comp.item2_id];

	double err = 1.;
	for(int k=0; k<rank; k++) err -= user_vec[k] * (item1_vec[k] - item2_vec[k]);

	if (err > 0) {
		double grad = -2 * err;		// gradient direction for l2 hinge loss

		for(int k=0; k<rank; k++) {
			double user_dir  = (grad * (item1_vec[k] - item2_vec[k]) + lambda / n_comps_user * user_vec[k]);
			double item1_dir = (grad * user_vec[k] + lambda / n_comps_item1 * item1_vec[k]);
			double item2_dir = (-grad * user_vec[k] + lambda / n_comps_item2 * item2_vec[k]);

			user_vec[k]  -= step_size * user_dir;
			item1_vec[k] -= step_size * item1_dir;
			item2_vec[k] -= step_size * item2_dir;
		}

		return true;
	}

	return false;
}

void Problem::run_sgd_random() {

	// Clustering
	/* Cluster the triples based on comparisons_train */

	srand(time(NULL));
	for(int i=0; i<n_users*rank; i++) U[i] = ((double)rand()/(RAND_MAX));
	for(int i=0; i<n_items*rank; i++) V[i] = ((double)rand()/(RAND_MAX));

    int n_iter = 1e4;
	for(int iter=1; iter<n_iter; iter++) {
		int idx = (int)((double)rand() * (double)n_train_comps / (double)RAND_MAX);

		sgd_step(comparisons_train[idx], alpha / (1. + beta/(double)iter));

		double ndcg = compute_ndcg();
		double test_err = compute_testerror();
	}

}

void Problem::run_sgd_nomad() {

	// Clustering
	/* Cluster the triples based on comparisons_train */

	srand(time(NULL));
	for(int i=0; i<n_users*rank; i++) U[i] = ((double)rand()/(RAND_MAX));
	for(int i=0; i<n_items*rank; i++) V[i] = ((double)rand()/(RAND_MAX));

    int n_iter = 1e4;
	for(int iter=1; iter<n_iter; iter++) {
		int idx = (int)((double)rand() * (double)n_train_comps / (double)RAND_MAX);

		sgd_step(comparisons_train[idx], alpha / (1. + beta/(double)iter));

		double ndcg = compute_ndcg();
		double test_err = compute_testerror();
	}

}

double Problem::compute_ndcg() {
	double ndcg_sum = 0.;
	for(int i=0; i<n_users; i++) {
		double dcg = 0.;
		double norm = 1.;
		// compute dcg
		ndcg_sum += dcg / norm;
	}
}

double Problem::compute_testerror() {
	int n_error = 0;
	for(int i=0; i<n_test_comps; i++) {
		double prod = 0.;
		int user_idx  = comparisons_test[i].user_id * rank;
		int item1_idx = comparisons_test[i].item1_id * rank;
		int item2_idx = comparisons_test[i].item2_id * rank;
		for(int k=0; k<rank; k++) prod += U[user_idx + k] * (V[item1_idx + k] - V[item2_idx + k]);
		if (prod < 0.) n_error++;
	}
	return (double)n_error / (double)n_test_comps;
}

void Problem::de_allocate () {
	delete this->U;
	delete this->V;
}

int main (int argc, char* argv[]) {
	Problem p(10, 16);		// rank = 10, #partition = 16
	p.read_data(argv[1], argv[2]);
	// p.alt_rankSVM();
	// p.run_sgd_random();
	return 0;
}
<commit_msg>test from stampede<commit_after>// Project: Parallel Collaborative Ranking with Alt-rankSVM and SGD
// Collaborative work by Dohyung Park and Jin Zhang
// Date: 11/26/2014
//
// The script will:
// [1]  convert preference data into item-based graph (adjacency matrix format)
// [2]  partition graph with Graclus
// [3a] solve the problem with alternative rankSVM via liblineaer
// [3b] solve the problem with stochasitic gradient descent in hogwild style
// [3c] solve the problem with stochastic gradient descent in nomad style
//
// Compile: g++ -std=c++11 -O3 -g -fopenmp collaborative_ranking.cpp
// Run: ./a.out [rating_file] [rating_format] [graph_output] [num_partitions]

#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include "collaborative_ranking.h"
#include "linear.h"

using namespace std;

class Problem {
	bool is_allocated, is_clustered;
	int n_users, n_items, n_train_comps, n_test_comps; 	// number of users/items in training sample, number of samples in traing and testing data set
	int rank, lambda, nparts;				// parameters
	double *U, *V;						// low rank U, V
	double alpha, beta;					// parameter for sgd
	Graph g;						// Graph used for clustering training data
	vector<int> n_comps_by_user, n_comps_by_item;	// number of comparisons for each user and item
	vector<comparison> comparisons_test;			// vector stores testing comparison data

	void de_allocate();					// check if U, V has been allocated
	bool sgd_step(const comparison &comp, const double step_size);

	public:
		Problem(int, int);					// default constructor
	void read_data(char* train_file, char* test_file);	// read function
	void alt_rankSVM();
	void run_sgd_random();
	void run_sgd_nomad();
	// two different sgd function
	double compute_ndcg();
	double compute_testerror();
};

// may be more parameters can be specified here
Problem::Problem (int r, int np): g(np) {
	this->rank = r;
	this->is_allocated = false;
	this->nparts = np;
}

void Problem::read_data (char* train_file, char* test_file) {
	this->g.read_data(train_file);	// training file will be feed to graph for clustering
	this->n_users = this->g.n;
	this->n_items = this->g.m;
	this->n_train_comps = this->g.omega;

	n_comps_by_user.clear(); n_comps_by_user.resize(this->n_users);
	n_comps_by_item.clear(); n_comps_by_item.resize(this->n_items);
	for(int i=0; i<this->n_users; i++) n_comps_by_user[i] = 0;
	for(int i=0; i<this->n_items; i++) n_comps_by_item[i] = 0;

	for(int i=0; i<this->n_train_comps; i++) {
		++n_comps_by_user[g.ucmp[i].user_id];
		++n_comps_by_item[g.ucmp[i].item1_id];
		++n_comps_by_item[g.ucmp[i].item2_id];
	}

	ifstream f(test_file);
	if (f) {
		int u, i, j;
		while (f >> u >> i >> j) {
			this->n_users = max(u, this->n_users);
			this->n_items = max(i, max(j, this->n_items));
			this->comparisons_test.push_back(comparison(u - 1, i - 1, j - 1) );
		}
		this->n_test_comps = this->comparisons_test.size();
	} else {
		printf("Error in opening the testing file\n");
		exit(EXIT_FAILURE);
	}
	f.close();
}

void Problem::alt_rankSVM () {
	if (!is_clustered) {
		this->g.cluster();		// call graph clustering prior to the computation
	}

	if (this->is_allocated) {
		this->de_allocate();
	}
	this->is_allocated = true;

	this->U = new double (this->n_users * this->rank);
	this->V = new double (this->n_items * this->rank);

	srand(time(NULL));
	for (int i = 0; i < this->n_users; ++i) {
		U[i] = ((double) rand() / RAND_MAX);
	}
	for (int i = 0; i < this->n_users; ++i) {
		V[i] = ((double) rand() / RAND_MAX);
	}

	// Alternating RankSVM
	struct feature_node **A, **B;
	A = new struct feature_node*[this->n_train_comps];
	for (int i = 0; i < this->n_train_comps; ++i) {
		A[i] = new struct feature_node[this->rank + 1];
		for (int j = 0; j < this->rank; j++) {
			A[i][j].index = j;
		}
		A[i][this->rank].index = -1;
	}

	B = new struct feature_node*[this->n_train_comps];
	for (int i = 0; i < this->n_train_comps; ++i) {
		B[i] = new struct feature_node[this->rank * 2 + 1];
		for (int j = 0; j < 2 * this->rank; ++j) {
			B[i][j].index = j;
		}
		B[i][this->rank * 2].index = -1;
	}

	for (int iter = 0; iter < 20; ++iter) {
		// Learning U
		// #pragma omp parallel for
		for (int i = 0; i < this->n_users; ++i) {
			for (int j = this->g.uidx[i]; j < this->g.uidx[i + 1]; ++j) {
				double *V1 = &V[this->g.ucmp[j].item1_id * this->rank];
				double *V2 = &V[this->g.ucmp[j].item2_id * this->rank];
				for (int s = 0; s < this->rank; ++s) {
					A[j][s].value = V1[s] - V2[s];
				}
			}

			// call LIBLINEAR with U[i * rank]
			struct problem P;
			P.l = this->g.uidx[i + 1] - this->g.uidx[i];
			P.n = this->rank;
			double *y = new double[P.l];
			for (int j = 0; j < P.l; ++j) {
				y[j] = 1.;
			}
			P.y = y;
			P.x = &A[this->g.uidx[i]];
			P.bias = -1.;

			struct parameter param;
			param.solver_type = L2R_L2LOSS_SVC_DUAL;
			param.C = 1.;
			struct model *M;
			if (!check_parameter(&P, &param) ) {
				// run SVM
				M = train(&P, &param);
				// store the result
				for (int j = 0; j < rank; ++j) {
					U[i * rank + j] = M->w[j];
				}
				//free_and_destory_model(&M);
			}
		}

		// Learning V
		// #pragma omp parallel for
		for (int i = 0; i < this->nparts; ++i) {
			// solve the SVM problem sequentially for each sample in the partition
			for (int j = this->g.pidx[i]; j < this->g.pidx[i + 1]; ++j) {
				// generate the training set for V using U
				for (int s = 0; s < this->rank; ++s) {
					B[j][s].value = U[this->g.pcmp[j].user_id * this->rank + s];		// U_i
					B[j][s + rank].value = -U[this->g.pcmp[j].user_id * this->rank + s];	// -U_i
				}

				// call LIBLINEAR with U[i*rank], B[j]
				struct problem P;
				P.l = 1;
				P.n = rank * 2;
				double y = 1.;
				P.y = &y;
				P.x = &B[j];
				P.bias = -1;

				struct parameter param;
				param.solver_type = L2R_L2LOSS_SVC_DUAL;
				param.C = 1.;

				struct model *M;
				if (!check_parameter(&P, &param) ) {
					// run SVM
					M = train(&P, &param);

					// store the result
					for (int s = 0; s < rank; ++s) {
						V[this->g.pcmp[j].item1_id * this->rank + s] = M->w[s];			// other threads might be doing the same thing
						V[this->g.pcmp[j].item2_id * this->rank + s] = M->w[s + this->rank];		// so add lock to the two steps is another option.
					}
					//free_and_destroy_model(&M);
				}
			}
		}
	}
}

bool Problem::sgd_step(const comparison &comp, const double step_size) {
	double *user_vec  = &U[comp.user_id * rank];
	double *item1_vec = &V[comp.item1_id * rank];
	double *item2_vec = &V[comp.item2_id * rank];

    int n_comps_user  = n_comps_by_user[comp.user_id];
    int n_comps_item1 = n_comps_by_item[comp.item1_id];
    int n_comps_item2 = n_comps_by_item[comp.item2_id];

	double err = 1.;
	for(int k=0; k<rank; k++) err -= user_vec[k] * (item1_vec[k] - item2_vec[k]);

	if (err > 0) {
		double grad = -2 * err;		// gradient direction for l2 hinge loss

		for(int k=0; k<rank; k++) {
			double user_dir  = (grad * (item1_vec[k] - item2_vec[k]) + lambda / n_comps_user * user_vec[k]);
			double item1_dir = (grad * user_vec[k] + lambda / n_comps_item1 * item1_vec[k]);
			double item2_dir = (-grad * user_vec[k] + lambda / n_comps_item2 * item2_vec[k]);

			user_vec[k]  -= step_size * user_dir;
			item1_vec[k] -= step_size * item1_dir;
			item2_vec[k] -= step_size * item2_dir;
		}

		return true;
	}

	return false;
}

void Problem::run_sgd_random() {

	// Clustering
	/* Cluster the triples based on comparisons_train */

	srand(time(NULL));
	for(int i=0; i<n_users*rank; i++) U[i] = ((double)rand()/(RAND_MAX));
	for(int i=0; i<n_items*rank; i++) V[i] = ((double)rand()/(RAND_MAX));

    int n_iter = 1e4;
	for(int iter=1; iter<n_iter; iter++) {
		int idx = (int)((double)rand() * (double)n_train_comps / (double)RAND_MAX);

		sgd_step(comparisons_train[idx], alpha / (1. + beta/(double)iter));

		double ndcg = compute_ndcg();
		double test_err = compute_testerror();
	}

}

void Problem::run_sgd_nomad() {

	// Clustering
	/* Cluster the triples based on comparisons_train */

	srand(time(NULL));
	for(int i=0; i<n_users*rank; i++) U[i] = ((double)rand()/(RAND_MAX));
	for(int i=0; i<n_items*rank; i++) V[i] = ((double)rand()/(RAND_MAX));

    int n_iter = 1e4;
	for(int iter=1; iter<n_iter; iter++) {
		int idx = (int)((double)rand() * (double)n_train_comps / (double)RAND_MAX);

		sgd_step(comparisons_train[idx], alpha / (1. + beta/(double)iter));

		double ndcg = compute_ndcg();
		double test_err = compute_testerror();
	}

}

double Problem::compute_ndcg() {
	double ndcg_sum = 0.;
	for(int i=0; i<n_users; i++) {
		double dcg = 0.;
		double norm = 1.;
		// compute dcg
		ndcg_sum += dcg / norm;
	}
}

double Problem::compute_testerror() {
	int n_error = 0;
	for(int i=0; i<n_test_comps; i++) {
		double prod = 0.;
		int user_idx  = comparisons_test[i].user_id * rank;
		int item1_idx = comparisons_test[i].item1_id * rank;
		int item2_idx = comparisons_test[i].item2_id * rank;
		for(int k=0; k<rank; k++) prod += U[user_idx + k] * (V[item1_idx + k] - V[item2_idx + k]);
		if (prod < 0.) n_error++;
	}
	return (double)n_error / (double)n_test_comps;
}

void Problem::de_allocate () {
	delete this->U;
	delete this->V;
}

int main (int argc, char* argv[]) {
	Problem p(10, 16);		// rank = 10, #partition = 16
	p.read_data(argv[1], argv[2]);
	// p.alt_rankSVM();
	// p.run_sgd_random();
	return 0;
}
<|endoftext|>


<commit_before>/* ************************************************************************** */
/*                                                                            */
/*                                                                            */
/*    ShaderProgram.hpp                              oooooo       oooooo      */
/*                                                 oooooooooo   oooooooooo    */
/*                                                         o%%%%%o            */
/*                                                         %:::::%            */
/*                                                        %:::::::%           */
/*    This file is part of the                             %:::::%            */
/*    Lums library.                                         %%%%%             */
/*                                                                            */
/* ************************************************************************** */

#ifndef LUMS_SHADER_PROGRAM_HPP
#define LUMS_SHADER_PROGRAM_HPP

#include <vector>
#include <LumsInclude/Graphics/OpenGL.hpp>
#include <LumsInclude/Math/Matrix.hpp>
#include <LumsInclude/Binary/BObject.hpp>

namespace lm
{
	class Shader;

	/**
     * @brief A class representing a linked shader
     */
	class ShaderProgram
	{
	public:
		/**
		 * Construct a shader program
		 */
		ShaderProgram();

		/**
		 * Get the raw shader program
		 * @return The raw shader program
		 */
		GLuint
		program() const
		{
			return _program;
		}

		/**
		 * Bind an attribute location inside the shader program
		 * @param index The index to be bound
		 * @param name The name of the attribute
		 */
		void
		bindAttribLocation(GLint index, const char* name) const
		{
			glBindAttribLocation(_program, index, name);
		}

		/**
		 * Attach a shader to the program
		 * @param shader The shader to attach
		 */
		void	attach(const Shader& shader);

		/**
		 * Link the shader
		 */
		void	link();

		/**
		 * Use the shader
		 */
		void	use() const;

        void    loadBinary(const BObject& object);

		/**
		 * Shader program dtor
		 */
		~ShaderProgram();

	private:
		GLuint				_program;
		std::vector<GLuint>	_shaders;

	};

	/**
	 * Set the value of an uniform
	 * @tparam T The type of the value
	 * @param program The shader
	 * @param name The uniform name
	 * @param value The value
	 */
	template <typename T>
    inline void
    uniform(ShaderProgram& program, const char* name, T& value)
    {
    	GLint loc = glGetUniformLocation(program.program(), name);
    	uniform(loc, value);
    }

    /**
	 * @cond
	 */
    inline void
    uniform(GLint loc, Matrix4f& mat)
    {
    	glUniformMatrix4fv(loc, 1, GL_FALSE, mat.data());
    }

    inline void
    uniform(GLint loc, float f)
    {
        glUniform1f(loc, f);
    }
    /**
     * @endcond
     */
}

#endif
<commit_msg>Fix #2<commit_after>/* ************************************************************************** */
/*                                                                            */
/*                                                                            */
/*    ShaderProgram.hpp                              oooooo       oooooo      */
/*                                                 oooooooooo   oooooooooo    */
/*                                                         o%%%%%o            */
/*                                                         %:::::%            */
/*                                                        %:::::::%           */
/*    This file is part of the                             %:::::%            */
/*    Lums library.                                         %%%%%             */
/*                                                                            */
/* ************************************************************************** */

#ifndef LUMS_SHADER_PROGRAM_HPP
#define LUMS_SHADER_PROGRAM_HPP

#include <vector>
#include <LumsInclude/Graphics/OpenGL.hpp>
#include <LumsInclude/Math/Matrix.hpp>
#include <LumsInclude/Binary/BObject.hpp>

namespace lm
{
	class Shader;

	/**
     * @brief A class representing a linked shader
     */
	class ShaderProgram
	{
	public:
		/**
		 * Construct a shader program
		 */
		ShaderProgram();

		/**
		 * Get the raw shader program
		 * @return The raw shader program
		 */
		GLuint
		program() const
		{
			return _program;
		}

		/**
		 * Bind an attribute location inside the shader program
		 * @param index The index to be bound
		 * @param name The name of the attribute
		 */
		void
		bindAttribLocation(GLint index, const char* name) const
		{
			glBindAttribLocation(_program, index, name);
		}

		/**
		 * Attach a shader to the program
		 * @param shader The shader to attach
		 */
		void	attach(const Shader& shader);

		/**
		 * Link the shader
		 */
		void	link();

		/**
		 * Use the shader
		 */
		void	use() const;

        void    loadBinary(const BObject& object);

		/**
		 * Shader program dtor
		 */
		~ShaderProgram();

	private:
		GLuint				_program;
		std::vector<GLuint>	_shaders;

	};

    /**
     * @cond
     */
    inline void
    uniform(GLint loc, Matrix4f& mat)
    {
        glUniformMatrix4fv(loc, 1, GL_FALSE, mat.data());
    }

    inline void
    uniform(GLint loc, float f)
    {
        glUniform1f(loc, f);
    }
    /**
     * @endcond
     */

	/**
	 * Set the value of an uniform
	 * @tparam T The type of the value
	 * @param program The shader
	 * @param name The uniform name
	 * @param value The value
	 */
	template <typename T>
    inline void
    uniform(ShaderProgram& program, const char* name, T& value)
    {
    	GLint loc = glGetUniformLocation(program.program(), name);
    	uniform(loc, value);
    }
}

#endif
<|endoftext|>


<commit_before>//===- SimplifyCFG.cpp - CFG Simplification Pass --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements dead code elimination and basic block merging.
//
// Specifically, this:
//   * removes basic blocks with no predecessors
//   * merges a basic block into its predecessor if there is only one and the
//     predecessor only has one successor.
//   * Eliminates PHI nodes for basic blocks with a single predecessor
//   * Eliminates a basic block that only contains an unconditional branch
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "simplifycfg"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Pass.h"
#include "llvm/ADT/Statistic.h"
#include <set>
using namespace llvm;

STATISTIC(NumSimpl, "Number of blocks simplified");

namespace {
  struct VISIBILITY_HIDDEN CFGSimplifyPass : public FunctionPass {
    virtual bool runOnFunction(Function &F);
  };
  RegisterPass<CFGSimplifyPass> X("simplifycfg", "Simplify the CFG");
}

// Public interface to the CFGSimplification pass
FunctionPass *llvm::createCFGSimplificationPass() {
  return new CFGSimplifyPass();
}

static bool MarkAliveBlocks(BasicBlock *BB, std::set<BasicBlock*> &Reachable) {
  if (Reachable.count(BB)) return false;
  Reachable.insert(BB);

  // Do a quick scan of the basic block, turning any obviously unreachable
  // instructions into LLVM unreachable insts.  The instruction combining pass
  // canonnicalizes unreachable insts into stores to null or undef.
  for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ++BBI)
    if (StoreInst *SI = dyn_cast<StoreInst>(BBI))
      if (isa<ConstantPointerNull>(SI->getOperand(1)) ||
          isa<UndefValue>(SI->getOperand(1))) {
        // Loop over all of the successors, removing BB's entry from any PHI
        // nodes.
        for (succ_iterator I = succ_begin(BB), SE = succ_end(BB); I != SE; ++I)
          (*I)->removePredecessor(BB);

        new UnreachableInst(SI);

        // All instructions after this are dead.
        for (; BBI != E; ) {
          if (!BBI->use_empty())
            BBI->replaceAllUsesWith(UndefValue::get(BBI->getType()));
          BB->getInstList().erase(BBI++);
        }
        break;
      }

  bool Changed = ConstantFoldTerminator(BB);
  for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI)
    Changed |= MarkAliveBlocks(*SI, Reachable);

  return Changed;
}

// It is possible that we may require multiple passes over the code to fully
// simplify the CFG.
//
bool CFGSimplifyPass::runOnFunction(Function &F) {
  std::set<BasicBlock*> Reachable;
  bool Changed = MarkAliveBlocks(F.begin(), Reachable);

  // If there are unreachable blocks in the CFG...
  if (Reachable.size() != F.size()) {
    assert(Reachable.size() < F.size());
    NumSimpl += F.size()-Reachable.size();

    // Loop over all of the basic blocks that are not reachable, dropping all of
    // their internal references...
    for (Function::iterator BB = ++F.begin(), E = F.end(); BB != E; ++BB)
      if (!Reachable.count(BB)) {
        for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI!=SE; ++SI)
          if (Reachable.count(*SI))
            (*SI)->removePredecessor(BB);
        BB->dropAllReferences();
      }

    for (Function::iterator I = ++F.begin(); I != F.end();)
      if (!Reachable.count(I))
        I = F.getBasicBlockList().erase(I);
      else
        ++I;

    Changed = true;
  }

  bool LocalChange = true;
  while (LocalChange) {
    LocalChange = false;

    // Loop over all of the basic blocks (except the first one) and remove them
    // if they are unneeded...
    //
    for (Function::iterator BBIt = ++F.begin(); BBIt != F.end(); ) {
      if (SimplifyCFG(BBIt++)) {
        LocalChange = true;
        ++NumSimpl;
      }
    }
    Changed |= LocalChange;
  }

  return Changed;
}
<commit_msg>switch MarkAliveBlocks over to using SmallPtrSet instead of std::set, speeding up simplifycfg by 20%<commit_after>//===- SimplifyCFG.cpp - CFG Simplification Pass --------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements dead code elimination and basic block merging.
//
// Specifically, this:
//   * removes basic blocks with no predecessors
//   * merges a basic block into its predecessor if there is only one and the
//     predecessor only has one successor.
//   * Eliminates PHI nodes for basic blocks with a single predecessor
//   * Eliminates a basic block that only contains an unconditional branch
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "simplifycfg"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Pass.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;

STATISTIC(NumSimpl, "Number of blocks simplified");

namespace {
  struct VISIBILITY_HIDDEN CFGSimplifyPass : public FunctionPass {
    virtual bool runOnFunction(Function &F);
  };
  RegisterPass<CFGSimplifyPass> X("simplifycfg", "Simplify the CFG");
}

// Public interface to the CFGSimplification pass
FunctionPass *llvm::createCFGSimplificationPass() {
  return new CFGSimplifyPass();
}

static bool MarkAliveBlocks(BasicBlock *BB,
                            SmallPtrSet<BasicBlock*, 16> &Reachable) {
  if (!Reachable.insert(BB)) return false;

  // Do a quick scan of the basic block, turning any obviously unreachable
  // instructions into LLVM unreachable insts.  The instruction combining pass
  // canonnicalizes unreachable insts into stores to null or undef.
  for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ++BBI)
    if (StoreInst *SI = dyn_cast<StoreInst>(BBI))
      if (isa<ConstantPointerNull>(SI->getOperand(1)) ||
          isa<UndefValue>(SI->getOperand(1))) {
        // Loop over all of the successors, removing BB's entry from any PHI
        // nodes.
        for (succ_iterator I = succ_begin(BB), SE = succ_end(BB); I != SE; ++I)
          (*I)->removePredecessor(BB);

        new UnreachableInst(SI);

        // All instructions after this are dead.
        for (; BBI != E; ) {
          if (!BBI->use_empty())
            BBI->replaceAllUsesWith(UndefValue::get(BBI->getType()));
          BB->getInstList().erase(BBI++);
        }
        break;
      }

  bool Changed = ConstantFoldTerminator(BB);
  for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI)
    Changed |= MarkAliveBlocks(*SI, Reachable);

  return Changed;
}

// It is possible that we may require multiple passes over the code to fully
// simplify the CFG.
//
bool CFGSimplifyPass::runOnFunction(Function &F) {
  SmallPtrSet<BasicBlock*, 16> Reachable;
  bool Changed = MarkAliveBlocks(F.begin(), Reachable);

  // If there are unreachable blocks in the CFG...
  if (Reachable.size() != F.size()) {
    assert(Reachable.size() < F.size());
    NumSimpl += F.size()-Reachable.size();

    // Loop over all of the basic blocks that are not reachable, dropping all of
    // their internal references...
    for (Function::iterator BB = ++F.begin(), E = F.end(); BB != E; ++BB)
      if (!Reachable.count(BB)) {
        for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI!=SE; ++SI)
          if (Reachable.count(*SI))
            (*SI)->removePredecessor(BB);
        BB->dropAllReferences();
      }

    for (Function::iterator I = ++F.begin(); I != F.end();)
      if (!Reachable.count(I))
        I = F.getBasicBlockList().erase(I);
      else
        ++I;

    Changed = true;
  }

  bool LocalChange = true;
  while (LocalChange) {
    LocalChange = false;

    // Loop over all of the basic blocks (except the first one) and remove them
    // if they are unneeded...
    //
    for (Function::iterator BBIt = ++F.begin(); BBIt != F.end(); ) {
      if (SimplifyCFG(BBIt++)) {
        LocalChange = true;
        ++NumSimpl;
      }
    }
    Changed |= LocalChange;
  }

  return Changed;
}
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Copyright 2015 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/runtime/browser/xwalk_platform_notification_service.h"

#include "content/public/browser/desktop_notification_delegate.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/platform_notification_data.h"

#if defined(OS_ANDROID)
#include "xwalk/runtime/browser/android/xwalk_contents_client_bridge.h"
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
#include "xwalk/runtime/browser/linux/xwalk_notification_manager.h"
#endif

namespace xwalk {

// static
XWalkPlatformNotificationService*
XWalkPlatformNotificationService::GetInstance() {
  return Singleton<XWalkPlatformNotificationService>::get();
}

XWalkPlatformNotificationService::XWalkPlatformNotificationService() {}

XWalkPlatformNotificationService::~XWalkPlatformNotificationService() {}

blink::WebNotificationPermission
XWalkPlatformNotificationService::CheckPermissionOnUIThread(
    content::BrowserContext* resource_context,
    const GURL& origin,
    int render_process_id) {
#if defined(OS_ANDROID)
  return blink::WebNotificationPermissionAllowed;
#else
  return blink::WebNotificationPermissionDenied;
#endif
}

blink::WebNotificationPermission
XWalkPlatformNotificationService::CheckPermissionOnIOThread(
    content::ResourceContext* resource_context,
    const GURL& origin,
    int render_process_id) {
#if defined(OS_ANDROID)
  return blink::WebNotificationPermissionAllowed;
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
  return blink::WebNotificationPermissionAllowed;
#else
  return blink::WebNotificationPermissionDenied;
#endif
}

void XWalkPlatformNotificationService::DisplayNotification(
    content::BrowserContext* browser_context,
    const GURL& origin,
    const SkBitmap& icon,
    const content::PlatformNotificationData& notification_data,
    scoped_ptr<content::DesktopNotificationDelegate> delegate,
    base::Closure* cancel_callback) {
#if defined(OS_ANDROID)
  scoped_ptr<content::RenderWidgetHostIterator> widgets(
      content::RenderWidgetHost::GetRenderWidgetHosts());
  while (content::RenderWidgetHost* rwh = widgets->GetNextHost()) {
    if (!rwh->GetProcess())
      continue;
    content::RenderViewHost* rvh = content::RenderViewHost::From(rwh);
    if (!rvh)
      continue;
    content::WebContents* web_contents =
        content::WebContents::FromRenderViewHost(rvh);
    if (!web_contents)
      continue;
    XWalkContentsClientBridgeBase* bridge =
        XWalkContentsClientBridgeBase::FromWebContents(web_contents);
    bridge->ShowNotification(notification_data, icon, delegate.Pass(),
                             cancel_callback);
    return;
  }
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
  if (!notification_manager_linux_)
    notification_manager_linux_.reset(new XWalkNotificationManager());
  notification_manager_linux_->ShowDesktopNotification(
      browser_context,
      origin,
      notification_data,
      delegate.Pass(),
      cancel_callback);
#endif
}

}  // namespace xwalk
<commit_msg>Need to allow WebNotification for Linux in XWalkPlatformNotificationService::CheckPermissionOnUIThread<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Copyright 2015 Intel Corporation. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "xwalk/runtime/browser/xwalk_platform_notification_service.h"

#include "content/public/browser/desktop_notification_delegate.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_iterator.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/platform_notification_data.h"

#if defined(OS_ANDROID)
#include "xwalk/runtime/browser/android/xwalk_contents_client_bridge.h"
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
#include "xwalk/runtime/browser/linux/xwalk_notification_manager.h"
#endif

namespace xwalk {

// static
XWalkPlatformNotificationService*
XWalkPlatformNotificationService::GetInstance() {
  return Singleton<XWalkPlatformNotificationService>::get();
}

XWalkPlatformNotificationService::XWalkPlatformNotificationService() {}

XWalkPlatformNotificationService::~XWalkPlatformNotificationService() {}

blink::WebNotificationPermission
XWalkPlatformNotificationService::CheckPermissionOnUIThread(
    content::BrowserContext* resource_context,
    const GURL& origin,
    int render_process_id) {
#if defined(OS_ANDROID)
  return blink::WebNotificationPermissionAllowed;
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
  return blink::WebNotificationPermissionAllowed;
#else
  return blink::WebNotificationPermissionDenied;
#endif
}

blink::WebNotificationPermission
XWalkPlatformNotificationService::CheckPermissionOnIOThread(
    content::ResourceContext* resource_context,
    const GURL& origin,
    int render_process_id) {
#if defined(OS_ANDROID)
  return blink::WebNotificationPermissionAllowed;
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
  return blink::WebNotificationPermissionAllowed;
#else
  return blink::WebNotificationPermissionDenied;
#endif
}

void XWalkPlatformNotificationService::DisplayNotification(
    content::BrowserContext* browser_context,
    const GURL& origin,
    const SkBitmap& icon,
    const content::PlatformNotificationData& notification_data,
    scoped_ptr<content::DesktopNotificationDelegate> delegate,
    base::Closure* cancel_callback) {
#if defined(OS_ANDROID)
  scoped_ptr<content::RenderWidgetHostIterator> widgets(
      content::RenderWidgetHost::GetRenderWidgetHosts());
  while (content::RenderWidgetHost* rwh = widgets->GetNextHost()) {
    if (!rwh->GetProcess())
      continue;
    content::RenderViewHost* rvh = content::RenderViewHost::From(rwh);
    if (!rvh)
      continue;
    content::WebContents* web_contents =
        content::WebContents::FromRenderViewHost(rvh);
    if (!web_contents)
      continue;
    XWalkContentsClientBridgeBase* bridge =
        XWalkContentsClientBridgeBase::FromWebContents(web_contents);
    bridge->ShowNotification(notification_data, icon, delegate.Pass(),
                             cancel_callback);
    return;
  }
#elif defined(OS_LINUX) && defined(USE_LIBNOTIFY)
  if (!notification_manager_linux_)
    notification_manager_linux_.reset(new XWalkNotificationManager());
  notification_manager_linux_->ShowDesktopNotification(
      browser_context,
      origin,
      notification_data,
      delegate.Pass(),
      cancel_callback);
#endif
}

}  // namespace xwalk
<|endoftext|>


<commit_before>/*
 * opencog/comboreduct/reduct/flat_normal_form.cc
 *
 * Copyright (C) 2002-2008 Novamente LLC
 * All Rights Reserved
 *
 * Written by Moshe Looks
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "flat_normal_form.h"

namespace opencog { namespace reduct {

  //does c contain p and !p?
  bool tautology(const clause& c) {
    return (std::adjacent_find(c.begin(),c.end(),
			       bind(std::equal_to<int>(),_1,
				    bind(std::negate<int>(),_2)))!=c.end());
  }
  //is c1 a subset of (or equal to) c2?
  bool subset_eq(const clause& c1,const clause& c2) {
    return (c2.size()>=c1.size() &&
	    std::includes(c2.begin(),c2.end(),
			  c1.begin(),c1.end(),c2.key_comp()));
  }
  bool subset(const clause& c1,const clause& c2) {
    return (c2.size()>c1.size() &&
	    std::includes(c2.begin(),c2.end(),
			  c1.begin(),c1.end(),c2.key_comp()));
  }
  int number_of_literals(const nf& f) {
    return std::accumulate(f.begin(),f.end(),0,
			   bind(std::plus<int>(),_1,bind(&clause::size,_2)));
  }

} // ~namespace reduct
} // ~namespace opencog

std::ostream& operator<<(std::ostream& out,const opencog::reduct::clause& c) {
    out << "(";
    if (!c.empty()) {
        out << *c.begin();
        for (opencog::reduct::clause::iterator i1=++c.begin();
             i1!=c.end();++i1)
            out << " " << *i1;
    }
    out << ")";
    return out;
}

std::ostream& operator<<(std::ostream& out,const opencog::reduct::nf& d) {
    for (opencog::reduct::nf::const_iterator c=d.begin();c!=d.end();++c)
        out << *c;
    return out;
}

<commit_msg>combo: add whitespace, improve readability.<commit_after>/*
 * opencog/comboreduct/reduct/flat_normal_form.cc
 *
 * Copyright (C) 2002-2008 Novamente LLC
 * All Rights Reserved
 *
 * Written by Moshe Looks
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include "flat_normal_form.h"

namespace opencog { namespace reduct {

  /// Does c contain p and !p?
  bool tautology(const clause& c)
  {
    return (std::adjacent_find(c.begin(), c.end(),
			       bind(std::equal_to<int>(), _1,
				    bind(std::negate<int>(), _2))) != c.end());
  }

  /// Is c1 a subset of (or equal to) c2?
  bool subset_eq(const clause& c1, const clause& c2)
  {
    return (c2.size() >= c1.size() &&
	    std::includes(c2.begin(), c2.end(),
			  c1.begin(), c1.end(), c2.key_comp()));
  }

  bool subset(const clause& c1, const clause& c2)
  {
    return (c2.size() > c1.size() &&
	    std::includes(c2.begin(), c2.end(),
			  c1.begin(), c1.end(), c2.key_comp()));
  }

  int number_of_literals(const nf& f)
  {
    return std::accumulate(f.begin(), f.end(), 0,
			   bind(std::plus<int>(), _1, bind(&clause::size, _2)));
  }

} // ~namespace reduct
} // ~namespace opencog

std::ostream& operator<<(std::ostream& out,const opencog::reduct::clause& c) {
    out << "(";
    if (!c.empty()) {
        out << *c.begin();
        for (opencog::reduct::clause::iterator i1=++c.begin();
             i1!=c.end();++i1)
            out << " " << *i1;
    }
    out << ")";
    return out;
}

std::ostream& operator<<(std::ostream& out,const opencog::reduct::nf& d) {
    for (opencog::reduct::nf::const_iterator c=d.begin();c!=d.end();++c)
        out << *c;
    return out;
}

<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <qitype/signal.hpp>
#include <qi/future.hpp>
#include <qi/application.hpp>
#include <qitype/functiontypefactory.hpp>

qiLogCategory("test");

class Foo
{
public:
  void func(int)               { }
  void func1(int *r, int)
  {
    // hackish sleep so that asynchronous trigger detection is safer
    qi::os::msleep(1); *r += 1;
  }
  void func2(int *r, int, int) { *r += 1; }
};
void foo(int *r, int, int)     { *r += 1; }
void foo2(int *r, char, char)  { *r += 1; }
void foo3(int *r, Foo *)       { *r += 1; }
void foolast(int, qi::Promise<void> prom, int* r) { prom.setValue(0); *r += 1;}

TEST(TestSignal, TestCompilation)
{
  int                    res = 0;
  qi::Signal<void (int)> s;
  Foo*                   f = 0;
  qi::Promise<void>      prom;

  //do not count
  s.connect(qi::makeGenericFunction(f, &Foo::func));
  s.connect(boost::bind<void>(&Foo::func, f, _1));

  s.connect(boost::bind(&foo, &res, 12, _1));
  s.connect(boost::bind(&foo2, &res, 12, _1));
  s.connect(boost::bind<void>(&Foo::func1, f, &res, _1));
  s.connect(boost::bind<void>(&Foo::func2, f, &res, 5, _1));
  s.connect(boost::bind(&foo3, &res, f));
  s.connect(boost::bind(&foolast, _1, prom, &res));

  s(42);
  int timeout = 1000;
  while (timeout > 0) {
    qi::os::msleep(1);
    if (res == 6)
      break;
    timeout -= 1;
  }
  ASSERT_EQ(6, res);
  ASSERT_TRUE(prom.future().isFinished());
  ASSERT_FALSE(prom.future().hasError());
}

void write42(boost::shared_ptr<int> ptr)
{
  *ptr = 42;
}

TEST(TestSignal, SharedPtr)
{
  // Redundant with Copy test, but just to be sure, check that shared_ptr
  // is correctly transmited.
  qi::Signal<void (boost::shared_ptr<int>)> sig;
  sig.connect(qi::makeGenericFunction(&write42), qi::MetaCallType_Queued);
  {
    boost::shared_ptr<int> ptr(new int(12));
    sig(ptr);
  };
}

void byRef(int& i, bool* done)
{
  qiLogDebug() <<"byRef " << &i << ' ' << done;
  i = 12;
  *done = true;
}

TEST(TestSignal, Copy)
{
  // Check that reference argument type are copied when an async call is made
  qi::Signal<void (int&, bool*)> sig;
  qiLogDebug() << "sync";
  sig.connect(qi::makeGenericFunction(byRef), qi::MetaCallType_Direct);
  bool done = false;
  int i = 0;
  qiLogDebug() << "iref is " << &i;
  sig(i, &done);
  ASSERT_TRUE(done); //synchronous
  //ASSERT_EQ(0, i); // byref, but still copies for small types
  qiLogDebug() << "async";
  sig =  qi::Signal<void (int&, bool*)>();
  sig.connect(qi::makeGenericFunction(byRef), qi::MetaCallType_Queued);
  i = 0;
  done = false;
  qiLogDebug() << "done is " << &done;
  sig(i, &done);
  for (unsigned c=0; !done && c<100;++c) qi::os::msleep(10);
  ASSERT_TRUE(done);
  ASSERT_EQ(0, i); // async: was copied
}

TEST(TestSignal, AutoDisconnect)
{
  // Test automatic disconnection when passing shared_ptrs
  int r = 0;
  boost::shared_ptr<Foo> foo(new Foo());
  qi::Signal<void (int*, int)> sig;
  sig.connect(foo, &Foo::func1, qi::MetaCallType_Direct);
  sig(&r, 0);
  ASSERT_EQ(1, r);
  foo.reset();
  sig(&r, 0);
  ASSERT_EQ(1, r);
}

TEST(TestSignal, AutoDisconnectTrack)
{
  // Test auto-disconnect using external tracker
  int r = 0;
  boost::shared_ptr<int> s(new int(2));
  Foo* ptr = new Foo();
  qi::Signal<void (int*, int)> sig;
  sig.connect(ptr, &Foo::func1, qi::MetaCallType_Direct).track(boost::weak_ptr<int>(s));
  sig(&r, 0);
  ASSERT_EQ(1, r);
  sig(&r, 1);
  ASSERT_EQ(2, r);
  s.reset();
  sig(&r, 1);
  ASSERT_EQ(2, r);
}

TEST(TestSignal, BadArity)
{
  qi::Signal<void()> s;
  // caught at compile-time by signal<T>
  ASSERT_EQ(qi::SignalBase::invalidLink, ((qi::SignalBase&)s).connect(&foo));
  //idem
  ASSERT_EQ(qi::SignalBase::invalidLink, ((qi::SignalBase&)s).connect(&foo2));
  ASSERT_EQ(qi::SignalBase::invalidLink, s.connect((Foo*)0, &Foo::func1));
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>test_signal: Robustify.<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <qitype/signal.hpp>
#include <qi/future.hpp>
#include <qi/application.hpp>
#include <qitype/functiontypefactory.hpp>

qiLogCategory("test");

class Foo
{
public:
  void func(int)               { }
  void func1(int *r, int)
  {
    // hackish sleep so that asynchronous trigger detection is safer
    qi::os::msleep(1); *r += 1;
  }
  void func2(int *r, int, int) { *r += 1; }
};
void foo(int *r, int, int)     { *r += 1; }
void foo2(int *r, char, char)  { *r += 1; }
void foo3(int *r, Foo *)       { *r += 1; }
void foolast(int, qi::Promise<void> prom, int* r) { prom.setValue(0); *r += 1;}

TEST(TestSignal, TestCompilation)
{
  int                    res = 0;
  qi::Signal<void (int)> s;
  Foo*                   f = 0;
  qi::Promise<void>      prom;

  //do not count
  s.connect(qi::makeGenericFunction(f, &Foo::func));
  s.connect(boost::bind<void>(&Foo::func, f, _1));

  s.connect(boost::bind(&foo, &res, 12, _1));
  s.connect(boost::bind(&foo2, &res, 12, _1));
  s.connect(boost::bind<void>(&Foo::func1, f, &res, _1));
  s.connect(boost::bind<void>(&Foo::func2, f, &res, 5, _1));
  s.connect(boost::bind(&foo3, &res, f));
  s.connect(boost::bind(&foolast, _1, prom, &res));

  s(42);
  int timeout = 100;
  while (timeout > 0) {
    qi::os::msleep(10);
    if (res == 6)
      break;
    timeout -= 1;
  }
  ASSERT_EQ(6, res);
  ASSERT_TRUE(prom.future().isFinished());
  ASSERT_FALSE(prom.future().hasError());
}

void write42(boost::shared_ptr<int> ptr)
{
  *ptr = 42;
}

TEST(TestSignal, SharedPtr)
{
  // Redundant with Copy test, but just to be sure, check that shared_ptr
  // is correctly transmited.
  qi::Signal<void (boost::shared_ptr<int>)> sig;
  sig.connect(qi::makeGenericFunction(&write42), qi::MetaCallType_Queued);
  {
    boost::shared_ptr<int> ptr(new int(12));
    sig(ptr);
  };
}

void byRef(int& i, bool* done)
{
  qiLogDebug() <<"byRef " << &i << ' ' << done;
  i = 12;
  *done = true;
}

TEST(TestSignal, Copy)
{
  // Check that reference argument type are copied when an async call is made
  qi::Signal<void (int&, bool*)> sig;
  qiLogDebug() << "sync";
  sig.connect(qi::makeGenericFunction(byRef), qi::MetaCallType_Direct);
  bool done = false;
  int i = 0;
  qiLogDebug() << "iref is " << &i;
  sig(i, &done);
  ASSERT_TRUE(done); //synchronous
  //ASSERT_EQ(0, i); // byref, but still copies for small types
  qiLogDebug() << "async";
  sig =  qi::Signal<void (int&, bool*)>();
  sig.connect(qi::makeGenericFunction(byRef), qi::MetaCallType_Queued);
  i = 0;
  done = false;
  qiLogDebug() << "done is " << &done;
  sig(i, &done);
  for (unsigned c=0; !done && c<100;++c) qi::os::msleep(10);
  ASSERT_TRUE(done);
  ASSERT_EQ(0, i); // async: was copied
}

TEST(TestSignal, AutoDisconnect)
{
  // Test automatic disconnection when passing shared_ptrs
  int r = 0;
  boost::shared_ptr<Foo> foo(new Foo());
  qi::Signal<void (int*, int)> sig;
  sig.connect(foo, &Foo::func1, qi::MetaCallType_Direct);
  sig(&r, 0);
  ASSERT_EQ(1, r);
  foo.reset();
  sig(&r, 0);
  ASSERT_EQ(1, r);
}

TEST(TestSignal, AutoDisconnectTrack)
{
  // Test auto-disconnect using external tracker
  int r = 0;
  boost::shared_ptr<int> s(new int(2));
  Foo* ptr = new Foo();
  qi::Signal<void (int*, int)> sig;
  sig.connect(ptr, &Foo::func1, qi::MetaCallType_Direct).track(boost::weak_ptr<int>(s));
  sig(&r, 0);
  ASSERT_EQ(1, r);
  sig(&r, 1);
  ASSERT_EQ(2, r);
  s.reset();
  sig(&r, 1);
  ASSERT_EQ(2, r);
}

TEST(TestSignal, BadArity)
{
  qi::Signal<void()> s;
  // caught at compile-time by signal<T>
  ASSERT_EQ(qi::SignalBase::invalidLink, ((qi::SignalBase&)s).connect(&foo));
  //idem
  ASSERT_EQ(qi::SignalBase::invalidLink, ((qi::SignalBase&)s).connect(&foo2));
  ASSERT_EQ(qi::SignalBase::invalidLink, s.connect((Foo*)0, &Foo::func1));
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file transaction.cpp
 * @author Dmitrii Khokhlov <winsvega@mail.ru>
 * @date 2015
 * Transaaction test functions.
 */

#include "TestHelper.h"

using namespace std;
using namespace json_spirit;
using namespace dev;
using namespace dev::eth;
using namespace dev::eth;

namespace dev {  namespace test {

Transaction createTransactionFromFields(mObject& _tObj)
{
	BOOST_REQUIRE(_tObj.count("data") > 0);
	BOOST_REQUIRE(_tObj.count("value") > 0);
	BOOST_REQUIRE(_tObj.count("gasPrice") > 0);
	BOOST_REQUIRE(_tObj.count("gasLimit") > 0);
	BOOST_REQUIRE(_tObj.count("nonce")> 0);
	BOOST_REQUIRE(_tObj.count("to") > 0);

	BOOST_REQUIRE(_tObj.count("v") > 0);
	BOOST_REQUIRE(_tObj.count("r") > 0);
	BOOST_REQUIRE(_tObj.count("s") > 0);

	//Construct Rlp of the given transaction
	RLPStream rlpStream;
	rlpStream.appendList(9);
	rlpStream <<  bigint(_tObj["nonce"].get_str()) << bigint(_tObj["gasPrice"].get_str()) << bigint(_tObj["gasLimit"].get_str());
	if (_tObj["to"].get_str().empty())
		rlpStream << "";
	else
		rlpStream << Address(_tObj["to"].get_str());
	rlpStream << bigint(_tObj["value"].get_str()) << importData(_tObj);
	u256 r = h256(fromHex(_tObj["r"].get_str()));
	u256 s = h256(fromHex(_tObj["s"].get_str()));
	rlpStream << bigint(_tObj["v"].get_str()) << r << s;

	return Transaction(rlpStream.out(), CheckSignature::Sender);
}

void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{
	for (auto& i: _v.get_obj())
	{
		cerr << i.first << endl;
		mObject& o = i.second.get_obj();

		if(_fillin == false)
		{
			BOOST_REQUIRE(o.count("rlp") > 0);
			bytes rlpReaded = importByteArray(o["rlp"].get_str());
			Transaction txFromRlp;

			try
			{
				txFromRlp = Transaction(rlpReaded, CheckSignature::Sender);
				if (!txFromRlp.signature().isValid())
					BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
			}
			catch(...)
			{
				BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transction object should not be defined because the RLP is invalid!");
				return;
			}

			BOOST_REQUIRE(o.count("transaction") > 0);

			mObject tObj = o["transaction"].get_obj();
			Transaction txFromFields = createTransactionFromFields(tObj);

			//Check the fields restored from RLP to original fields
			BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!");
			BOOST_CHECK_MESSAGE(txFromFields.value() == txFromRlp.value(), "Value in given RLP not matching the Transaction value!");
			BOOST_CHECK_MESSAGE(txFromFields.gasPrice() == txFromRlp.gasPrice(), "GasPrice in given RLP not matching the Transaction gasPrice!");
			BOOST_CHECK_MESSAGE(txFromFields.gas() == txFromRlp.gas(),"Gas in given RLP not matching the Transaction gas!");
			BOOST_CHECK_MESSAGE(txFromFields.nonce() == txFromRlp.nonce(),"Nonce in given RLP not matching the Transaction nonce!");
			BOOST_CHECK_MESSAGE(txFromFields.receiveAddress() == txFromRlp.receiveAddress(), "Receive address in given RLP not matching the Transaction 'to' address!");
			BOOST_CHECK_MESSAGE(txFromFields.sender() == txFromRlp.sender(), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!");
			BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!");
			BOOST_REQUIRE (o.count("sender") > 0);

			Address addressReaded = Address(o["sender"].get_str());
			BOOST_CHECK_MESSAGE(txFromFields.sender() ==  addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!");
		}

		if(_fillin == true)
		{
			BOOST_REQUIRE(o.count("transaction") > 0);
			mObject tObj = o["transaction"].get_obj();

			//Construct Rlp of the given transaction
			RLPStream rlpStream;
			rlpStream.appendList(tObj.size());

			if(tObj.count("nonce") > 0)
				rlpStream << bigint(tObj["nonce"].get_str());

			if(tObj.count("gasPrice") > 0)
				rlpStream << bigint(tObj["gasPrice"].get_str());

			if(tObj.count("gasLimit") > 0)
				rlpStream << bigint(tObj["gasLimit"].get_str());

			if(tObj.count("to") > 0)
			{
				if (tObj["to"].get_str().empty())
					rlpStream << "";
				else
					rlpStream << Address(tObj["to"].get_str());
			}

			if(tObj.count("value") > 0)
				rlpStream << bigint(tObj["value"].get_str());

			if(tObj.count("data") > 0)
				rlpStream << importData(tObj);

			if(tObj.count("v") > 0)
				rlpStream << bigint(tObj["v"].get_str());

			if(tObj.count("r") > 0)
			{
				u256 r = h256(fromHex(tObj["r"].get_str()));
				rlpStream << r;
			}

			if(tObj.count("s") > 0)
			{
				u256 s = h256(fromHex(tObj["s"].get_str()));
				rlpStream << s;
			}

			if(tObj.count("extrafield") > 0)
				rlpStream << bigint(tObj["extrafield"].get_str());

			o["rlp"] = "0x" + toHex(rlpStream.out());

			try
			{
				Transaction txFromFields(rlpStream.out(), CheckSignature::Sender);
				if (!txFromFields.signature().isValid())
					BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );

				o["sender"] = toString(txFromFields.sender());
			}
			catch(...)
			{
				o.erase(o.find("transaction"));
			}
		}
	}//for
}//doTransactionTests

} }// Namespace Close

BOOST_AUTO_TEST_SUITE(TransactionTests)

BOOST_AUTO_TEST_CASE(ttFillerTest)
{
	dev::test::executeTests("ttTransactionTest", "/TransactionTests", dev::test::doTransactionTests);
}

BOOST_AUTO_TEST_CASE(ttDataStringTest)
{
	dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests);
}

BOOST_AUTO_TEST_CASE(ttCreateTest)
{
	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	{
		string arg = boost::unit_test::framework::master_test_suite().argv[i];
		if (arg == "--createtest")
		{
			if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
			{
				cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
				return;
			}
			try
			{
				cnote << "Populating tests...";
				json_spirit::mValue v;
				string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
				json_spirit::read_string(s, v);
				dev::test::doTransactionTests(v, true);
				writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
			}
			catch (Exception const& _e)
			{
				BOOST_ERROR("Failed transaction test with Exception: " << diagnostic_information(_e));
			}
			catch (std::exception const& _e)
			{
				BOOST_ERROR("Failed transaction test with Exception: " << _e.what());
			}
		}
	}
}

BOOST_AUTO_TEST_CASE(userDefinedFileTT)
{
	dev::test::userDefinedTest("--ttTest", dev::test::doTransactionTests);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Chris suggestions<commit_after>/*
	This file is part of cpp-ethereum.

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

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file transaction.cpp
 * @author Dmitrii Khokhlov <winsvega@mail.ru>
 * @date 2015
 * Transaaction test functions.
 */

#include "TestHelper.h"

using namespace std;
using namespace json_spirit;
using namespace dev;
using namespace dev::eth;
using namespace dev::eth;

namespace dev {  namespace test {

Transaction createTransactionFromFields(mObject& _tObj)
{
	BOOST_REQUIRE(_tObj.count("data") > 0);
	BOOST_REQUIRE(_tObj.count("value") > 0);
	BOOST_REQUIRE(_tObj.count("gasPrice") > 0);
	BOOST_REQUIRE(_tObj.count("gasLimit") > 0);
	BOOST_REQUIRE(_tObj.count("nonce")> 0);
	BOOST_REQUIRE(_tObj.count("to") > 0);

	BOOST_REQUIRE(_tObj.count("v") > 0);
	BOOST_REQUIRE(_tObj.count("r") > 0);
	BOOST_REQUIRE(_tObj.count("s") > 0);

	//Construct Rlp of the given transaction
	RLPStream rlpStream;
	rlpStream.appendList(9);
	rlpStream <<  bigint(_tObj["nonce"].get_str()) << bigint(_tObj["gasPrice"].get_str()) << bigint(_tObj["gasLimit"].get_str());
	if (_tObj["to"].get_str().empty())
		rlpStream << "";
	else
		rlpStream << Address(_tObj["to"].get_str());
	rlpStream << bigint(_tObj["value"].get_str()) << importData(_tObj);
	u256 r = h256(fromHex(_tObj["r"].get_str()));
	u256 s = h256(fromHex(_tObj["s"].get_str()));
	rlpStream << bigint(_tObj["v"].get_str()) << r << s;

	return Transaction(rlpStream.out(), CheckSignature::Sender);
}

void doTransactionTests(json_spirit::mValue& _v, bool _fillin)
{
	for (auto& i: _v.get_obj())
	{
		cerr << i.first << endl;
		mObject& o = i.second.get_obj();

		if (_fillin == false)
		{
			BOOST_REQUIRE(o.count("rlp") > 0);
			bytes rlpReaded = importByteArray(o["rlp"].get_str());
			Transaction txFromRlp;

			try
			{
				txFromRlp = Transaction(rlpReaded, CheckSignature::Sender);
				if (!txFromRlp.signature().isValid())
					BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );
			}
			catch(...)
			{
				BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transction object should not be defined because the RLP is invalid!");
				return;
			}

			BOOST_REQUIRE(o.count("transaction") > 0);

			mObject tObj = o["transaction"].get_obj();
			Transaction txFromFields = createTransactionFromFields(tObj);

			//Check the fields restored from RLP to original fields
			BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!");
			BOOST_CHECK_MESSAGE(txFromFields.value() == txFromRlp.value(), "Value in given RLP not matching the Transaction value!");
			BOOST_CHECK_MESSAGE(txFromFields.gasPrice() == txFromRlp.gasPrice(), "GasPrice in given RLP not matching the Transaction gasPrice!");
			BOOST_CHECK_MESSAGE(txFromFields.gas() == txFromRlp.gas(),"Gas in given RLP not matching the Transaction gas!");
			BOOST_CHECK_MESSAGE(txFromFields.nonce() == txFromRlp.nonce(),"Nonce in given RLP not matching the Transaction nonce!");
			BOOST_CHECK_MESSAGE(txFromFields.receiveAddress() == txFromRlp.receiveAddress(), "Receive address in given RLP not matching the Transaction 'to' address!");
			BOOST_CHECK_MESSAGE(txFromFields.sender() == txFromRlp.sender(), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!");
			BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!");
			BOOST_REQUIRE (o.count("sender") > 0);

			Address addressReaded = Address(o["sender"].get_str());
			BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!");
		}
		else
		{
			BOOST_REQUIRE(o.count("transaction") > 0);
			mObject tObj = o["transaction"].get_obj();

			//Construct Rlp of the given transaction
			RLPStream rlpStream;
			rlpStream.appendList(tObj.size());

			if (tObj.count("nonce") > 0)
				rlpStream << bigint(tObj["nonce"].get_str());

			if (tObj.count("gasPrice") > 0)
				rlpStream << bigint(tObj["gasPrice"].get_str());

			if (tObj.count("gasLimit") > 0)
				rlpStream << bigint(tObj["gasLimit"].get_str());

			if (tObj.count("to") > 0)
			{
				if (tObj["to"].get_str().empty())
					rlpStream << "";
				else
					rlpStream << Address(tObj["to"].get_str());
			}

			if (tObj.count("value") > 0)
				rlpStream << bigint(tObj["value"].get_str());

			if (tObj.count("data") > 0)
				rlpStream << importData(tObj);

			if (tObj.count("v") > 0)
				rlpStream << bigint(tObj["v"].get_str());

			if (tObj.count("r") > 0)
			{
				u256 r = h256(fromHex(tObj["r"].get_str()));
				rlpStream << r;
			}

			if (tObj.count("s") > 0)
			{
				u256 s = h256(fromHex(tObj["s"].get_str()));
				rlpStream << s;
			}

			if (tObj.count("extrafield") > 0)
				rlpStream << bigint(tObj["extrafield"].get_str());

			o["rlp"] = "0x" + toHex(rlpStream.out());

			try
			{
				Transaction txFromFields(rlpStream.out(), CheckSignature::Sender);
				if (!txFromFields.signature().isValid())
					BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") );

				o["sender"] = toString(txFromFields.sender());
			}
			catch(...)
			{
				o.erase(o.find("transaction"));
			}
		}
	}//for
}//doTransactionTests

} }// Namespace Close

BOOST_AUTO_TEST_SUITE(TransactionTests)

BOOST_AUTO_TEST_CASE(TransactionTest)
{
	dev::test::executeTests("ttTransactionTest", "/TransactionTests", dev::test::doTransactionTests);
}

BOOST_AUTO_TEST_CASE(tt10mbDataField)
{
	dev::test::executeTests("tt10mbDataField", "/TransactionTests", dev::test::doTransactionTests);
}

BOOST_AUTO_TEST_CASE(ttCreateTest)
{
	for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)
	{
		string arg = boost::unit_test::framework::master_test_suite().argv[i];
		if (arg == "--createtest")
		{
			if (boost::unit_test::framework::master_test_suite().argc <= i + 2)
			{
				cnote << "usage: ./testeth --createtest <PathToConstructor> <PathToDestiny>\n";
				return;
			}
			try
			{
				cnote << "Populating tests...";
				json_spirit::mValue v;
				string s = asString(dev::contents(boost::unit_test::framework::master_test_suite().argv[i + 1]));
				BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + (string)boost::unit_test::framework::master_test_suite().argv[i + 1] + " is empty.");
				json_spirit::read_string(s, v);
				dev::test::doTransactionTests(v, true);
				writeFile(boost::unit_test::framework::master_test_suite().argv[i + 2], asBytes(json_spirit::write_string(v, true)));
			}
			catch (Exception const& _e)
			{
				BOOST_ERROR("Failed transaction test with Exception: " << diagnostic_information(_e));
			}
			catch (std::exception const& _e)
			{
				BOOST_ERROR("Failed transaction test with Exception: " << _e.what());
			}
		}
	}
}

BOOST_AUTO_TEST_CASE(userDefinedFileTT)
{
	dev::test::userDefinedTest("--ttTest", dev::test::doTransactionTests);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include <cstddef>
#include <array>

#include "types.hpp"
#include "keyboard.hpp"
#include "kernel_utils.hpp"
#include "console.hpp"
#include "shell.hpp"
#include "timer.hpp"

namespace {

//Declarations of the different functions

void reboot_command();
void help_command();
void uptime_command();
void clear_command();
void date_command();
void sleep_command();

struct command_definition {
    const char* name;
    void (*function)();
};

std::array<command_definition, 6> commands = {{
    {"reboot", reboot_command},
    {"help", help_command},
    {"uptime", uptime_command},
    {"clear", clear_command},
    {"date", date_command},
    {"sleep", sleep_command}
}};

std::size_t current_input_length = 0;
char current_input[50];

void exec_command();

void keyboard_handler(){
    uint8_t key = in_byte(0x60);

    if(key & 0x80){
        //TODO Handle shift
    } else {
        if(key == 0x1C){
            current_input[current_input_length] = '\0';

            k_print_line();

            exec_command();

            current_input_length = 0;

            k_print("thor> ");
        } else if(key == 0x0E){
            set_column(get_column() - 1);
            k_print(' ');
            set_column(get_column() - 1);

            --current_input_length;
        } else {
           auto qwertz_key = key_to_ascii(key);

           if(qwertz_key > 0){
               current_input[current_input_length++] = qwertz_key;
               k_print(qwertz_key);
           }
        }
    }
}

bool str_equals(const char* a, const char* b){
    while(*a && *a == *b){
        ++a;
        ++b;
    }

    return *a == *b;
}

void reboot_command(){
    interrupt<60>();
}

void help_command(){
    k_print("Available commands:\n");

    for(auto& command : commands){
        k_print('\t');
        k_print_line(command.name);
    }
}

void uptime_command(){
    k_print("Uptime: ");
    k_print(timer_seconds());
    k_print_line("s");
}

void exec_command(){
    for(auto& command : commands){
        if(str_equals(current_input, command.name)){
            command.function();

            return;
        }
    }

    k_print("The command \"");
    k_print(current_input);
    k_print("\" does not exist \n");
}

void clear_command(){
    wipeout();
}

#define CURRENT_YEAR        2013
#define century_register    0x00
#define cmos_address        0x70
#define cmos_data           0x71

int get_update_in_progress_flag() {
      out_byte(cmos_address, 0x0A);
      return (in_byte(cmos_data) & 0x80);
}

uint8_t get_RTC_register(int reg) {
      out_byte(cmos_address, reg);
      return in_byte(cmos_data);
}

void date_command(){
    uint8_t second;
    uint8_t minute;
    uint8_t hour;
    uint8_t day;
    uint8_t month;
    unsigned int year;

    uint8_t century;
    uint8_t last_second;
    uint8_t last_minute;
    uint8_t last_hour;
    uint8_t last_day;
    uint8_t last_month;
    uint8_t last_year;
    uint8_t last_century;
    uint8_t registerB;

    while (get_update_in_progress_flag()){};                // Make sure an update isn't in progress

    second = get_RTC_register(0x00);
    minute = get_RTC_register(0x02);
    hour = get_RTC_register(0x04);
    day = get_RTC_register(0x07);
    month = get_RTC_register(0x08);
    year = get_RTC_register(0x09);

    if(century_register != 0) {
        century = get_RTC_register(century_register);
    }

    do {
        last_second = second;
        last_minute = minute;
        last_hour = hour;
        last_day = day;
        last_month = month;
        last_year = year;
        last_century = century;

        while (get_update_in_progress_flag()){};           // Make sure an update isn't in progress

        second = get_RTC_register(0x00);
        minute = get_RTC_register(0x02);
        hour = get_RTC_register(0x04);
        day = get_RTC_register(0x07);
        month = get_RTC_register(0x08);
        year = get_RTC_register(0x09);

        if(century_register != 0) {
            century = get_RTC_register(century_register);
        }
    } while( (last_second != second) || (last_minute != minute) || (last_hour != hour) ||
        (last_day != day) || (last_month != month) || (last_year != year) ||
        (last_century != century) );

    registerB = get_RTC_register(0x0B);

    // Convert BCD to binary values if necessary

    if (!(registerB & 0x04)) {
        second = (second & 0x0F) + ((second / 16) * 10);
        minute = (minute & 0x0F) + ((minute / 16) * 10);
        hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);
        day = (day & 0x0F) + ((day / 16) * 10);
        month = (month & 0x0F) + ((month / 16) * 10);
        year = (year & 0x0F) + ((year / 16) * 10);

        if(century_register != 0) {
            century = (century & 0x0F) + ((century / 16) * 10);
        }
    }

    // Convert 12 hour clock to 24 hour clock if necessary

    if (!(registerB & 0x02) && (hour & 0x80)) {
        hour = ((hour & 0x7F) + 12) % 24;
    }

    // Calculate the full (4-digit) year

    if(century_register != 0) {
        year += century * 100;
    } else {
        year += (CURRENT_YEAR / 100) * 100;
        if(year < CURRENT_YEAR) year += 100;
    }

    k_print((std::size_t) day);
    k_print('.');
    k_print((std::size_t) month);
    k_print('.');
    k_print((std::size_t) year);

    k_print(' ');

    k_print((std::size_t) hour);
    k_print(':');
    k_print((std::size_t) minute);
    k_print(':');
    k_print((std::size_t) second);

    k_print_line();
}

void sleep_command(){
    sleep_ms(5000);
}

} //end of anonymous namespace

void init_shell(){
    current_input_length = 0;

    clear_command();

    k_print("thor> ");

    register_irq_handler<1>(keyboard_handler);
}
<commit_msg>Create echo command<commit_after>#include <cstddef>
#include <array>

#include "types.hpp"
#include "keyboard.hpp"
#include "kernel_utils.hpp"
#include "console.hpp"
#include "shell.hpp"
#include "timer.hpp"

namespace {

//Declarations of the different functions

void reboot_command(const char* params);
void help_command(const char* params);
void uptime_command(const char* params);
void clear_command(const char* params);
void date_command(const char* params);
void sleep_command(const char* params);
void echo_command(const char* params);

struct command_definition {
    const char* name;
    void (*function)(const char*);
};

std::array<command_definition, 7> commands = {{
    {"reboot", reboot_command},
    {"help", help_command},
    {"uptime", uptime_command},
    {"clear", clear_command},
    {"date", date_command},
    {"sleep", sleep_command},
    {"echo", echo_command}
}};

std::size_t current_input_length = 0;
char current_input[50];

void exec_command();

void keyboard_handler(){
    uint8_t key = in_byte(0x60);

    if(key & 0x80){
        //TODO Handle shift
    } else {
        if(key == 0x1C){
            current_input[current_input_length] = '\0';

            k_print_line();

            exec_command();

            current_input_length = 0;

            k_print("thor> ");
        } else if(key == 0x0E){
            set_column(get_column() - 1);
            k_print(' ');
            set_column(get_column() - 1);

            --current_input_length;
        } else {
           auto qwertz_key = key_to_ascii(key);

           if(qwertz_key > 0){
               current_input[current_input_length++] = qwertz_key;
               k_print(qwertz_key);
           }
        }
    }
}

bool str_equals(const char* a, const char* b){
    while(*a && *a == *b){
        ++a;
        ++b;
    }

    return *a == *b;
}

bool str_contains(const char* a, char c){
    while(*a){
        if(*a == c){
            return true;
        }
        ++a;
    }

    return false;
}

void str_copy(const char* a, char* b){
    while(*a){
        *b++ = *a++;
    }

    *b = '\0';
}

const char* str_until(char* a, char c){
    char* it = a;
    while(*it){
        if(*it == c){
            *it = '\0';
            return a;
        }
        ++it;
    }

    return a;
}

const char* str_from(char* a, char c){
    char* it = a;
    while(*it){
        if(*it == c){
            return ++it;
        }
        ++it;
    }

    return a;
}

void exec_command(){
    char buffer[50];

    for(auto& command : commands){
        const char* input_command = current_input;
        if(str_contains(current_input, ' ')){
            str_copy(current_input, buffer);
            input_command = str_until(buffer, ' ');
        }

        if(str_equals(input_command, command.name)){
            command.function(current_input);

            return;
        }
    }

    k_print("The command \"");
    k_print(current_input);
    k_print("\" does not exist \n");
}

void clear_command(const char* params){
    wipeout();
}

void reboot_command(const char* params){
    interrupt<60>();
}

void help_command(const char* params){
    k_print("Available commands:\n");

    for(auto& command : commands){
        k_print('\t');
        k_print_line(command.name);
    }
}

void uptime_command(const char* params){
    k_print("Uptime: ");
    k_print(timer_seconds());
    k_print_line("s");
}

#define CURRENT_YEAR        2013
#define century_register    0x00
#define cmos_address        0x70
#define cmos_data           0x71

int get_update_in_progress_flag() {
      out_byte(cmos_address, 0x0A);
      return (in_byte(cmos_data) & 0x80);
}

uint8_t get_RTC_register(int reg) {
      out_byte(cmos_address, reg);
      return in_byte(cmos_data);
}

void date_command(const char* params){
    uint8_t second;
    uint8_t minute;
    uint8_t hour;
    uint8_t day;
    uint8_t month;
    unsigned int year;

    uint8_t century;
    uint8_t last_second;
    uint8_t last_minute;
    uint8_t last_hour;
    uint8_t last_day;
    uint8_t last_month;
    uint8_t last_year;
    uint8_t last_century;
    uint8_t registerB;

    while (get_update_in_progress_flag()){};                // Make sure an update isn't in progress

    second = get_RTC_register(0x00);
    minute = get_RTC_register(0x02);
    hour = get_RTC_register(0x04);
    day = get_RTC_register(0x07);
    month = get_RTC_register(0x08);
    year = get_RTC_register(0x09);

    if(century_register != 0) {
        century = get_RTC_register(century_register);
    }

    do {
        last_second = second;
        last_minute = minute;
        last_hour = hour;
        last_day = day;
        last_month = month;
        last_year = year;
        last_century = century;

        while (get_update_in_progress_flag()){};           // Make sure an update isn't in progress

        second = get_RTC_register(0x00);
        minute = get_RTC_register(0x02);
        hour = get_RTC_register(0x04);
        day = get_RTC_register(0x07);
        month = get_RTC_register(0x08);
        year = get_RTC_register(0x09);

        if(century_register != 0) {
            century = get_RTC_register(century_register);
        }
    } while( (last_second != second) || (last_minute != minute) || (last_hour != hour) ||
        (last_day != day) || (last_month != month) || (last_year != year) ||
        (last_century != century) );

    registerB = get_RTC_register(0x0B);

    // Convert BCD to binary values if necessary

    if (!(registerB & 0x04)) {
        second = (second & 0x0F) + ((second / 16) * 10);
        minute = (minute & 0x0F) + ((minute / 16) * 10);
        hour = ( (hour & 0x0F) + (((hour & 0x70) / 16) * 10) ) | (hour & 0x80);
        day = (day & 0x0F) + ((day / 16) * 10);
        month = (month & 0x0F) + ((month / 16) * 10);
        year = (year & 0x0F) + ((year / 16) * 10);

        if(century_register != 0) {
            century = (century & 0x0F) + ((century / 16) * 10);
        }
    }

    // Convert 12 hour clock to 24 hour clock if necessary

    if (!(registerB & 0x02) && (hour & 0x80)) {
        hour = ((hour & 0x7F) + 12) % 24;
    }

    // Calculate the full (4-digit) year

    if(century_register != 0) {
        year += century * 100;
    } else {
        year += (CURRENT_YEAR / 100) * 100;
        if(year < CURRENT_YEAR) year += 100;
    }

    k_print((std::size_t) day);
    k_print('.');
    k_print((std::size_t) month);
    k_print('.');
    k_print((std::size_t) year);

    k_print(' ');

    k_print((std::size_t) hour);
    k_print(':');
    k_print((std::size_t) minute);
    k_print(':');
    k_print((std::size_t) second);

    k_print_line();
}

void sleep_command(const char* params){
    sleep_ms(5000);
}

void echo_command(const char* params){
    k_print_line(params + 5);
}

} //end of anonymous namespace

void init_shell(){
    current_input_length = 0;

    clear_command(0);

    k_print("thor> ");

    register_irq_handler<1>(keyboard_handler);
}
<|endoftext|>


<commit_before>/* ===========================
  Copyright (c) 2013 Philippe Tillet
  UMinTL - Unconstrained Minimization Template Library

  License : MIT X11 - See the LICENSE file in the root folder
 * ===========================*/

#ifndef UMINTL_MINIMIZE_HPP_
#define UMINTL_MINIMIZE_HPP_

#include "umintl/optimization_result.hpp"

#include "umintl/model_base.hpp"

#include "umintl/function_wrapper.hpp"
#include "umintl/optimization_context.hpp"

#include "umintl/directions/conjugate_gradient.hpp"
#include "umintl/directions/quasi_newton.hpp"
#include "umintl/directions/low_memory_quasi_newton.hpp"
#include "umintl/directions/steepest_descent.hpp"
#include "umintl/directions/truncated_newton.hpp"

#include "umintl/line_search/strong_wolfe_powell.hpp"

#include "umintl/stopping_criterion/value_treshold.hpp"
#include "umintl/stopping_criterion/gradient_treshold.hpp"

#include <iomanip>
#include <sstream>

namespace umintl{

    /** @brief The minimizer class
     *
     *  @tparam BackendType the linear algebra backend of the minimizer
     */
    template<class BackendType>
    class minimizer{
    public:

        /** @brief The constructor
         *
         * @param _direction the descent direction used by the minimizer
         * @param _stopping_criterion the stopping criterion
         * @param _max_iter the maximum number of iterations
         * @param _verbosity_level the verbosity level
         */
        minimizer(umintl::direction<BackendType> * _direction = new quasi_newton<BackendType>()
                             , umintl::stopping_criterion<BackendType> * _stopping_criterion = new gradient_treshold<BackendType>()
                             , unsigned int _max_iter = 1024, unsigned int _verbosity_level = 0) :
            direction(_direction)
          , line_search(new strong_wolfe_powell<BackendType>())
          , stopping_criterion(_stopping_criterion)
          , model(new deterministic<BackendType>())
          , hessian_vector_product_computation(CENTERED_DIFFERENCE)
          , verbosity_level(_verbosity_level), max_iter(_max_iter){

        }

        tools::shared_ptr<umintl::direction<BackendType> > direction;
        tools::shared_ptr<umintl::line_search<BackendType> > line_search;
        tools::shared_ptr<umintl::stopping_criterion<BackendType> > stopping_criterion;
        tools::shared_ptr< model_base<BackendType> > model;
        computation_type hessian_vector_product_computation;

        double tolerance;

        unsigned int verbosity_level;
        unsigned int max_iter;

    private:

        /** @brief Get a brief info string on the minimizer
         *
         *  @return String containing the verbosity level, maximum number of iteration, and the direction used
         */
        std::string info() const{
          std::ostringstream oss;
          oss << "Verbosity Level : " << verbosity_level << std::endl;
          oss << "Maximum number of iterations : " << max_iter << std::endl;
          oss << "Direction : " << direction->info() << std::endl;
          return oss.str();
        }

        /** @brief Clean memory and terminate the optimization result
         *
         *  @return Optimization result
         */
        optimization_result terminate(optimization_result::termination_cause_type termination_cause, typename BackendType::VectorType & res, std::size_t N, optimization_context<BackendType> & context){
            optimization_result result;
            BackendType::copy(N,context.x(),res);
            result.f = context.val();
            result.iteration = context.iter();
            result.n_functions_eval = context.fun().n_value_computations();
            result.n_gradient_eval = context.fun().n_gradient_computations();
            result.termination_cause = termination_cause;

            clean_all(context);

            return result;
        }

        /** @brief Init the components of the procedure (ie allocate memory for the temporaries, typically)
         */
        void init_all(optimization_context<BackendType> & c){
            direction->init(c);
            line_search->init(c);
            stopping_criterion->init(c);
        }

        /** @brief Clean the components of the procedure (ie free memory for the temporaries, typically)
         */
        void clean_all(optimization_context<BackendType> & c){
            direction->clean(c);
            line_search->clean(c);
            stopping_criterion->clean(c);
        }

    public:
        template<class Fun>
        optimization_result operator()(typename BackendType::VectorType & res, Fun & fun, typename BackendType::VectorType const & x0, std::size_t N){
            typedef typename BackendType::VectorType VectorType;
            tools::shared_ptr<umintl::direction<BackendType> > steepest_descent(new umintl::steepest_descent<BackendType>());
            line_search_result<BackendType> search_res(N);
            optimization_context<BackendType> c(x0, N, *model, new detail::function_wrapper_impl<BackendType, Fun>(fun,N,hessian_vector_product_computation));

            init_all(c);

            if(verbosity_level >= 1)
                std::cout << info() << std::endl;

            tools::shared_ptr<umintl::direction<BackendType> > current_direction;
            if(dynamic_cast<truncated_newton<BackendType> * >(direction.get()))
              current_direction = steepest_descent;
            else
              current_direction = steepest_descent;

            //Main loop
            c.fun().compute_value_gradient(c.x(), c.val(), c.g(), c.model().get_value_gradient_tag());
            for( ; c.iter() < max_iter ; ++c.iter()){
                if(verbosity_level >= 2 ){
                    std::cout << "Ieration  " << c.iter()
                              << "| cost : " << c.val()
                              << "| NVal : " << c.fun().n_value_computations()
                              << "| NGrad : " << c.fun().n_gradient_computations();
                    if(unsigned int NHv = c.fun().n_hessian_vector_product_computations())
                     std::cout<< "| NHv : " << NHv ;
                    if(unsigned int ND = c.fun().n_datapoints_accessed())
                     std::cout << "| NAccesses " << (float)ND;
                    std::cout << std::endl;
                }

                (*current_direction)(c);

                c.dphi_0() = BackendType::dot(N,c.p(),c.g());
                //Not a descent direction...
                if(c.dphi_0()>0){
                    //current_direction->reset(c);
                    current_direction = steepest_descent;
                    (*current_direction)(c);
                    c.dphi_0() = BackendType::dot(N,c.p(),c.g());
                }

                (*line_search)(search_res, current_direction.get(), c);

                if(search_res.has_failed){
                    return terminate(optimization_result::LINE_SEARCH_FAILED, res, N, c);
                }

//                BackendType::copy(c.N(), c.x(), search_res.best_x);
//                BackendType::axpy(c.N(),0.0001,c.p(),search_res.best_x);

                c.alpha() = search_res.best_alpha;

                BackendType::copy(N,c.x(),c.xm1());
                BackendType::copy(N,search_res.best_x,c.x());

                BackendType::copy(N,c.g(),c.gm1());
                BackendType::copy(N,search_res.best_g,c.g());

                c.valm1() = c.val();
                c.val() = search_res.best_phi;

                if((*stopping_criterion)(c)){
                    return terminate(optimization_result::STOPPING_CRITERION, res, N, c);
                }
                current_direction = direction;

                if(model->update(c))
                  c.fun().compute_value_gradient(c.x(), c.val(), c.g(), c.model().get_value_gradient_tag());
            }

            return terminate(optimization_result::MAX_ITERATION_REACHED, res, N, c);
        }
    };

}

#endif
<commit_msg>Removed warning<commit_after>/* ===========================
  Copyright (c) 2013 Philippe Tillet
  UMinTL - Unconstrained Minimization Template Library

  License : MIT X11 - See the LICENSE file in the root folder
 * ===========================*/

#ifndef UMINTL_MINIMIZE_HPP_
#define UMINTL_MINIMIZE_HPP_

#include "umintl/optimization_result.hpp"

#include "umintl/model_base.hpp"

#include "umintl/function_wrapper.hpp"
#include "umintl/optimization_context.hpp"

#include "umintl/directions/conjugate_gradient.hpp"
#include "umintl/directions/quasi_newton.hpp"
#include "umintl/directions/low_memory_quasi_newton.hpp"
#include "umintl/directions/steepest_descent.hpp"
#include "umintl/directions/truncated_newton.hpp"

#include "umintl/line_search/strong_wolfe_powell.hpp"

#include "umintl/stopping_criterion/value_treshold.hpp"
#include "umintl/stopping_criterion/gradient_treshold.hpp"

#include <iomanip>
#include <sstream>

namespace umintl{

    /** @brief The minimizer class
     *
     *  @tparam BackendType the linear algebra backend of the minimizer
     */
    template<class BackendType>
    class minimizer{
    public:

        /** @brief The constructor
         *
         * @param _direction the descent direction used by the minimizer
         * @param _stopping_criterion the stopping criterion
         * @param _max_iter the maximum number of iterations
         * @param _verbosity_level the verbosity level
         */
        minimizer(umintl::direction<BackendType> * _direction = new quasi_newton<BackendType>()
                             , umintl::stopping_criterion<BackendType> * _stopping_criterion = new gradient_treshold<BackendType>()
                             , unsigned int _max_iter = 1024, unsigned int _verbosity_level = 0) :
            direction(_direction)
          , line_search(new strong_wolfe_powell<BackendType>())
          , stopping_criterion(_stopping_criterion)
          , model(new deterministic<BackendType>())
          , hessian_vector_product_computation(CENTERED_DIFFERENCE)
          , verbosity_level(_verbosity_level), max_iter(_max_iter){

        }

        tools::shared_ptr<umintl::direction<BackendType> > direction;
        tools::shared_ptr<umintl::line_search<BackendType> > line_search;
        tools::shared_ptr<umintl::stopping_criterion<BackendType> > stopping_criterion;
        tools::shared_ptr< model_base<BackendType> > model;
        computation_type hessian_vector_product_computation;

        double tolerance;

        unsigned int verbosity_level;
        unsigned int max_iter;

    private:

        /** @brief Get a brief info string on the minimizer
         *
         *  @return String containing the verbosity level, maximum number of iteration, and the direction used
         */
        std::string info() const{
          std::ostringstream oss;
          oss << "Verbosity Level : " << verbosity_level << std::endl;
          oss << "Maximum number of iterations : " << max_iter << std::endl;
          oss << "Direction : " << direction->info() << std::endl;
          return oss.str();
        }

        /** @brief Clean memory and terminate the optimization result
         *
         *  @return Optimization result
         */
        optimization_result terminate(optimization_result::termination_cause_type termination_cause, typename BackendType::VectorType & res, std::size_t N, optimization_context<BackendType> & context){
            optimization_result result;
            BackendType::copy(N,context.x(),res);
            result.f = context.val();
            result.iteration = context.iter();
            result.n_functions_eval = context.fun().n_value_computations();
            result.n_gradient_eval = context.fun().n_gradient_computations();
            result.termination_cause = termination_cause;

            clean_all(context);

            return result;
        }

        /** @brief Init the components of the procedure (ie allocate memory for the temporaries, typically)
         */
        void init_all(optimization_context<BackendType> & c){
            direction->init(c);
            line_search->init(c);
            stopping_criterion->init(c);
        }

        /** @brief Clean the components of the procedure (ie free memory for the temporaries, typically)
         */
        void clean_all(optimization_context<BackendType> & c){
            direction->clean(c);
            line_search->clean(c);
            stopping_criterion->clean(c);
        }

    public:
        template<class Fun>
        optimization_result operator()(typename BackendType::VectorType & res, Fun & fun, typename BackendType::VectorType const & x0, std::size_t N){
            tools::shared_ptr<umintl::direction<BackendType> > steepest_descent(new umintl::steepest_descent<BackendType>());
            line_search_result<BackendType> search_res(N);
            optimization_context<BackendType> c(x0, N, *model, new detail::function_wrapper_impl<BackendType, Fun>(fun,N,hessian_vector_product_computation));

            init_all(c);

            if(verbosity_level >= 1)
                std::cout << info() << std::endl;

            tools::shared_ptr<umintl::direction<BackendType> > current_direction;
            if(dynamic_cast<truncated_newton<BackendType> * >(direction.get()))
              current_direction = steepest_descent;
            else
              current_direction = steepest_descent;

            //Main loop
            c.fun().compute_value_gradient(c.x(), c.val(), c.g(), c.model().get_value_gradient_tag());
            for( ; c.iter() < max_iter ; ++c.iter()){
                if(verbosity_level >= 2 ){
                    std::cout << "Ieration  " << c.iter()
                              << "| cost : " << c.val()
                              << "| NVal : " << c.fun().n_value_computations()
                              << "| NGrad : " << c.fun().n_gradient_computations();
                    if(unsigned int NHv = c.fun().n_hessian_vector_product_computations())
                     std::cout<< "| NHv : " << NHv ;
                    if(unsigned int ND = c.fun().n_datapoints_accessed())
                     std::cout << "| NAccesses " << (float)ND;
                    std::cout << std::endl;
                }

                (*current_direction)(c);

                c.dphi_0() = BackendType::dot(N,c.p(),c.g());
                //Not a descent direction...
                if(c.dphi_0()>0){
                    //current_direction->reset(c);
                    current_direction = steepest_descent;
                    (*current_direction)(c);
                    c.dphi_0() = BackendType::dot(N,c.p(),c.g());
                }

                (*line_search)(search_res, current_direction.get(), c);

                if(search_res.has_failed){
                    return terminate(optimization_result::LINE_SEARCH_FAILED, res, N, c);
                }

//                BackendType::copy(c.N(), c.x(), search_res.best_x);
//                BackendType::axpy(c.N(),0.0001,c.p(),search_res.best_x);

                c.alpha() = search_res.best_alpha;

                BackendType::copy(N,c.x(),c.xm1());
                BackendType::copy(N,search_res.best_x,c.x());

                BackendType::copy(N,c.g(),c.gm1());
                BackendType::copy(N,search_res.best_g,c.g());

                c.valm1() = c.val();
                c.val() = search_res.best_phi;

                if((*stopping_criterion)(c)){
                    return terminate(optimization_result::STOPPING_CRITERION, res, N, c);
                }
                current_direction = direction;

                if(model->update(c))
                  c.fun().compute_value_gradient(c.x(), c.val(), c.g(), c.model().get_value_gradient_tag());
            }

            return terminate(optimization_result::MAX_ITERATION_REACHED, res, N, c);
        }
    };

}

#endif
<|endoftext|>