/
basis.h
1777 lines (1503 loc) · 63.2 KB
/
basis.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/************************************************************//**
@file basis.h
Defines template base classes for indexing quantum mechanical states
arranged into subspaces (defined by good symmetry quantum numbers).
General scheme:
The foundational class is the "subspace" type, representing a
subspace with good quantum numbers (e.g., LSJT). This class sets
up and stores indexing of state quantum numbers within that
subspace.
Access to this indexing is via instantiating a "state". A state
has to refer to a "subspace" in order to know its quantum numbers.
Its definition therefore depends upon the "subspace" type. The
actual information content of a state consists of a pointer to the
subspace and an index representing the state within that subspace.
Going in the other direction in terms of the hierarchy of
mathematical structures, a "space" is a collection "subspaces".
Its definition therefore *also* depends upon the "subspace" type.
Finally, in order to keep track of the matrix elements of an
operator (of good JP quantum numbers), it is necessary to
enumerate the allowed sectors, i.e., the pairs of "subspaces"
within the "space" which are connected under the angular momentum
and parity selection rules. These sectors are indexed by a
"sector enumeration". Its definition depends upon the "space"
type, and therefore indirectly on the "subspace" type.
So notice that the hierarchy of dependencies of template
definitions
state <- subspace -> space -> sectors
does not quite parallel the mathematical hierarchy
state -> subspace -> space -> sectors.
Possible extensions:
Arguably, each subspace and space should have defined a
TruncationLabelsType, with a corresponding data member and
accessors. The constructor would then record the truncation
scheme for posterity and later reference.
For standardized debugging output, add a String conversion to
interface of each type (state, subspace, ...), then use this in
standardized Print functions.
Compilation directives:
BASIS_HASH: In lookup tables, replace std::map with
std::unordered_map, using boost hash extensions.
Library dependencies:
boost -- only if BASIS_HASH enabled
Language: C++11
Mark A. Caprio
University of Notre Dame
+ 11/21/15 (mac): Created (indexing_base.h), abstracted from code in indexing_lsjt.
+ 3/5/16 (mac): Update header comment.
+ 3/9/16 (mac): Relax protection of BaseSpace indexing containers
- from private to protected to support sp3rlib.
+ 3/11/16 (mac): Add subspace size() method and space
- TotalDimension() and ContainsSubspace() methods.
+ 5/3/16 (mac): Add boost-style hashing option ad hoc on subspace labels.
+ 6/8/16 (mac): Extract to new basis module:
- Rename file from indexing_base.h to indexing.h.
- Change namespace from shell to basis.
- Systematize switching between map and unordered_map via BASIS_HASH
directive.
- Remove deprecated subspace method Dimension().
+ 6/16/16 (mac): Fix missing typename qualifier.
+ 6/24/16 (mac): Add direction enum class.
+ 6/30/16 (mac):
- Flesh out documentation of member functions.
- Add utility member functions ContainsState, ContainsSector,
IsDiagonal.
+ 7/5/16 (mac): Add pass-through typedef StateLabelsType to BaseState.
+ 7/13/16 (mac): Clean up accessor naming: Add labels() accessor to
subspace and state, deprecating subspace GetSubspaceLabels() and
state GetStateLabels(). Add subspace() accessor to state, deprecating
Subspace().
+ 7/25/16 (mac): Add utility member function IsUpperTriangle.
+ 10/25/16 (mac):
- Implement return of flag value for failed lookup.
- Provide sector lookup by sector key and refactor ContainsSector and
LookUpSectorIndex.
+ 11/22/16 (mac):
- Fix wrong return in broken-out ContainsSector.
- Reexpand (remultiply?) ContainsSector and LookUpSectorIndex.
+ 2/17/17 (mac): Add generic DebugStr for BaseSectors.
+ 4/4/17 (mac):
- Rename from indexing.h to basis.h.
- Rename compilation flag INDEXING_HASH to BASIS_HASH.
+ 6/6/7 (mac): Disable deprecated member functions by default
(BASIS_ALLOW_DEPRECATED).
+ 6/11/17 (mac): Rename TotalDimension to Dimension.
+ 08/11/17 (pjf): Emit warnings if deprecated member functions are used.
+ 05/09/19 (pjf): Use std::size_t for indices and sizes, to prevent
integer overflow.
+ 05/27/19 (pjf): Modify BaseSpace and BaseSectors to fix fragility problems:
- Move BaseSpace subspaces_ and lookup_ into shared_ptrs; copying a
space is now a lightweight operation.
- Store copy of bra and ket spaces inside BaseSectors.
- Construct BaseSector at access time, dereferencing from local copy of
space.
- Add BaseSpace::EmplaceSubspace() for in-place addition of subspaces.
+ 06/24/21 (pjf): Modify to allow unlimited nesting of spaces:
- Extract labels to BaseLabeling, with an explicit (empty) specialization
for labels of type void (i.e. no labels).
- Add new template parameter to BaseSpace to define a LabelsType for spaces;
this allows instantiating a space of spaces.
- Add dimension() accessor to BaseSubspace and BaseSpace.
- Store offsets to subspaces and total dimension directly in BaseSpace.
+ 06/25/21 (pjf):
- Add accessor for subspace offset in BaseSpace.
- Fix initialization of dimension_ in BaseSpace.
- Add BaseDegenerateSpace as friend of BaseSpace.
+ 06/28/21 (pjf): Fix friend declaration in BaseSpace.
+ 07/02/21 (pjf):
- Replace `typedef`s with alias declarations (`using`).
- Add constructors for BaseSubspace and BaseSpace which accept labels.
+ 07/03/21 (pjf):
- Remove BaseLabeling and replace with inheritance from partial
template specialization.
- Mark labels_ as private and const to prevent modification
after construction.
- Mark constructors as protected to prevent direct initialization.
+ 07/04/21 (pjf):
- Add tDerivedSubspaceType and tStateType as template arguments to
BaseSubspace.
- Add GetState accessors to BaseSubspace.
+ 08/08/21 (pjf):
- Modify BaseSector and BaseSectors to allow bra and ket space types to
differ.
- Add additional template argument to BaseSectors so that custom sector type
can be used, instead of default instantiation of BaseSector.
+ 08/16/21 (pjf):
- Switch from storing shared_ptr<vector> to vector<shared_ptr> in BaseSpace.
- Add tDerivedSpaceType as template argument to BaseSpace for CRTP with
std::enable_shared_from_this.
- Replace raw pointers with shared_ptr in BaseSector.
+ 08/17/21 (pjf):
- Revert to storing instances of sector in BaseSectors rather than just keys.
- Only copy space into BaseSectors if it is not managed by a shared_ptr.
+ 08/18/21 (pjf): Add std::vector-like size management to BaseSubspace and
BaseSpace.
+ 09/22/21 (pjf):
- Improve reserve() in BaseSubspace and BaseSpace.
- Add iterator support to BaseSubspace, BaseSpace, and BaseSectors.
+ 09/24/21 (pjf):
- Fix use-after-move in BaseSectors::PushBack.
- Add indexing offsets for BaseSectors, and num_elements accessor to
both BaseSectors and BaseSector.
- Fix BaseSectors::DebugStr for size/dimension distinction.
+ 09/30/21 (pjf): Add BaseSpace::full_size() accessor.
+ 11/04/21 (pjf):
- Revert to shared pointer to vector in BaseSpace.
- Remove std::enable_shared_from_this.
- Add GetSubspacePtr() accessor to BaseSpace using shared_ptr aliasing.
- Make BaseSector take shared pointers instead of const references.
+ 02/03/22 (mac): Add alias StateType to BaseSubspace.
+ 03/25/22 (pjf):
- Modify BaseSubspace to allow definition with `void` labels.
+ 04/02/22 (pjf):
- Defer initialization of shared_ptr in BaseSpace until
PushSubspace/EmplaceSubspace/reserve.
- Make labels in BaseSubspace and BaseSpace non-const, to avoid deleting
copy and move constructors.
+ 04/03/22 (pjf): Normalize all constructors so that fields get initialized
correctly.
+ 04/12/22 (pjf): Allow BaseSectors between non-direct subspace of space.
+ 02/03/23 (mac): Add alias StateType to BaseSubspace.
+ 05/09/23 (pjf): Fix comparison of pointers in BaseSectors.
+ 05/12/23 (pjf):
- Fix iterator types.
- Fix constness of member shared_ptr in BaseSector.
- Use std::addressof for comparison of objects in BaseSectors.
+ 03/05/24 (mac): Add alias LabelsType to BaseState.
****************************************************************/
#ifndef BASIS_BASIS_H_
#define BASIS_BASIS_H_
#include <cassert>
#include <cstddef>
#include <iterator>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
// for DebugStr
#include <iosfwd>
#include <sstream>
#include <string>
#ifdef BASIS_ALLOW_DEPRECATED
// emit warnings on deprecated
#include "mcutils/deprecated.h"
#endif
#ifdef BASIS_HASH
#include <unordered_map>
#include <boost/container_hash/hash.hpp>
#else
#include <map>
#endif
namespace basis {
static constexpr std::size_t kNone = std::numeric_limits<std::size_t>::max();
// Flag value for missing target in index lookups.
////////////////////////////////////////////////////////////////
// generic subspace
////////////////////////////////////////////////////////////////
/// BaseSubspace -- holds indexing of states within a symmetry
/// subspace
///
/// The derived class is expected to set up a constructor and
/// friendlier accessors for the individual labels.
///
/// The derived class passes itself as the first template argument, as an
/// example of the Curiously Recurring Template Pattern (CRTP). This allows
/// BaseSubspace access to the full type information of the derived class.
///
/// Template arguments:
/// tDerivedSubspaceType : type of the derived subspace class (for CRTP)
/// tSubspaceLabelsType : tuple for subspace labels, e.g., std::tuple<int,int,int,int,int>
/// tStateType : type (possibly incomplete) for states
/// tStateLabelsType : tuple for state labels, e.g., std::tuple<int>
///
/// Note: Even if only a single integer label is needed, we must use
/// tuple<int> (as opposed to plain int) to make the two forms of the
/// state constructor syntactically distinct.
// declare BaseSubspace template
template <
typename tDerivedSubspaceType, typename tSubspaceLabelsType,
typename tStateType, typename tStateLabelsType
>
class BaseSubspace;
// specialize class for case with no labels
template <
typename tDerivedSubspaceType,
typename tStateType, typename tStateLabelsType
>
class BaseSubspace<tDerivedSubspaceType, void, tStateType, tStateLabelsType>
{
public:
////////////////////////////////////////////////////////////////
// common typedefs
////////////////////////////////////////////////////////////////
using StateLabelsType = tStateLabelsType;
using StateType = tStateType;
protected:
////////////////////////////////////////////////////////////////
// general constructors
////////////////////////////////////////////////////////////////
/// default constructor
// Implicitly invoked by derived class.
BaseSubspace()
: dimension_{}
{}
public:
////////////////////////////////////////////////////////////////
// iterators
////////////////////////////////////////////////////////////////
struct iterator
{
using iterator_category = std::input_iterator_tag; // we don't satisfy the requirements of forward_iterator_tag because we return temporaries
using difference_type = std::make_signed_t<std::size_t>;
using value_type = tStateType;
using pointer = void*;
// using pointer = value_type*; // n.b. we can't return a pointer to a temporary
using reference = value_type; // n.b. this can't be a reference since value_type is always a temporary
iterator(const tDerivedSubspaceType* subspace_ptr, std::size_t index)
: subspace_ptr_{subspace_ptr}, index_{index}
{}
reference operator*() const { return subspace_ptr_->GetState(index_); }
reference operator[](std::size_t index) const { return subspace_ptr_->GetState(index_+index); }
iterator& operator++() { index_++; return *this; }
iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; }
iterator& operator--() { index_--; return *this; }
iterator operator--(int) { iterator tmp = *this; --(*this); return tmp; }
iterator& operator+=(difference_type n) { index_ += n; return *this; }
iterator& operator-=(difference_type n) { index_ -= n; return *this; }
friend iterator operator+(iterator it, difference_type n) { it += n; return it; }
friend iterator operator-(iterator it, difference_type n) { it -= n; return it; }
friend difference_type operator-(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_ - rhs.index_);
}
friend bool operator==(const iterator& lhs, const iterator& rhs)
{
return (lhs.subspace_ptr_==rhs.subspace_ptr_) && (lhs.index_==rhs.index_);
}
friend bool operator!=(const iterator& lhs, const iterator& rhs)
{
return (lhs.subspace_ptr_!=rhs.subspace_ptr_) || (lhs.index_!=rhs.index_);
}
friend bool operator<(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_<rhs.index_);
}
friend bool operator>(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_>rhs.index_);
}
friend bool operator<=(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_<=rhs.index_);
}
friend bool operator>=(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_>=rhs.index_);
}
private:
const tDerivedSubspaceType* subspace_ptr_;
std::size_t index_;
};
using value_type = tStateType;
using const_reference = const tStateType&;
using const_iterator = iterator;
using difference_type = typename iterator::difference_type;
using size_type = std::make_unsigned_t<difference_type>;
iterator begin() const
{
return iterator{static_cast<const tDerivedSubspaceType*>(this), 0};
}
iterator end() const
{
return iterator{static_cast<const tDerivedSubspaceType*>(this), size()};
}
iterator cbegin() const
{
return iterator{static_cast<const tDerivedSubspaceType*>(this), 0};
}
iterator cend() const
{
return iterator{static_cast<const tDerivedSubspaceType*>(this), size()};
}
////////////////////////////////////////////////////////////////
// retrieval
////////////////////////////////////////////////////////////////
const StateLabelsType& GetStateLabels(std::size_t index) const
/// Retrieve the labels of a state within the subspace, given its
/// index within the subspace.
///
/// Note: It is not normally expected that this member function
/// should be used directly. The idea is instead to work with the
/// *state* type (derived from BaseState) associated with this
/// subspace. One would rather instantiate a *state*, identified
/// by this index, then query the state for various specific
/// labels, as they are needed, using accessors provided by the
/// state.
{
return state_table_[index];
}
bool ContainsState(const StateLabelsType& state_labels) const
/// Given the labels for a state, returns whether or not the state
/// is found within the subspace.
{
return lookup_.count(state_labels);
};
std::size_t LookUpStateIndex(const StateLabelsType& state_labels) const
/// Given the labels for a state, look up its index within the
/// subspace.
///
/// If no such labels are found, basis::kNone is returned.
{
// PREVIOUSLY: trap failed lookup with assert for easier debugging
// assert(ContainsState(state_labels));
// return lookup_.at(state_labels);
auto pos = lookup_.find(state_labels);
if (pos==lookup_.end())
return kNone;
else
return pos->second;
};
StateType GetState(std::size_t index) const;
/// Given the index for a state, construct the corresponding state object.
///
/// Defined below, outside the definition of the class, so that
/// instantiation is deferred until tStateType is a complete type.
StateType GetState(const StateLabelsType& state_labels) const;
/// Given the labels for a state, construct the corresponding state object.
///
/// Defined below, outside the definition of the class, so that
/// instantiation is deferred until tStateType is a complete type.
////////////////////////////////////////////////////////////////
// size retrieval
////////////////////////////////////////////////////////////////
std::size_t size() const
/// Return the size of the subspace.
{
return dimension_;
}
std::size_t dimension() const
/// Return the size of the subspace.
{
return dimension_;
}
protected:
////////////////////////////////////////////////////////////////
// state label storage management (for initial construction)
////////////////////////////////////////////////////////////////
inline void reserve(std::size_t new_cap)
/// Reserve storage for labels.
{
state_table_.reserve(new_cap);
lookup_.reserve(new_cap);
}
inline std::size_t capacity() const noexcept
/// Get size of reserved storage for labels.
{
return state_table_.capacity();
}
inline void shrink_to_fit()
/// Shrink reserved storage for labels to fit contents.
{
state_table_.shrink_to_fit();
}
////////////////////////////////////////////////////////////////
// state label push (for initial construction)
////////////////////////////////////////////////////////////////
void PushStateLabels(const StateLabelsType& state_labels)
/// Create indexing information (in both directions, index <->
/// labels) for a state.
{
lookup_[state_labels] = dimension_; // index for lookup
state_table_.push_back(state_labels); // save state
dimension_++;
};
private:
////////////////////////////////////////////////////////////////
// private storage
////////////////////////////////////////////////////////////////
// subspace properties
std::size_t dimension_;
// state labels (accessible by index)
std::vector<StateLabelsType> state_table_;
// state index lookup by labels
#ifdef BASIS_HASH
std::unordered_map<StateLabelsType,std::size_t,boost::hash<StateLabelsType>> lookup_;
#else
std::map<StateLabelsType,std::size_t> lookup_;
#endif
};
// implementations of BaseSubspace::GetState; we do this outside the class
// declaration to delay instantiation until tDerivedSubspaceType and
// tStateType are complete types
template <
typename tDerivedSubspaceType,
typename tStateType, typename tStateLabelsType
>
tStateType BaseSubspace<tDerivedSubspaceType,void,tStateType,tStateLabelsType>::GetState(
std::size_t index
) const
{
return tStateType{*static_cast<const tDerivedSubspaceType*>(this), index};
}
template <
typename tDerivedSubspaceType,
typename tStateType, typename tStateLabelsType
>
tStateType BaseSubspace<tDerivedSubspaceType,void,tStateType,tStateLabelsType>::GetState(
const tStateLabelsType& state_labels
) const
{
return tStateType{*static_cast<const tDerivedSubspaceType*>(this), state_labels};
}
// inherit from BaseSubspace and add labels
template <
typename tDerivedSubspaceType, typename tSubspaceLabelsType,
typename tStateType, typename tStateLabelsType
>
class BaseSubspace : public BaseSubspace<tDerivedSubspaceType, void, tStateType, tStateLabelsType>
{
public:
////////////////////////////////////////////////////////////////
// common typedefs
////////////////////////////////////////////////////////////////
using LabelsType = tSubspaceLabelsType;
using SubspaceLabelsType = tSubspaceLabelsType;
protected:
////////////////////////////////////////////////////////////////
// general constructors
////////////////////////////////////////////////////////////////
/// default constructor
// Implicitly invoked by derived class.
BaseSubspace() = default;
// pass-through constructor accepting labels
template<
typename T = SubspaceLabelsType,
std::enable_if_t<std::is_constructible_v<SubspaceLabelsType, T>>* = nullptr
>
explicit BaseSubspace(T&& labels)
: BaseSubspace<tDerivedSubspaceType, void, tStateType, tStateLabelsType>{},
labels_{std::forward<T>(labels)}
{}
public:
////////////////////////////////////////////////////////////////
// retrieval
////////////////////////////////////////////////////////////////
const SubspaceLabelsType& labels() const
/// Return the labels of the subspace itself.
{
return labels_;
}
#ifdef BASIS_ALLOW_DEPRECATED
DEPRECATED("use labels() instead")
const SubspaceLabelsType& GetSubspaceLabels() const
/// Return the labels of the subspace itself.
///
/// DEPRECATED in favor of labels().
///
/// To fix: grep GetSubspaceLabels -R --include="*.cpp"
{
return labels_;
}
#endif
private:
////////////////////////////////////////////////////////////////
// private storage
////////////////////////////////////////////////////////////////
// subspace properties
SubspaceLabelsType labels_;
};
////////////////////////////////////////////////////////////////
// generic state realized within subspace
////////////////////////////////////////////////////////////////
/// BaseState -- realization of a state withinin a given subspace
///
/// The derived class is expected to set up a constructor and
/// friendlier accessors for the individual labels.
///
/// The space (and the indexing it provides) is *not* copied into the
/// state but rather stored by pointer reference. It should
/// therefore exist for the lifetime of the state object.
///
/// Template arguments:
/// tSubspaceType : subspace type in which this state lives
template <typename tSubspaceType>
class BaseState
{
public:
////////////////////////////////////////////////////////////////
// common typedefs
////////////////////////////////////////////////////////////////
using SubspaceType = tSubspaceType;
using LabelsType = typename SubspaceType::StateLabelsType;
using StateLabelsType = typename SubspaceType::StateLabelsType;
protected:
////////////////////////////////////////////////////////////////
// general constructors
////////////////////////////////////////////////////////////////
/// default constructor -- disabled
BaseState();
// copy constructor -- synthesized
// constructors
BaseState(const SubspaceType& subspace, std::size_t index)
/// Construct state, given index within subspace.
: subspace_ptr_(&subspace), index_(index)
{
assert(ValidIndex());
}
BaseState(const SubspaceType& subspace, const StateLabelsType& state_labels)
/// Construct state, by reverse lookup on labels within subspace.
{
// Debugging: Delegation to BaseState(subspace,index)
// fails. Argument index is saved in index_ as far as the
// subordinate BaseState(...,index) call is concerned, but
// after return to present calling constructor, index_
// contains garbage. (Why???)
//
// BaseState(subspace,index);
subspace_ptr_ = &subspace;
index_ = subspace.LookUpStateIndex(state_labels);
assert(index_!=basis::kNone);
}
public:
////////////////////////////////////////////////////////////////
// retrieval
////////////////////////////////////////////////////////////////
const SubspaceType& subspace() const
/// Return reference to subspace in which this state lies.
{return *subspace_ptr_;}
#ifdef BASIS_ALLOW_DEPRECATED
DEPRECATED("use subspace() instead")
const SubspaceType& Subspace() const
/// Return reference to subspace in which this state lies.
///
/// DEPRECATED in favor of subspace().
{return *subspace_ptr_;}
#endif
const StateLabelsType& labels() const
/// Return labels of this state.
///
/// Note: It is not normally expected that this member function
/// should be used directly (see related comment for
/// BaseSubspace::GetStateLabels). Rather, derived types will
/// provide accessors for convenient access to individual labels.
{
return subspace().GetStateLabels(index());
}
#ifdef BASIS_ALLOW_DEPRECATED
DEPRECATED("use labels() instead")
const StateLabelsType& GetStateLabels() const
/// Return labels of this state.
///
/// DEPRECATED in favor of labels().
///
/// Note: It is not normally expected that this member function
/// should be used directly (see related comment for
/// BaseSubspace::GetStateLabels). Rather, derived types will
/// provide accessors for convenient access to individual labels.
{
return Subspace().GetStateLabels(index());
}
#endif
std::size_t index() const
/// Retrieve integer index of state within subspace.
{return index_;}
////////////////////////////////////////////////////////////////
// generic iteration support -- DISABLED
////////////////////////////////////////////////////////////////
// currently DISABLED, pending decision about whether or not
// this is a good thing
//
// Example:
//
// for (RelativeStateLSJT state(space); state.ValidIndex(); ++state)
// {
// std::cout << state.index() << " " << state.N() << std::endl;
// };
//
// This usage requires ValidIndex() to be made public.
// BaseState(const SubspaceType& subspace)
// // Construct state, defaulting to 0th state in space.
// // Meant for use with iterator-style iteration over states.
// {
// space_ptr = subspace;
// index_ = 0;
// }
// BaseState& operator ++();
// // Provide prefix increment operator.
// //
// // Meant for use with iterator-style iteration over states.
// {
// ++index_;
// return *this;
// }
////////////////////////////////////////////////////////////////
// validation
////////////////////////////////////////////////////////////////
private:
std::size_t ValidIndex() const
/// Verify whether or not state indexing lies within allowed
/// dimension.
///
/// For use on construction (or possibly with iteration).
{
return index() < subspace().size();
}
private:
////////////////////////////////////////////////////////////////
// private storage
////////////////////////////////////////////////////////////////
const SubspaceType* subspace_ptr_; ///< subspace in which state lies
std::size_t index_; ///< 0-based index within space
};
////////////////////////////////////////////////////////////////
// generic space
////////////////////////////////////////////////////////////////
/// BaseSpace -- container to hold subspaces, with reverse lookup by
/// subspace labels
///
/// Template arguments:
/// tDerivedSpaceType (typename) : type of the derived space class (for CRTP)
/// tSubspaceType (typename) : type for subspace
/// tSpaceLabelsType (typename, optional) : type for space labels
// declare BaseSpace template
template <typename tDerivedSpaceType, typename tSubspaceType, typename tSpaceLabelsType = void>
class BaseSpace;
// specialize class for case with no labels
template <typename tDerivedSpaceType, typename tSubspaceType>
class BaseSpace<tDerivedSpaceType, tSubspaceType, void>
{
public:
////////////////////////////////////////////////////////////////
// common typedefs
////////////////////////////////////////////////////////////////
using SubspaceType = tSubspaceType;
protected:
////////////////////////////////////////////////////////////////
// constructors
////////////////////////////////////////////////////////////////
BaseSpace()
: dimension_{0}
{}
public:
////////////////////////////////////////////////////////////////
// iterators
////////////////////////////////////////////////////////////////
struct iterator
{
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::make_signed_t<std::size_t>;
using value_type = const SubspaceType;
using pointer = const SubspaceType*;
using reference = const SubspaceType&;
iterator(const tDerivedSpaceType* space_ptr, std::size_t index)
: space_ptr_{space_ptr}, index_{index}
{}
reference operator*() const { return space_ptr_->GetSubspace(index_); }
pointer operator->() const { return &(*this); }
reference operator[](std::size_t index) const { return space_ptr_->GetSubspace(index_+index); }
iterator& operator++() { index_++; return *this; }
iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; }
iterator& operator--() { index_--; return *this; }
iterator operator--(int) { iterator tmp = *this; --(*this); return tmp; }
iterator& operator+=(difference_type n) { index_ += n; return *this; }
iterator& operator-=(difference_type n) { index_ -= n; return *this; }
friend iterator operator+(iterator it, difference_type n) { it += n; return it; }
friend iterator operator-(iterator it, difference_type n) { it -= n; return it; }
friend difference_type operator-(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_ - rhs.index_);
}
friend bool operator==(const iterator& lhs, const iterator& rhs)
{
return (lhs.space_ptr_==rhs.space_ptr_) && (lhs.index_==rhs.index_);
}
friend bool operator!=(const iterator& lhs, const iterator& rhs)
{
return (lhs.space_ptr_!=rhs.space_ptr_) || (lhs.index_!=rhs.index_);
}
friend bool operator<(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_<rhs.index_);
}
friend bool operator>(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_>rhs.index_);
}
friend bool operator<=(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_<=rhs.index_);
}
friend bool operator>=(const iterator& lhs, const iterator& rhs)
{
return (lhs.index_>=rhs.index_);
}
private:
const tDerivedSpaceType* space_ptr_;
std::size_t index_;
};
using value_type = tSubspaceType;
using const_reference = const tSubspaceType&;
using const_iterator = iterator;
using difference_type = typename iterator::difference_type;
using size_type = std::make_unsigned_t<difference_type>;
iterator begin() const { return iterator(static_cast<const tDerivedSpaceType*>(this), 0); }
iterator end() const { return iterator(static_cast<const tDerivedSpaceType*>(this), size()); }
iterator cbegin() const { return iterator(static_cast<const tDerivedSpaceType*>(this), 0); }
iterator cend() const { return iterator(static_cast<const tDerivedSpaceType*>(this), size()); }
////////////////////////////////////////////////////////////////
// subspace lookup and retrieval
////////////////////////////////////////////////////////////////
bool ContainsSubspace(const typename SubspaceType::LabelsType& subspace_labels) const
/// Given the labels for a subspace, returns whether or not the
/// subspace is found within the space.
{
return (subspaces_ptr_) && lookup_.count(subspace_labels);
}
std::size_t LookUpSubspaceIndex(
const typename SubspaceType::LabelsType& subspace_labels
) const
/// Given the labels for a subspace, look up its index within the
/// space.
///
/// If no such labels are found, basis::kNone is returned.
{
// PREVIOUSLY: trap failed lookup with assert for easier debugging
// assert(ContainsSubspace(subspace_labels));
// return lookup_.at(subspace_labels);
// short-circuit if subspaces_ptr_ is nullptr
if (!subspaces_ptr_)
return kNone;
auto pos = lookup_.find(subspace_labels);
if (pos==lookup_.end())
return kNone;
else
return pos->second;
};
const SubspaceType& LookUpSubspace(
const typename SubspaceType::LabelsType& subspace_labels
) const
/// Given the labels for a subspace, retrieve a reference to the
/// subspace.
///
/// If no such labels are found, an exception will result.
{
if (!subspaces_ptr_)
throw std::out_of_range("empty space");
std::size_t subspace_index = LookUpSubspaceIndex(subspace_labels);
if (subspace_index==kNone)
throw std::out_of_range("key not found");
return subspaces_ptr_->at(subspace_index);
};
const SubspaceType& GetSubspace(std::size_t i) const
/// Given the index for a subspace, return a reference to the
/// subspace.
{
if (!subspaces_ptr_)
throw std::out_of_range("empty space");
return subspaces_ptr_->at(i);
};
std::shared_ptr<const SubspaceType> GetSubspacePtr(std::size_t i) const
/// Given the index for a subspace, return a shared pointer to the
/// subspace.
{
if (!subspaces_ptr_)
throw std::out_of_range("empty space");
return std::shared_ptr<const SubspaceType>(
subspaces_ptr_, &(subspaces_ptr_->at(i))
);
};
std::size_t GetSubspaceOffset(std::size_t i) const
/// Given the index for a subspace, return the offset of the subspace
/// in the full space indexing.
{
return subspace_offsets_.at(i);
}
////////////////////////////////////////////////////////////////
// size retrieval
////////////////////////////////////////////////////////////////
std::size_t size() const
/// Return the number of subspaces within the space.
{
if (!subspaces_ptr_)
return 0;
return subspaces_ptr_->size();
};
inline std::size_t full_size() const { return size(); }
/// Get the total number of subspaces, considering degeneracies.
std::size_t dimension() const
// Return the total dimension of all subspaces within the space.
{
return dimension_;
}
#ifdef BASIS_ALLOW_DEPRECATED
DEPRECATED("use dimension() instead")
std::size_t Dimension() const
/// Return the total dimension of all subspaces within the space.
{
std::size_t dimension = 0;
for (std::size_t subspace_index=0; subspace_index<size(); ++subspace_index)
dimension += GetSubspace(subspace_index).size();
return dimension;
}
#endif
protected:
////////////////////////////////////////////////////////////////