<commit_before>#include "problem.h"
#include "factor.h"
#include <time.h>

double prediction_time = 0.0;
extern Stats* stats;
bool debug = false;

void exit_with_help(){
	cerr << "Usage: ./predict (options) [testfile] [model]" << endl;
	cerr << "options:" << endl;
	cerr << "-s solver: (default 0)" << endl;
	cerr << "	0 -- Viterbi(chain)" << endl;
	cerr << "	1 -- sparseLP" << endl;
	cerr << "       2 -- GDMM" << endl;
	cerr << "-p problem_type: " << endl;
	cerr << "   chain -- sequence labeling problem" << endl;
	cerr << "   network -- network matching problem" << endl;
	cerr << "   uai -- uai format problem" << endl;
	cerr << "-e eta: GDMM step size" << endl;
	cerr << "-o rho: coefficient/weight of message" << endl;
	cerr << "-m max_iter: max number of iterations" << endl;
	exit(0);
}

void parse_cmd_line(int argc, char** argv, Param* param){

	int i;
	vector<string> args;
	for (i = 1; i < argc; i++){
		string arg(argv[i]);
		//cerr << "arg[i]:" << arg << "|" << endl;
		args.push_back(arg);
	}
	for(i=0;i<args.size();i++){
		string arg = args[i];
		if (arg == "-debug"){
			debug = true;
			continue;
		}
		if( arg[0] != '-' )
			break;

		if( ++i >= args.size() )
			exit_with_help();

		string arg2 = args[i];

		if (arg == "--printmodel"){
			param->print_to_loguai2 = true;
			param->loguai2fname = arg2;
			continue;
		}
		switch(arg[1]){
			case 's': param->solver = stoi(arg2);
				  break;
			case 'e': param->eta = stof(arg2);
				  break;
			case 'o': param->rho = stof(arg2);
				  break;
			case 'm': param->max_iter = stoi(arg2);
				  break;
			case 'p': param->problem_type = string(arg2);
				  break;
			default:
				  cerr << "unknown option: " << arg << " " << arg2 << endl;
				  exit(0);
		}
	}

	if(i>=args.size())
		exit_with_help();

	param->testFname = argv[i+1];
	i++;
	if( i<args.size() )
		param->modelFname = argv[i+1];
	else{
		param->modelFname = new char[FNAME_LEN];
		strcpy(param->modelFname,"model");
	}
}

double struct_predict(Problem* prob, Param* param){
	Float hit = 0.0;
	Float N = 0.0;
	int n = 0;
	stats = new Stats();

	int K = prob->K;
	cout << "constructing factors...";
	vector<UniFactor*> x;
	for (int i = 0; i < K; i++){
		UniFactor* x_i = new UniFactor(K, prob->node_score_vecs[i], param);
		x.push_back(x_i);
	}
	vector<UniFactor*> xt;
	for (int i = 0; i < K; i++){
		UniFactor* xt_i = new UniFactor(K, prob->node_score_vecs[K+i], param);
		xt.push_back(xt_i);
	}
	cout << "done" << endl;

	//////////////////////////////////////
	// get row solutions
	/////////////////////////////////////
	//ifstream fin("data/rowsol");
	//int* rowsol = new int[K];
	//int* colsol = new int[K];
	//int max_top = 0;
	//Float row_cost = 0.0;
	//Float col_cost = 0.0;
	//Float avg_top = 0.0;
	/*for( int k = 0; k < K; k++){
	  fin >> colsol[k];
	  colsol[k]--;
	  rowsol[colsol[k]] = k;

	  for(int i = 0; i < K; i++){
	  if (x[colsol[k]]->sorted_index[i].second == k){
	  if (max_top < i){
	  max_top = i;
	  }
	  avg_top += i;
	  row_cost += x[colsol[k]]->sorted_index[i].first;
	  break;
	  }
	  }
	  for(int i = 0; i < K; i++){
	  if (xt[k]->sorted_index[i].second == colsol[k]){
	  if (max_top < i){
	  max_top = i;
	  }
	  avg_top += i;
	  col_cost += xt[k]->sorted_index[i].first;
	  break;
	  }
	  }
	  }*/
	//cout << "row_cost=" << row_cost << ", col_cost=" << col_cost << endl;
	//cout << "max_top="<< max_top << ", avg_top=" << avg_top/(2*K)<< endl;

	int iter = 0;
	Float rho = param->rho;
	int* indices = new int[K*2];
	for (int i = 0; i < K*2; i++){
		indices[i] = i;
	}
	bool* taken = new bool[K];
	Float best_decoded = 1e100;
	while (iter++ < param->max_iter){
		stats->maintain_time -= get_current_time();
		//random_shuffle(indices, indices+K*2);
		stats->maintain_time += get_current_time();
		Float act_size_sum = 0;
		Float ever_nnz_size_sum = 0;
		Float recall_rate = 0.0;
		for (int k = 0; k < K*2; k++){
			if (k % 2 == 0){
				int i = k/2;
				UniFactor* node = x[i];
				//if (node->inside[rowsol[i]]){
				//    recall_rate += 1.0;
				//} else {
				//    node->act_set.push_back(rowsol[i]);
				//    node->inside[rowsol[i]] = true;
				//}

				//add a new coordinate into active set
				node->search();

				//given active set, solve subproblem
				node->subsolve();

				act_size_sum += node->act_set.size();
				ever_nnz_size_sum += node->ever_nnz_msg.size();
				stats->maintain_time -= get_current_time();
				Float* msg = node->msg;
				Float* y = node->y;
				for (vector<int>::iterator it = node->act_set.begin(); it != node->act_set.end(); it++){
					int j = *it;
					xt[j]->msg[i] = -msg[j];
					if (abs(msg[j]) > 1e-12){
						xt[j]->add_ever_nnz(i);
					}
				}
				stats->maintain_time += get_current_time();
			} else {
				int j = k/2;
				UniFactor* node = xt[j];
				//if (node->inside[colsol[j]]){
				//    recall_rate += 1.0;
				//} else {
				//    node->act_set.push_back(colsol[j]);
				//    node->inside[colsol[j]] = true;
				//}
				node->search();
				node->subsolve();
				act_size_sum += node->act_set.size();
				ever_nnz_size_sum += node->ever_nnz_msg.size();
				stats->maintain_time -= get_current_time();
				Float* msg = node->msg;
				Float* y = node->y;
				for (vector<int>::iterator it = node->act_set.begin(); it != node->act_set.end(); it++){
					int i = *it;
					x[i]->msg[j] = -msg[i];
					if (abs(msg[i]) > 1e-12){
						x[i]->add_ever_nnz(j);
					}
				}
				stats->maintain_time += get_current_time();
			}
		}
		// msg[i] = (x[i][j] - xt[j][i] + mu[i][j])
		// msg[i] = (x[i][j] - xt[j][i] + mu[i][j])
		stats->maintain_time -= get_current_time();
		for (int i = 0; i < K; i++){
			for (vector<int>::iterator it = x[i]->act_set.begin(); it != x[i]->act_set.end(); it++){
				int j = *it;
				Float delta = x[i]->y[j];
				x[i]->msg[j] += delta;
				xt[j]->msg[i] -= delta;
				if (abs(x[i]->msg[j]) > 1e-12){
					x[i]->add_ever_nnz(j);
					xt[j]->add_ever_nnz(i);
				}
			}
		}
		for (int j = 0; j < K; j++){
			for (vector<int>::iterator it = xt[j]->act_set.begin(); it != xt[j]->act_set.end(); it++){
				int i = *it;
				Float delta = -xt[j]->y[i];
				x[i]->msg[j] += delta;
				xt[j]->msg[i] -= delta;
				if (abs(x[i]->msg[j]) > 1e-12){
					x[i]->add_ever_nnz(j);
					xt[j]->add_ever_nnz(i);
				}
			}
		}
		Float cost = 0.0, infea = 0.0;
		for (int i = 0; i < K; i++){
			for (vector<int>::iterator it = x[i]->act_set.begin(); it != x[i]->act_set.end(); it++){
				int j = *it;
				cost += x[i]->y[j] * x[i]->c[j];
				infea += abs(xt[j]->y[i] - x[i]->y[j]);
				//cout << x[i]->y[j] << "\t";
			}
		}

		for (int j = 0; j < K; j++){
			for (vector<int>::iterator it = xt[j]->act_set.begin(); it != xt[j]->act_set.end(); it++){
				int i = *it;
				cost += xt[j]->y[i] * xt[j]->c[i];
				infea += abs(xt[j]->y[i] - x[i]->y[j]);
				//cout << xt[j]->y[i] << "\t";
			}
			//cout << endl;
		}
		if (iter % 1 == 0){
			memset(taken, false, sizeof(bool)*K);
			Float decoded = 0.0;
			random_shuffle(indices, indices+K*2);
			for (int k = 0; k < K*2; k++){
				if (indices[k] >= K){
					continue;
				}
				int i = indices[k];
				Float max_y = 0.0;
				int index = -1;
				for (vector<int>::iterator it = x[i]->act_set.begin(); it != x[i]->act_set.end(); it++){
					int j = *it;
					if (!taken[j] && (x[i]->y[j] > max_y)){
						max_y = x[i]->y[j];
						index = j;
					}
				}
				if (index == -1){
					for (int j = 0; j < K; j++){
						if (!taken[j]){
							index = j;
							break;
						}
					}
				}
				taken[index] = true;
				decoded += x[i]->c[index];
			}
			if (decoded < best_decoded){
				best_decoded = decoded;
			}
		}
		stats->maintain_time += get_current_time();

		//cout << endl;
		cout << "iter=" << iter;
		cout << ", recall_rate=" << recall_rate/(2*K);
		cout << ", act_size=" << act_size_sum/(2*K);
		cout << ", ever_nnz_size=" << ever_nnz_size_sum/(2*K);
		cout << ", cost=" << cost/2.0 << ", infea=" << infea << ", best_decoded=" << best_decoded;
		cout << ", search=" << stats->uni_search_time;
		cout << ", subsolve=" << stats->uni_subsolve_time;
		cout << ", maintain=" << stats->maintain_time;
		cout << endl;
		if (infea < 1e-5){
			break;
		}
	}
	delete taken;
	return 0;
}

