88 typedef std::array<size_t, NDim> index;
90 explicit grid_iterator(
const std::array<size_t, NDim>& dims)
94 std::fill(i.begin(), i.end(), 0);
98 explicit grid_iterator(
size_t dim)
101 std::fill(N.begin(), N.end(), dim);
102 std::fill(i.begin(), i.end(), 0);
106 size_t operator[](
size_t d)
const
111 const index& operator*()
const
116 size_t position()
const
121 grid_iterator& operator++()
124 for (
size_t d = NDim; d--;) {
137 operator bool()
const {
return !done; }
265 typedef typename control_lattice<NDim>::index index;
266 typedef typename control_lattice<NDim>::point point;
268 template <
class CooIter,
class ValIter>
269 control_lattice_dense(
270 const point& coo_min,
const point& coo_max, index grid_size,
271 CooIter coo_begin, CooIter coo_end, ValIter val_begin)
276 for (
unsigned i = 0; i < NDim; ++i) {
277 hinv[i] = (grid[i] - 1) / (cmax[i] - cmin[i]);
278 cmin[i] -= 1 / hinv[i];
282 boost::multi_array<double, NDim> delta(grid);
283 boost::multi_array<double, NDim> omega(grid);
285 std::fill(delta.data(), delta.data() + delta.num_elements(), 0.0);
286 std::fill(omega.data(), omega.data() + omega.num_elements(), 0.0);
288 CooIter p = coo_begin;
289 ValIter v = val_begin;
291 for (; p != coo_end; ++p, ++v) {
292 if (!boxed(coo_min, *p, coo_max))
298 for (
unsigned d = 0; d < NDim; ++d) {
299 double u = ((*p)[d] - cmin[d]) * hinv[d];
304 std::array<double, power<4, NDim>::value> w;
309 for (
unsigned k = 0; k < NDim; ++k)
310 prod *= Bspline(d[k], s[k]);
312 w[d.position()] = prod;
313 sum_w2 += prod * prod;
317 double w1 = w[d.position()];
319 double phi = (*v) * w1 / sum_w2;
323 delta(j) += w2 * phi;
331 delta.data(), delta.data() + delta.num_elements(),
332 omega.data(), phi.data(), safe_divide);
335 double operator()(
const point& p)
const
340 for (
unsigned d = 0; d < NDim; ++d) {
341 double u = (p[d] - cmin[d]) * hinv[d];
350 for (
unsigned k = 0; k < NDim; ++k)
351 w *= Bspline(d[k], s[k]);
353 f += w * phi(i + (*d));
359 void report(std::ostream& os)
const
361 boost::io::ios_all_saver stream_state(os);
363 os <<
"dense [" << grid[0];
364 for (
unsigned i = 1; i < NDim; ++i)
365 os <<
", " << grid[i];
366 os <<
"] (" << phi.num_elements() *
sizeof(double) <<
" bytes)";
369 void append_refined(
const control_lattice_dense& r)
371 static const std::array<double, 5> s = {
372 0.125, 0.500, 0.750, 0.500, 0.125
376 double f = r.phi(*i);
384 for (
unsigned k = 0; k < NDim; ++k) {
385 j[k] = 2 * i[k] + d[k] - 3;
386 if (j[k] >= grid[k]) {
396 for (
unsigned k = 0; k < NDim; ++k)
404 double fill_ratio()
const
406 size_t total = phi.num_elements();
407 size_t nonzeros = total - std::count(phi.data(), phi.data() + total, 0.0);
409 return static_cast<double>(nonzeros) / total;
414 point cmin, cmax, hinv;
417 boost::multi_array<double, NDim> phi;
425 typedef typename control_lattice<NDim>::index index;
426 typedef typename control_lattice<NDim>::point point;
428 template <
class CooIter,
class ValIter>
429 control_lattice_sparse(
430 const point& coo_min,
const point& coo_max, index grid_size,
431 CooIter coo_begin, CooIter coo_end, ValIter val_begin)
436 for (
unsigned i = 0; i < NDim; ++i) {
437 hinv[i] = (grid[i] - 1) / (cmax[i] - cmin[i]);
438 cmin[i] -= 1 / hinv[i];
442 std::map<index, two_doubles> dw;
444 CooIter p = coo_begin;
445 ValIter v = val_begin;
447 for (; p != coo_end; ++p, ++v) {
448 if (!boxed(coo_min, *p, coo_max))
454 for (
unsigned d = 0; d < NDim; ++d) {
455 double u = ((*p)[d] - cmin[d]) * hinv[d];
460 std::array<double, power<4, NDim>::value> w;
465 for (
unsigned k = 0; k < NDim; ++k)
466 prod *= Bspline(d[k], s[k]);
468 w[d.position()] = prod;
469 sum_w2 += prod * prod;
473 double w1 = w[d.position()];
475 double phi = (*v) * w1 / sum_w2;
477 two_doubles delta_omega = { w2 * phi, w2 };
479 append(dw[i + (*d)], delta_omega);
484 boost::make_transform_iterator(dw.begin(), delta_over_omega),
485 boost::make_transform_iterator(dw.end(), delta_over_omega));
488 double operator()(
const point& p)
const
493 for (
unsigned d = 0; d < NDim; ++d) {
494 double u = (p[d] - cmin[d]) * hinv[d];
503 for (
unsigned k = 0; k < NDim; ++k)
504 w *= Bspline(d[k], s[k]);
506 f += w * get_phi(i + (*d));
512 void report(std::ostream& os)
const
514 boost::io::ios_all_saver stream_state(os);
516 size_t grid_size = grid[0];
518 os <<
"sparse [" << grid[0];
519 for (
unsigned i = 1; i < NDim; ++i) {
520 os <<
", " << grid[i];
521 grid_size *= grid[i];
524 size_t bytes = phi.size() *
sizeof(std::pair<index, double>);
525 size_t dense_bytes = grid_size *
sizeof(double);
527 double compression =
static_cast<double>(bytes) / dense_bytes;
528 os <<
"] (" << bytes <<
" bytes, compression: "
529 << std::fixed << std::setprecision(2) << compression <<
")";
534 point cmin, cmax, hinv;
537 typedef boost::container::flat_map<index, double> sparse_grid;
540 typedef std::array<double, 2> two_doubles;
542 static std::pair<index, double> delta_over_omega(
const std::pair<index, two_doubles>& dw)
544 return std::make_pair(dw.first, safe_divide(dw.second[0], dw.second[1]));
547 static void append(two_doubles& a,
const two_doubles& b)
549 std::transform(a.begin(), a.end(), b.begin(), a.begin(), std::plus<double>());
552 double get_phi(
const index& i)
const
554 typename sparse_grid::const_iterator c = phi.find(i);
555 return c == phi.end() ? 0.0 : c->second;
562class linear_approximation
566 typedef typename detail::control_lattice<NDim>::point point;
568 template <
class CooIter,
class ValIter>
569 linear_approximation(CooIter coo_begin, CooIter coo_end, ValIter val_begin)
571 namespace ublas = boost::numeric::ublas;
573 size_t n = std::distance(coo_begin, coo_end);
577 std::fill(C.begin(), C.end(), 0.0);
578 C[NDim] = std::accumulate(val_begin, val_begin + n, 0.0) / n;
582 ublas::matrix<double> A(NDim + 1, NDim + 1);
584 ublas::vector<double> f(NDim + 1);
587 CooIter p = coo_begin;
588 ValIter v = val_begin;
590 double sum_val = 0.0;
593 for (; p != coo_end; ++p, ++v, ++n) {
594 std::array<double, NDim + 1> x;
595 std::copy(p->begin(), p->end(), boost::begin(x));
598 for (
unsigned i = 0; i <= NDim; ++i) {
599 for (
unsigned j = 0; j <= NDim; ++j) {
600 A(i, j) += x[i] * x[j];
608 ublas::permutation_matrix<size_t> pm(NDim + 1);
609 ublas::lu_factorize(A, pm);
611 bool singular =
false;
612 for (
unsigned i = 0; i <= NDim; ++i) {
613 if (A(i, i) == 0.0) {
620 std::fill(C.begin(), C.end(), 0.0);
621 C[NDim] = sum_val / n;
624 ublas::lu_substitute(A, pm, f);
625 for (
unsigned i = 0; i <= NDim; ++i)
630 double operator()(
const point& p)
const
634 for (
unsigned i = 0; i < NDim; ++i)
642 std::array<double, NDim + 1> C;
650 typedef std::array<size_t, NDim> index;
651 typedef std::array<double, NDim> point;
653 template <
class CooIter,
class ValIter>
655 const point& coo_min,
const point& coo_max, index grid,
656 CooIter coo_begin, CooIter coo_end, ValIter val_begin,
657 unsigned max_levels = 8,
double tol = 1e-8,
double min_fill = 0.5,
658 std::function<
double(point)> initial = std::function<
double(point)>())
661 coo_min, coo_max, grid,
662 coo_begin, coo_end, val_begin,
663 max_levels, tol, min_fill, initial);
666 template <
class CooRange,
class ValRange>
668 const point& coo_min,
const point& coo_max, index grid,
669 CooRange coo, ValRange val,
670 unsigned max_levels = 8,
double tol = 1e-8,
double min_fill = 0.5,
671 std::function<
double(point)> initial = std::function<
double(point)>())
674 coo_min, coo_max, grid,
675 boost::begin(coo), boost::end(coo), boost::begin(val),
676 max_levels, tol, min_fill, initial);
679 double operator()(
const point& p)
const
683 for (
const auto& psi : cl) {
690 friend std::ostream& operator<<(std::ostream& os,
const MBA& h)
693 for (
const auto& psi : h.cl) {
694 os <<
"level " << ++level <<
": ";
708 std::list<std::shared_ptr<lattice>> cl;
710 template <
class CooIter,
class ValIter>
712 const point& cmin,
const point& cmax, index grid,
713 CooIter coo_begin, CooIter coo_end, ValIter val_begin,
714 unsigned max_levels,
double tol,
double min_fill,
715 std::function<
double(point)> initial)
717 using namespace mba::detail;
719 const ptrdiff_t n = std::distance(coo_begin, coo_end);
720 std::vector<double> val(val_begin, val_begin + n);
722 double res, eps = 0.0;
723 for (ptrdiff_t i = 0; i < n; ++i)
724 eps = std::max(eps, std::abs(val[i]));
729 cl.push_back(std::make_shared<initial_approximation>(initial));
730 res = cl.back()->residual(coo_begin, coo_end, val.begin());
738 auto psi = std::make_shared<dense_lattice>(
739 cmin, cmax, grid, coo_begin, coo_end, val.begin());
741 res = psi->residual(coo_begin, coo_end, val.begin());
742 double fill = psi->fill_ratio();
744 for (; (lev < max_levels) && (res > eps) && (fill > min_fill); ++lev) {
745 grid = grid * 2ul - 1ul;
747 auto f = std::make_shared<dense_lattice>(
748 cmin, cmax, grid, coo_begin, coo_end, val.begin());
750 res = f->residual(coo_begin, coo_end, val.begin());
751 fill = f->fill_ratio();
753 f->append_refined(*psi);
761 for (; (lev < max_levels) && (res > eps); ++lev) {
762 grid = grid * 2ul - 1ul;
764 cl.push_back(std::make_shared<sparse_lattice>(
765 cmin, cmax, grid, coo_begin, coo_end, val.begin()));
767 res = cl.back()->residual(coo_begin, coo_end, val.begin());