Blame c++/iir_blur/iir_blur.cpp

bw 7cdc43
/*
bw 7cdc43
    ......... 2016 Ivan Mahonin
bw 7cdc43
bw 7cdc43
    This program is free software: you can redistribute it and/or modify
bw 7cdc43
    it under the terms of the GNU General Public License as published by
bw 7cdc43
    the Free Software Foundation, either version 3 of the License, or
bw 7cdc43
    (at your option) any later version.
bw 7cdc43
bw 7cdc43
    This program is distributed in the hope that it will be useful,
bw 7cdc43
    but WITHOUT ANY WARRANTY; without even the implied warranty of
bw 7cdc43
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
bw 7cdc43
    GNU General Public License for more details.
bw 7cdc43
bw 7cdc43
    You should have received a copy of the GNU General Public License
bw 7cdc43
    along with this program.  If not, see <http: licenses="" www.gnu.org="">.</http:>
bw 7cdc43
*/
bw 7cdc43
bw 249abc
#include <cstdarg></cstdarg>
bw 249abc
#include <cstdio></cstdio>
bw 249abc
#include <cstring></cstring>
bw 249abc
#include <cmath></cmath>
bw 249abc
bw 249abc
#include <iostream></iostream>
bw 249abc
#include <iomanip></iomanip>
bw 249abc
#include <fstream></fstream>
bw d8ace3
#include <sstream></sstream>
bw 249abc
#include <vector></vector>
bw 249abc
#include <set></set>
bw d8ace3
#include <map></map>
bw 249abc
bw 249abc
#include "surface.h"
bw 249abc
bw 249abc
bw 249abc
using namespace std;
bw 249abc
bw 249abc
bw d8ace3
// options
bw d8ace3
const double initial_radius = 16.0;
bw d8ace3
const double min_radius = 1.0;
bw d8ace3
const double max_radius = 2048;
bw d8ace3
const double step = 0.1;
bw d8ace3
const double large_params_step = 0.05;
bw d8ace3
const double params_step = 0.025;
bw d8ace3
const double threshold = 0.012;
bw d8ace3
bw d8ace3
const char logfile[] = "results/coef.log";
bw d8ace3
const char final_coefs_file[] = "results/coef.hpp";
bw d8ace3
const char final_coefs_file2[] = "results/coef2.hpp";
bw d8ace3
bw d8ace3
bw d8ace3
bw d8ace3
bw 249abc
#define COMPARE_HELPER(a) a < other.a ? true : other.a < a ? false :
bw 249abc
bw 249abc
#define COMPARE(a) a < other.a;
bw 249abc
#define COMPARE2(a, b) COMPARE_HELPER(a) COMPARE(b)
bw 249abc
#define COMPARE3(a, b, c) COMPARE_HELPER(a) COMPARE2(b, c)
bw 249abc
#define COMPARE4(a, b, c, d) COMPARE_HELPER(a) COMPARE3(b, c, d)
bw 249abc
bw 249abc
const double pi = 3.14159265358979323846;
bw 249abc
bw 249abc
string strprintf(const char *format, ...)
bw 249abc
{
bw 249abc
	va_list args;
bw 249abc
	va_start(args,format);
bw 249abc
	static char buffer[1024*1024];
bw 249abc
	vsprintf(buffer, format, args);
bw 249abc
	return buffer;
bw 249abc
}
bw 249abc
bw 249abc
template<typename t=""></typename>
bw 249abc
inline bool less(const T &a, const T &b, bool def)
bw 249abc
	{ return a < b ? true : b < a ? false : def; }
