DOLFINx 0.12.0.0
DOLFINx C++
Loading...
Searching...
No Matches
AdjacencyList.h
1// Copyright (C) 2019-2025 Garth N. Wells
2//
3// This file is part of DOLFINx (https://www.fenicsproject.org)
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6
7#pragma once
8
9#include <cassert>
10#include <concepts>
11#include <cstdint>
12#include <format>
13#include <iterator>
14#include <numeric>
15#include <optional>
16#include <span>
17#include <stdexcept>
18#include <string>
19#include <utility>
20#include <vector>
21
23{
39template <typename LinkData, typename NodeData = std::nullptr_t>
41{
42public:
44 using link_type = LinkData;
46 using node_data_type = NodeData;
47
51 explicit AdjacencyList(const std::int32_t n) : _array(n), _offsets(n + 1)
52 {
53 std::iota(_array.begin(), _array.end(), 0);
54 std::iota(_offsets.begin(), _offsets.end(), 0);
55 }
56
64 template <typename U, typename V>
65 requires std::is_convertible_v<std::remove_cvref_t<U>,
66 std::vector<LinkData>>
67 and std::is_convertible_v<std::remove_cvref_t<V>,
68 std::vector<std::int32_t>>
69 AdjacencyList(U&& data, V&& offsets)
70 : _array(std::forward<U>(data)), _offsets(std::forward<V>(offsets))
71 {
72 if (_offsets.back() != (std::int32_t)_array.size())
73 {
74 throw std::runtime_error("Last offset must equal the size of the data "
75 "array.");
76 }
77 }
78
87 template <typename U, typename V, typename W>
88 requires std::is_convertible_v<std::remove_cvref_t<U>,
89 std::vector<LinkData>>
90 and std::is_convertible_v<std::remove_cvref_t<V>,
91 std::vector<std::int32_t>>
92 and std::is_convertible_v<std::remove_cvref_t<W>,
93 std::vector<NodeData>>
94 AdjacencyList(U&& data, V&& offsets, W&& node_data)
95 : _array(std::forward<U>(data)), _offsets(std::forward<V>(offsets)),
96 _node_data(std::forward<W>(node_data))
97 {
98 if (!_node_data.has_value() or _node_data->size() != _offsets.size() - 1)
99 {
100 throw std::runtime_error("Node data size must equal the number of "
101 "nodes.");
102 }
103 _array.reserve(_offsets.back());
104 if (_offsets.back() != (std::int32_t)_array.size())
105 {
106 throw std::runtime_error("Last offset must equal the size of the data "
107 "array.");
108 }
109 }
110
116 template <typename X>
117 explicit AdjacencyList(const std::vector<X>& data)
118 {
119 // Initialize offsets and compute total size
120 _offsets.reserve(data.size() + 1);
121 _offsets.push_back(0);
122 for (auto& row : data)
123 _offsets.push_back(_offsets.back() + row.size());
124
125 _array.reserve(_offsets.back());
126 for (auto& e : data)
127 _array.insert(_array.end(), e.begin(), e.end());
128 }
129
131 AdjacencyList(const AdjacencyList& list) = default;
132
134 AdjacencyList(AdjacencyList&& list) = default;
135
137 ~AdjacencyList() = default;
138
140 AdjacencyList& operator=(const AdjacencyList& list) = default;
141
144
147 bool operator==(const AdjacencyList& list) const
148 {
149 return this->_array == list._array and this->_offsets == list._offsets;
150 }
151
154 std::int32_t num_nodes() const { return _offsets.size() - 1; }
155
159 int num_links(std::size_t node) const
160 {
161 assert((node + 1) < _offsets.size());
162 return _offsets[node + 1] - _offsets[node];
163 }
164
169 std::span<LinkData> links(std::size_t node)
170 {
171 auto it = std::next(_offsets.begin(), node);
172 return std::span<LinkData>(std::next(_array.begin(), *it),
173 std::next(_array.begin(), *(it + 1)));
174 }
175
180 std::span<const LinkData> links(std::size_t node) const
181 {
182 auto it = std::next(_offsets.begin(), node);
183 return std::span<const LinkData>(std::next(_array.begin(), *it),
184 std::next(_array.begin(), *(it + 1)));
185 }
186
188 const std::vector<LinkData>& array() const { return _array; }
189
191 std::vector<LinkData>& array() { return _array; }
192
194 const std::vector<std::int32_t>& offsets() const { return _offsets; }
195
197 std::vector<std::int32_t>& offsets() { return _offsets; }
198
201 const std::optional<std::vector<NodeData>>& node_data() const
202 {
203 return _node_data;
204 }
205
208 std::optional<std::vector<NodeData>>& node_data() { return _node_data; }
209
212 std::string str() const
213 {
214 std::string s
215 = std::format("<AdjacencyList> with {} nodes\n", this->num_nodes());
216 for (std::size_t e = 0; e < _offsets.size() - 1; ++e)
217 {
218 std::format_to(std::back_inserter(s), " {}: [", e);
219 for (auto link : this->links(e))
220 std::format_to(std::back_inserter(s), "{} ", link);
221 s += "]\n";
222 }
223 return s;
224 }
225
226private:
227 // Connections (links/edges) for all entities stored as a contiguous
228 // array
229 std::vector<LinkData> _array;
230
231 // Position of first connection for each entity (using local index)
232 std::vector<std::int32_t> _offsets;
233
234 // Node data, where _node_data[i] is the data associated with node `i`
235 std::optional<std::vector<NodeData>> _node_data = std::nullopt;
236};
237
239template <typename T, typename U>
240AdjacencyList(T, U) -> AdjacencyList<typename T::value_type, std::nullptr_t>;
241
243template <typename T, typename U, typename W>
244AdjacencyList(T, U, W)
245 -> AdjacencyList<typename T::value_type, typename W::value_type>;
246
255template <typename V = std::nullptr_t, typename U>
256 requires requires {
257 typename std::decay_t<U>::value_type;
258 requires std::convertible_to<
259 U, std::vector<typename std::decay_t<U>::value_type>>;
260 }
261AdjacencyList<typename std::decay_t<U>::value_type, V>
262regular_adjacency_list(U&& data, int degree)
263{
264 if (degree == 0 and !data.empty())
265 {
266 throw std::runtime_error("Degree is zero but data is not empty for "
267 "constant degree AdjacencyList");
268 }
269
270 if (degree > 0 and data.size() % degree != 0)
271 {
272 throw std::runtime_error(
273 "Incompatible data size and degree for constant degree AdjacencyList");
274 }
275
276 std::int32_t num_nodes = degree == 0 ? data.size() : data.size() / degree;
277 std::vector<std::int32_t> offsets(num_nodes + 1, 0);
278 for (std::size_t i = 1; i < offsets.size(); ++i)
279 offsets[i] = offsets[i - 1] + degree;
281 std::forward<U>(data), std::move(offsets));
282}
283
284} // namespace dolfinx::graph
This class provides a static adjacency list data structure.
Definition AdjacencyList.h:41
int num_links(std::size_t node) const
Number of connections for given node.
Definition AdjacencyList.h:159
bool operator==(const AdjacencyList &list) const
Definition AdjacencyList.h:147
std::vector< std::int32_t > & offsets()
Offset for each node in array().
Definition AdjacencyList.h:197
AdjacencyList & operator=(AdjacencyList &&list)=default
Move assignment operator.
AdjacencyList(U &&data, V &&offsets, W &&node_data)
Construct adjacency list from arrays of link (edge) data, offsets, and node data.
Definition AdjacencyList.h:94
const std::vector< LinkData > & array() const
Return contiguous array of links for all nodes (const version).
Definition AdjacencyList.h:188
AdjacencyList(const std::int32_t n)
Construct trivial adjacency list where each of the n nodes is connected to itself.
Definition AdjacencyList.h:51
AdjacencyList(AdjacencyList &&list)=default
Move constructor.
AdjacencyList & operator=(const AdjacencyList &list)=default
Assignment operator.
std::span< LinkData > links(std::size_t node)
Get the links (edges) for given node.
Definition AdjacencyList.h:169
AdjacencyList(U &&data, V &&offsets)
Construct adjacency list from arrays of link (edge) data and offsets.
Definition AdjacencyList.h:69
AdjacencyList(const std::vector< X > &data)
Definition AdjacencyList.h:117
NodeData node_data_type
Adjacency list node data type.
Definition AdjacencyList.h:46
std::int32_t num_nodes() const
Get the number of nodes.
Definition AdjacencyList.h:154
AdjacencyList(const AdjacencyList &list)=default
Copy constructor.
LinkData link_type
Adjacency list link (edge) type.
Definition AdjacencyList.h:44
const std::optional< std::vector< NodeData > > & node_data() const
Definition AdjacencyList.h:201
const std::vector< std::int32_t > & offsets() const
Offset for each node in array() (const version).
Definition AdjacencyList.h:194
std::span< const LinkData > links(std::size_t node) const
Get the links (edges) for given node (const version).
Definition AdjacencyList.h:180
std::string str() const
Informal string representation (pretty-print).
Definition AdjacencyList.h:212
std::optional< std::vector< NodeData > > & node_data()
Definition AdjacencyList.h:208
~AdjacencyList()=default
Destructor.
std::vector< LinkData > & array()
Return contiguous array of links for all nodes.
Definition AdjacencyList.h:191
Graph data structures and algorithms.
Definition AdjacencyList.h:23
AdjacencyList< typename std::decay_t< U >::value_type, V > regular_adjacency_list(U &&data, int degree)
Construct a constant degree (valency) adjacency list.
Definition AdjacencyList.h:262