CASM  1.1.0
A Clusters Approach to Statistical Mechanics
PolyTrie.hh
Go to the documentation of this file.
1 
2 #ifndef POLYTRIE_HH
3 #define POLYTRIE_HH
4 
5 #include <stdlib.h>
6 
7 #include <cassert>
8 #include <iostream>
9 #include <new>
10 
11 #include "casm/container/Array.hh"
13 #include "casm/misc/CASM_TMP.hh"
14 
15 namespace CASM {
16 
27 template <typename T>
28 class PolyTrie;
29 template <typename T>
30 class PTNode;
31 template <typename T>
32 class PTLeaf;
33 
34 namespace ComparePTLeaf {
35 class ByMonomialOrder;
36 }
37 template <typename PTType, bool IsConst = false>
38 class PTIterator;
39 
40 template <typename T>
41 class PTNode : protected Array<PTNode<T> *> {
42  protected:
43  static double PT_TOL() { return 1e-6; }
44  friend class PolyTrie<T>;
46  T m_val;
47 
48  using Array<PTNode<T> *>::size;
49  using Array<PTNode<T> *>::at;
51 
53  PTNode<T> *valid_leaf_at(PolyTrie<T> &home_trie, const Array<Index> &ind);
54 
55  public:
56  PTNode(PTNode<T> *_up, const T &_val = 0) : up_node(_up), m_val(_val){};
57 
58  const T &val() const { return m_val; };
59  virtual ~PTNode();
60 
61  virtual void remove();
62 };
63 
64 //==========================================================
65 template <typename T>
66 class PTLeaf : public PTNode<T> {
67  private:
71 
72  protected:
73  friend class PolyTrie<T>;
74 
75  public:
76  PTLeaf(PTNode<T> *_up, const Array<Index> &_key, const T &_val)
77  : PTNode<T>(_up, _val),
78  next_leaf(nullptr),
79  prev_leaf_addr(nullptr),
80  m_key(_key){};
81 
82  ~PTLeaf();
83 
85 
86  using PTNode<T>::remove;
87 
90  // void remove();
91 
92  const Array<Index> &key() const { return m_key; };
93 
94  T &val_ref() { return PTNode<T>::m_val; }
95  const T &val_ref() const { return PTNode<T>::m_val; }
96 
97  // Const and non-const list traversal
98  PTLeaf<T> *next() { return next_leaf; };
99  PTLeaf<T> const *next() const { return next_leaf; };
100 
102 
105  void swap_after_prev(PTLeaf<T> *other);
106 
108  // insert at is passed a reference to the pointer at which insertion will
109  // occur,
110  // e.g.: ptr_to_new_leaf->insert_at(ptr_to_list_head); <-- ptr_to_list_head
111  // can be NULL
112  void insert_at(PTLeaf<T> *&insertion_ptr);
113 
114  // prev can't be NULL
115  void insert_after(PTLeaf<T> *prev);
116  // next can't be NULL
118  void make_tail() { next_leaf = NULL; }
119 };
120 
121 namespace ComparePTLeaf {
123  public:
124  template <typename T>
125  static bool compare(const PTLeaf<T> &A, const PTLeaf<T> &B) {
126  return (A.key().sum() >= B.key().sum()) && (A.key() >= B.key());
127  }
128  template <typename T>
129  bool operator()(const PTLeaf<T> &A, const PTLeaf<T> &B) const {
130  return compare(A, B);
131  }
132 };
133 
134 class CustomOrder {
135  public:
136  template <typename T>
137  static bool compare(const PTLeaf<T> &A, const PTLeaf<T> &B) {
138  if (A.key().size() < 9 || B.key().size() < 9)
139  return ByMonomialOrder::compare(A, B);
140 
141  if (A.key().sum() > B.key().sum()) return true;
142  if (A.key().sum() < B.key().sum()) return false;
143 
144  Array<Index> sub1A(A.key().sub_array(0, A.key().size() - 7)),
145  sub2A(A.key().sub_array(A.key().size() - 6, A.key().size() - 4)),
146  sub3A(A.key().sub_array(A.key().size() - 3, A.key().size() - 1)),
147  sub1B(B.key().sub_array(0, B.key().size() - 7)),
148  sub2B(B.key().sub_array(B.key().size() - 6, B.key().size() - 4)),
149  sub3B(B.key().sub_array(B.key().size() - 3, B.key().size() - 1));
150  if (sub1A.sum() > sub1B.sum()) return true;
151  if (sub1A.sum() < sub1B.sum()) return false;
152  if (sub1A.max() > sub1B.max()) return true;
153  if (sub1A.max() < sub1B.max()) return false;
154  if (sub2A.sum() > sub2B.sum()) return true;
155  if (sub2A.sum() < sub2B.sum()) return false;
156  if (sub3A.sum() > sub3B.sum()) return true;
157  if (sub3A.sum() < sub3B.sum()) return false;
158  if (almost_equal(std::abs(A.val()), std::abs(B.val())))
159  return ByMonomialOrder::compare(A, B) && A.val() + TOL > B.val();
160 
161  return std::abs(A.val()) > std::abs(B.val());
162  }
163  template <typename T>
164  bool operator()(const PTLeaf<T> &A, const PTLeaf<T> &B) const {
165  return compare(A, B);
166  }
167 };
168 } // namespace ComparePTLeaf
169 
170 //==========================================================
171 
172 template <typename T>
173 class PolyTrie : public PTNode<T> {
176  using PTNode<T>::size;
177  using PTNode<T>::at;
178 
180 
183 
184  public:
185  typedef T value_type;
186 
188 
191 
192  PolyTrie(Index _depth)
193  : PTNode<T>(nullptr), m_depth(_depth), m_leaf_list(nullptr){};
194  PolyTrie(const PolyTrie<T> &orig);
195  // ~PTNode() should take care of PolyTrie destruction, except for the edge
196  // case m_depth=0
198 
200  void remove(){};
201 
203  void remove(const Array<Index> &ind);
204 
206  void swap(PolyTrie<T> &other);
207 
209  void redefine(Index new_depth);
210 
211  void clear();
212 
213  Index depth() const { return m_depth; };
214 
216  T get(const Array<Index> &ind) const;
217 
220  T &at(const Array<Index> &ind);
221 
222  T &operator()(const Array<Index> &ind);
223 
224  T operator()(const Array<Index> &ind) const;
225 
227  void set(const Array<Index> &ind, const T &_val);
228 
229  void list_leaf(PTLeaf<T> *new_leaf);
230 
233  bool prune_zeros(double tol = PTNode<T>::PT_TOL());
234 
236  PTLeaf<T> const *begin_ptr() const { return m_leaf_list; }
237 
240 
241  iterator end() { return iterator(); }
242  const_iterator end() const { return const_iterator(); };
243 
244  void print_sparse(std::ostream &out) const;
245 
246  // Arithmetic operations
247  PolyTrie &operator*=(const T &scale);
250 
251  PolyTrie operator+(const PolyTrie<T> &RHS) const;
252  PolyTrie operator-(const PolyTrie<T> &RHS) const;
253 
254  bool compare(const PolyTrie<T> &RHS,
255  double tol = 2 * PTNode<T>::PT_TOL()) const;
256  bool operator==(const PolyTrie<T> &RHS) const;
257  bool almost_zero(double tol = 2 * PTNode<T>::PT_TOL()) const;
258 
259  template <typename CompareType>
260  void sort_leaves(const CompareType &compare);
261 };
262 
263 //==========================================================
264 template <typename PTType, bool IsConst>
265 class PTIterator {
266  public:
273 
274  private:
276 
277  public:
278  PTIterator(leaf_type *_leaf_ptr = 0) : m_curr_leaf_ptr(_leaf_ptr){};
280 
281  template <bool IsConst2>
283  return m_curr_leaf_ptr == _it.m_curr_leaf_ptr;
284  }
285 
286  template <bool IsConst2>
288  return !((*this) == _it);
289  }
290 
293  return *this;
294  }
296  PTIterator t_it(*this);
297  ++(*this);
298  return t_it;
299  }
300 
302  m_curr_leaf_ptr = m_curr_leaf_ptr->remove_and_next();
303  return *this;
304  }
305 
306  reference operator*() { return m_curr_leaf_ptr->val_ref(); }
307  pointer operator->() { return &operator*; }
308  const Array<Index> &key() { return m_curr_leaf_ptr->key(); }
309 
310  leaf_type *leaf_ptr() const { return m_curr_leaf_ptr; };
311 };
312 
313 //==========================================================
314 
315 template <typename PTType, bool IsConst>
317  : m_curr_leaf_ptr(_it.leaf_ptr()) {}
318 
319 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
320 
321 template <typename T>
323  while (size() <= i) {
324  push_back(nullptr);
325  }
326  return at(i) ? at(i) : at(i) = new PTNode<T>(this);
327 }
328 
329 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
330 
331 template <typename T>
333  const Array<Index> &ind) {
334  if (ind.size() == 0 && home_trie.depth() == 0 &&
335  this == static_cast<PTNode<T> *>(&home_trie)) {
336  if (!home_trie.begin_ptr())
337  home_trie.list_leaf(new PTLeaf<T>(this, ind, 0));
338  return home_trie.begin_ptr();
339  }
340 
341  while (size() <= ind.back()) {
342  push_back(nullptr);
343  }
344 
345  // Check if there's a valid leaf at 'ind' element and create a new one if not
346  if (!at(ind.back())) {
347  at(ind.back()) = new PTLeaf<T>(this, ind, 0);
348  home_trie.list_leaf(static_cast<PTLeaf<T> *>(at(ind.back())));
349  }
350 
351  return at(ind.back());
352 }
353 
354 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
355 
356 template <typename T>
358  if (!up_node) {
359  delete this;
360  return;
361  }
362 
363  bool remove_up(true), not_removed(true);
364 
365  for (Index i = 0; i < up_node->size() && (remove_up || not_removed); i++) {
366  if ((up_node->at(i)) == this) {
367  up_node->at(i) = nullptr;
368  not_removed = false;
369  }
370  remove_up = remove_up && !(up_node->at(i));
371  }
372  if (remove_up) {
373  // clearing up_node saves some time when it is deleted
374  up_node->clear();
375  up_node->remove();
376  }
377  // std::cout << "Finishing remove by deleting myself:\n";
378  delete this;
379  return;
380 }
381 
382 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
383 
384 template <typename T>
386  for (Index i = 0; i < size(); i++) {
387  if (at(i)) delete at(i);
388  }
389 }
390 
391 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
392 
393 template <typename T>
395  swap(prev_leaf_addr, other->prev_leaf_addr);
396  *prev_leaf_addr = this;
397  *(other->prev_leaf_addr) = other;
398 }
399 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
400 template <typename T>
402  insert_at(prev->next_leaf);
403 }
404 
405 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
406 
407 template <typename T>
408 void PTLeaf<T>::insert_at(PTLeaf<T> *&insertion_ptr) {
409  // 'insertion_ptr' refers to 'next_leaf' in the PTLeaf that will become
410  // 'previous' (or pointer that is head of list) This is the definition of
411  // prev_leaf_addr
412  prev_leaf_addr = &insertion_ptr;
413 
414  // insertion_ptr currently points to leaf that will become 'next'
415  next_leaf = insertion_ptr;
416 
417  // next_leaf->prev_leaf_addr should point to the next_leaf pointer in this
418  // leaf
419  if (next_leaf) next_leaf->prev_leaf_addr = &next_leaf;
420 
421  // insertion_ptr is next_leaf in 'previous', and it should be set to this
422  // the following line is equivalent to insertion_ptr=this
423  (*prev_leaf_addr) = this;
424 }
425 
426 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
427 
428 template <typename T>
430  assert(next && next->prev_leaf_addr &&
431  "PTLeaf insertion failed because 'next' leaf address is not in List.");
432 
433  // 'next' will become 'next_leaf'
434  next_leaf = next;
435 
436  // prev_leaf_addr should be same as next->prev_leaf_addr
437  prev_leaf_addr = next->prev_leaf_addr;
438 
439  // *prev_leaf_addr is next_leaf in 'previous' leaf; it should point to this
440  (*prev_leaf_addr) = this;
441 
442  // next->prev_leaf_addr should point to next_leaf ptr in this
443  next->prev_leaf_addr = &next_leaf;
444 }
445 
446 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
447 template <typename T>
449  // std::cout << "I'm PTLeaf " << this << " and I'm being destroyed!!!
450  // next_leaf is " << next_leaf << " and prev_leaf_addr is " << prev_leaf_addr
451  // << " and " << *prev_leaf_addr << "\n";
452 
453  if (prev_leaf_addr) *prev_leaf_addr = next_leaf;
454 
455  if (next_leaf) {
456  next_leaf->prev_leaf_addr = prev_leaf_addr;
457  next_leaf = nullptr;
458  }
459  prev_leaf_addr = nullptr;
460 }
461 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
462 template <typename T>
464  PTLeaf<T> *save_next(next_leaf);
465 
466  // remove deletes 'this' so can only return afterwards
467  remove();
468  return save_next;
469 }
470 
471 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
472 
473 template <typename T>
475  : PTNode<T>(nullptr), m_depth(orig.m_depth), m_leaf_list(nullptr) {
476  PolyTrie<T>::const_iterator it(orig.begin()), it_end(orig.end());
477  // PolyTrie<T>::set() does all the work -- result is a pruned PolyTrie that is
478  // a copy of 'orig'
479  for (; it != it_end; ++it) set(it.key(), *it);
480 }
481 
482 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
483 // ~PTNode() should take care of PolyTrie destruction, except for the edge case
484 // m_depth=0
485 template <typename T>
487  if (depth() == 0 && begin_ptr()) delete begin_ptr();
488 }
489 
490 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
491 
492 template <typename T>
494  Index count(0);
495  PolyTrie<T>::const_iterator it(begin()), it_end(end());
496  for (; it != it_end; ++it) count++;
497  return count;
498 }
499 
500 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
501 
502 template <typename T>
503 T PolyTrie<T>::get(const Array<Index> &ind) const {
504  assert(ind.size() == depth() &&
505  "In PolyTrie<T>::get(), ind.size() must match PolyTrie<T>::depth().");
506  if (ind.size() == 0) {
507  if (begin_ptr()) return begin_ptr()->val();
508  return 0;
509  }
510 
511  PTNode<T> const *tnode(this);
512  for (Index i = 0; i < ind.size(); i++) {
513  if (ind[i] >= tnode->size() || !(tnode->at(ind[i]))) {
514  return 0;
515  }
516  tnode = tnode->at(ind[i]);
517  }
518  return tnode->val();
519 }
520 
521 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
522 
523 template <typename T>
524 void PolyTrie<T>::set(const Array<Index> &ind, const T &_val) {
525  assert(ind.size() == depth() &&
526  "In PolyTrie<T>::set(), ind.size() must match PolyTrie<T>::depth().");
527 
528  if (CASM::almost_zero(_val, PTNode<T>::PT_TOL())) {
529  remove(ind);
530  }
531 
532  PTNode<T> *tnode(this);
533  for (Index i = 0; i < ind.size() - 1; i++) {
534  tnode = tnode->valid_node_at(ind[i]);
535  }
536 
537  tnode = tnode->valid_leaf_at(*this, ind);
538  tnode->m_val = _val;
539  return;
540 }
541 
542 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
543 
544 template <typename T>
546  assert(ind.size() == depth() &&
547  "In PolyTrie<T>::at(), ind.size() must match PolyTrie<T>::depth().");
548 
549  PTNode<T> *tnode(this);
550  for (Index i = 0; i < ind.size() - 1; i++) {
551  tnode = tnode->valid_node_at(ind[i]);
552  }
553 
554  tnode = tnode->valid_leaf_at(*this, ind);
555 
556  return tnode->m_val;
557 }
558 
559 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
560 template <typename T>
562  assert(ind.size() == depth() &&
563  "In PolyTrie<T>::operator(), ind.size() must match "
564  "PolyTrie<T>::depth().");
565 
566  PTNode<T> *tnode(this);
567  for (Index i = 0; i < ind.size() - 1; i++) {
568  tnode = tnode->valid_node_at(ind[i]);
569  }
570 
571  tnode = tnode->valid_leaf_at(*this, ind);
572 
573  return tnode->m_val;
574 }
575 
576 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
577 template <typename T>
579  assert(ind.size() == depth() &&
580  "In PolyTrie<T>::get(), ind.size() must match PolyTrie<T>::depth().");
581  if (ind.size() == 0) {
582  if (begin_ptr()) return begin_ptr()->val();
583  return 0;
584  }
585 
586  PTNode<T> const *tnode(this);
587  for (Index i = 0; i < ind.size(); i++) {
588  if (ind[i] >= tnode->size() || !(tnode->at(ind[i]))) {
589  return 0;
590  }
591  tnode = tnode->at(ind[i]);
592  }
593  return tnode->val();
594 }
595 
596 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
597 
598 template <typename T>
600  new_leaf->insert_at(m_leaf_list);
601 }
602 
603 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
604 
605 template <typename T>
607  PTLeaf<T> *current(begin_ptr());
608  while (current) {
609  current = current->remove_and_next();
610  }
611 }
612 
613 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
614 
615 template <typename T>
616 void PolyTrie<T>::redefine(Index new_depth) {
617  clear();
618  m_depth = new_depth;
619 }
620 
621 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
622 
623 template <typename T>
625  if (this == &other) return;
626 
627  std::swap(m_depth, other.m_depth);
628  for (Index i = 0; i < size(); i++) {
629  if (at(i)) {
630  at(i)->up_node = &other;
631  }
632  }
633  Array<PTNode<T> *>::swap(other);
634 
635  for (Index i = 0; i < size(); i++) {
636  if (at(i)) {
637  at(i)->up_node = this;
638  }
639  }
640 
641  std::swap(m_leaf_list, other.m_leaf_list);
642  if (m_leaf_list) m_leaf_list->prev_leaf_addr = &m_leaf_list;
643  if (other.m_leaf_list)
644  other.m_leaf_list->prev_leaf_addr = &(other.m_leaf_list);
645 }
646 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
647 
648 template <typename T>
650  assert(
651  ind.size() == depth() &&
652  "In PolyTrie<T>::remove(), ind.size() must match PolyTrie<T>::depth().");
653  PTNode<T> *tnode(this);
654  for (Index i = 0; i < ind.size(); i++) {
655  if (ind[i] >= tnode->size() || !(tnode->at(ind[i]))) {
656  return;
657  }
658  tnode = tnode->at(ind[i]);
659  }
660  tnode->remove();
661  return;
662 }
663 
664 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
665 
666 template <typename T>
667 bool PolyTrie<T>::prune_zeros(double tol) {
668  bool is_edited(false);
669  PolyTrie<T>::iterator it(begin()), it_end(end());
670  for (; it != it_end; ++it) {
671  while (it != it_end && CASM::almost_zero(*it, tol)) {
672  it.remove_and_next();
673  is_edited = true;
674  }
675  }
676  return is_edited;
677 }
678 
679 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
680 
681 template <typename T>
682 void PolyTrie<T>::print_sparse(std::ostream &out) const {
683  PolyTrie<T>::const_iterator it(begin()), it_end(end());
684  for (; it != it_end; ++it) {
686  out << it.key() << ": " << *it << '\n';
687  }
688 }
689 
690 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
691 
692 template <typename T>
694  if (CASM::almost_zero(scale, PTNode<T>::PT_TOL())) {
695  clear();
696  return *this;
697  }
698 
699  PolyTrie<T>::iterator it(begin()), it_end(end());
700  for (; it != it_end; ++it) *it *= scale;
701 
702  return *this;
703 }
704 
705 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
706 
707 template <typename T>
709  PolyTrie<T>::const_iterator it(RHS.begin()), it_end(RHS.end());
710  for (; it != it_end; ++it) {
711  if (CASM::almost_zero(at(it.key()) += *it, PTNode<T>::PT_TOL()))
712  remove(it.key());
713  }
714  return *this;
715 }
716 
717 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
718 
719 template <typename T>
721  PolyTrie<T>::const_iterator it(RHS.begin()), it_end(RHS.end());
722  for (; it != it_end; ++it) {
723  if (CASM::almost_zero(at(it.key()) -= *it, PTNode<T>::PT_TOL()))
724  remove(it.key());
725  }
726  return *this;
727 }
728 
729 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
730 
731 template <typename T>
733  PolyTrie<T> result(*this);
734  return result += RHS;
735 }
736 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
737 
738 template <typename T>
740  PolyTrie<T> result(*this);
741  return result -= RHS;
742 }
743 
744 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
745 
746 template <typename T>
747 bool PolyTrie<T>::compare(const PolyTrie<T> &RHS, double tol) const {
748  return ((*this) - RHS).almost_zero(tol);
749 }
750 
751 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
752 
753 template <typename T>
754 bool PolyTrie<T>::operator==(const PolyTrie<T> &RHS) const {
755  return compare(RHS);
756 }
757 
758 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
759 
760 template <typename T>
761 bool PolyTrie<T>::almost_zero(double tol) const {
762  PolyTrie<T>::const_iterator it(begin()), it_end(end());
763 
764  for (; it != it_end; ++it) {
765  if (!CASM::almost_zero(*it, tol)) return false;
766  }
767  return true;
768 }
769 
770 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
771 
772 template <typename T>
773 template <typename CompareType>
774 void PolyTrie<T>::sort_leaves(const CompareType &compare) {
775  if (!m_leaf_list) return;
776 
777  // Working with two sublists, 'a_list', and 'b_list' -- define pointers to
778  // each
779  PTLeaf<T> *a_ptr, *b_ptr;
780 
781  // merge_elem is the element to be merged and tail is the merge position
782  PTLeaf<T> *merge_elem, *tail;
783 
784  // size of a_list and size of b_list
785  int a_size, b_size;
786 
787  // merge_size is the target size of a_list and b_list at the beggining of each
788  // iteration.
789  // nmerges is the number of merges performed during the interation
790  int merge_size(1), nmerges(2);
791  // count number of merges we do in this pass
792  // If we have done only one merge, we're finished.
793  while (nmerges > 1) {
794  nmerges = 0;
795 
796  a_ptr = m_leaf_list;
797  tail = NULL;
798 
799  while (a_ptr) {
800  // there exists a merge to be done
801  nmerges++;
802  // step `merge_size' places along from p
803  b_ptr = a_ptr;
804  a_size = 0;
805  for (int i = 0; i < merge_size; i++) {
806  a_size++;
807  if (!(b_ptr = b_ptr->next())) break;
808  }
809 
810  // if b_ptr hasn't fallen off the end of the list, we have two
811  // m_leaf_lists to merge
812  b_size = merge_size;
813 
814  // now we merge a_list with b_list, keeping the result ordered
815  while (a_size > 0 || (b_size > 0 && b_ptr)) {
816  // decide whether next merge_elem comes from a_list or b_list
817  if (a_size == 0) {
818  // a_list is empty; merge_elem must come from b_list.
819  merge_elem = b_ptr;
820  b_ptr = b_ptr->next();
821  b_size--;
822  } else if (b_size == 0 || !b_ptr) {
823  // b_list is empty; merge_elem must come from a_list.
824  merge_elem = a_ptr;
825  a_ptr = a_ptr->next();
826  a_size--;
827  } else if (compare(*a_ptr, *b_ptr)) {
828  // First element of b_list is "truer" (or same); merge_elem must come
829  // from a_list.
830  merge_elem = a_ptr;
831  a_ptr = a_ptr->next();
832  a_size--;
833  } else {
834  // First element of b_list is "truer"; merge_elem must come from
835  // b_list.
836  merge_elem = b_ptr;
837  b_ptr = b_ptr->next();
838  b_size--;
839  }
840 
841  // add the next PTLeaf<T> to the merged list
842  if (tail) {
843  merge_elem->insert_after(tail);
844  } else {
845  merge_elem->insert_at(m_leaf_list);
846  }
847  tail = merge_elem;
848  }
849 
850  // we've reached the end of a_list and b_list, so point a_ptr at the the
851  // same position as b_ptr, which will either be NULL or the beginning of
852  // the next a_list
853  a_ptr = b_ptr;
854  }
855  // set the new element as the tail (set internal pointer to NULL)
856  tail->make_tail();
857 
858  // double the merge size for next iteration
859  merge_size *= 2;
860  }
861 }
862 
865 } // namespace CASM
866 
867 #endif /* POLYTRIE_H_ */
Index count
Basic std::vector like container (deprecated)
Definition: Array.hh:45
T & back()
Definition: Array.hh:160
PTNode< T > * & at(Index ind)
Definition: Array.hh:140
bool operator()(const PTLeaf< T > &A, const PTLeaf< T > &B) const
Definition: PolyTrie.hh:129
static bool compare(const PTLeaf< T > &A, const PTLeaf< T > &B)
Definition: PolyTrie.hh:125
bool operator()(const PTLeaf< T > &A, const PTLeaf< T > &B) const
Definition: PolyTrie.hh:164
static bool compare(const PTLeaf< T > &A, const PTLeaf< T > &B)
Definition: PolyTrie.hh:137
CASM_TMP::ConstSwitch< IsConst, typename PTType::leaf_type > leaf_type
Definition: PolyTrie.hh:268
CASM_TMP::ConstSwitch< IsConst, typename PTType::value_type > * pointer
Definition: PolyTrie.hh:270
pointer operator->()
Definition: PolyTrie.hh:307
PTIterator & remove_and_next()
Definition: PolyTrie.hh:301
leaf_type * leaf_ptr() const
Definition: PolyTrie.hh:310
bool operator==(const PTIterator< PTType, IsConst2 > &_it)
Definition: PolyTrie.hh:282
CASM_TMP::ConstSwitch< IsConst, typename PTType::value_type > & reference
Definition: PolyTrie.hh:272
bool operator!=(const PTIterator< PTType, IsConst2 > &_it)
Definition: PolyTrie.hh:287
reference operator*()
Definition: PolyTrie.hh:306
PTIterator(leaf_type *_leaf_ptr=0)
Definition: PolyTrie.hh:278
PTIterator & operator++()
Definition: PolyTrie.hh:291
const Array< Index > & key()
Definition: PolyTrie.hh:308
PTIterator operator++(int)
Definition: PolyTrie.hh:295
leaf_type * m_curr_leaf_ptr
Definition: PolyTrie.hh:275
PTLeaf< T > * next_leaf
Definition: PolyTrie.hh:68
PTLeaf< T > * next()
Definition: PolyTrie.hh:98
const T & val_ref() const
Definition: PolyTrie.hh:95
PTLeaf< T > ** prev_leaf_addr
Definition: PolyTrie.hh:69
void make_tail()
Definition: PolyTrie.hh:118
PTLeaf< T > const * next() const
Definition: PolyTrie.hh:99
ComparePTLeaf::ByMonomialOrder CompareByMonomialOrder
Definition: PolyTrie.hh:84
T & val_ref()
Definition: PolyTrie.hh:94
PTLeaf(PTNode< T > *_up, const Array< Index > &_key, const T &_val)
Definition: PolyTrie.hh:76
const Array< Index > & key() const
Definition: PolyTrie.hh:92
Array< Index > m_key
Definition: PolyTrie.hh:70
PTNode< T > * up_node
Definition: PolyTrie.hh:45
static double PT_TOL()
Definition: PolyTrie.hh:43
const T & val() const
Definition: PolyTrie.hh:58
PTNode(PTNode< T > *_up, const T &_val=0)
Definition: PolyTrie.hh:56
PTLeaf< T > * begin_ptr()
Definition: PolyTrie.hh:235
iterator end()
Definition: PolyTrie.hh:241
const_iterator end() const
Definition: PolyTrie.hh:242
void remove()
Virtual from PTNode<T>, you cannot remove a PolyTrie.
Definition: PolyTrie.hh:200
const_iterator begin() const
Definition: PolyTrie.hh:239
Index depth() const
Definition: PolyTrie.hh:213
PTIterator< PolyTrie< T >, true > const_iterator
Definition: PolyTrie.hh:190
PTLeaf< T > const * begin_ptr() const
Definition: PolyTrie.hh:236
PTLeaf< T > * m_leaf_list
Definition: PolyTrie.hh:175
iterator begin()
Definition: PolyTrie.hh:238
PTLeaf< T > leaf_type
Definition: PolyTrie.hh:187
PTIterator< PolyTrie< T > > iterator
Definition: PolyTrie.hh:189
PolyTrie(Index _depth)
Definition: PolyTrie.hh:192
T sum() const
Definition: Array.hh:552
ReturnArray< T > sub_array(Index ind_begin, Index ind_end) const
Definition: Array.hh:562
void push_back(const PTNode< T > * &toPush)
Definition: Array.hh:431
PolyTrie operator-(const PolyTrie< T > &RHS) const
Definition: PolyTrie.hh:739
PolyTrie operator+(const PolyTrie< T > &RHS) const
Definition: PolyTrie.hh:732
void swap(PolyTrie< T > &other)
Efficient swap of this PolyTrie with another.
Definition: PolyTrie.hh:624
void insert_before(PTLeaf< T > *next)
Definition: PolyTrie.hh:429
bool prune_zeros(double tol=PTNode< T >::PT_TOL())
Definition: PolyTrie.hh:667
void list_leaf(PTLeaf< T > *new_leaf)
Definition: PolyTrie.hh:599
void swap_after_prev(PTLeaf< T > *other)
Definition: PolyTrie.hh:394
T operator()(const Array< Index > &ind) const
Definition: PolyTrie.hh:578
void clear()
Definition: PolyTrie.hh:606
PTNode< T > * valid_node_at(Index i)
Definition: PolyTrie.hh:322
Index num_nonzero() const
Definition: PolyTrie.hh:493
bool operator==(const PolyTrie< T > &RHS) const
Definition: PolyTrie.hh:754
T get(const Array< Index > &ind) const
get() provides constant access does not change trie structure
Definition: PolyTrie.hh:503
void redefine(Index new_depth)
Clears all leaves and resets depth.
Definition: PolyTrie.hh:616
void insert_after(PTLeaf< T > *prev)
Definition: PolyTrie.hh:401
bool compare(const PolyTrie< T > &RHS, double tol=2 *PTNode< T >::PT_TOL()) const
Definition: PolyTrie.hh:747
void print_sparse(std::ostream &out) const
Definition: PolyTrie.hh:682
virtual ~PTNode()
Definition: PolyTrie.hh:385
PolyTrie & operator*=(const T &scale)
Definition: PolyTrie.hh:693
void set(const Array< Index > &ind, const T &_val)
set() allows assignment that prunes the trie if _val is approximately 0;
Definition: PolyTrie.hh:524
bool almost_zero(double tol=2 *PTNode< T >::PT_TOL()) const
Definition: PolyTrie.hh:761
PTLeaf< T > * remove_and_next()
Definition: PolyTrie.hh:463
void sort_leaves(const CompareType &compare)
Definition: PolyTrie.hh:774
T & at(const Array< Index > &ind)
Definition: PolyTrie.hh:545
PolyTrie & operator+=(const PolyTrie< T > &RHS)
Definition: PolyTrie.hh:708
T & operator()(const Array< Index > &ind)
Definition: PolyTrie.hh:561
PolyTrie & operator-=(const PolyTrie< T > &RHS)
Definition: PolyTrie.hh:720
PTNode< T > * valid_leaf_at(PolyTrie< T > &home_trie, const Array< Index > &ind)
Definition: PolyTrie.hh:332
virtual void remove()
Definition: PolyTrie.hh:357
PolyTrie(const PolyTrie< T > &orig)
Definition: PolyTrie.hh:474
void insert_at(PTLeaf< T > *&insertion_ptr)
List insertion methods.
Definition: PolyTrie.hh:408
void remove(const Array< Index > &ind)
Remove entry at 'ind'.
Definition: PolyTrie.hh:649
typename std::conditional< IsConst, const T, T >::type ConstSwitch
Definition: CASM_TMP.hh:78
Main CASM namespace.
Definition: APICommand.hh:8
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
bool compare(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Compare ClusterInvariants.
void swap(ConfigDoF &A, ConfigDoF &B)
Definition: ConfigDoF.cc:260
const double TOL
Definition: definitions.hh:30
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39