bw 249abc
bw 249abc
bw 249abc
double gauss(double x, double radius) {
bw 249abc
	static const double k = 1.0/sqrt(2.0*pi);
bw 249abc
	return k/radius*exp(-0.5*x*x/(radius*radius));
bw 249abc
}
bw 249abc
bw 249abc
bw 249abc
class Params {
bw 249abc
public:
bw 249abc
	union {
bw 249abc
		struct { double k0, k1, k2; };
bw 249abc
		double k[3];
bw 249abc
	};
bw 249abc
bw 249abc
	Params(): k0(), k1(), k2() { }
bw 249abc
	Params(double k0, double k1, double k2): k0(k0), k1(k1), k2(k2) { }
bw 249abc
bw 249abc
bw 249abc
	bool operator< (const Params &other) const
bw 249abc
		{ return COMPARE3(k0, k1, k2); }
bw 249abc
};
bw 249abc
bw 249abc
bw 249abc
class Checker {
bw 249abc
private:
bw 249abc
	vector<double> blank;</double>
bw 249abc
	vector<double> tmp;</double>
bw 249abc
bw 249abc
public:
bw 7cdc43
	int offset;
bw 249abc
	bool valid;
bw 249abc
	double radius;
bw 249abc
bw 7cdc43
	Checker(double radius): offset(3), valid(), radius(radius) {
bw 249abc
		blank.resize((int)ceil(radius*10));
bw 7cdc43
		tmp.resize(blank.size() + 2*offset);
bw 249abc
		for(int i = 0; i < (int)blank.size(); ++i)
bw 249abc
			blank[i] = gauss(i, radius);
bw 249abc
	}
bw 249abc
bw 249abc
	Params convert_params(const Params ¶ms) {
bw 249abc
		double a = 1.0/params.k0;
bw 249abc
		double b = a*cos(pi*params.k1);
bw 249abc
		double c = 1.0/params.k2;
bw 249abc
bw 249abc
		Params p;
bw 7cdc43
		p.k0 = (a*a + 2.0*c*b)/(c*a*a);
bw 7cdc43
		p.k1 = -(c + 2.0*b)/(c*a*a);
bw 7cdc43
		p.k2 = 1.0/(c*a*a);
bw 249abc
bw 249abc
		return p;
bw 249abc
	}
bw 249abc
bw 249abc
	double check2(const Params ¶ms) {
bw 249abc
		if ( abs(params.k0) > 0.99999999
bw 7cdc43
		  //|| abs(params.k1) > 0.99999999
bw 249abc
		  || abs(params.k2) > 0.99999999
bw 249abc
		  || params.k0 < 1e-6
bw 249abc
		  || abs(params.k2) < 1e-6 ) return INFINITY;
bw 7cdc43
		return check(convert_params(params));
bw 7cdc43
		//return check(params);
bw 249abc
	}
bw 249abc
bw 7cdc43
	double check(const Params ¶ms) {
bw 249abc
		valid = false;
bw 249abc
bw 249abc
		//if (mode3a && fabs(params.k0 + (params.k1 + params.k2)/(params.k0 + params.k1 + params.k2)) >= 0.999999999)
bw 249abc
		//	return INFINITY;
bw 249abc
		if (fabs(params.k0) < 1e-10 && fabs(params.k1) < 1e-10 && fabs(params.k2) < 1e-10)
bw 249abc
			return INFINITY;
bw 249abc
bw 7cdc43
		double k = 1.0 - params.k0 - params.k1 - params.k2;
bw 7cdc43
		tmp[offset] = k;
bw 7cdc43
		for(int i = offset+1, end = (int)tmp.size()-offset; i < end; ++i)
bw 7cdc43
			tmp[i] = params.k0*tmp[i-1]
bw 7cdc43
				   + params.k1*tmp[i-2]
bw 7cdc43
				   + params.k2*tmp[i-3];
bw 7cdc43
		for(int i = (int)tmp.size()-offset-1, end = offset-1; i > end; --i)
bw 7cdc43
			tmp[i] = k*tmp[i]
bw 7cdc43
				   + params.k0*tmp[i+1]
bw 7cdc43
				   + params.k1*tmp[i+2]
bw 7cdc43
				   + params.k2*tmp[i+3];
bw 249abc
bw 249abc
		double delta = 0.0;
bw 7cdc43
		//double minv = tmp[offset];
bw 7cdc43
		//double kblank = 1.0/blank[0];
bw 7cdc43
		for(int i = 0; i < (int)blank.size(); ++i) {
bw 7cdc43
			double t = tmp[i + offset];
bw 7cdc43
			double d = blank[i] - t;
bw 7cdc43
			delta += fabs(d*d);
bw 7cdc43
			//if (t < minv) minv = t;
bw 7cdc43
			//if (minv < 0) minv = 0;
bw 7cdc43
			//delta += 2*fabs(t - minv);
bw 7cdc43
			//delta += 0.1*fabs(d/(kblank*blank[i] + 0.1));
bw 249abc
		}
bw 249abc
bw 249abc
		if (isinf(delta) || isnan(delta)) return INFINITY;
bw 249abc
bw 249abc
		valid = true;
bw 7cdc43
		return sqrt(delta/blank.size())*blank.size();
bw 249abc
	}
bw 249abc
bw 249abc
bw 249abc
	void graph(const string &filename) {
bw 7cdc43
		int base_size = 768;
bw 249abc
		int count = blank.size();
bw 7cdc43
		int scale = base_size/count + 1;
bw 7cdc43
		int div   = count/768 + 1;
bw 249abc
bw 7cdc43
		int pad = max(16, count*scale/div/8);
bw 7cdc43
		int gw = count*scale/div;
bw 249abc
		int gh = gw;
bw 249abc
bw 7cdc43
		Surface::Color axis = Surface::convert_color(0, 0, 1, 1);
bw 7cdc43
		Surface::Color ca = Surface::convert_color(1, 0, 0, 0.25);
bw 7cdc43
		Surface::Color cb = Surface::convert_color(0, 0, 0, 0.75);
bw 249abc
bw 249abc
		Surface s(gw + 2*pad, gh + 2*pad);
bw 249abc
		s.clear(1.0, 1.0, 1.0, 1.0);
bw 249abc
bw 249abc
		s.set_color(axis);
bw 249abc
		s.move_to(pad, pad);
bw 249abc
		s.line_by(0, gh);
bw 249abc
		s.line_by(gw, 0);
bw 249abc
bw 249abc
		s.set_color(ca);
bw 249abc
		s.move_to(pad, pad);
bw 249abc
		for(int i = 0; i < count; ++i)
bw 7cdc43
			s.line_to(pad + i*scale/div, pad + (int)round((1.0 - blank[i]/blank[0])*gh));
bw 249abc
bw 249abc
		if (valid) {
bw 249abc
			s.set_color(cb);
bw 249abc
			s.move_to(pad, pad);
bw 7cdc43
			for(int i = 0; i < count; ++i)
bw 7cdc43
				s.line_to(pad + i*scale/div, pad + (int)round((1.0 - tmp[i + offset]/blank[0])*gh));
bw 249abc
		}
bw 249abc
bw 249abc
		s.save(filename);
bw 249abc
	}
bw 249abc
};
bw 249abc
bw 249abc
bw 249abc
class Finder {
bw 249abc
public:
bw 249abc
	class Entry {
bw 249abc
	public:
bw 249abc
		double value;
bw 249abc
		Params min;
bw 249abc
		Params current;
bw 249abc
		Params max;
bw 249abc
bw 249abc
		Finder *finder;
bw 249abc
		Entry *parent;
bw 249abc
		int level;
bw 249abc
		int index;
bw 249abc
		int max_variants;
bw 249abc
		set<entry> variants;</entry>
bw 249abc
bw 249abc
		Entry(): value(INFINITY), finder(), parent(), level(), index(), max_variants() { }
bw 249abc
bw 249abc
		bool operator< (const Entry &other) const
bw 249abc
			{ return COMPARE4(value, min, current, max); }
bw 249abc
bw 249abc
		void add_variant(const Entry &entry) {
bw 249abc
			if (isinf(entry.value) || isnan(entry.value) || max_variants == 0) return;
bw 249abc
			if ((int)variants.size() < max_variants || entry.value < variants.rbegin()->value) {
bw 249abc
				variants.insert(entry);
bw 249abc
				if (max_variants < (int)variants.size()) {
bw 249abc
					set<entry>::iterator i = variants.end();</entry>
bw 249abc
					variants.erase(--i);
bw 249abc
				}
bw 249abc
			}
bw 249abc
		}
bw 249abc
bw 249abc
		void report_index() {
bw 249abc
			if (parent) {
bw 249abc
				parent->report_index();
bw 249abc
				cout << "["  << index << "]";
bw 249abc
			}
bw 249abc
		}
bw 249abc
bw 249abc
		void report(bool open) {
bw 249abc
			if (level < finder->max_report_level) {
bw 249abc
				cout << "level " << level << " ";
bw 249abc
				report_index();
bw 7cdc43
				for(int i = level; i < finder->max_report_level; ++i)
bw 7cdc43
					cout << "   ";
bw 7cdc43
				cout << (open ? " begin" : " end  ")
bw 7cdc43
					 << fixed
bw 7cdc43
					 << setprecision(8)
bw 249abc
					 << " " << current.k0
bw 249abc
					 << " " << current.k1
bw 249abc
					 << " " << current.k2
bw 249abc
					 << " " << value
bw 7cdc43
					 << " (" << finder->best << ")"
bw 249abc
					 << endl;
bw 249abc
			}
bw 249abc
		}
bw 249abc
bw 249abc
		double find() {
bw 249abc
			if (max_variants <= 0) return value;
bw 249abc
bw 7cdc43
			if (value < finder->best) finder->best = value;
bw 249abc
			report(true);
bw 249abc
bw 249abc
			int i[3];
bw 249abc
			for(i[0] = 0; i[0] < finder->sub_division; ++i[0])
bw 249abc
			for(i[1] = 0; i[1] < finder->sub_division; ++i[1])
bw 249abc
			for(i[2] = 0; i[2] < finder->sub_division; ++i[2]) {
bw 7cdc43
				Params p;
bw 7cdc43
				for(int j = 0; j < 3; ++j)
bw 7cdc43
					p.k[j] = (max.k[j] - min.k[j])/finder->sub_division*(i[j] + 0.5) + min.k[j];
bw 7cdc43
				finder->value(i[0], i[1], i[2]) = finder->checker.check2(p);
bw 7cdc43
			}
bw 7cdc43
bw 7cdc43
			finder->clear_zones();
bw 7cdc43
			for(i[0] = 1; i[0] < finder->sub_division-1; ++i[0])
bw 7cdc43
			for(i[1] = 1; i[1] < finder->sub_division-1; ++i[1])
bw 7cdc43
			for(i[2] = 1; i[2] < finder->sub_division-1; ++i[2])
bw 7cdc43
				if (finder->is_local_minimum(i[0], i[1], i[2])) {
bw 7cdc43
					Zone &z = finder->zone_for_value(i[0], i[1], i[2]);
bw 7cdc43
					double &v = finder->value(i[0], i[1], i[2]);
bw 7cdc43
					if (v < z.value) z.set(v, i);
bw 7cdc43
				}
bw 7cdc43
bw 7cdc43
			for(i[0] = 0; i[0] < finder->zone_count; ++i[0])
bw 7cdc43
			for(i[1] = 0; i[1] < finder->zone_count; ++i[1])
bw 7cdc43
			for(i[2] = 0; i[2] < finder->zone_count; ++i[2]) {
bw 7cdc43
				Zone &z = finder->zone(i[0], i[1], i[2]);
bw 7cdc43
				if (!isinf(z.value)) {
bw 7cdc43
					Entry sub;
bw 7cdc43
					sub.finder = finder;
bw 7cdc43
					sub.parent = this;
bw 7cdc43
					sub.level = level + 1;
bw 7cdc43
					sub.max_variants = max_variants/2;
bw 7cdc43
					if (sub.max_variants < 1) sub.max_variants = 1;
bw 7cdc43
					for(int j = 0; j < 3; ++j) {
bw 7cdc43
						sub.min.k[j]     = (max.k[j] - min.k[j])/finder->sub_division*(z.index[j] + 0.5 - finder->zone_size) + min.k[j];
bw 7cdc43
						sub.current.k[j] = (max.k[j] - min.k[j])/finder->sub_division*(z.index[j] + 0.5) + min.k[j];
bw 7cdc43
						sub.max.k[j]     = (max.k[j] - min.k[j])/finder->sub_division*(z.index[j] + 0.5 + finder->zone_size) + min.k[j];
bw 7cdc43
					}
bw 7cdc43
					sub.value = z.value;
bw 7cdc43
					add_variant(sub);
bw 249abc
				}
bw 249abc
			}
bw 249abc
bw 249abc
			if (level < finder->max_level) {
bw 249abc
				vector<entry> v(variants.begin(), variants.end());</entry>
bw 249abc
				variants.clear();
bw 249abc
				for(vector<entry>::iterator i = v.begin(); i != v.end(); ++i) {</entry>
bw 249abc
					i->index = i - v.begin();
bw 249abc
					i->find();
bw 249abc
					variants.insert(*i);
bw 249abc
				}
bw 249abc
			}
bw 249abc
bw 249abc
			if (!variants.empty() && variants.begin()->value < value) {
bw 249abc
				value = variants.begin()->value;
bw 249abc
				current = variants.begin()->current;
bw 249abc
			}
bw 249abc
bw 7cdc43
			if (value < finder->best) finder->best = value;
bw 249abc
			report(false);
bw 249abc
			return value;
bw 249abc
		}
bw 249abc
	};
bw 249abc
bw 7cdc43
	struct Zone {
bw 7cdc43
		double value;
bw 7cdc43
		int index[3];
bw 7cdc43
bw 7cdc43
		Zone() { clear(); }
bw 7cdc43
		void clear() { value = INFINITY; memset(index, 0, sizeof(index)); }
bw 7cdc43
		void set(double value, int *i) { this->value = value; memcpy(index, i, sizeof(index)); }
bw 7cdc43
	};
bw 7cdc43
bw 249abc
	Checker checker;
bw 249abc
bw 249abc
	int sub_division;
bw 7cdc43
	int zone_count;
bw 7cdc43
	int zone_size;
bw 7cdc43
	int s0;
bw 7cdc43
	int s1;
bw 7cdc43
	int s2;
bw 249abc
	int max_level;
bw 249abc
	int max_report_level;
bw 7cdc43
	vector<double> values;</double>
bw 7cdc43
	vector<zone> zones;</zone>
bw 249abc
bw 7cdc43
	double best;
bw 249abc
	Entry root;
bw 249abc
bw 249abc
	Finder(
bw 249abc
		double radius,
bw 249abc
		Params min,
bw 249abc
		Params max,
bw 7cdc43
		int zone_count,
bw 7cdc43
		int zone_size,
bw 249abc
		int max_variants,
bw 249abc
		int max_level,
bw 249abc
		int max_report_level
bw 249abc
	):
bw 249abc
		checker(radius),
bw 7cdc43
		sub_division(zone_count*zone_size),
bw 7cdc43
		zone_count(zone_count),
bw 7cdc43
		zone_size(zone_size),
bw 7cdc43
		s0(1),
bw 7cdc43
		s1(sub_division),
bw 7cdc43
		s2(sub_division*sub_division),
bw 249abc
		max_level(max_level),
bw 7cdc43
		max_report_level(max_report_level),
bw 7cdc43
		values(sub_division*sub_division*sub_division),
bw 7cdc43
		zones(zone_count*zone_count*zone_count),
bw 7cdc43
		best(INFINITY)
bw 249abc
	{
bw 249abc
		root.finder = this;
bw 249abc
		root.min = min;
bw 249abc
		root.max = max;
bw 249abc
		root.max_variants = max_variants;
bw 249abc
	}
bw 249abc
bw 249abc
	double find() {
bw 249abc
		for(int j = 0; j < 3; ++j)
bw 249abc
			root.current.k[j] = 0.5*(root.max.k[j] - root.min.k[j]) + root.min.k[j];
bw 249abc
		root.value = checker.check2(root.current);
bw 7cdc43
		best = root.value;
bw 249abc
		return root.find();
bw 249abc
	}
bw 7cdc43
bw 7cdc43
	double& value(int i0, int i1, int i2)
bw 7cdc43
		{ return values[i0*s0 + i1*s1 + i2*s2]; }
bw 7cdc43
bw 7cdc43
	bool is_local_minimum(int i0, int i1, int i2) {
bw 7cdc43
		double *vp = &value(i0, i1, i2);
bw 7cdc43
		double v = *vp;
bw 7cdc43
		return v < *(vp-s0) && v <= *(vp+s0)
bw 7cdc43
			&& v < *(vp-s1) && v <= *(vp+s1)
bw 7cdc43
			&& v < *(vp-s2) && v <= *(vp+s2);
bw 7cdc43
	}
bw 7cdc43
bw 7cdc43
	Zone& zone_for_value(int i0, int i1, int i2)
bw 7cdc43
		{ return zones[(i2/zone_size*zone_count + i1/zone_size)*zone_count + i0/zone_size]; }
bw 7cdc43
	Zone& zone(int i0, int i1, int i2)
bw 7cdc43
		{ return zones[(i2*zone_count + i1)*zone_count + i0]; }
bw 7cdc43
bw 7cdc43
	void clear_zones() {
bw 7cdc43
		for(vector<zone>::iterator i = zones.begin(); i != zones.end(); ++i)</zone>
bw 7cdc43
			i->clear();
bw 7cdc43
	}
bw 249abc
};
bw 249abc
bw 249abc
double find_near(Checker &checker, double step, Params ¶ms) {
bw 249abc
	double best_value = checker.check2(params);
bw 249abc
	Params best_params = params;
bw 249abc
	while(true) {
bw 249abc
		bool found = false;
bw 249abc
		for(int i = 0; i < 3; ++i) {
bw 249abc
			for(int j = -1; j <= 1; j += 2) {
bw 249abc
				Params p = params;
bw 249abc
				p.k[i] += j*step;
bw 249abc
				double v = checker.check2(p);
bw 249abc
				if (v < best_value) { best_value = v; best_params = p; }
bw 249abc
			}
bw 249abc
		}
bw 249abc
		if (found) params = best_params; else break;
bw 249abc
	}
bw 249abc
	return best_value;
bw 249abc
}
bw 249abc
bw 7cdc43
double find_near2(Checker &checker, double step, Params ¶ms) {
bw 7cdc43
	Finder finder(
bw 7cdc43
		checker.radius,
bw 7cdc43
		Params(params.k0-step, params.k1-step, params.k2-step),
bw 7cdc43
		Params(params.k0+step, params.k1+step, params.k2+step),
bw 7cdc43
		4,
bw 7cdc43
		4,
bw d8ace3
		1,
bw 7cdc43
		16,
bw 7cdc43
		1
bw 7cdc43
	);
bw 7cdc43
	finder.find();
bw 7cdc43
	params = finder.root.current;
bw 7cdc43
	return finder.root.value;
bw 7cdc43
}
bw 7cdc43
bw d8ace3
double find_near3(Checker &checker, double step, Params ¶ms) {
bw d8ace3
	Finder finder(
bw d8ace3
		checker.radius,
bw d8ace3
		Params(params.k0-step, params.k1-step, params.k2-step),
bw d8ace3
		Params(params.k0+step, params.k1+step, params.k2+step),
bw d8ace3
		8,
bw d8ace3
		8,
bw d8ace3
		1,
bw d8ace3
		10,
bw d8ace3
		4
bw d8ace3
	);
bw d8ace3
	finder.find();
bw d8ace3
	params = finder.root.current;
bw d8ace3
	return finder.root.value;
bw d8ace3
}
bw d8ace3
bw d8ace3
double initial_find(Checker &checker, Params ¶ms) {
bw d8ace3
	Finder finder(
bw d8ace3
		checker.radius,
bw d8ace3
		Params(0, 0, -1),
bw d8ace3
		Params(1, 1, 1),
bw d8ace3
		16,
bw d8ace3
		16,
bw d8ace3
		1,
bw d8ace3
		4,
bw d8ace3
		8
bw d8ace3
	);
bw d8ace3
	finder.find();
bw d8ace3
	params = finder.root.current;
bw d8ace3
	return finder.root.value;
bw d8ace3
}
bw d8ace3
bw d8ace3
map< double, pair<params, double=""> > coefs;</params,>
bw d8ace3
bw d8ace3
double fix_radius(double r)
bw d8ace3
	{ return round(r/step)*step; }