int main(int argc, char** argv){
	if (argc < 2){
		exit_with_help();
	}

	prediction_time = -get_current_time();
	srand(time(NULL));
	Param* param = new Param();
	parse_cmd_line(argc, argv, param);

	Problem* prob = NULL;
	if (param->problem_type=="bipartite"){
		prob = new BipartiteMatchingProblem(param);
		prob->construct_data();
		int K = ((BipartiteMatchingProblem*)prob)->K;
		cerr << "prob.K=" << K << endl;
	}

	if (prob == NULL){
		cerr << "Need to specific problem type!" << endl;
	}

	cerr << "param.rho=" << param->rho << endl;
	cerr << "param.eta=" << param->eta << endl;

	/*
	   double t1 = get_current_time();
	   vector<Float*> cc;
	   for (int i = 0; i < 200; i++){
	   Float* temp_float = new Float[4];
	   cc.push_back(temp_float);
	   }
	   for (int tt = 0; tt < 3000*1000; tt++)
	   for (int i = 0; i < 200; i++){
	   Float* cl = cc[rand()%200];
	   Float* cr = cc[rand()%200];
	   for (int j = 0; j < 4; j++)
	   cl[j] = cr[j];
	   }
	   cerr << get_current_time() - t1 << endl;
	 */

	if (param->solver == 2){
		cerr << "Acc=" << struct_predict(prob, param) << endl;
	}
	prediction_time += get_current_time();
	cerr << "prediction time=" << prediction_time << endl;
	return 0;
}
<commit_msg>add some comment.<commit_after>#include "problem.h"
#include "factor.h"
#include <time.h>

double prediction_time = 0.0;
extern Stats* stats;
bool debug = false;

void exit_with_help(){
	cerr << "Usage: ./predict (options) [testfile] [model]" << endl;
	cerr << "options:" << endl;
	cerr << "-s solver: (default 0)" << endl;
	cerr << "	0 -- Viterbi(chain)" << endl;
	cerr << "	1 -- sparseLP" << endl;
	cerr << "       2 -- GDMM" << endl;
	cerr << "-p problem_type: " << endl;
	cerr << "   chain -- sequence labeling problem" << endl;
	cerr << "   network -- network matching problem" << endl;
	cerr << "   uai -- uai format problem" << endl;
	cerr << "-e eta: GDMM step size" << endl;
	cerr << "-o rho: coefficient/weight of message" << endl;
	cerr << "-m max_iter: max number of iterations" << endl;
	exit(0);
}

void parse_cmd_line(int argc, char** argv, Param* param){

	int i;
	vector<string> args;
	for (i = 1; i < argc; i++){
		string arg(argv[i]);
		//cerr << "arg[i]:" << arg << "|" << endl;
		args.push_back(arg);
	}
	for(i=0;i<args.size();i++){
		string arg = args[i];
		if (arg == "-debug"){
			debug = true;
			continue;
		}
		if( arg[0] != '-' )
			break;

		if( ++i >= args.size() )
			exit_with_help();

		string arg2 = args[i];

		if (arg == "--printmodel"){
			param->print_to_loguai2 = true;
			param->loguai2fname = arg2;
			continue;
		}
		switch(arg[1]){
			case 's': param->solver = stoi(arg2);
				  break;
			case 'e': param->eta = stof(arg2);
				  break;
			case 'o': param->rho = stof(arg2);
				  break;
			case 'm': param->max_iter = stoi(arg2);
				  break;
			case 'p': param->problem_type = string(arg2);
				  break;
			default:
				  cerr << "unknown option: " << arg << " " << arg2 << endl;
				  exit(0);
		}
	}

	if(i>=args.size())
		exit_with_help();

	param->testFname = argv[i+1];
	i++;
	if( i<args.size() )
		param->modelFname = argv[i+1];
	else{
		param->modelFname = new char[FNAME_LEN];
		strcpy(param->modelFname,"model");
	}
}

double struct_predict(Problem* prob, Param* param){
	Float hit = 0.0;
	Float N = 0.0;
	int n = 0;
	stats = new Stats();

	int K = prob->K;
	cout << "constructing factors...";
	vector<UniFactor*> x;	//x is the permutation matrix sliced depend on rows.
	for (int i = 0; i < K; i++){
		UniFactor* x_i = new UniFactor(K, prob->node_score_vecs[i], param);
		x.push_back(x_i);
	}
	vector<UniFactor*> xt;
	for (int i = 0; i < K; i++){
		UniFactor* xt_i = new UniFactor(K, prob->node_score_vecs[K+i], param);
		xt.push_back(xt_i);
	}
	cout << "done" << endl;

	//////////////////////////////////////
	// get row solutions
	/////////////////////////////////////
	//ifstream fin("data/rowsol");
	//int* rowsol = new int[K];
	//int* colsol = new int[K];
	//int max_top = 0;
	//Float row_cost = 0.0;
	//Float col_cost = 0.0;
	//Float avg_top = 0.0;
	/*for( int k = 0; k < K; k++){
	  fin >> colsol[k];
	  colsol[k]--;
	  rowsol[colsol[k]] = k;

	  for(int i = 0; i < K; i++){
	  if (x[colsol[k]]->sorted_index[i].second == k){
	  if (max_top < i){
	  max_top = i;
	  }
	  avg_top += i;
	  row_cost += x[colsol[k]]->sorted_index[i].first;
	  break;
	  }
	  }
	  for(int i = 0; i < K; i++){
	  if (xt[k]->sorted_index[i].second == colsol[k]){
	  if (max_top < i){
	  max_top = i;
	  }
	  avg_top += i;
	  col_cost += xt[k]->sorted_index[i].first;
	  break;
	  }
	  }
	  }*/
	//cout << "row_cost=" << row_cost << ", col_cost=" << col_cost << endl;
	//cout << "max_top="<< max_top << ", avg_top=" << avg_top/(2*K)<< endl;

	int iter = 0;
	Float rho = param->rho;
	int* indices = new int[K*2];
	for (int i = 0; i < K*2; i++){
		indices[i] = i;
	}
	bool* taken = new bool[K];
	Float best_decoded = 1e100;
	while (iter++ < param->max_iter){
		stats->maintain_time -= get_current_time();
		//random_shuffle(indices, indices+K*2);
		stats->maintain_time += get_current_time();
		Float act_size_sum = 0;
		Float ever_nnz_size_sum = 0;
		Float recall_rate = 0.0;
		for (int k = 0; k < K*2; k++){
			if (k % 2 == 0){
				int i = k/2;
				UniFactor* node = x[i];
				//if (node->inside[rowsol[i]]){
				//    recall_rate += 1.0;
				//} else {
				//    node->act_set.push_back(rowsol[i]);
				//    node->inside[rowsol[i]] = true;
				//}

				//add a new coordinate into active set
				node->search();

				//given active set, solve subproblem
				node->subsolve();

				act_size_sum += node->act_set.size();
				ever_nnz_size_sum += node->ever_nnz_msg.size();
				stats->maintain_time -= get_current_time();
				Float* msg = node->msg;
				Float* y = node->y;
				for (vector<int>::iterator it = node->act_set.begin(); it != node->act_set.end(); it++){
					int j = *it;
					xt[j]->msg[i] = -msg[j];
					if (abs(msg[j]) > 1e-12){
						xt[j]->add_ever_nnz(i);
					}
				}
				stats->maintain_time += get_current_time();
			} else {
				int j = k/2;
				UniFactor* node = xt[j];
				//if (node->inside[colsol[j]]){
				//    recall_rate += 1.0;
				//} else {
				//    node->act_set.push_back(colsol[j]);
				//    node->inside[colsol[j]] = true;
				//}
				node->search();
				node->subsolve();
				act_size_sum += node->act_set.size();
				ever_nnz_size_sum += node->ever_nnz_msg.size();
				stats->maintain_time -= get_current_time();
				Float* msg = node->msg;
				Float* y = node->y;
				for (vector<int>::iterator it = node->act_set.begin(); it != node->act_set.end(); it++){
					int i = *it;
					x[i]->msg[j] = -msg[i];
					if (abs(msg[i]) > 1e-12){
						x[i]->add_ever_nnz(j);
					}
				}
				stats->maintain_time += get_current_time();
			}
		}
		// msg[i] = (x[i][j] - xt[j][i] + mu[i][j])
		// msg[i] = (x[i][j] - xt[j][i] + mu[i][j])
		stats->maintain_time -= get_current_time();
		for (int i = 0; i < K; i++){
			for (vector<int>::iterator it = x[i]->act_set.begin(); it != x[i]->act_set.end(); it++){
				int j = *it;
				Float delta = x[i]->y[j];
				x[i]->msg[j] += delta;
				xt[j]->msg[i] -= delta;
				if (abs(x[i]->msg[j]) > 1e-12){
					x[i]->add_ever_nnz(j);
					xt[j]->add_ever_nnz(i);
				}
			}
		}
		for (int j = 0; j < K; j++){
			for (vector<int>::iterator it = xt[j]->act_set.begin(); it != xt[j]->act_set.end(); it++){
				int i = *it;
				Float delta = -xt[j]->y[i];
				x[i]->msg[j] += delta;
				xt[j]->msg[i] -= delta;
				if (abs(x[i]->msg[j]) > 1e-12){
					x[i]->add_ever_nnz(j);
					xt[j]->add_ever_nnz(i);
				}
			}
		}
		Float cost = 0.0, infea = 0.0;
		for (int i = 0; i < K; i++){
			for (vector<int>::iterator it = x[i]->act_set.begin(); it != x[i]->act_set.end(); it++){
				int j = *it;
				cost += x[i]->y[j] * x[i]->c[j];
				infea += abs(xt[j]->y[i] - x[i]->y[j]);
				//cout << x[i]->y[j] << "\t";
			}
		}

		for (int j = 0; j < K; j++){
			for (vector<int>::iterator it = xt[j]->act_set.begin(); it != xt[j]->act_set.end(); it++){
				int i = *it;
				cost += xt[j]->y[i] * xt[j]->c[i];
				infea += abs(xt[j]->y[i] - x[i]->y[j]);
				//cout << xt[j]->y[i] << "\t";
			}
			//cout << endl;
		}
		if (iter % 1 == 0){
			memset(taken, false, sizeof(bool)*K);
			Float decoded = 0.0;
			random_shuffle(indices, indices+K*2);
			for (int k = 0; k < K*2; k++){
				if (indices[k] >= K){
					continue;
				}
				int i = indices[k];
				Float max_y = 0.0;
				int index = -1;
				for (vector<int>::iterator it = x[i]->act_set.begin(); it != x[i]->act_set.end(); it++){
					int j = *it;
					if (!taken[j] && (x[i]->y[j] > max_y)){
						max_y = x[i]->y[j];
						index = j;
					}
				}
				if (index == -1){
					for (int j = 0; j < K; j++){
						if (!taken[j]){
							index = j;
							break;
						}
					}
				}
				taken[index] = true;
				decoded += x[i]->c[index];
			}
			if (decoded < best_decoded){
				best_decoded = decoded;
			}
		}
		stats->maintain_time += get_current_time();

		//cout << endl;
		cout << "iter=" << iter;
		cout << ", recall_rate=" << recall_rate/(2*K);
		cout << ", act_size=" << act_size_sum/(2*K);
		cout << ", ever_nnz_size=" << ever_nnz_size_sum/(2*K);
		cout << ", cost=" << cost/2.0 << ", infea=" << infea << ", best_decoded=" << best_decoded;
		cout << ", search=" << stats->uni_search_time;
		cout << ", subsolve=" << stats->uni_subsolve_time;
		cout << ", maintain=" << stats->maintain_time;
		cout << endl;
		if (infea < 1e-5){
			break;
		}
	}
	delete taken;
	return 0;
}

