MADNESS 0.10.1
key.h
Go to the documentation of this file.
1/*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30*/
31
32#ifndef MADNESS_MRA_KEY_H__INCLUDED
33#define MADNESS_MRA_KEY_H__INCLUDED
34
35/// \file key.h
36/// \brief Multidimension Key for MRA tree and associated iterators
37
38#include <madness/mra/bc.h>
39#include <madness/mra/power.h>
43
44#include <cstdint>
45#include <vector>
46
47namespace madness {
48
49 // // this has problems when nproc is a large-ish power of 2 such as 256
50 // // and leads to bad data distribution.
51 // static inline unsigned int sdbm(int n, const unsigned char* c, unsigned int sum=0) {
52 // for (int i=0; i<n; ++i) sum = c[i] + (sum << 6) + (sum << 16) - sum;
53 // return sum;
54 // }
55
56 typedef int64_t Translation;
57 typedef int Level;
58
59 template<std::size_t NDIM>
60 class KeyChildIterator;
61
62 /// Key is the index for a node of the 2^NDIM-tree
63
64 /// See KeyChildIterator for facile generation of children,
65 /// and foreach_child(parent,op) for facile application of operators
66 /// to child keys.
67 template<std::size_t NDIM>
68 class Key {
69 public:
70// static const typename Vector<Translation,NDIM>::size_type static_size = Vector<Translation,NDIM>::static_size;
71 static const std::size_t static_size = NDIM;
72
73 private:
74 friend class KeyChildIterator<NDIM> ;
78
79
80 public:
81
82 /// Default constructor makes an \em uninitialized key
83 Key() {}
84
85 /// Constructor with given n, l
87 {
88 rehash();
89 }
90
91 /// Constructor with given n and l=0
92 Key(int n) : n(n), l(0)
93 {
94 rehash();
95 }
96
97 // /// easy constructor ... UGH !!!!!!!!!!!!!!!!!!!!!!
98 // Key(const int n, const int l0, const int l1, const int l2) : n(n) {
99 // MADNESS_ASSERT(NDIM==3);
100 // l=Vector<Translation, NDIM>(0);
101 // l[0]=l0; l[1]=l1; l[2]=l2;
102 // rehash();
103 // }
104
105 /// Returns an invalid key
107 return Key<NDIM> (-1);
108 }
109
110 /// Checks if a key is invalid
111 bool is_invalid() const {
112 return n == -1;
113 }
114
115 /// Checks if a key is valid
116 bool is_valid() const {
117 return n != -1;
118 }
119
120 /// Equality test
121 bool operator==(const Key& other) const {
122 if (hashval != other.hashval) return false;
123 if (n != other.n) return false;
124 for (unsigned int i=0; i<NDIM; i++)
125 if (l[i] != other.l[i]) return false;
126 return true; // everything is equal
127 }
128
129 bool operator!=(const Key& other) const {
130 return !(*this == other);
131 }
132
133 /// Comparison operator less than to enable storage in STL map
134 bool operator<(const Key& other) const {
135 if (hashval < other.hashval) return true;
136 if (hashval > other.hashval) return false;
137
138 if (n < other.n) return true;
139 if (n > other.n) return false;
140
141 for (unsigned int i=0; i<NDIM; i++) {
142 if (l[i] < other.l[i]) return true;
143 if (l[i] > other.l[i]) return false;
144 }
145
146 return false; // everything is equal
147 }
148
149 inline hashT
150 hash() const {
151 return hashval;
152 }
153
154 // template<typename Archive>
155 // inline void
156 // serialize(Archive& ar) {
157 // ar & archive::wrap((unsigned char*) this, sizeof(*this));
158 // }
159
160 Level
161 level() const {
162 return n;
163 }
164
166 translation() const {
167 return l;
168 }
169
170 /// const accessor to elements of this->translation()
171 const Translation& operator[](std::size_t d) const {
172 return l[d];
173 }
174
175 uint64_t
176 distsq() const {
177 uint64_t dist = 0;
178 for (std::size_t d = 0; d < NDIM; ++d) {
179 dist += l[d] * l[d];
180 }
181 return dist;
182 }
183
184 /// like distsq() but accounts for periodicity
185 uint64_t
186 distsq_bc(const array_of_bools<NDIM>& is_periodic) const {
187 const Translation twonm1 = (Translation(1) << level()) >> 1;
188
189 uint64_t dsq = 0;
190 for (std::size_t d = 0; d < NDIM; ++d) {
191 Translation la = translation()[d];
192 if (is_periodic[d]) {
193 if (la > twonm1) {
194 la -= twonm1 * 2;
195 MADNESS_ASSERT(la <= twonm1);
196 }
197 if (la < -twonm1) {
198 la += twonm1 * 2;
199 MADNESS_ASSERT(la >= -twonm1);
200 }
201 }
202 dsq += la * la;
203 }
204
205 return dsq;
206 }
207
208 /// like "periodic" distsq() but only selects the prescribed axes
209 template <std::size_t NDIM2>
210 std::enable_if_t<NDIM >= NDIM2, uint64_t>
211 distsq_bc(const array_of_bools<NDIM>& is_periodic, const std::array<std::size_t, NDIM2>& axes) const {
212 const Translation twonm1 = (Translation(1) << level()) >> 1;
213
214 uint64_t dsq = 0;
215 for (std::size_t a = 0; a < NDIM2; ++a) {
216 const auto d = axes[a];
218 Translation la = translation()[d];
219 if (is_periodic[d]) {
220 if (la > twonm1) {
221 la -= twonm1 * 2;
222 MADNESS_ASSERT(la <= twonm1);
223 }
224 if (la < -twonm1) {
225 la += twonm1 * 2;
226 MADNESS_ASSERT(la >= -twonm1);
227 }
228 }
229 dsq += la * la;
230 }
231
232 return dsq;
233 }
234
235 /// Returns the key of the parent
236
237 /// Default is the immediate parent (generation=1). To get
238 /// the grandparent use generation=2, and similarly for
239 /// great-grandparents.
240 ///
241 /// !! If there is no such parent it quietly returns the
242 /// closest match (which may be self if this is the top of the
243 /// tree).
244 Key
245 parent(int generation = 1) const {
247 if (generation > n)
248 generation = n;
249 for (std::size_t i = 0; i < NDIM; ++i)
250 pl[i] = l[i] >> generation;
251 return Key(n - generation, pl);
252 }
253
254
255 bool
256 is_child_of(const Key& key) const {
257 if (this->n < key.n) {
258 return false; // I can't be child of something lower on the tree
259 }
260 else if (this->n == key.n) {
261 return (*this == key); // I am child of myself
262 }
263 else {
264 Level dn = this->n - key.n;
265 Key mama = this->parent(dn);
266 return (mama == key);
267 }
268 }
269
270
271 bool
272 is_parent_of(const Key& key) const {
273 return (key.is_child_of(*this));
274 }
275
276 /// Assuming keys are at the same level, returns true if displaced by no more than 1 in any direction
277
278 /// Assumes key and this are at the same level
279 bool
280 is_neighbor_of(const Key& key, const array_of_bools<NDIM>& bperiodic) const {
281 Translation dist = 0;
282 Translation TWON1 = (Translation(1)<<n) - 1;
283 for (std::size_t i=0; i<NDIM; ++i)
284 {
285 Translation ll = std::abs(l[i] - key.l[i]);
286 if (bperiodic[i] && ll==TWON1) ll=1;
287 dist = std::max(dist, ll);
288 }
289 return (dist <= 1);
290 }
291
292 /// given a displacement, generate a neighbor key; ignore boundary conditions and disp's level
293
294 /// @param[in] disp the displacement
295 /// @return a new key
296 Key neighbor(const Key<NDIM>& disp) const {
298 return Key(this->level(),l);
299 }
300
301 /// given a displacement, generate a neighbor key; ignore boundary conditions and disp's level
302
303 /// @param[in] disp the displacement
304 /// @return a new key
307 return Key(this->level(),l);
308 }
309
310
311 /// check if this MultiIndex contains point x, disregarding these two dimensions
312 bool thisKeyContains(const Vector<double,NDIM>& x, const unsigned int& dim0,
313 const unsigned int& dim1) const {
314
315 // it's sufficient if one single dimension is out
316 bool contains=true;
317 const double twotoN = std::pow(2.0,double(n));
318 MADNESS_ASSERT(dim0<NDIM and dim1<NDIM);
319
320 for (unsigned int i=0; i<NDIM; i++ ) {
321
322 // check bounds
323 MADNESS_ASSERT((x[i]>=0.0) and (x[i]<=1.0));
324
325 // leave these two dimensions out
326 if ((i==dim0) or (i==dim1)) continue;
327
328 const int ll=int (x[i]*twotoN);
329 if (not (l[i]==ll)) contains=false;
330 }
331 return contains;
332 }
333
334 /// break key into two low-dimensional keys
335 template<std::size_t LDIM, std::size_t KDIM>
336 void break_apart(Key<LDIM>& key1, Key<KDIM>& key2) const {
337
338 // if LDIM==NDIM the 2nd key will be constructed empty
339 MADNESS_ASSERT((LDIM+KDIM==NDIM) or (LDIM==NDIM));
342 for (int i=0; i<static_cast<int>(LDIM); ++i) {
343 l1[i]=l[i];
344 }
345MADNESS_PRAGMA_GCC(diagnostic push)
346MADNESS_PRAGMA_GCC(diagnostic ignored "-Waggressive-loop-optimizations")
347 for (size_t i=LDIM; i<NDIM; ++i) {
348 l2[i-LDIM]=l[i];
349 }
350MADNESS_PRAGMA_GCC(diagnostic pop)
351
352 key1=Key<LDIM>(n,l1);
353 key2=Key<KDIM>(n,l2);
354 }
355
356 /// extract a new key consisting of first VDIM dimensions of this
357 template<std::size_t VDIM>
359 static_assert(VDIM <= NDIM, "VDIM must be less than or equal to NDIM");
361 for (int i = 0; i < VDIM; ++i) t[i] = this->translation()[i];
362 return Key<VDIM>(this->level(),t);
363 }
364
365 /// extract a new key consisting of last VDIM dimensions of this
366 template<std::size_t VDIM>
368 static_assert(VDIM <= NDIM, "VDIM must be less than or equal to NDIM");
370 for (int i = 0; i < VDIM; ++i) t[i] = this->translation()[NDIM-VDIM+i];
371 return Key<VDIM>(this->level(),t);
372 }
373
374 /// extract a new key with the Translations indicated in the v array
375 template<std::size_t VDIM>
376 Key<VDIM> extract_key(const std::array<int,VDIM>& v) const {
378 for (int i = 0; i < VDIM; ++i) t[i] = this->translation()[v[i]];
379 return Key<VDIM>(this->level(),t);
380 };
381
382 /// extract a new key with the Translations complementary to the ones indicated in the v array
383 template<std::size_t VDIM>
384 Key<NDIM-VDIM> extract_complement_key(const std::array<int,VDIM>& v) const {
385
386 // return the complement of v, e.g. v={0,1}, v_complement={2,3,4} if NDIM==5
387 // v must be contiguous and ascending (i.e. 1,2,3 or 2,3,4)
388 auto v_complement = [](const std::array<int, VDIM>& v) {
389 std::array<int, NDIM - VDIM> result;
390 for (std::size_t i = 0; i < NDIM - VDIM; i++) result[i] = (v.back() + i + 1) % NDIM;
391 return result;
392 };
393 return extract_key(v_complement(v));
394 };
395
396 /// merge with other key (ie concatenate), use level of rhs, not of this
397 template<std::size_t LDIM>
400 for (int i=0; i<static_cast<int>(NDIM); ++i) t[i] =this->l[i];
401 for (int i=0; i<static_cast<int>(LDIM); ++i) t[NDIM+i]=rhs.translation()[i];
402 return Key<NDIM+LDIM>(rhs.level(),t);
403 }
404
405 /// return if the other key is pointing in the same direction and is farther out
406
407 /// unlike in distsq() the direction is taken into account, and other must be
408 /// longer than this in each dimension
409 /// @param[in] other a key
410 /// @return if other is farther out
411 bool is_farther_out_than(const Key<NDIM>& other) const {
412 for (size_t i=0; i<NDIM; ++i) {
413 if ((other.translation()[i]>0) and (other.translation()[i]>l[i])) return false;
414 if ((other.translation()[i]<0) and (other.translation()[i]<l[i])) return false;
415 }
416 return true;
417 }
418
419
420 /// Recomputes hashval ... presently only done when reading from external storage
421 void
423 //hashval = sdbm(sizeof(n)+sizeof(l), (unsigned char*)(&n));
424 // default hash is still best
425
428 }
429 };
430
431 template<std::size_t NDIM>
432 std::ostream&
433 operator<<(std::ostream& s, const Key<NDIM>& key) {
434 s << "(" << key.level() << "," << key.translation() << ")";
435 return s;
436 }
437
438 /// given a source and a target, return the displacement in translation
439
440 /// @param[in] source the source key
441 /// @param[in] target the target key
442 /// @return disp such that target = source + disp
443 template<size_t NDIM>
445 MADNESS_ASSERT(source.level()==target.level());
446 const Vector<Translation,NDIM> l = target.translation()-source.translation();
447 return Key<NDIM>(source.level(),l);
448 }
449
450
451
452 /// Iterates in lexical order thru all children of a key
453
454 /// Example usage:
455 /// \code
456 /// for (KeyChildIterator<NDIM> it(key); it; ++it) print(it.key());
457 /// \endcode
458 template<std::size_t NDIM>
464
465 public:
467 p(0), finished(true) {
468 }
469
471 parent(parent), child(parent.n + 1, parent.l * 2), p(0),
472 finished(false) {
473 }
474
475 /// Pre-increment of an iterator (i.e., ++it)
478 if (finished)
479 return *this;
480 std::size_t i;
481 for (i = 0; i < NDIM; ++i) {
482 if (p[i] == 0) {
483 ++(p[i]);
484 ++(child.l[i]);
485 for (std::size_t j = 0; j < i; ++j) {
486 --(p[j]);
487 --(child.l[j]);
488 }
489 break;
490 }
491 }
492 finished = (i == NDIM);
493 child.rehash();
494 return *this;
495 }
496
497 /// True if iterator is not at end
498 operator bool() const {
499 return !finished;
500 }
501
502 template<typename Archive>
503 inline void
504 serialize(Archive& ar) {
505 ar & archive::wrap((unsigned char*) this, sizeof(*this));
506 }
507
508 /// Returns the key of the child
509 inline const Key<NDIM>&
510 key() const {
511 return child;
512 }
513 };
514
515 /// Applies op(key) to each child key of parent
516 template<std::size_t NDIM, typename opT>
517 inline void
518 foreach_child(const Key<NDIM>& parent, opT& op) {
520 it(parent); it; ++it)
521 op(it.key());
522 }
523
524 /// Applies member function of obj to each child key of parent
525 template<std::size_t NDIM, typename objT>
526 inline void
527 foreach_child(const Key<NDIM>& parent, objT* obj, void
528 (objT::*memfun)(const Key<NDIM>&)) {
530 it(parent); it; ++it)
531 (obj ->* memfun)(it.key());
532 }
533
534 namespace archive {
535
536 // For efficiency serialize opaque so is just one memcpy, but
537 // when reading from external storage rehash() so that we
538 // can read data even if hash algorithm/function has changed.
539
540 template <class Archive, std::size_t NDIM>
541 struct ArchiveLoadImpl< Archive, Key<NDIM> > {
542 static void load(const Archive& ar, Key<NDIM>& t) {
543 ar & archive::wrap((unsigned char*) &t, sizeof(t));
544 }
545 };
546
547 template <std::size_t NDIM>
549 static void load(const BinaryFstreamInputArchive& ar, Key<NDIM>& t) {
550 ar & archive::wrap((unsigned char*) &t, sizeof(t));
551 t.rehash(); // <<<<<<<<<< This is the point
552 }
553 };
554
555 template <class Archive, std::size_t NDIM>
556 struct ArchiveStoreImpl< Archive, Key<NDIM> > {
557 static void store(const Archive& ar, const Key<NDIM>& t) {
558 ar & archive::wrap((unsigned char*) &t, sizeof(t));
559 }
560 };
561 }
562
563}
564
565#endif // MADNESS_MRA_KEY_H__INCLUDED
566
Provides BoundaryConditions.
Implements an archive wrapping a binary filestream.
Iterates in lexical order thru all children of a key.
Definition key.h:459
Vector< Translation, NDIM > p
Definition key.h:462
KeyChildIterator(const Key< NDIM > &parent)
Definition key.h:470
bool finished
Definition key.h:463
const Key< NDIM > & key() const
Returns the key of the child.
Definition key.h:510
KeyChildIterator()
Definition key.h:466
Key< NDIM > child
Definition key.h:461
Key< NDIM > parent
Definition key.h:460
void serialize(Archive &ar)
Definition key.h:504
KeyChildIterator & operator++()
Pre-increment of an iterator (i.e., ++it)
Definition key.h:477
Key is the index for a node of the 2^NDIM-tree.
Definition key.h:68
Key< VDIM > extract_back() const
extract a new key consisting of last VDIM dimensions of this
Definition key.h:367
Key< NDIM+LDIM > merge_with(const Key< LDIM > &rhs) const
merge with other key (ie concatenate), use level of rhs, not of this
Definition key.h:398
Level level() const
Definition key.h:161
uint64_t distsq_bc(const array_of_bools< NDIM > &is_periodic) const
like distsq() but accounts for periodicity
Definition key.h:186
bool is_farther_out_than(const Key< NDIM > &other) const
return if the other key is pointing in the same direction and is farther out
Definition key.h:411
Vector< Translation, NDIM > l
Definition key.h:76
Key neighbor(const Vector< Translation, NDIM > &disp) const
given a displacement, generate a neighbor key; ignore boundary conditions and disp's level
Definition key.h:305
Key(int n)
Constructor with given n and l=0.
Definition key.h:92
Key(Level n, const Vector< Translation, NDIM > &l)
Constructor with given n, l.
Definition key.h:86
bool is_parent_of(const Key &key) const
Definition key.h:272
bool is_neighbor_of(const Key &key, const array_of_bools< NDIM > &bperiodic) const
Assuming keys are at the same level, returns true if displaced by no more than 1 in any direction.
Definition key.h:280
Key()
Default constructor makes an uninitialized key.
Definition key.h:83
bool is_valid() const
Checks if a key is valid.
Definition key.h:116
hashT hash() const
Definition key.h:150
bool thisKeyContains(const Vector< double, NDIM > &x, const unsigned int &dim0, const unsigned int &dim1) const
check if this MultiIndex contains point x, disregarding these two dimensions
Definition key.h:312
bool is_invalid() const
Checks if a key is invalid.
Definition key.h:111
bool operator==(const Key &other) const
Equality test.
Definition key.h:121
const Translation & operator[](std::size_t d) const
const accessor to elements of this->translation()
Definition key.h:171
Level n
Definition key.h:75
static const std::size_t static_size
Definition key.h:71
uint64_t distsq_bc(const array_of_bools< NDIM > &is_periodic, const std::array< std::size_t, NDIM2 > &axes) const
Definition key.h:211
bool operator!=(const Key &other) const
Definition key.h:129
Key< NDIM-VDIM > extract_complement_key(const std::array< int, VDIM > &v) const
extract a new key with the Translations complementary to the ones indicated in the v array
Definition key.h:384
Key< VDIM > extract_front() const
extract a new key consisting of first VDIM dimensions of this
Definition key.h:358
Key< VDIM > extract_key(const std::array< int, VDIM > &v) const
extract a new key with the Translations indicated in the v array
Definition key.h:376
hashT hashval
Definition key.h:77
Key parent(int generation=1) const
Returns the key of the parent.
Definition key.h:245
void rehash()
Recomputes hashval ... presently only done when reading from external storage.
Definition key.h:422
const Vector< Translation, NDIM > & translation() const
Definition key.h:166
bool operator<(const Key &other) const
Comparison operator less than to enable storage in STL map.
Definition key.h:134
static Key< NDIM > invalid()
Returns an invalid key.
Definition key.h:106
uint64_t distsq() const
Definition key.h:176
Key neighbor(const Key< NDIM > &disp) const
given a displacement, generate a neighbor key; ignore boundary conditions and disp's level
Definition key.h:296
bool is_child_of(const Key &key) const
Definition key.h:256
void break_apart(Key< LDIM > &key1, Key< KDIM > &key2) const
break key into two low-dimensional keys
Definition key.h:336
A simple, fixed dimension vector.
Definition vector.h:64
Wraps an archive around a binary filestream for input.
Definition binary_fstream_archive.h:104
syntactic sugar for std::array<bool, N>
Definition array_of_bools.h:19
archive_array< T > wrap(const T *, unsigned int)
Factory function to wrap a dynamically allocated pointer as a typed archive_array.
Definition archive.h:913
static const double v
Definition hatom_sf_dirac.cc:20
Tensor< double > op(const Tensor< double > &x)
Definition kain.cc:508
#define MADNESS_PRAGMA_GCC(x)
Definition madness_config.h:205
#define MADNESS_ASSERT(condition)
Assert a condition that should be free of side-effects since in release builds this might be a no-op.
Definition madness_exception.h:134
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
std::ostream & operator<<(std::ostream &os, const particle< PDIM > &p)
Definition lowrankfunction.h:397
void hash_combine(hashT &seed, const T &v)
Combine hash values.
Definition worldhash.h:260
int64_t Translation
Definition key.h:56
Key< NDIM > displacement(const Key< NDIM > &source, const Key< NDIM > &target)
given a source and a target, return the displacement in translation
Definition key.h:444
int Level
Definition key.h:57
static double pop(std::vector< double > &v)
Definition SCF.cc:113
std::size_t hashT
The hash value type.
Definition worldhash.h:145
void foreach_child(const Key< NDIM > &parent, opT &op)
Applies op(key) to each child key of parent.
Definition key.h:518
madness::hashT hash_value(const std::array< T, N > &a)
Hash std::array with madness hash.
Definition array_addons.h:78
static long abs(long a)
Definition tensor.h:218
static const double d
Definition nonlinschro.cc:121
static const double a
Definition nonlinschro.cc:118
static void load(const Archive &ar, Key< NDIM > &t)
Definition key.h:542
static void load(const BinaryFstreamInputArchive &ar, Key< NDIM > &t)
Definition key.h:549
Default load of an object via serialize(ar, t).
Definition archive.h:666
static void store(const Archive &ar, const Key< NDIM > &t)
Definition key.h:557
Default store of an object via serialize(ar, t).
Definition archive.h:611
double dist(const Vector< double, 3 > v1, const Vector< double, 3 > v2)
distance between v1 and v2
Definition test_localizer.cc:38
constexpr std::size_t NDIM
Definition testgconv.cc:54
double source(const coordT &r)
Definition testperiodic.cc:48
Implement the madness:Vector class, an extension of std::array that supports some mathematical operat...
Defines hash functions for use in distributed containers.
FLOAT target(const FLOAT &x)
Definition y.cc:295