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 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 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 7cdc43
		4,
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 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 7cdc43
void log_params(double radius, const Params ¶ms, double value) {
bw 249abc
	ofstream f(logfile, ios_base::app);
bw 249abc
	f << "    { " << radius
bw 249abc
	  << setprecision(13)
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 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 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 249abc
void process() {
bw 7cdc43
	const double initial_radius = 16.0;
bw 7cdc43
	const double min_radius = 1.0;
bw 7cdc43
	const double max_radius = 2048;
bw 7cdc43
	const double step = 0.1;
bw 7cdc43
	const double params_step = 0.05;
bw 249abc
bw 249abc
	cout << "find initial params" << endl;
bw 249abc
	Finder finder(
bw 249abc
		initial_radius,
bw 7cdc43
		Params(0, -1, -1),
bw 7cdc43
		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 7cdc43
	cout << find_near(finder.checker, params_step, finder.root.current) << endl;
bw 249abc
	graph(finder.checker, finder.root.current);
bw 249abc
bw 249abc
	log_begin();
bw 249abc
	log_params(finder);
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 7cdc43
		cout << "   " << r << endl;
bw 249abc
bw 7cdc43
		double value = find_near2(checker, params_step, params);
bw 7cdc43
		checker.check2(params);
bw 249abc
		graph(checker, params);
bw 7cdc43
		if (abs(round(r*10) - r*10) < 1e-10)
bw 7cdc43
			log_params(checker, params, value);
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 7cdc43
		cout << "   " << r << endl;
bw 249abc
bw 7cdc43
		double value = find_near2(checker, params_step, params);
bw 249abc
		graph(checker, params);
bw 7cdc43
		checker.check2(params);
bw 7cdc43
		if (abs(round(r*10) - r*10) < 1e-10)
bw 7cdc43
			log_params(checker, params, value);
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
	log_end();
bw 249abc
}
bw 249abc
bw 249abc
bw 249abc
bw 249abc
int main() {
bw 7cdc43
	test();
bw 249abc
	process();
bw 249abc
}