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