int main(int argc, char** argv){
	if (argc < 2){
		exit_with_help();
	}

	prediction_time = -get_current_time();
	srand(time(NULL));
	Param* param = new Param();
	parse_cmd_line(argc, argv, param);

	Problem* prob = NULL;
	if (param->problem_type=="bipartite"){
		prob = new BipartiteMatchingProblem(param);
		prob->construct_data();
		int K = ((BipartiteMatchingProblem*)prob)->K;
		cerr << "prob.K=" << K << endl;
	}

	if (prob == NULL){
		cerr << "Need to specific problem type!" << endl;
	}

	cerr << "param.rho=" << param->rho << endl;
	cerr << "param.eta=" << param->eta << endl;

	/*
	   double t1 = get_current_time();
	   vector<Float*> cc;
	   for (int i = 0; i < 200; i++){
	   Float* temp_float = new Float[4];
	   cc.push_back(temp_float);
	   }
	   for (int tt = 0; tt < 3000*1000; tt++)
	   for (int i = 0; i < 200; i++){
	   Float* cl = cc[rand()%200];
	   Float* cr = cc[rand()%200];
	   for (int j = 0; j < 4; j++)
	   cl[j] = cr[j];
	   }
	   cerr << get_current_time() - t1 << endl;
	 */

	if (param->solver == 2){
		cerr << "Acc=" << struct_predict(prob, param) << endl;
	}
	prediction_time += get_current_time();
	cerr << "prediction time=" << prediction_time << endl;
	return 0;
}
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright (C) 2016-2017 Kitsune Ral <kitsune-ral@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "printer.h"

#include "exception.h"

#include <algorithm>
#include <locale>

enum {
    CannotReadTemplateFile = PrinterCodes, CannotWriteToFile,
};

using namespace std;
using namespace kainjow::mustache;

Printer::Printer(context_type&& context, const vector<string>& templateFileNames,
                 const string& inputBasePath, string outputBasePath,
                 const string& outFilesListPath)
    : _context(context), _outputBasePath(std::move(outputBasePath))
{
    // Enriching the context with "My Mustache library"
    _context.set("@filePartial", lambda2 {
        [inputBasePath, this](const string& s, const renderer& render) {
            ifstream ifs { inputBasePath + s };
            if (!ifs.good())
            {
                ifs.open(inputBasePath + s + ".mustache");
                if (!ifs.good())
                {
                    cerr << "Failed to open file for a partial: "
                         << inputBasePath + s << endl;
                    // FIXME: Figure a better error reporting mechanism
                    return "/* Failed to open " + inputBasePath + s + " */";
                }
            }
            string embeddedTemplate;
            getline(ifs, embeddedTemplate, '\0'); // Won't work on files with NULs
            return render(embeddedTemplate, false);
        }
    });
    _context.set("@cap", lambda2 {
        [](const string& s, const renderer& render)
        {
            return capitalizedCopy(render(s, false));
        }
    });
    _context.set("@toupper", lambda2 {
        [](string s, const renderer& render) {
            s = render(s, false);
            transform(s.begin(), s.end(), s.begin(),
                      [] (char c) { return toupper(c, locale::classic()); });
            return s;
        }
    });
    _context.set("@tolower", lambda2 {
        [](string s, const renderer& render) {
            s = render(s, false);
            transform(s.begin(), s.end(), s.begin(),
                      [] (char c) { return tolower(c, locale::classic()); });
            return s;
        }
    });
    for (const auto& templateFileName: templateFileNames)
    {
        auto templateFilePath = inputBasePath + templateFileName;
        cout << "Opening " << templateFilePath << endl;
        ifstream ifs { templateFilePath };
        if (!ifs.good())
        {
            cerr << "Failed to open " << templateFilePath << std::endl;
            fail(CannotReadTemplateFile);
        }
        string templateContents;
        if (!getline(ifs, templateContents, '\0')) // Won't work on files with NULs
        {
            cerr << "Failed to read from " << templateFilePath << std::endl;
            fail(CannotReadTemplateFile);
        }
        mustache fileTemplate { templateContents };
        fileTemplate.set_custom_escape([](const string& s) { return s; });
        _templates.emplace_back(dropSuffix(templateFileName, ".mustache"),
                                std::move(fileTemplate));
    }
    if (!outFilesListPath.empty())
    {
        cout << "Opening " << _outputBasePath << outFilesListPath << endl;
        _outFilesList.open(_outputBasePath + outFilesListPath);
        if (!_outFilesList)
            cerr << "No out files list set or cannot write to the file" << endl;
    }
}

template <typename ObjT>
inline void setList(ObjT* object, const string& name, list&& list)
{
    (*object)[name + '?'] = !list.empty();
    if (!list.empty())
    {
        using namespace placeholders;
        for_each(list.begin(), list.end() - 1,
                 bind(&data::set, _1, "hasMore", true));
        list.back().set("last?", true);
    }
    (*object)[name] = list;
}

string renderType(const TypeUsage& tu)
{
    if (tu.innerTypes.empty())
        return tu.name;

    // Template type
    mustache m { tu.name };
    object mInnerTypes;
    int i = 0;
    for (const auto& t: tu.innerTypes)
        mInnerTypes.emplace(to_string(++i), renderType(t)); // {{1}}, {{2}} and so on

    return m.render(mInnerTypes);
}

