Hypercube.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <array>
7 #include <cstddef>
8 #include <limits>
9 #include <ostream>
10 
13 #include "Utilities/Gsl.hpp"
14 #include "Utilities/Requires.hpp"
15 #include "Utilities/StdHelpers.hpp"
16 
17 /*!
18  * \brief An element of dimension `ElementDim` on the boundary of a hypercube of
19  * dimension `HypercubeDim`
20  *
21  * A hypercube of dimension \f$n\f$ (`HypercubeDim`) is composed of
22  * \f$2^{n-k}\binom{n}{k}\f$ elements of dimension \f$k \leq n\f$
23  * (`ElementDim`). For example, a 3D cube has 8 vertices (\f$k=0\f$), 12 edges
24  * (\f$k=1\f$), 6 faces (\f$k=2\f$) and 1 cell (\f$k=3\f$). Each element is
25  * identified by the \f$k\f$ dimensions it shares with the parent hypercube
26  * and \f$n - k\f$ indices that specify whether it is located on the lower or
27  * upper side of the parent hypercube's remaining dimensions.
28  */
29 template <size_t ElementDim, size_t HypercubeDim>
31  static_assert(ElementDim <= HypercubeDim);
32 
35 
36  template <size_t NumIndices = HypercubeDim - ElementDim,
37  Requires<NumIndices == 0> = nullptr>
38  HypercubeElement() noexcept {
39  for (size_t d = 0; d < ElementDim; ++d) {
40  gsl::at(dimensions_in_parent_, d) = d;
41  }
42  }
43 
44  template <size_t LocalElementDim = ElementDim,
47 
48  template <typename... Indices, size_t LocalElementDim = ElementDim,
49  size_t LocalHypercubeDim = HypercubeDim,
50  Requires<(LocalElementDim == 0 and LocalHypercubeDim > 0 and
51  sizeof...(Indices) == LocalHypercubeDim)> = nullptr>
52  explicit HypercubeElement(Indices... indices) noexcept
53  : index_{{static_cast<Side>(indices)...}} {}
54 
55  template <size_t LocalElementDim = ElementDim,
57  HypercubeElement(size_t dim_in_parent,
59 
60  // @{
61  /// The parent hypercube's dimensions that this element shares
63 
64  template <size_t LocalElementDim = ElementDim,
66  size_t dimension_in_parent() const noexcept;
67  // @}
68 
69  // @{
70  /// Whether this element is located on the lower or upper side in those
71  /// dimensions that it does not share with its parent hypercube
72  const std::array<Side, HypercubeDim - ElementDim>& index() const noexcept;
73 
74  const Side& side_in_parent_dimension(size_t d) const noexcept;
75 
76  template <size_t NumIndices = HypercubeDim - ElementDim,
77  Requires<NumIndices == 1> = nullptr>
78  const Side& side() const noexcept {
79  return index_[0];
80  }
81  // @}
82 
83  bool operator==(const HypercubeElement& rhs) const noexcept {
84  return dimensions_in_parent_ == rhs.dimensions_in_parent_ and
85  index_ == rhs.index_;
86  }
87 
88  bool operator!=(const HypercubeElement& rhs) const noexcept {
89  return not(*this == rhs);
90  }
91 
92  private:
93  std::array<size_t, ElementDim> dimensions_in_parent_{};
94  std::array<Side, HypercubeDim - ElementDim> index_{};
95 };
96 
97 template <size_t ElementDim, size_t HypercubeDim>
98 std::ostream& operator<<(
99  std::ostream& os,
100  const HypercubeElement<ElementDim, HypercubeDim>& element) noexcept;
101 
102 /// A vertex in a `Dim`-dimensional hypercube
103 template <size_t Dim>
105 
106 /// An edge in a `Dim`-dimensional hypercube
107 template <size_t Dim>
109 
110 /// A face in a `Dim`-dimensional hypercube
111 template <size_t Dim>
113 
114 /// A cell in a `Dim`-dimensional hypercube
115 template <size_t Dim>
117 
118 /*!
119  * \brief Iterator over all `ElementDim`-dimensional elements on the boundary of
120  * a `HypercubeDim`-dimensional hypercube.
121  *
122  * \see `HypercubeElement`
123  */
124 template <size_t ElementDim, size_t HypercubeDim>
126  static_assert(
127  ElementDim <= HypercubeDim,
128  "Hypercube element dimension must not exceed hypercube dimension.");
129 
130  public:
131  static constexpr size_t num_indices = HypercubeDim - ElementDim;
132 
133  /// The number of `ElementDim`-dimensional elements on the boundary of a
134  /// `HypercubeDim`-dimensional hypercube.
135  static constexpr size_t size() noexcept {
136  return two_to_the(num_indices) * factorial(HypercubeDim) /
137  factorial(ElementDim) / factorial(num_indices);
138  }
139 
140  HypercubeElementsIterator() noexcept;
141 
142  static HypercubeElementsIterator begin() noexcept;
143 
144  static HypercubeElementsIterator end() noexcept;
145 
146  HypercubeElementsIterator& operator++() noexcept;
147 
148  // NOLINTNEXTLINE(cert-dcl21-cpp) returned object doesn't need to be const
149  HypercubeElementsIterator operator++(int) noexcept;
150 
151  HypercubeElement<ElementDim, HypercubeDim> operator*() const noexcept;
152 
153  private:
154  template <size_t LocalElementDim = ElementDim,
155  Requires<(LocalElementDim > 0)> = nullptr>
156  void increment_dimension_in_parent(size_t d) noexcept;
157 
158  template <size_t LocalElementDim, size_t LocalHypercubeDim>
159  // NOLINTNEXTLINE(readability-redundant-declaration)
160  friend bool operator==(
161  const HypercubeElementsIterator<LocalElementDim, LocalHypercubeDim>& lhs,
162  const HypercubeElementsIterator<LocalElementDim, LocalHypercubeDim>&
163  rhs) noexcept;
164 
165  std::array<size_t, ElementDim> dimensions_in_parent_{};
166  size_t index_ = std::numeric_limits<size_t>::max();
167 };
168 
169 template <size_t ElementDim, size_t HypercubeDim>
170 bool operator!=(
173 
174 /// Iterate over all vertices in a `Dim`-dimensional hypercube
175 template <size_t Dim>
177 
178 /// Iterate over all edges in a `Dim`-dimensional hypercube
179 template <size_t Dim>
181 
182 /// Iterate over all faces in a `Dim`-dimensional hypercube
183 template <size_t Dim>
185 
186 /// Iterate over all cells in a `Dim`-dimensional hypercube
187 template <size_t Dim>
gsl::at
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid.
Definition: Gsl.hpp:125
two_to_the
constexpr T two_to_the(T n)
Definition: ConstantExpressions.hpp:36
HypercubeElementsIterator
Iterator over all ElementDim-dimensional elements on the boundary of a HypercubeDim-dimensional hyper...
Definition: Hypercube.hpp:125
std::rel_ops::operator!=
T operator!=(T... args)
HypercubeElement::index
const std::array< Side, HypercubeDim - ElementDim > & index() const noexcept
Whether this element is located on the lower or upper side in those dimensions that it does not share...
Definition: Hypercube.cpp:78
Side.hpp
factorial
constexpr uint64_t factorial(const uint64_t n) noexcept
Compute the factorial of .
Definition: ConstantExpressions.hpp:89
HypercubeElementsIterator::size
static constexpr size_t size() noexcept
The number of ElementDim-dimensional elements on the boundary of a HypercubeDim-dimensional hypercube...
Definition: Hypercube.hpp:135
std::ostream
cstddef
array
HypercubeElement::dimensions_in_parent
const std::array< size_t, ElementDim > & dimensions_in_parent() const noexcept
The parent hypercube's dimensions that this element shares.
Definition: Hypercube.cpp:64
ConstantExpressions.hpp
HypercubeElement
An element of dimension ElementDim on the boundary of a hypercube of dimension HypercubeDim
Definition: Hypercube.hpp:30
Side
Side
Definition: Side.hpp:17
limits
Gsl.hpp
Requires.hpp
StdHelpers.hpp
Requires
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t
Definition: Requires.hpp:67
std::numeric_limits::max
T max(T... args)
ostream