Blame c++/iir_blur/iir_blur.cpp

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 249abc
#include <vector></vector>
bw 249abc
#include <set></set>
bw 249abc
bw 249abc
#include "surface.h"
bw 249abc
bw 249abc
bw 249abc
using namespace std;
bw 249abc
bw 249abc
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
bw 249abc
const double pi = 3.14159265358979323846;
bw 249abc
const char logfile[] = "results/coef.log";
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 249abc
	int maxi;
bw 249abc
	double maxv;
bw 249abc
	bool valid;
bw 249abc
	double radius;
bw 249abc
bw 249abc
	Checker(double radius): maxi(), maxv(), valid(), radius(radius) {
bw 249abc
		blank.resize((int)ceil(radius*10));
bw 249abc
		tmp.resize(blank.size());
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 249abc
		p.k0 = -(a*a + 2.0*c*b)/(c*a*a);
bw 249abc
		p.k1 = (c + 2.0*b)/(c*a*a);
bw 249abc
		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 249abc
		  || 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 249abc
		return check(convert_params(params), true);
bw 249abc
	}
bw 249abc
bw 249abc
	double check(const Params ¶ms, bool mode3a = true) {
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 (!mode3a && fabs(params.k1 + params.k2/(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 249abc
		maxv = 1.0 - params.k0 - params.k1 - params.k2;
bw 249abc
		int offset = 3;
bw 249abc
		maxi = offset;
bw 249abc
		tmp[offset] = 1.0;
bw 249abc
		for(int i = offset; i < (int)tmp.size(); ++i) {
bw 249abc
			if (mode3a)
bw 249abc
				tmp[i] = (i == offset ? maxv : 0.0)
bw 249abc
					   + params.k0*tmp[i-1]
bw 249abc
					   + params.k1*tmp[i-2]
bw 249abc
					   + params.k2*tmp[i-3];
bw 249abc
			else
bw 249abc
				tmp[i] = (i == offset ? 1.0 : 0.0)
bw 249abc
					   + (i-1 == offset ? params.k0 : 0.0)
bw 249abc
					   + params.k1*tmp[i-1]
bw 249abc
					   + params.k2*tmp[i-2];
bw 249abc
			if (i < (int)tmp.size()/2 && maxv < tmp[i]) { maxv = tmp[i]; maxi = i; }
bw 249abc
		}
bw 249abc
bw 249abc
		//if (maxv < 1e-20 || isnan(maxv)) return INFINITY;
bw 249abc
		//maxi = (int)round(radius) + offset;
bw 249abc
bw 249abc
		//double k = blank[0]/maxv;
bw 249abc
		double delta = 0.0;
bw 249abc
		for(int i = maxi; i < (int)tmp.size(); ++i) {
bw 249abc
			double t = tmp[i];
bw 249abc
			//double d = blank[i - maxi] - t;
bw 249abc
			//delta += d*d;
bw 249abc
			//if (t < 0) delta += 5*d*d;
bw 249abc
			delta += fabs(blank[i - maxi] - t);
bw 249abc
			if (t < 0) delta += fabs(t);
bw 249abc
		}
bw 249abc
bw 249abc
		if (isinf(delta) || isnan(delta)) return INFINITY;
bw 249abc
bw 249abc
		valid = true;
bw 249abc
		return delta;
bw 249abc
	}
bw 249abc
bw 249abc
bw 249abc
	void graph(const string &filename) {
bw 249abc
		int count = blank.size();
bw 249abc
		int scale = 256/count + 1;
bw 249abc
bw 249abc
		int pad = max(16, count/8);
bw 249abc
		int gw = count*scale;
bw 249abc
		int gh = gw;
bw 249abc
bw 249abc
		Surface::Color axis = Surface::convert_color(0, 0, 0, 1);
bw 249abc
		Surface::Color ca = Surface::convert_color(0, 0, 1, 0.75);
bw 249abc
		Surface::Color cb = Surface::convert_color(1, 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 249abc
			s.line_to(pad + i*scale, 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 249abc
			for(int i = 0; i < count - maxi; ++i)
bw 249abc
				s.line_to(pad + i*scale, pad + (int)round((1.0 - tmp[i + maxi]/maxv)*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 249abc
				cout << (open ? " begin" : " end")
bw 249abc
					 << " " << current.k0
bw 249abc
					 << " " << current.k1
bw 249abc
					 << " " << current.k2
bw 249abc
					 << " " << value
bw 249abc
					 << endl;
bw 249abc
			}
bw 249abc
		}
bw 249abc
bw 249abc
		double find() {
bw 249abc
			if (max_variants <= 0) return value;
bw 249abc
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 249abc
				Entry sub;
bw 249abc
				sub.finder = finder;
bw 249abc
				sub.parent = this;
bw 249abc
				sub.level = level + 1;
bw 249abc
				sub.max_variants = max_variants/4;
bw 249abc
				if (sub.max_variants < 1) sub.max_variants = 1;
bw 249abc
				for(int j = 0; j < 3; ++j) {
bw 249abc
					sub.min.k[j]     = (max.k[j] - min.k[j])/finder->sub_division*(i[j] + 0.5 - 4.0) + min.k[j];
bw 249abc
					sub.current.k[j] = (max.k[j] - min.k[j])/finder->sub_division*(i[j] + 0.5 + 0.0) + min.k[j];
bw 249abc
					sub.max.k[j]     = (max.k[j] - min.k[j])/finder->sub_division*(i[j] + 0.5 + 4.0) + min.k[j];
bw 249abc
				}
bw 249abc
				sub.value = finder->checker.check2(sub.current);
bw 249abc
				add_variant(sub);
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 249abc
			report(false);
bw 249abc
			return value;
bw 249abc
		}
bw 249abc
	};
bw 249abc
bw 249abc
	Checker checker;
bw 249abc
bw 249abc
	int sub_division;
bw 249abc
	int max_level;
bw 249abc
	int max_report_level;
bw 249abc
bw 249abc
	Entry root;
bw 249abc
bw 249abc
	Finder(
bw 249abc
		double radius,
bw 249abc
		Params min,
bw 249abc
		Params max,
bw 249abc
		int sub_division,
bw 249abc
		int max_variants,
bw 249abc
		int max_level,
bw 249abc
		int max_report_level
bw 249abc
	):
bw 249abc
		checker(radius),
bw 249abc
		sub_division(sub_division),
bw 249abc
		max_level(max_level),
bw 249abc
		max_report_level(max_report_level)
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 249abc
		return root.find();
bw 249abc
	}
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 249abc
void log_begin() {
bw 249abc
	ofstream f(logfile, ios_base::app);
bw 249abc
	f << endl << "double coefs[][7] = {" << endl;
bw 249abc
}
bw 249abc
bw 249abc
void log_params(double radius, int maxi, double maxv, const Params ¶ms, double value) {
bw 249abc
	ofstream f(logfile, ios_base::app);
bw 249abc
	f << "    { " << radius
bw 249abc
	  << ", "     << maxi
bw 249abc
	  << setprecision(13)
bw 249abc
	  << ", "     << maxv
bw 249abc
	  << ", "     << params.k0
bw 249abc
	  << ", "     << params.k1
bw 249abc
	  << ", "     << params.k2
bw 249abc
	  << ", "     << value
bw 249abc
	  << " },"    << endl;
bw 249abc
	cout << endl;
bw 249abc
}
bw 249abc
bw 249abc
void log_params(const Checker &checker, const Params ¶ms, double value) {
bw 249abc
	log_params(checker.radius, checker.maxi, checker.maxv, 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 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 249abc
void process() {
bw 249abc
	const double initial_radius = 8.0;
bw 249abc
	//const double min_radius = 1.0;
bw 249abc
	//const double max_radius = 2048;
bw 249abc
	//const double step = 0.1;
bw 249abc
	//const double params_step = 1e-7;
bw 249abc
bw 249abc
	cout << "find initial params" << endl;
bw 249abc
	Finder finder(
bw 249abc
		initial_radius,
bw 249abc
		Params( 0.25, -1, -1),
bw 249abc
		Params( 1,  1,  1),
bw 249abc
		256,
bw 249abc
		1,
bw 249abc
		3,
bw 249abc
		5
bw 249abc
	);
bw 249abc
bw 249abc
	finder.find();
bw 249abc
	finder.checker.check2(finder.root.current);
bw 249abc
	graph(finder.checker, finder.root.current);
bw 249abc
bw 249abc
	log_begin();
bw 249abc
	log_params(finder);
bw 249abc
bw 249abc
	/*
bw 249abc
	cout << "walk back" << endl;
bw 249abc
	Params params = finder.root.current;
bw 249abc
	for(double r = finder.checker.radius; r > min_radius - 0.5*step; r -= step) {
bw 249abc
		Checker checker(r);
bw 249abc
		cout << "   " << r << flush;
bw 249abc
bw 249abc
		double value = find_near(checker, params_step, params);
bw 249abc
		graph(checker, params);
bw 249abc
bw 249abc
		cout << " " << params.k0
bw 249abc
			 << " " << params.k1
bw 249abc
			 << " " << params.k2
bw 249abc
			 << " " << value
bw 249abc
			 << endl;
bw 249abc
	}
bw 249abc
bw 249abc
	cout << "walk forward" << endl;
bw 249abc
	params = finder.root.current;
bw 249abc
	for(double r = finder.checker.radius; r < max_radius + 0.5*step; r += step) {
bw 249abc
		Checker checker(r);
bw 249abc
		cout << "   " << r << flush;
bw 249abc
bw 249abc
		double value = find_near(checker, params_step, params);
bw 249abc
		graph(checker, params);
bw 249abc
bw 249abc
		cout << " " << params.k0
bw 249abc
			 << " " << params.k1
bw 249abc
			 << " " << params.k2
bw 249abc
			 << " " << value
bw 249abc
			 << endl;
bw 249abc
	}
bw 249abc
	*/
bw 249abc
bw 249abc
	log_end();
bw 249abc
}
bw 249abc
bw 249abc
bw 249abc
bw 249abc
int main() {
bw 249abc
	process();
bw 249abc
bw 249abc
	/*
bw 249abc
	string logfile = "results/coef.log";
bw 249abc
bw 249abc
	{ ofstream f(logfile.c_str(), ios_base::app); f << endl << "double coefs[][7] = {" << endl; }
bw 249abc
bw 249abc
	Params prev(0.914, 0.129, -0.216);
bw 249abc
	for(double r = 4.0; r < 2048.1; r *= pow(2.0, 0.125)) {
bw 249abc
		cout << endl;
bw 249abc
		cout << "find coefficients for radius " << r << endl;
bw 249abc
bw 249abc
		double x = 0.1*log2(r)/2;
bw 249abc
bw 249abc
		Finder finder(
bw 249abc
			r,
bw 249abc
			Params(prev.k0 - x, prev.k1 - x, prev.k2 - x),
bw 249abc
			Params(prev.k0 + x, prev.k1 + x, prev.k2 + x),
bw 249abc
			128,
bw 249abc
			1,
bw 249abc
			3,
bw 249abc
			5
bw 249abc
		);
bw 249abc
bw 249abc
		finder.find();
bw 249abc
		finder.checker.check(finder.root.current);
bw 249abc
		finder.checker.graph(strprintf("iir_%08.3f.tga", finder.checker.radius));
bw 249abc
bw 249abc
		ofstream f(logfile.c_str(), ios_base::app);
bw 249abc
		f << "    { " << finder.checker.radius
bw 249abc
		  << ", "     << finder.checker.maxi
bw 249abc
		  << setprecision(20)
bw 249abc
		  << ", "     << finder.checker.maxv
bw 249abc
		  << ", "     <<  finder.root.current.k0
bw 249abc
		  << ", "     << finder.root.current.k1
bw 249abc
		  << ", "     << finder.root.current.k2
bw 249abc
		  << ", "     << finder.root.value
bw 249abc
		  << " },"    << endl;
bw 249abc
		cout << endl;
bw 249abc
bw 249abc
		prev = finder.root.current;
bw 249abc
	}
bw 249abc
bw 249abc
	{ ofstream f(logfile.c_str(), ios_base::app); f << "};" << endl << endl; }
bw 249abc
	*/
bw 249abc
}