void dumpFieldAttrs(const VarDecl& param, object& fieldDef)
{
    fieldDef["required?"] = param.required;
    fieldDef["required"] = param.required; // Swagger compatibility
    fieldDef["defaultValue"] = param.defaultValue;
    for (const auto& attr: param.type.attributes)
        fieldDef.emplace(attr);

    for (const auto& listAttr: param.type.lists)
    {
        list mAttrValue;
        for (const auto& i: listAttr.second)
            mAttrValue.emplace_back(i);
        fieldDef.emplace(listAttr.first, move(mAttrValue));
    }
}

vector<string> Printer::print(const Model& model) const
{
    auto context = _context;
    context.set("filenameBase", model.filename);
    {
        // Imports
        list mImports;
        for (const auto& import: model.imports)
            mImports.emplace_back(import);
        setList(&context, "imports", std::move(mImports));
    }
    {
        // Data definitions
        list mTypes;
        for (const auto& type: model.types)
        {
            object mType { { "classname", type.first } };
            list mFields;
            for (const auto& f: type.second.fields)
            {
                object fieldDef { { "name", f.name }
                                , { "datatype", renderType(f.type) } };
                dumpFieldAttrs(f, fieldDef);
                mFields.emplace_back(move(fieldDef));
            }
            setList(&mType, "vars", move(mFields));
            mTypes.emplace_back(object { { "model", move(mType) } });
        }
        if (!mTypes.empty())
            context.set("models", mTypes);
    }
    {
        // Operations
        list mClasses;
        for (const auto& callClass: model.callClasses)
        {
            for (const auto& call: callClass.callOverloads)
            {
                object mClass { { "operationId", call.name }
                              , { "camelCaseOperationId", camelCase(call.name) }
                              , { "httpMethod",  call.verb }
                              , { "path", call.path }
                              , { "skipAuth", !call.needsSecurity }
                };
                list mPathParts;
                for (const auto& pp: call.pathParts)
                    mPathParts.emplace_back(object { { "part", pp } });
                setList(&mClass, "pathParts", move(mPathParts));

                for (const auto& pp: {
                    make_pair("pathParams", call.pathParams),
                    make_pair("queryParams", call.queryParams),
                    make_pair("headerParams", call.headerParams),
                    make_pair("bodyParams", call.bodyParams),
                    make_pair("allParams", call.collateParams())
                })
                {
                    list mParams;
                    for (const auto& param: pp.second)
                    {
                        object mParam { { "dataType", renderType(param.type) }
                                      , { "baseName", param.name }
                                      , { "paramName", param.name }
                        };
                        dumpFieldAttrs(param, mParam);
                        mParams.emplace_back(move(mParam));
                    }
                    setList(&mClass, pp.first, move(mParams));
                }
                {
                    list mResponses;
                    for (const auto& response: call.responses)
                    {
                        object mResponse { { "code", response.code }
                                         , { "normalResponse?",
                                                response.code == "200" }
                        };
                        list mProperties;
                        for (const auto& p: response.properties)
                        {
                            object mProperty { { "dataType", renderType(p.type) }
                                             , { "paramName", p.name }
                            };
                            dumpFieldAttrs(p, mProperty);
                            mProperties.emplace_back(move(mProperty));
                        }
                        setList(&mResponse, "properties", move(mProperties));
                        mResponses.emplace_back(move(mResponse));
                    }
                    setList(&mClass, "responses", move(mResponses));
                }
                mClasses.emplace_back(move(mClass));
            }
        }
        if (!mClasses.empty())
            context.set("operations",
                        object { { "className", "NOT_IMPLEMENTED" }
                               , { "operation", mClasses }
                        });
        context.set("basePathWithoutHost", model.basePath);
        context.set("basePath", model.hostAddress + model.basePath);
    }
    vector<string> fileNames;
    for (auto fileTemplate: _templates)
    {
        ostringstream fileNameStr;
        fileNameStr << _outputBasePath << model.fileDir;
        fileTemplate.first.render({ "base", model.filename }, fileNameStr);
        if (!fileTemplate.first.error_message().empty())
        {
            cerr << "When rendering the filename:" << endl
                 << fileTemplate.first.error_message() << endl;
            continue; // FIXME: should be fail()
        }
        auto fileName = fileNameStr.str();
        cout << "Printing " << fileName << endl;

        ofstream ofs { fileName };
        if (!ofs.good())
        {
            cerr << "Couldn't open " << fileName << " for writing" << endl;
            fail(CannotWriteToFile);
        }
        fileTemplate.second.set_custom_escape([](const string& s) { return s; });
        fileTemplate.second.render(context, ofs);
        if (fileTemplate.second.error_message().empty())
            _outFilesList << fileName << endl;
        else
            cerr << "When rendering the file:" << endl
                 << fileTemplate.second.error_message() << endl;
        fileNames.emplace_back(std::move(fileName));
    }
    return fileNames;
}
<commit_msg>Export the list of parent types to templates<commit_after>/******************************************************************************
 * Copyright (C) 2016-2017 Kitsune Ral <kitsune-ral@users.sf.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "printer.h"

#include "exception.h"

#include <algorithm>
#include <locale>

enum {
    CannotReadTemplateFile = PrinterCodes, CannotWriteToFile,
};

using namespace std;
using namespace kainjow::mustache;

Printer::Printer(context_type&& context, const vector<string>& templateFileNames,
                 const string& inputBasePath, string outputBasePath,
                 const string& outFilesListPath)
    : _context(context), _outputBasePath(std::move(outputBasePath))
{
    // Enriching the context with "My Mustache library"
    _context.set("@filePartial", lambda2 {
        [inputBasePath, this](const string& s, const renderer& render) {
            ifstream ifs { inputBasePath + s };
            if (!ifs.good())
            {
                ifs.open(inputBasePath + s + ".mustache");
                if (!ifs.good())
                {
                    cerr << "Failed to open file for a partial: "
                         << inputBasePath + s << endl;
                    // FIXME: Figure a better error reporting mechanism
                    return "/* Failed to open " + inputBasePath + s + " */";
                }
            }
            string embeddedTemplate;
            getline(ifs, embeddedTemplate, '\0'); // Won't work on files with NULs
            return render(embeddedTemplate, false);
        }
    });
    _context.set("@cap", lambda2 {
        [](const string& s, const renderer& render)
        {
            return capitalizedCopy(render(s, false));
        }
    });
    _context.set("@toupper", lambda2 {
        [](string s, const renderer& render) {
            s = render(s, false);
            transform(s.begin(), s.end(), s.begin(),
                      [] (char c) { return toupper(c, locale::classic()); });
            return s;
        }
    });
    _context.set("@tolower", lambda2 {
        [](string s, const renderer& render) {
            s = render(s, false);
            transform(s.begin(), s.end(), s.begin(),
                      [] (char c) { return tolower(c, locale::classic()); });
            return s;
        }
    });
    for (const auto& templateFileName: templateFileNames)
    {
        auto templateFilePath = inputBasePath + templateFileName;
        cout << "Opening " << templateFilePath << endl;
        ifstream ifs { templateFilePath };
        if (!ifs.good())
        {
            cerr << "Failed to open " << templateFilePath << std::endl;
            fail(CannotReadTemplateFile);
        }
        string templateContents;
        if (!getline(ifs, templateContents, '\0')) // Won't work on files with NULs
        {
            cerr << "Failed to read from " << templateFilePath << std::endl;
            fail(CannotReadTemplateFile);
        }
        mustache fileTemplate { templateContents };
        fileTemplate.set_custom_escape([](const string& s) { return s; });
        _templates.emplace_back(dropSuffix(templateFileName, ".mustache"),
                                std::move(fileTemplate));
    }
    if (!outFilesListPath.empty())
    {
        cout << "Opening " << _outputBasePath << outFilesListPath << endl;
        _outFilesList.open(_outputBasePath + outFilesListPath);
        if (!_outFilesList)
            cerr << "No out files list set or cannot write to the file" << endl;
    }
}

template <typename ObjT>
inline void setList(ObjT* object, const string& name, list&& list)
{
    (*object)[name + '?'] = !list.empty();
    if (!list.empty())
    {
        using namespace placeholders;
        for_each(list.begin(), list.end() - 1,
                 bind(&data::set, _1, "hasMore", true));
        list.back().set("last?", true);
    }
    (*object)[name] = list;
}

string renderType(const TypeUsage& tu)
{
    if (tu.innerTypes.empty())
        return tu.name;

    // Template type
    mustache m { tu.name };
    object mInnerTypes;
    int i = 0;
    for (const auto& t: tu.innerTypes)
        mInnerTypes.emplace(to_string(++i), renderType(t)); // {{1}}, {{2}} and so on

    return m.render(mInnerTypes);
}

void dumpFieldAttrs(const VarDecl& param, object& fieldDef)
{
    fieldDef["required?"] = param.required;
    fieldDef["required"] = param.required; // Swagger compatibility
    fieldDef["defaultValue"] = param.defaultValue;
    for (const auto& attr: param.type.attributes)
        fieldDef.emplace(attr);

    for (const auto& listAttr: param.type.lists)
    {
        list mAttrValue;
        for (const auto& i: listAttr.second)
            mAttrValue.emplace_back(i);
        fieldDef.emplace(listAttr.first, move(mAttrValue));
    }
}

