|
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 |
}
|