Blame test/simulation/clknetsim/generator.cc

Packit 96c956
/*
Packit 96c956
 * Copyright (C) 2010  Miroslav Lichvar <mlichvar@redhat.com>
Packit 96c956
 * 
Packit 96c956
 * This program is free software; you can redistribute it and/or modify
Packit 96c956
 * it under the terms of the GNU General Public License as published by
Packit 96c956
 * the Free Software Foundation; either version 2 of the License, or
Packit 96c956
 * (at your option) any later version.
Packit 96c956
 * 
Packit 96c956
 * This program is distributed in the hope that it will be useful,
Packit 96c956
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 96c956
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 96c956
 * GNU General Public License for more details.
Packit 96c956
 * 
Packit 96c956
 * You should have received a copy of the GNU General Public License
Packit 96c956
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 96c956
 */
Packit 96c956
Packit 96c956
#include "generator.h"
Packit 96c956
Packit 96c956
static void syntax_assert(bool condition) {
Packit 96c956
	if (!condition) {
Packit 96c956
		fprintf(stderr, "syntax error\n");
Packit 96c956
		exit(1);
Packit 96c956
	}
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator::Generator(const vector<Generator *> *input) {
Packit 96c956
	if (input)
Packit 96c956
		this->input = *input;
Packit 96c956
	constant = false;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator::~Generator() {
Packit 96c956
	while (!input.empty()) {
Packit 96c956
		delete input.back();
Packit 96c956
		input.pop_back();
Packit 96c956
	}
Packit 96c956
}
Packit 96c956
Packit 96c956
bool Generator::is_constant() const {
Packit 96c956
	return constant;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_float::Generator_float(double f): Generator(NULL) {
Packit 96c956
	this->f = f;
Packit 96c956
	constant = true;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_float::generate(const Generator_variables *variables) {
Packit 96c956
	return f;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_variable::Generator_variable(string name): Generator(NULL) {
Packit 96c956
	this->name = name;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_variable::generate(const Generator_variables *variables) {
Packit 96c956
	Generator_variables::const_iterator iter;
Packit 96c956
Packit 96c956
	syntax_assert(variables);
Packit 96c956
	iter = variables->find(name);
Packit 96c956
	syntax_assert(iter != variables->end());
Packit 96c956
Packit 96c956
	return iter->second;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_random_uniform::Generator_random_uniform(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL) {
Packit 96c956
	syntax_assert(!input || input->size() == 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_random_uniform::generate(const Generator_variables *variables) {
Packit 96c956
	double x;
Packit 96c956
Packit 96c956
	x = ((random() & 0x7fffffff) + 1) / 2147483649.0;
Packit 96c956
	x = ((random() & 0x7fffffff) + x) / 2147483648.0;
Packit 96c956
Packit 96c956
	return x;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_random_normal::Generator_random_normal(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL), uniform(NULL) {
Packit 96c956
	syntax_assert(!input || input->size() == 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_random_normal::generate(const Generator_variables *variables) {
Packit 96c956
	/* Marsaglia polar method */
Packit 96c956
Packit 96c956
	double x, y, s;
Packit 96c956
Packit 96c956
	do {
Packit 96c956
		x = 2.0 * uniform.generate(variables) - 1.0;
Packit 96c956
		y = 2.0 * uniform.generate(variables) - 1.0;
Packit 96c956
		s = x * x + y * y;
Packit 96c956
	} while (s >= 1.0);
Packit 96c956
Packit 96c956
	x *= sqrt(-2.0 * log(s) / s);
Packit 96c956
Packit 96c956
	return x;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_random_exponential::Generator_random_exponential(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL), uniform(NULL) {
Packit 96c956
	syntax_assert(!input || input->size() == 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_random_exponential::generate(const Generator_variables *variables) {
Packit 96c956
	return -log(uniform.generate(variables));
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_random_poisson::Generator_random_poisson(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL), uniform(NULL) {
Packit 96c956
	double lambda;
Packit 96c956
Packit 96c956
	syntax_assert(input && input->size() == 1 && (*input)[0]->is_constant());
Packit 96c956
Packit 96c956
	lambda = (*input)[0]->generate(NULL);
Packit 96c956
	syntax_assert(lambda >= 1 && lambda <= 20);
Packit 96c956
	L = exp(-lambda);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_random_poisson::generate(const Generator_variables *variables) {
Packit 96c956
	double p;
Packit 96c956
	int k;
Packit 96c956
Packit 96c956
	for (p = 1.0, k = 0; k < 100; k++) {
Packit 96c956
		p *= uniform.generate(variables);
Packit 96c956
		if (p <= L)
Packit 96c956
			break;
Packit 96c956
	}
Packit 96c956
Packit 96c956
	return k;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_file::Generator_file(const char *file): Generator(NULL) {
Packit 96c956
	input = fopen(file, "r");
Packit 96c956
	if (!input) {
Packit 96c956
		fprintf(stderr, "can't open %s\n", file);
Packit 96c956
		exit(1);
Packit 96c956
	}
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_file::~Generator_file() {
Packit 96c956
	fclose(input);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_file::generate(const Generator_variables *variables) {
Packit 96c956
	double x;
Packit 96c956
Packit 96c956
	while (1) {
Packit 96c956
		if (fscanf(input, "%lf", &x) != 1) {
Packit 96c956
			if (feof(input)) {
Packit 96c956
				fseek(input, 0, SEEK_SET);
Packit 96c956
				continue;
Packit 96c956
			}
Packit 96c956
			assert(0);
Packit 96c956
		}
Packit 96c956
		break;
Packit 96c956
	}
Packit 96c956
	return x;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_wave_pulse::Generator_wave_pulse(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL) {
Packit 96c956
	syntax_assert(input && input->size() == 2 &&
Packit 96c956
			(*input)[0]->is_constant() && (*input)[1]->is_constant());
Packit 96c956
	high = (*input)[0]->generate(NULL);
Packit 96c956
	low = (*input)[1]->generate(NULL);
Packit 96c956
	counter = 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_wave_pulse::generate(const Generator_variables *variables) {
Packit 96c956
	counter++;
Packit 96c956
	if (counter > high + low)
Packit 96c956
		counter = 1;
Packit 96c956
	if (counter <= high)
Packit 96c956
		return 1.0;
Packit 96c956
	return -1.0;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_wave_sine::Generator_wave_sine(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL) {
Packit 96c956
	syntax_assert(input && input->size() == 1 && (*input)[0]->is_constant());
Packit 96c956
	length = (*input)[0]->generate(NULL);
Packit 96c956
	counter = 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_wave_sine::generate(const Generator_variables *variables) {
Packit 96c956
	return sin(counter++ / length * 2 * M_PI);
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_wave_cosine::Generator_wave_cosine(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL) {
Packit 96c956
	syntax_assert(input && input->size() == 1 && (*input)[0]->is_constant());
Packit 96c956
	length = (*input)[0]->generate(NULL);
Packit 96c956
	counter = 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_wave_cosine::generate(const Generator_variables *variables) {
Packit 96c956
	return cos(counter++ / length * 2 * M_PI);
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_wave_triangle::Generator_wave_triangle(const vector<Generator *> *input):
Packit 96c956
	Generator(NULL) {
Packit 96c956
	syntax_assert(input && input->size() == 1 && (*input)[0]->is_constant());
Packit 96c956
	length = (*input)[0]->generate(NULL);
Packit 96c956
	counter = 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_wave_triangle::generate(const Generator_variables *variables) {
Packit 96c956
	double phase;
Packit 96c956
	phase = counter / length - floor(counter / length);
Packit 96c956
	counter++;
Packit 96c956
	return -4.0 * (fabs(phase - 0.5) - 0.25);
Packit 96c956
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_sum::Generator_sum(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
	sum = 0.0;
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_sum::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
Packit 96c956
	for (i = 0; i < input.size(); i++)
Packit 96c956
		sum += input[i]->generate(variables);
Packit 96c956
	return sum;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_multiply::Generator_multiply(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_multiply::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
	double x = 1.0;
Packit 96c956
Packit 96c956
	for (i = 0; i < input.size(); i++)
Packit 96c956
		x *= input[i]->generate(variables);
Packit 96c956
	return x;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_add::Generator_add(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_add::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
	double x = 0.0;
Packit 96c956
Packit 96c956
	for (i = 0; i < input.size(); i++)
Packit 96c956
		x += input[i]->generate(variables);
Packit 96c956
	return x;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_modulo::Generator_modulo(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
	syntax_assert(input && input->size() > 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_modulo::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
	double x = input[0]->generate(variables);
Packit 96c956
Packit 96c956
	for (i = 1; i < input.size(); i++)
Packit 96c956
		x = fmod(x, input[i]->generate(variables));
Packit 96c956
Packit 96c956
	return x;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_equal::Generator_equal(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
	syntax_assert(input && input->size() > 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_equal::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
	double x, min = 0.0, max = 0.0, epsilon = input[0]->generate(variables);
Packit 96c956
Packit 96c956
	for (i = 1; i < input.size(); i++) {
Packit 96c956
		x = input[i]->generate(variables);
Packit 96c956
		if (i == 1 || min > x)
Packit 96c956
			min = x;
Packit 96c956
		if (i == 1 || max < x)
Packit 96c956
			max = x;
Packit 96c956
	}
Packit 96c956
Packit 96c956
	return max - min <= epsilon ? 1.0 : 0.0;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_max::Generator_max(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
	syntax_assert(input && input->size() > 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_max::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
	double x, max = 0.0;
Packit 96c956
Packit 96c956
	for (i = 0; i < input.size(); i++) {
Packit 96c956
		x = input[i]->generate(variables);
Packit 96c956
		if (!i || max < x)
Packit 96c956
			max = x;
Packit 96c956
	}
Packit 96c956
Packit 96c956
	return max;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_min::Generator_min(const vector<Generator *> *input):
Packit 96c956
	Generator(input) {
Packit 96c956
	syntax_assert(input && input->size() > 0);
Packit 96c956
}
Packit 96c956
Packit 96c956
double Generator_min::generate(const Generator_variables *variables) {
Packit 96c956
	unsigned int i;
Packit 96c956
	double x, min = 0.0;
Packit 96c956
Packit 96c956
	for (i = 0; i < input.size(); i++) {
Packit 96c956
		x = input[i]->generate(variables);
Packit 96c956
		if (!i || min > x)
Packit 96c956
			min = x;
Packit 96c956
	}
Packit 96c956
Packit 96c956
	return min;
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_generator::Generator_generator() {
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator_generator::~Generator_generator() {
Packit 96c956
}
Packit 96c956
Packit 96c956
Generator *Generator_generator::generate(char *code) const {
Packit 96c956
	const char *ws = " \t\n\r", *wsp = " \t\n\r()";
Packit 96c956
	int len, paren;
Packit 96c956
	Generator *ret;
Packit 96c956
	vector<Generator *> generators;
Packit 96c956
	char *arg, *name, *end, *string = NULL;
Packit 96c956
Packit 96c956
	//printf("code: |%s|\n", code);
Packit 96c956
	len = strlen(code);
Packit 96c956
	end = code + len;
Packit 96c956
Packit 96c956
	if (code[0] == '(') {
Packit 96c956
		syntax_assert(len > 2 && code[len - 1] == ')');
Packit 96c956
		code[len - 1] = '\0';
Packit 96c956
		code++;
Packit 96c956
		end = code + len - 2;
Packit 96c956
	}
Packit 96c956
Packit 96c956
	code += strspn(code, ws);
Packit 96c956
	
Packit 96c956
	name = code;
Packit 96c956
Packit 96c956
	code += strcspn(code, wsp);
Packit 96c956
	code[0] = '\0';
Packit 96c956
	code++;
Packit 96c956
Packit 96c956
	code += strspn(code, ws);
Packit 96c956
Packit 96c956
	while (code < end) {
Packit 96c956
		arg = code;
Packit 96c956
Packit 96c956
		if (arg[0] == '(') {
Packit 96c956
			code = ++arg;
Packit 96c956
			for (paren = 1; code < end; code++) {
Packit 96c956
				if (code[0] == '(')
Packit 96c956
					paren++;
Packit 96c956
				else if (code[0] == ')')
Packit 96c956
					paren--;
Packit 96c956
				if (paren == 0)
Packit 96c956
					break;
Packit 96c956
			}
Packit 96c956
Packit 96c956
			syntax_assert(paren == 0 && code[0] == ')');
Packit 96c956
			code[0] = '\0';
Packit 96c956
			code++;
Packit 96c956
Packit 96c956
			//printf("generator: %s\n", arg);
Packit 96c956
			generators.push_back(generate(arg));
Packit 96c956
			syntax_assert(generators.back());
Packit 96c956
		} else if (arg[0] == '"') {
Packit 96c956
			string = code = ++arg;
Packit 96c956
			code += strcspn(code, "\"");
Packit 96c956
			syntax_assert(code[0] == '"');
Packit 96c956
			code[0] = '\0';
Packit 96c956
			code++;
Packit 96c956
			//printf("string: |%s|\n", string);
Packit 96c956
		} else {
Packit 96c956
			code += strcspn(code, wsp);
Packit 96c956
			syntax_assert(code[0] != ')' && code[0] != '(');
Packit 96c956
			code[0] = '\0';
Packit 96c956
			code++;
Packit 96c956
			if (isalpha(arg[0])) {
Packit 96c956
				generators.push_back(new Generator_variable(arg));
Packit 96c956
				//printf("variable: %s\n", arg);
Packit 96c956
			} else {
Packit 96c956
				generators.push_back(new Generator_float(atof(arg)));
Packit 96c956
				//printf("float: %f\n", generators.back()->generate());
Packit 96c956
			}
Packit 96c956
		}
Packit 96c956
Packit 96c956
		code += strspn(code, ws);
Packit 96c956
	}
Packit 96c956
Packit 96c956
	if (strcmp(name, "*") == 0)
Packit 96c956
		ret = new Generator_multiply(&generators);
Packit 96c956
	else if (strcmp(name, "+") == 0)
Packit 96c956
		ret = new Generator_add(&generators);
Packit 96c956
	else if (strcmp(name, "%") == 0)
Packit 96c956
		ret = new Generator_modulo(&generators);
Packit 96c956
	else if (strcmp(name, "sum") == 0)
Packit 96c956
		ret = new Generator_sum(&generators);
Packit 96c956
	else if (strcmp(name, "uniform") == 0)
Packit 96c956
		ret = new Generator_random_uniform(&generators);
Packit 96c956
	else if (strcmp(name, "normal") == 0)
Packit 96c956
		ret = new Generator_random_normal(&generators);
Packit 96c956
	else if (strcmp(name, "exponential") == 0)
Packit 96c956
		ret = new Generator_random_exponential(&generators);
Packit 96c956
	else if (strcmp(name, "poisson") == 0)
Packit 96c956
		ret = new Generator_random_poisson(&generators);
Packit 96c956
	else if (strcmp(name, "file") == 0)
Packit 96c956
		ret = new Generator_file(string);
Packit 96c956
	else if (strcmp(name, "pulse") == 0)
Packit 96c956
		ret = new Generator_wave_pulse(&generators);
Packit 96c956
	else if (strcmp(name, "sine") == 0)
Packit 96c956
		ret = new Generator_wave_sine(&generators);
Packit 96c956
	else if (strcmp(name, "cosine") == 0)
Packit 96c956
		ret = new Generator_wave_cosine(&generators);
Packit 96c956
	else if (strcmp(name, "triangle") == 0)
Packit 96c956
		ret = new Generator_wave_triangle(&generators);
Packit 96c956
	else if (strcmp(name, "equal") == 0)
Packit 96c956
		ret = new Generator_equal(&generators);
Packit 96c956
	else if (strcmp(name, "max") == 0)
Packit 96c956
		ret = new Generator_max(&generators);
Packit 96c956
	else if (strcmp(name, "min") == 0)
Packit 96c956
		ret = new Generator_min(&generators);
Packit 96c956
	else {
Packit 96c956
		ret = NULL;
Packit 96c956
		syntax_assert(0);
Packit 96c956
	}
Packit 96c956
Packit 96c956
	return ret;
Packit 96c956
}