vector<string> Printer::print(const Model& model) const
{
    auto context = _context;
    context.set("filenameBase", model.filename);
    {
        // Imports
        list mImports;
        for (const auto& import: model.imports)
            mImports.emplace_back(import);
        setList(&context, "imports", std::move(mImports));
    }
    {
        // Data definitions
        list mTypes;
        for (const auto& type: model.types)
        {
            object mType { { "classname", type.first } };
            {
                list mParents;
                for (const auto& t: type.second.parentTypes)
                    mParents.emplace_back(renderType(t));
                setList(&mType, "parents", move(mParents));
            }
            {
                list mFields;
                for (const auto& f: type.second.fields)
                {
                    object fieldDef { { "name",     f.name },
                                      { "datatype", renderType(f.type) } };
                    dumpFieldAttrs(f, fieldDef);
                    mFields.emplace_back(move(fieldDef));
                }
                setList(&mType, "vars", move(mFields));
            }
            mTypes.emplace_back(object { { "model", move(mType) } });
        }
        if (!mTypes.empty())
            context.set("models", mTypes);
    }
    {
        // Operations
        list mClasses;
        for (const auto& callClass: model.callClasses)
        {
            for (const auto& call: callClass.callOverloads)
            {
                object mClass { { "operationId", call.name }
                              , { "camelCaseOperationId", camelCase(call.name) }
                              , { "httpMethod",  call.verb }
                              , { "path", call.path }
                              , { "skipAuth", !call.needsSecurity }
                };
                list mPathParts;
                for (const auto& pp: call.pathParts)
                    mPathParts.emplace_back(object { { "part", pp } });
                setList(&mClass, "pathParts", move(mPathParts));

                for (const auto& pp: {
                    make_pair("pathParams", call.pathParams),
                    make_pair("queryParams", call.queryParams),
                    make_pair("headerParams", call.headerParams),
                    make_pair("bodyParams", call.bodyParams),
                    make_pair("allParams", call.collateParams())
                })
                {
                    list mParams;
                    for (const auto& param: pp.second)
                    {
                        object mParam { { "dataType", renderType(param.type) }
                                      , { "baseName", param.name }
                                      , { "paramName", param.name }
                        };
                        dumpFieldAttrs(param, mParam);
                        mParams.emplace_back(move(mParam));
                    }
                    setList(&mClass, pp.first, move(mParams));
                }
                {
                    list mResponses;
                    for (const auto& response: call.responses)
                    {
                        object mResponse { { "code", response.code }
                                         , { "normalResponse?",
                                                response.code == "200" }
                        };
                        list mProperties;
                        for (const auto& p: response.properties)
                        {
                            object mProperty { { "dataType", renderType(p.type) }
                                             , { "paramName", p.name }
                            };
                            dumpFieldAttrs(p, mProperty);
                            mProperties.emplace_back(move(mProperty));
                        }
                        setList(&mResponse, "properties", move(mProperties));
                        mResponses.emplace_back(move(mResponse));
                    }
                    setList(&mClass, "responses", move(mResponses));
                }
                mClasses.emplace_back(move(mClass));
            }
        }
        if (!mClasses.empty())
            context.set("operations",
                        object { { "className", "NOT_IMPLEMENTED" }
                               , { "operation", mClasses }
                        });
        context.set("basePathWithoutHost", model.basePath);
        context.set("basePath", model.hostAddress + model.basePath);
    }
    vector<string> fileNames;
    for (auto fileTemplate: _templates)
    {
        ostringstream fileNameStr;
        fileNameStr << _outputBasePath << model.fileDir;
        fileTemplate.first.render({ "base", model.filename }, fileNameStr);
        if (!fileTemplate.first.error_message().empty())
        {
            cerr << "When rendering the filename:" << endl
                 << fileTemplate.first.error_message() << endl;
            continue; // FIXME: should be fail()
        }
        auto fileName = fileNameStr.str();
        cout << "Printing " << fileName << endl;

        ofstream ofs { fileName };
        if (!ofs.good())
        {
            cerr << "Couldn't open " << fileName << " for writing" << endl;
            fail(CannotWriteToFile);
        }
        fileTemplate.second.set_custom_escape([](const string& s) { return s; });
        fileTemplate.second.render(context, ofs);
        if (fileTemplate.second.error_message().empty())
            _outFilesList << fileName << endl;
        else
            cerr << "When rendering the file:" << endl
                 << fileTemplate.second.error_message() << endl;
        fileNames.emplace_back(std::move(fileName));
    }
    return fileNames;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/util/debug.hh>
#include <hpp/pinocchio/configuration.hh>
#include <hpp/core/constraint-set.hh>
#include <hpp/core/config-projector.hh>

namespace hpp {
  namespace core {
    HPP_PREDEF_CLASS (ConfigProjectorTrivial);
    typedef boost::shared_ptr <ConfigProjectorTrivial>
    ConfigProjectorTrivialPtr_t;
    class ConfigProjectorTrivial : public ConfigProjector
    {
    public:
      static ConfigProjectorTrivialPtr_t create (const DevicePtr_t& robot)
      {
	ConfigProjectorTrivial* ptr = new ConfigProjectorTrivial (robot);
	ConfigProjectorTrivialPtr_t shPtr (ptr);
	ptr->init (shPtr);
	return shPtr;
      }
      ConfigProjectorTrivial (const DevicePtr_t& robot)
	: ConfigProjector (robot, "trivial ConfigProjector", 0, 0)
      {
      }
      // Do not copy, return shared pointer to this.
      virtual ConstraintPtr_t copy () const
      {
	return weak_.lock ();
      }
      bool impl_compute (ConfigurationOut_t configuration)
      {
	computeLockedDofs (configuration);
	return true;
      }
      void projectOnKernel (ConfigurationIn_t,
          ConfigurationIn_t, ConfigurationOut_t)
      {}
      /// Check whether a configuration statisfies the constraint.
      virtual bool isSatisfied (ConfigurationIn_t)
      {
	return true;
      }
      virtual bool isSatisfied (ConfigurationIn_t, vector_t& error)
      {
	error.resize (0);
	return true;
      }

      void init (ConfigProjectorTrivialPtr_t weak)
      {
	ConfigProjector::init (weak);
	weak_ = weak;
      }
      ConfigProjectorTrivialWkPtr_t weak_;
    }; // class ConfigProjectorTrivial

    bool ConstraintSet::impl_compute (ConfigurationOut_t configuration)
    {
      for (Constraints_t::iterator itConstraint = constraints_.begin ();
	   itConstraint != constraints_.end (); ++itConstraint) {
	if (!(*itConstraint)->impl_compute (configuration)) return false;
      }
      return true;
    }

    ConstraintPtr_t ConstraintSet::copy () const
    {
      return createCopy (weak_.lock ());
    }

    ConstraintSet::ConstraintSet (const DevicePtr_t& robot,
				  const std::string& name) :
      Constraint (name), constraints_ ()
    {
      constraints_.push_back (ConfigProjectorTrivial::create (robot));
      trivialOrNotConfigProjectorIt_ = constraints_.begin ();
      configProjectorIt_ = constraints_.end ();
    }

    ConstraintSet::ConstraintSet (const ConstraintSet& other) :
      Constraint (other), constraints_ ()
    {
      for (Constraints_t::const_iterator it = other.constraints_.begin ();
	   it != other.constraints_.end (); ++it) {
	constraints_.push_back ((*it)->copy ());
      }

      configProjectorIt_ = constraints_.begin ();
      Constraints_t::const_iterator b = other.constraints_.begin();
      Constraints_t::const_iterator it = other.configProjectorIt_;
      std::advance (configProjectorIt_, std::distance (b, it));

      trivialOrNotConfigProjectorIt_ = constraints_.begin ();
      b = other.constraints_.begin();
      it = other.configProjectorIt_;
      std::advance (trivialOrNotConfigProjectorIt_, std::distance (b, it));
    }

    void ConstraintSet::removeFirstElement ()
    {
      constraints_.pop_front ();
    }

    ConfigProjectorPtr_t ConstraintSet::configProjector () const
    {
      if (configProjectorIt_ != constraints_.end ())
        return HPP_STATIC_PTR_CAST (ConfigProjector, *configProjectorIt_);
      else return ConfigProjectorPtr_t ();
    }

    bool ConstraintSet::isSatisfied (ConfigurationIn_t configuration)
    {
      for (Constraints_t::iterator itConstraint = constraints_.begin ();
	   itConstraint != constraints_.end (); ++itConstraint) {
	if (!(*itConstraint)->isSatisfied (configuration)) {
	  return false;
	}
      }
      return true;
    }

    bool ConstraintSet::isSatisfied (ConfigurationIn_t configuration,
				     vector_t& error)
    {
      bool result = true;
      error.resize (0);
      vector_t localError;
      for (Constraints_t::iterator itConstraint = constraints_.begin ();
	   itConstraint != constraints_.end (); ++itConstraint) {
	if (!(*itConstraint)->isSatisfied (configuration, localError)) {
	  error.conservativeResize (error.size () + localError.size ());
	  error.tail (localError.size ()) = localError;
	  result = false;
	}
      }
      return result;
    }

    size_type ConstraintSet::numberNonLockedDof () const
    {
      return HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)
        ->numberNonLockedDof ();
    }

    void ConstraintSet::compressVector (vectorIn_t normal,
					vectorOut_t small) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->compressVector (normal, small);
    }

    void ConstraintSet::uncompressVector (vectorIn_t small,
					  vectorOut_t normal) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->uncompressVector (small, normal);
    }

    void ConstraintSet::compressMatrix (matrixIn_t normal, matrixOut_t small,
					bool rows) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->compressMatrix (normal, small, rows);
    }

    void ConstraintSet::uncompressMatrix (matrixIn_t small,
					  matrixOut_t normal,
					  bool rows) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->uncompressMatrix (small, normal, rows);
    }

  } // namespace core
} // namespace core
<commit_msg>Fix ConstraintSet::isSatisfied<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/util/debug.hh>
#include <hpp/pinocchio/configuration.hh>
#include <hpp/core/constraint-set.hh>
#include <hpp/core/config-projector.hh>

