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