bw d8ace3
bw 249abc
void log_begin() {
bw 249abc
	ofstream f(logfile, ios_base::app);
bw d8ace3
	f << endl << "double coefs[][5] = {" << endl;
bw 249abc
}
bw 249abc
bw 7cdc43
void log_params(double radius, const Params ¶ms, double value) {
bw 249abc
	ofstream f(logfile, ios_base::app);
bw 249abc
	f << "    { " << radius
bw d8ace3
	  << setprecision(20)
bw 249abc
	  << ", "     << params.k0
bw d8ace3
	  << ", "     << fabs(params.k1)
bw 249abc
	  << ", "     << params.k2
bw 249abc
	  << ", "     << value
bw 249abc
	  << " },"    << endl;
bw 249abc
	cout << endl;
bw d8ace3
	coefs[fix_radius(radius)].first = params;
bw d8ace3
	coefs[fix_radius(radius)].second = value;
bw 249abc
}
bw 249abc
bw 249abc
void log_params(const Checker &checker, const Params ¶ms, double value) {
bw 7cdc43
	log_params(checker.radius, params, value);
bw 249abc
}
bw 249abc
bw 249abc
void log_params(const Finder &finder) {
bw 249abc
	log_params(finder.checker, finder.root.current, finder.root.value);
bw 249abc
}
bw 249abc
bw 249abc
void log_end() {
bw 249abc
	ofstream f(logfile, ios_base::app);
bw 249abc
	f << "};" << endl << endl;
bw 249abc
}
bw 249abc
bw d8ace3
bw 249abc
void graph(Checker &checker, const Params ¶ms) {
bw 249abc
	int ri = roundf(checker.radius);
bw 249abc
	if (fabs(checker.radius - ri) > 1e-5) return;
bw 249abc
bw 249abc
	bool is_power_of_two = false;
bw 249abc
	for(int i = 1; i <= 4096; i *= 2)
bw 249abc
		if (ri == i) is_power_of_two = true;
bw 249abc
bw 249abc
	if (!is_power_of_two && ri%16 != 0)
bw 249abc
		return;
bw 249abc
bw 249abc
	checker.check2(params);
bw 249abc
	checker.graph(strprintf("iir_%04d.tga", ri));
bw 249abc
}
bw 249abc
bw 7cdc43
void test() {
bw 7cdc43
	Checker checker(16);
bw 7cdc43
	Params p(0.9304775714874, -0.02728819847107, 0.9257968425751);
bw 7cdc43
	cout << fixed << setprecision(8) << checker.check2(p) << endl;
bw 7cdc43
	checker.graph("test.tga");
bw 7cdc43
}
bw 7cdc43
bw d8ace3
void walk(
bw d8ace3
	double current_radius,
bw d8ace3
	double target_radius,
bw d8ace3
	double step,
bw d8ace3
	double large_params_step,
bw d8ace3
	double params_step,
bw d8ace3
	Params params
bw d8ace3
) {
bw d8ace3
	cout << "walk from " << current_radius << " to "<< target_radius << endl;
bw d8ace3
	step = fabs(step);
bw d8ace3
	if (target_radius < current_radius) step = -step;
bw d8ace3
bw d8ace3
	Params p = params;
bw d8ace3
	{ Checker checker(current_radius); find_near3(checker, large_params_step, p); }
bw d8ace3
	for(double r = current_radius; (target_radius - r)/step > -0.5; r += step) {
bw d8ace3
		Checker checker(r);
bw d8ace3
		cout << "   " << r << endl;
bw d8ace3
bw d8ace3
		double value = find_near2(checker, params_step, p);
bw d8ace3
		if (value > threshold) {
bw d8ace3
			value = find_near3(checker, large_params_step, p);
bw d8ace3
			value = find_near2(checker, params_step, p);
bw d8ace3
		}
bw d8ace3
		if (value > threshold) {
bw d8ace3
			value = initial_find(checker, p);
bw d8ace3
			value = find_near3(checker, large_params_step, p);
bw d8ace3
			value = find_near2(checker, params_step, p);
bw d8ace3
		}
bw d8ace3
bw d8ace3
		value = checker.check2(p);
bw d8ace3
		graph(checker, p);
bw d8ace3
		log_params(checker, p, value);
bw 249abc
bw d8ace3
		cout << "  " << r
bw d8ace3
			 << " " << p.k0
bw d8ace3
			 << " " << p.k1
bw d8ace3
			 << " " << p.k2
bw d8ace3
			 << " " << value
bw d8ace3
			 << endl;
bw d8ace3
	}
bw d8ace3
}
bw d8ace3
bw d8ace3
void find_initial_params() {
bw 249abc
	cout << "find initial params" << endl;
bw 249abc
	Finder finder(
bw 249abc
		initial_radius,
bw d8ace3
		Params(0, 0, -1),
bw d8ace3
		Params(1, 1,  1),
bw 7cdc43
		16,
bw 7cdc43
		16,
bw 249abc
		1,
bw 7cdc43
		4,
bw 7cdc43
		8
bw 249abc
	);
bw 249abc
bw 249abc
	finder.find();
bw 7cdc43
	cout << finder.checker.check2(finder.root.current) << endl;
bw d8ace3
	cout << find_near3(finder.checker, large_params_step, finder.root.current) << endl;
bw 249abc
	graph(finder.checker, finder.root.current);
bw 249abc
	log_params(finder);
bw d8ace3
}
bw 249abc
bw d8ace3
void save_coefs(const string &filename, const map< double, pair<params, double=""> > &coefs) {</params,>
bw d8ace3
	ofstream f(filename.c_str(), ios_base::out | ios_base::trunc);
bw d8ace3
	f << endl << "double coefs[][5] = {" << endl;
bw d8ace3
	for(map< double, pair<params, double=""> >::const_iterator i = coefs.begin(); i != coefs.end(); ++i)</params,>
bw d8ace3
		f << "    { " << i->first
bw d8ace3
		  << setprecision(20)
bw d8ace3
		  << ", "     << i->second.first.k0
bw d8ace3
		  << ", "     << fabs(i->second.first.k1)
bw d8ace3
		  << ", "     << i->second.first.k2
bw d8ace3
		  << ", "     << i->second.second
bw d8ace3
		  << " },"    << endl;
bw d8ace3
	f << "};" << endl << endl;
bw d8ace3
}
bw 249abc
bw d8ace3
void save_coefs2(const string &filename, const map< double, pair<params, double=""> > &coefs) {</params,>
bw d8ace3
	ofstream f(filename.c_str(), ios_base::out | ios_base::trunc);
bw d8ace3
	f << endl;
bw d8ace3
	f << "double min_radius = " << min_radius << endl;
bw d8ace3
	f << "double max_radius = " << max_radius << endl;
bw d8ace3
	f << "double step = " << step << endl;
bw d8ace3
	f << "double coefs[][3] = {" << endl;
bw d8ace3
	for(double r = min_radius; r < max_radius + 0.5*step; r += step) {
bw d8ace3
		Params p = coefs.count(fix_radius(r)) ? coefs.find(fix_radius(r))->second.first : Params(0.5, 0.0, 0.5);
bw d8ace3
		f << "    " << setprecision(20)
bw d8ace3
		  << "{ "   << p.k0
bw d8ace3
		  << ", "   << fabs(p.k1)
bw d8ace3
		  << ", "   << p.k2
bw d8ace3
		  << " },"  << endl;
bw d8ace3
	}
bw d8ace3
	f << "};" << endl << endl;
bw d8ace3
}
bw 249abc
bw d8ace3
void check_coefs() {
bw d8ace3
	if (coefs.size() < 3) return;
bw d8ace3
bw d8ace3
	cout << "check coefs:" << endl;
bw d8ace3
	map< double, pair<params, double=""> >::const_iterator i = coefs.begin();</params,>
bw d8ace3
	Params p2 = i->second.first; ++i; p2.k1 = fabs(p2.k1);
bw d8ace3
	Params p1 = i->second.first; ++i; p1.k1 = fabs(p1.k1);
bw d8ace3
	while(i != coefs.end()) {
bw d8ace3
		double r = i->first;
bw d8ace3
		Params p0 = i->second.first; ++i; p0.k1 = fabs(p0.k1);
bw d8ace3
bw d8ace3
		for(int i = 0; i < 3; ++i)
bw d8ace3
			if (fabs(p0.k[i] - p1.k[i]) > 2.0*fabs(p1.k[i] - p2.k[i]) && fabs(p0.k[i] - p1.k[i]) > 0.0000005)
bw d8ace3
				cout << "  big step for k" << i << " for radius " << r << ": " << fabs(p0.k[i] - p1.k[i]) << endl;
bw d8ace3
bw d8ace3
		p2 = p1;
bw d8ace3
		p1 = p0;
bw 249abc
	}
bw d8ace3
	cout << "check coefs complete" << endl;
bw d8ace3
}
bw 249abc
bw d8ace3
void load_coefs(const string &filename, map< double, pair<params, double=""> > &coefs) {</params,>
bw d8ace3
	cout << "loading..."<< endl;
bw d8ace3
	ifstream f(filename.c_str());
bw d8ace3
	while(f) {
bw d8ace3
		string line;
bw d8ace3
		getline(f, line);
bw d8ace3
		stringstream s(line);
bw 249abc
bw d8ace3
		string w[6];
bw d8ace3
		double radius = 0, value = 0;
bw d8ace3
		Params p;
bw d8ace3
		s >> w[0] >> radius
bw d8ace3
		  >> w[1] >> p.k0
bw d8ace3
		  >> w[2] >> p.k1
bw d8ace3
		  >> w[3] >> p.k2
bw d8ace3
		  >> w[4] >> value
bw d8ace3
		  >> w[5];
bw d8ace3
bw d8ace3
		if ( w[0] == "{"
bw d8ace3
		  && w[1] == ","
bw d8ace3
		  && w[2] == ","
bw d8ace3
		  && w[3] == ","
bw d8ace3
		  && w[4] == ","
bw d8ace3
	  	  && w[5] == "},"
bw d8ace3
	  	  && radius + 0.5*step > min_radius
bw d8ace3
		  && radius - 0.5*step < max_radius
bw d8ace3
		  && fabs(radius - fix_radius(radius)) < 1e-5 )
bw d8ace3
		{
bw d8ace3
			radius = fix_radius(radius);
bw d8ace3
			Checker checker(radius);
bw d8ace3
			double v = checker.check2(p);
bw d8ace3
			if (fabs(value - v) > 1e-5)
bw d8ace3
				cout << "  loading: wrong value for radius " << radius << " (" << value << " vs " << v << ")"<< endl;
bw d8ace3
bw d8ace3
			if (!coefs.count(radius) || v < coefs[radius].second) {
bw d8ace3
				coefs[radius].first = p;
bw d8ace3
				coefs[radius].second = v;
bw d8ace3
			}
bw d8ace3
		}
bw d8ace3
	}
bw d8ace3
	cout << "done"<< endl;
bw d8ace3
}
bw 249abc
bw d8ace3
bool is_valid_coefs(double radius) {
bw d8ace3
	return coefs.count(fix_radius(radius)) && coefs[fix_radius(radius)].second < threshold;
bw d8ace3
}
bw d8ace3
bw d8ace3
void build_diapasones_down(map<double, double=""> &diapasones) {</double,>
bw d8ace3
	bool valid = true;
bw d8ace3
	double begin = initial_radius;
bw d8ace3
	double end = begin;
bw d8ace3
	for(double r = initial_radius; r > min_radius - 0.5*step; r -= step) {
bw d8ace3
		bool v = is_valid_coefs(r);
bw d8ace3
		if (!valid && v)
bw d8ace3
			diapasones[begin] = end;
bw d8ace3
		if (v) begin = r; else end = r;
bw d8ace3
		valid = v;
bw 249abc
	}
bw d8ace3
	if (!valid) diapasones[begin] = end;
bw d8ace3
}
bw 249abc
bw d8ace3
void build_diapasones_up(map<double, double=""> &diapasones) {</double,>
bw d8ace3
	bool valid = true;
bw d8ace3
	double begin = initial_radius;
bw d8ace3
	double end = begin;
bw d8ace3
	for(double r = initial_radius; r < max_radius + 0.5*step; r += step) {
bw d8ace3
		bool v = is_valid_coefs(r);
bw d8ace3
		if (!valid && v)
bw d8ace3
			diapasones[begin] = end;
bw d8ace3
		if (v) begin = r; else end = r;
bw d8ace3
		valid = v;
bw d8ace3
	}
bw d8ace3
	if (!valid) diapasones[begin] = end;
bw 249abc
}
bw 249abc
bw d8ace3
void process() {
bw d8ace3
	log_begin();
bw d8ace3
bw d8ace3
	load_coefs(logfile, coefs);
bw d8ace3
	save_coefs(final_coefs_file, coefs);
bw d8ace3
	save_coefs2(final_coefs_file2, coefs);
bw d8ace3
	check_coefs();
bw 249abc
bw d8ace3
	if (!is_valid_coefs(initial_radius))
bw d8ace3
		find_initial_params();
bw d8ace3
bw d8ace3
	cout << "diapasones to find:" << endl;
bw d8ace3
	map<double, double=""> diapasones;</double,>
bw d8ace3
	build_diapasones_down(diapasones);
bw d8ace3
	build_diapasones_up(diapasones);
bw d8ace3
	for(map<double, double="">::const_iterator i = diapasones.begin(); i != diapasones.end(); ++i)</double,>
bw d8ace3
		cout << "  " << i->first << " " << i->second << endl;
bw d8ace3
bw d8ace3
	cout << "process diapasones:" << endl;
bw d8ace3
	for(map<double, double="">::const_iterator i = diapasones.begin(); i != diapasones.end(); ++i)</double,>
bw d8ace3
		walk(i->first, i->second, step, large_params_step, params_step, coefs[fix_radius(i->first)].first);
bw d8ace3
bw d8ace3
	log_end();
bw d8ace3
	save_coefs(final_coefs_file, coefs);
bw d8ace3
	save_coefs2(final_coefs_file2, coefs);
bw d8ace3
	check_coefs();
bw d8ace3
}
bw 249abc
bw 249abc
int main() {
bw 7cdc43
	test();
bw 249abc
	process();
bw 249abc
}