namespace hpp {
  namespace core {
    HPP_PREDEF_CLASS (ConfigProjectorTrivial);
    typedef boost::shared_ptr <ConfigProjectorTrivial>
    ConfigProjectorTrivialPtr_t;
    class ConfigProjectorTrivial : public ConfigProjector
    {
    public:
      static ConfigProjectorTrivialPtr_t create (const DevicePtr_t& robot)
      {
	ConfigProjectorTrivial* ptr = new ConfigProjectorTrivial (robot);
	ConfigProjectorTrivialPtr_t shPtr (ptr);
	ptr->init (shPtr);
	return shPtr;
      }
      ConfigProjectorTrivial (const DevicePtr_t& robot)
	: ConfigProjector (robot, "trivial ConfigProjector", 0, 0)
      {
      }
      // Do not copy, return shared pointer to this.
      virtual ConstraintPtr_t copy () const
      {
	return weak_.lock ();
      }
      bool impl_compute (ConfigurationOut_t configuration)
      {
	computeLockedDofs (configuration);
	return true;
      }
      void projectOnKernel (ConfigurationIn_t,
          ConfigurationIn_t, ConfigurationOut_t)
      {}
      /// Check whether a configuration statisfies the constraint.
      virtual bool isSatisfied (ConfigurationIn_t)
      {
	return true;
      }
      virtual bool isSatisfied (ConfigurationIn_t, vector_t& error)
      {
	error.resize (0);
	return true;
      }

      void init (ConfigProjectorTrivialPtr_t weak)
      {
	ConfigProjector::init (weak);
	weak_ = weak;
      }
      ConfigProjectorTrivialWkPtr_t weak_;
    }; // class ConfigProjectorTrivial

    bool ConstraintSet::impl_compute (ConfigurationOut_t configuration)
    {
      for (Constraints_t::iterator itConstraint = constraints_.begin ();
	   itConstraint != constraints_.end (); ++itConstraint) {
	if (!(*itConstraint)->impl_compute (configuration)) return false;
      }
      return true;
    }

    ConstraintPtr_t ConstraintSet::copy () const
    {
      return createCopy (weak_.lock ());
    }

    ConstraintSet::ConstraintSet (const DevicePtr_t& robot,
				  const std::string& name) :
      Constraint (name), constraints_ ()
    {
      constraints_.push_back (ConfigProjectorTrivial::create (robot));
      trivialOrNotConfigProjectorIt_ = constraints_.begin ();
      configProjectorIt_ = constraints_.end ();
    }

    ConstraintSet::ConstraintSet (const ConstraintSet& other) :
      Constraint (other), constraints_ ()
    {
      for (Constraints_t::const_iterator it = other.constraints_.begin ();
	   it != other.constraints_.end (); ++it) {
	constraints_.push_back ((*it)->copy ());
      }

      configProjectorIt_ = constraints_.begin ();
      Constraints_t::const_iterator b = other.constraints_.begin();
      Constraints_t::const_iterator it = other.configProjectorIt_;
      std::advance (configProjectorIt_, std::distance (b, it));

      trivialOrNotConfigProjectorIt_ = constraints_.begin ();
      b = other.constraints_.begin();
      it = other.configProjectorIt_;
      std::advance (trivialOrNotConfigProjectorIt_, std::distance (b, it));
    }

    void ConstraintSet::removeFirstElement ()
    {
      constraints_.pop_front ();
    }

    ConfigProjectorPtr_t ConstraintSet::configProjector () const
    {
      if (configProjectorIt_ != constraints_.end ())
        return HPP_STATIC_PTR_CAST (ConfigProjector, *configProjectorIt_);
      else return ConfigProjectorPtr_t ();
    }

    bool ConstraintSet::isSatisfied (ConfigurationIn_t configuration)
    {
      for (Constraints_t::iterator itConstraint = constraints_.begin ();
	   itConstraint != constraints_.end (); ++itConstraint) {
	if (!(*itConstraint)->isSatisfied (configuration)) {
	  return false;
	}
      }
      return true;
    }

    bool ConstraintSet::isSatisfied (ConfigurationIn_t configuration,
				     vector_t& error)
    {
      bool result = true;
      error.resize (0);
      vector_t localError;
      for (Constraints_t::iterator itConstraint = constraints_.begin ();
	   itConstraint != constraints_.end (); ++itConstraint) {
	if (!(*itConstraint)->isSatisfied (configuration, localError)) {
	  result = false;
	}
	error.conservativeResize (error.size () + localError.size ());
	error.tail (localError.size ()) = localError;
      }
      return result;
    }

    size_type ConstraintSet::numberNonLockedDof () const
    {
      return HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)
        ->numberNonLockedDof ();
    }

    void ConstraintSet::compressVector (vectorIn_t normal,
					vectorOut_t small) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->compressVector (normal, small);
    }

    void ConstraintSet::uncompressVector (vectorIn_t small,
					  vectorOut_t normal) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->uncompressVector (small, normal);
    }

    void ConstraintSet::compressMatrix (matrixIn_t normal, matrixOut_t small,
					bool rows) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->compressMatrix (normal, small, rows);
    }

    void ConstraintSet::uncompressMatrix (matrixIn_t small,
					  matrixOut_t normal,
					  bool rows) const
    {
      HPP_STATIC_PTR_CAST (ConfigProjector, *trivialOrNotConfigProjectorIt_)->uncompressMatrix (small, normal, rows);
    }

  } // namespace core
} // namespace core
<|endoftext|>


<commit_before>/*
Copyright 2016 Colin Girling

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef OCL_GUARD_TEST_TESTSTRING_HPP
#define OCL_GUARD_TEST_TESTSTRING_HPP

#include "TestMemoryUtility.hpp"
#include "TestStringUtility.hpp"
#include <cstddef>
#include <cstdlib>
#include <cstring>

namespace ocl
{

/*
 * String class for test harness, with an interface complete enough for general usage.
 */

class TestString
{
public:
    typedef TestStringUtility::size_type size_type;

    /// size_type has the potential of being signed or unsigned,
    /// so ensure signed/unsigned mismatch compiler warnings are suppressed.
    static size_type const size_type_default = static_cast<size_type>(0);

public:
    TestString(char const* str = NULL)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        if (str != NULL)
            TestStringUtility::UnsafeAllocateCopy(m_string, m_length, str);
    }

    TestString(char ch, size_type len)
        : m_length(len)
        , m_string(NULL)
    {
        if (len > size_type_default)
        {
            TestStringUtility::Allocate(m_string, len);
            if (m_string != NULL)
                TestStringUtility::UnsafeFill(m_string, ch, len);
            else
                m_length = size_type_default;
        }
    }

    TestString(TestString const& str)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        TestStringUtility::SafeAllocateCopy(m_string, m_length, str.m_string, str.m_length);
    }

    ~TestString()
    {
        TestStringUtility::FastFree(m_string);
    }

    TestString& operator =(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
            TestStringUtility::SafeReallocCopy(m_string, m_length, str);
        else
            Clear();
        return *this;
    }

    TestString& operator =(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocCopy(m_string,
                                               m_length,
                                               str.m_string,
                                               str.m_length);
        }
        else
            Clear();

        return *this;
    }

    TestString& operator +=(char const* str)
    {
        Append(str);
        return *this;
    }

    TestString& operator +=(TestString const& str)
    {
        Append(str);
        return *this;
    }

    char operator [](size_type index) const
    {
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : '\0';
    }

    char& operator [](size_type index)
    {
        static char spare = '\0';
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : spare;
    }

    operator char const*() const throw()
    {
        return Ptr();
    }

    bool operator ==(char const* str) const
    {
        if (m_string == NULL)
            return (str == NULL) || (*str == '\0');
        return ::strcmp(m_string, str) == 0;
    }

    bool operator ==(TestString const& str) const
    {
        if (m_string == NULL)
            return str.m_string == NULL;
        return ::strcmp(m_string, str.Ptr()) == 0;
    }

public:
    char const* Ptr() const throw()
    {
        return m_string != NULL ? m_string : "";
    }

    size_type GetLength() const throw()
    {
        return m_length;
    }

    bool IsEmpty() const throw()
    {
        return m_string == NULL;
    }

    void Clear()
    {
        TestStringUtility::FastFree(m_string);
        m_string = NULL;
        m_length = size_type_default;
    }

    bool Find(char ch, size_type& pos, size_type start = size_type_default) const
    {
        if (m_string != NULL)
            return TestStringUtility::UnsafeFind(m_string, ch, pos, start);
        return false;
    }

    /// Extract a partial string, and optionally remove the partial string
    /// from this string.
    void GetSubString(TestString& sub_str,
                      size_type start,
                      size_type count,
                      bool remove = false)
    {
        sub_str.Clear();
        TestStringUtility::SafeReallocCopy(sub_str.m_string,
                                           sub_str.m_length,
                                           m_string + start,
                                           count);
        if (remove)
        {
            if (sub_str.m_length < m_length)
            {
                size_type chars_remaining = m_length - sub_str.m_length;
                ::memmove(m_string, m_string + sub_str.m_length, chars_remaining);
                *(m_string + chars_remaining) = '\0';
                m_length = chars_remaining;
            }
            else
                Clear();
        }
    }

    /// Replace the current sting with str.
    void Assign(char const* str)
    {
        TestStringUtility::SafeReallocCopy(m_string, m_length, str);
    }

    /// Replace the current sting with str.
    void Assign(TestString const& str)
    {
        TestStringUtility::SafeReallocCopy(m_string, m_length, str.m_string);
    }

    /// Move str into this string.
    void Move(char*& str, size_type len)
    {
        TestStringUtility::FastFree(m_string);
        m_string = str;
        m_length = len;
        str = NULL;
    }

    void Prepend(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str),
                                                 m_string,
                                                 m_length);
        }
    }

    void Append(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str));
        }
    }

    void Append(char const* str, size_type count)
    {
        if ((str != NULL) && (*str != '\0') &&
            (count > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 count);
        }
    }

    void Append(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str.m_string,
                                                 str.m_length);
        }
    }

    /// Append a boolean converted to a "true" ot "false" string.
    void Append(bool value)
    {
        char const* str = value ? "true" : "false";
        Append(str);
    }

    /// Append a single character.
    void Append(char value)
    {
        char str[2];
        str[0] = value;
        str[1] = '\0';
        Append(str);
    }

    /// Append number of characters.
    void Append(char value, size_type count)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = value;
                Append(start, count);
                TestStringUtility::FastFree(start);
            }
            else
                Append(value);
        }
    }

    /// Append number of characters then a string value.
    void Append(char ch, size_type count, char const* value, size_type len)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count + len);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = ch;
                ::memcpy(str, value, len + 1);
                Append(start, count + len);
                TestStringUtility::FastFree(start);
            }
            else
                Append(ch);
        }
        else
            Append(value, len);
    }

    void Append(signed char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

private:
    template<typename T>
    void privateAppendValue(T value, size_type pad)
    {
        size_type length = size_type_default;
        char* str = TestStringUtility::GetString(value, length);
        if (str != NULL)
        {
            if (IsEmpty() && (pad == size_type_default))
                Move(str, length);
            else
            {
                if (pad > length)
                    Append('0', pad - length, str, length);
                else
                    Append(str, length);
                TestStringUtility::FastFree(str);
            }
        }
    }

    size_type privateSafeLength(char const* str)
    {
        return TestStringUtility::SafeLength(str);
    }

private:
    size_type m_length;
    char* m_string;
};

} // namespace ocl

#endif // OCL_GUARD_TEST_TESTSTRING_HPP
<commit_msg>Fixed bug with GetSubString being able to go past end of buffer in TestString class.<commit_after>/*
Copyright 2016 Colin Girling

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef OCL_GUARD_TEST_TESTSTRING_HPP
#define OCL_GUARD_TEST_TESTSTRING_HPP

#include "TestMemoryUtility.hpp"
#include "TestStringUtility.hpp"
#include <cstddef>
#include <cstdlib>
#include <cstring>

namespace ocl
{

/*
 * String class for test harness, with an interface complete enough for general usage.
 */

class TestString
{
public:
    typedef TestStringUtility::size_type size_type;

    /// size_type has the potential of being signed or unsigned,
    /// so ensure signed/unsigned mismatch compiler warnings are suppressed.
    static size_type const size_type_default = static_cast<size_type>(0);

public:
    TestString(char const* str = NULL)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        if (str != NULL)
            TestStringUtility::UnsafeAllocateCopy(m_string, m_length, str);
    }

    TestString(char ch, size_type len)
        : m_length(len)
        , m_string(NULL)
    {
        if (len > size_type_default)
        {
            TestStringUtility::Allocate(m_string, len);
            if (m_string != NULL)
                TestStringUtility::UnsafeFill(m_string, ch, len);
            else
                m_length = size_type_default;
        }
    }

    TestString(TestString const& str)
        : m_length(size_type_default)
        , m_string(NULL)
    {
        TestStringUtility::SafeAllocateCopy(m_string, m_length, str.m_string, str.m_length);
    }

    ~TestString()
    {
        TestStringUtility::FastFree(m_string);
    }

    TestString& operator =(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
            TestStringUtility::SafeReallocCopy(m_string, m_length, str);
        else
            Clear();
        return *this;
    }

    TestString& operator =(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocCopy(m_string,
                                               m_length,
                                               str.m_string,
                                               str.m_length);
        }
        else
            Clear();

        return *this;
    }

    TestString& operator +=(char const* str)
    {
        Append(str);
        return *this;
    }

    TestString& operator +=(TestString const& str)
    {
        Append(str);
        return *this;
    }

    char operator [](size_type index) const
    {
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : '\0';
    }

    char& operator [](size_type index)
    {
        static char spare = '\0';
        return ((m_string != NULL) && (index < m_length)) ? m_string[index] : spare;
    }

    operator char const*() const throw()
    {
        return Ptr();
    }

    bool operator ==(char const* str) const
    {
        if (m_string == NULL)
            return (str == NULL) || (*str == '\0');
        return ::strcmp(m_string, str) == 0;
    }

    bool operator ==(TestString const& str) const
    {
        if (m_string == NULL)
            return str.m_string == NULL;
        return ::strcmp(m_string, str.Ptr()) == 0;
    }

public:
    char const* Ptr() const throw()
    {
        return m_string != NULL ? m_string : "";
    }

    size_type GetLength() const throw()
    {
        return m_length;
    }

    bool IsEmpty() const throw()
    {
        return m_string == NULL;
    }

    void Clear()
    {
        TestStringUtility::FastFree(m_string);
        m_string = NULL;
        m_length = size_type_default;
    }

    bool Find(char ch, size_type& pos, size_type start = size_type_default) const
    {
        if (m_string != NULL)
            return TestStringUtility::UnsafeFind(m_string, ch, pos, start);
        return false;
    }

    /// Extract a partial string, and optionally remove the partial string
    /// from this string.
    void GetSubString(TestString& sub_str,
                      size_type start,
                      size_type count,
                      bool remove = false)
    {
        sub_str.Clear();
        if (start + count <= m_length)
        {
            TestStringUtility::SafeReallocCopy(sub_str.m_string,
                                               sub_str.m_length,
                                               m_string + start,
                                               count);
            if (remove)
            {
                if (sub_str.m_length < m_length)
                {
                    size_type chars_remaining = m_length - sub_str.m_length;
                    ::memmove(m_string, m_string + sub_str.m_length, chars_remaining);
                    *(m_string + chars_remaining) = '\0';
                    m_length = chars_remaining;
                }
                else
                    Clear();
            }
        }
    }

    /// Replace the current sting with str.
    void Assign(char const* str)
    {
        TestStringUtility::SafeReallocCopy(m_string, m_length, str);
    }

    /// Replace the current sting with str.
    void Assign(TestString const& str)
    {
        TestStringUtility::SafeReallocCopy(m_string, m_length, str.m_string);
    }

    /// Move str into this string.
    void Move(char*& str, size_type len)
    {
        TestStringUtility::FastFree(m_string);
        m_string = str;
        m_length = len;
        str = NULL;
    }

    void Prepend(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str),
                                                 m_string,
                                                 m_length);
        }
    }

    void Append(char const* str)
    {
        if ((str != NULL) && (*str != '\0'))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 privateSafeLength(str));
        }
    }

    void Append(char const* str, size_type count)
    {
        if ((str != NULL) && (*str != '\0') &&
            (count > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str,
                                                 count);
        }
    }

    void Append(TestString const& str)
    {
        if ((str.m_string != NULL) &&
            (*str.m_string != '\0') &&
            (str.m_length > size_type_default))
        {
            TestStringUtility::SafeReallocAppend(m_string,
                                                 m_length,
                                                 m_string,
                                                 m_length,
                                                 str.m_string,
                                                 str.m_length);
        }
    }

    /// Append a boolean converted to a "true" ot "false" string.
    void Append(bool value)
    {
        char const* str = value ? "true" : "false";
        Append(str);
    }

    /// Append a single character.
    void Append(char value)
    {
        char str[2];
        str[0] = value;
        str[1] = '\0';
        Append(str);
    }

    /// Append number of characters.
    void Append(char value, size_type count)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = value;
                Append(start, count);
                TestStringUtility::FastFree(start);
            }
            else
                Append(value);
        }
    }

    /// Append number of characters then a string value.
    void Append(char ch, size_type count, char const* value, size_type len)
    {
        if (count > size_type_default)
        {
            char* str = NULL;
            TestStringUtility::Allocate(str, count + len);
            if (str != NULL)
            {
                char* start = str;
                for (char* str_end = str + count; str < str_end; ++str)
                    *str = ch;
                ::memcpy(str, value, len + 1);
                Append(start, count + len);
                TestStringUtility::FastFree(start);
            }
            else
                Append(ch);
        }
        else
            Append(value, len);
    }

    void Append(signed char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned char value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned short value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned int value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(signed long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

    void Append(unsigned long value, size_type pad = size_type_default)
    {
        privateAppendValue(value, pad);
    }

private:
    template<typename T>
    void privateAppendValue(T value, size_type pad)
    {
        size_type length = size_type_default;
        char* str = TestStringUtility::GetString(value, length);
        if (str != NULL)
        {
            if (IsEmpty() && (pad == size_type_default))
                Move(str, length);
            else
            {
                if (pad > length)
                    Append('0', pad - length, str, length);
                else
                    Append(str, length);
                TestStringUtility::FastFree(str);
            }
        }
    }

    size_type privateSafeLength(char const* str)
    {
        return TestStringUtility::SafeLength(str);
    }

private:
    size_type m_length;
    char* m_string;
};

} // namespace ocl

#endif // OCL_GUARD_TEST_TESTSTRING_HPP
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void basicStuff(const MatrixType& m)
{
  typedef typename MatrixType::Scalar Scalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  int rows = m.rows();
  int cols = m.cols();

  // this test relies a lot on Random.h, and there's not much more that we can do
  // to test it, hence I consider that we will have tested Random.h
  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
                              ::Identity(rows, rows),
             square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
  VectorType v1 = VectorType::Random(rows),
             v2 = VectorType::Random(rows),
             vzero = VectorType::Zero(rows);

  Scalar x = ei_random<Scalar>();

  int r = ei_random<int>(0, rows-1),
      c = ei_random<int>(0, cols-1);

  m1.coeffRef(r,c) = x;
  VERIFY_IS_APPROX(x, m1.coeff(r,c));
  m1(r,c) = x;
  VERIFY_IS_APPROX(x, m1(r,c));
  v1.coeffRef(r) = x;
  VERIFY_IS_APPROX(x, v1.coeff(r));
  v1(r) = x;
  VERIFY_IS_APPROX(x, v1(r));
  v1[r] = x;
  VERIFY_IS_APPROX(x, v1[r]);

  VERIFY_IS_APPROX(               v1,    v1);
  VERIFY_IS_NOT_APPROX(           v1,    2*v1);
  VERIFY_IS_MUCH_SMALLER_THAN(    vzero, v1);
  if(NumTraits<Scalar>::HasFloatingPoint)
    VERIFY_IS_MUCH_SMALLER_THAN(  vzero, v1.norm());
  VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1,    v1);
  VERIFY_IS_APPROX(               vzero, v1-v1);
  VERIFY_IS_APPROX(               m1,    m1);
  VERIFY_IS_NOT_APPROX(           m1,    2*m1);
  VERIFY_IS_MUCH_SMALLER_THAN(    mzero, m1);
  VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1,    m1);
  VERIFY_IS_APPROX(               mzero, m1-m1);

  // always test operator() on each read-only expression class,
  // in order to check const-qualifiers.
  // indeed, if an expression class (here Zero) is meant to be read-only,
  // hence has no _write() method, the corresponding MatrixBase method (here zero())
  // should return a const-qualified object so that it is the const-qualified
  // operator() that gets called, which in turn calls _read().
  VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1));

  // now test copying a row-vector into a (column-)vector and conversely.
  square.col(r) = square.row(r).eval();
  Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
  Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
  rv = square.row(r);
  cv = square.col(r);
  VERIFY_IS_APPROX(rv, cv.transpose());

  if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
  {
    VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1)));
  }

  VERIFY_IS_APPROX(m3 = m1,m1);
  MatrixType m4;
  VERIFY_IS_APPROX(m4 = m1,m1);

  // test swap
  m3 = m1;
  m1.swap(m2);
  VERIFY_IS_APPROX(m3, m2);
  if(rows*cols>=3)
  {
    VERIFY_IS_NOT_APPROX(m3, m1);
  }
}

void casting()
{
  Matrix4f m = Matrix4f::Random(), m2;
  Matrix4d n = m.cast<double>();
  VERIFY(m.isApprox(n.cast<float>()));
  m2 = m.cast<float>(); // check the specialization when NewType == Type
  VERIFY(m.isApprox(m2));
}

void test_basicstuff()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( basicStuff(Matrix<float, 1, 1>()) );
    CALL_SUBTEST( basicStuff(Matrix4d()) );
    CALL_SUBTEST( basicStuff(MatrixXcf(3, 3)) );
    CALL_SUBTEST( basicStuff(MatrixXi(8, 12)) );
    CALL_SUBTEST( basicStuff(MatrixXcd(20, 20)) );
    CALL_SUBTEST( basicStuff(Matrix<float, 100, 100>()) );
    CALL_SUBTEST( basicStuff(Matrix<long double,Dynamic,Dynamic>(10,10)) );
  }
}
<commit_msg>gni, forgot to call the new subtest<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen 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 Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void basicStuff(const MatrixType& m)
{
  typedef typename MatrixType::Scalar Scalar;
  typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType;

  int rows = m.rows();
  int cols = m.cols();

  // this test relies a lot on Random.h, and there's not much more that we can do
  // to test it, hence I consider that we will have tested Random.h
  MatrixType m1 = MatrixType::Random(rows, cols),
             m2 = MatrixType::Random(rows, cols),
             m3(rows, cols),
             mzero = MatrixType::Zero(rows, cols),
             identity = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>
                              ::Identity(rows, rows),
             square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows);
  VectorType v1 = VectorType::Random(rows),
             v2 = VectorType::Random(rows),
             vzero = VectorType::Zero(rows);

  Scalar x = ei_random<Scalar>();

  int r = ei_random<int>(0, rows-1),
      c = ei_random<int>(0, cols-1);

  m1.coeffRef(r,c) = x;
  VERIFY_IS_APPROX(x, m1.coeff(r,c));
  m1(r,c) = x;
  VERIFY_IS_APPROX(x, m1(r,c));
  v1.coeffRef(r) = x;
  VERIFY_IS_APPROX(x, v1.coeff(r));
  v1(r) = x;
  VERIFY_IS_APPROX(x, v1(r));
  v1[r] = x;
  VERIFY_IS_APPROX(x, v1[r]);

  VERIFY_IS_APPROX(               v1,    v1);
  VERIFY_IS_NOT_APPROX(           v1,    2*v1);
  VERIFY_IS_MUCH_SMALLER_THAN(    vzero, v1);
  if(NumTraits<Scalar>::HasFloatingPoint)
    VERIFY_IS_MUCH_SMALLER_THAN(  vzero, v1.norm());
  VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1,    v1);
  VERIFY_IS_APPROX(               vzero, v1-v1);
  VERIFY_IS_APPROX(               m1,    m1);
  VERIFY_IS_NOT_APPROX(           m1,    2*m1);
  VERIFY_IS_MUCH_SMALLER_THAN(    mzero, m1);
  VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1,    m1);
  VERIFY_IS_APPROX(               mzero, m1-m1);

  // always test operator() on each read-only expression class,
  // in order to check const-qualifiers.
  // indeed, if an expression class (here Zero) is meant to be read-only,
  // hence has no _write() method, the corresponding MatrixBase method (here zero())
  // should return a const-qualified object so that it is the const-qualified
  // operator() that gets called, which in turn calls _read().
  VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1));

  // now test copying a row-vector into a (column-)vector and conversely.
  square.col(r) = square.row(r).eval();
  Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows);
  Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
  rv = square.row(r);
  cv = square.col(r);
  VERIFY_IS_APPROX(rv, cv.transpose());

  if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
  {
    VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1)));
  }

  VERIFY_IS_APPROX(m3 = m1,m1);
  MatrixType m4;
  VERIFY_IS_APPROX(m4 = m1,m1);

  // test swap
  m3 = m1;
  m1.swap(m2);
  VERIFY_IS_APPROX(m3, m2);
  if(rows*cols>=3)
  {
    VERIFY_IS_NOT_APPROX(m3, m1);
  }
}

void casting()
{
  Matrix4f m = Matrix4f::Random(), m2;
  Matrix4d n = m.cast<double>();
  VERIFY(m.isApprox(n.cast<float>()));
  m2 = m.cast<float>(); // check the specialization when NewType == Type
  VERIFY(m.isApprox(m2));
}

void test_basicstuff()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST( basicStuff(Matrix<float, 1, 1>()) );
    CALL_SUBTEST( basicStuff(Matrix4d()) );
    CALL_SUBTEST( basicStuff(MatrixXcf(3, 3)) );
    CALL_SUBTEST( basicStuff(MatrixXi(8, 12)) );
    CALL_SUBTEST( basicStuff(MatrixXcd(20, 20)) );
    CALL_SUBTEST( basicStuff(Matrix<float, 100, 100>()) );
    CALL_SUBTEST( basicStuff(Matrix<long double,Dynamic,Dynamic>(10,10)) );
  }

  CALL_SUBTEST(casting());
}
<|endoftext|>