PhysicsBasedAnimationToolkit 0.0.10
Cross-platform C++20 library of algorithms and data structures commonly used in computer graphics research on physically-based simulation.
Loading...
Searching...
No Matches
Adjacency.h
Go to the documentation of this file.
1
9
10#ifndef PBAT_GRAPH_ADJACENCY_H
11#define PBAT_GRAPH_ADJACENCY_H
12
13#include "pbat/Aliases.h"
14#include "pbat/common/ArgSort.h"
15#include "pbat/common/Eigen.h"
17
18#include <concepts>
19#include <iterator>
20#include <tuple>
21#include <vector>
22
23namespace pbat {
24namespace graph {
25
32template <class TWeight = Scalar, class TIndex = Index>
33using WeightedEdge = Eigen::Triplet<TWeight, TIndex>;
34
40template <class TWeightedEdge>
42{
43 using ScalarType = std::remove_cvref_t<
44 decltype(std::declval<TWeightedEdge>().value())>;
45 using IndexType =
46 std::remove_cvref_t<decltype(std::declval<TWeightedEdge>().row())>;
48};
49
65template <
66 class TWeightedEdgeIterator,
67 class TWeightedEdge = typename std::iterator_traits<TWeightedEdgeIterator>::value_type,
68 class TScalar = typename WeightedEdgeTraits<TWeightedEdge>::ScalarType,
71 TWeightedEdgeIterator begin,
72 TWeightedEdgeIterator end,
73 TIndex m = TIndex(-1),
74 TIndex n = TIndex(-1)) -> Eigen::SparseMatrix<TScalar, Eigen::RowMajor, TIndex>
75{
76 if (m < 0)
77 {
78 m = std::max_element(
79 begin,
80 end,
81 [](TWeightedEdge const& lhs, TWeightedEdge const& rhs) {
82 return lhs.row() < rhs.row();
83 })
84 ->row() +
85 TIndex(1);
86 }
87 if (n < 0)
88 {
89 n = std::max_element(
90 begin,
91 end,
92 [](TWeightedEdge const& lhs, TWeightedEdge const& rhs) {
93 return lhs.col() < rhs.col();
94 })
95 ->col() +
96 TIndex(1);
97 }
98 Eigen::SparseMatrix<TScalar, Eigen::RowMajor, TIndex> G(m, n);
99 G.setFromTriplets(begin, end);
100 return G;
101}
102
112template <
113 class TDerivedA,
114 class TScalar = typename TDerivedA::Scalar,
115 std::integral TIndex = typename TDerivedA::StorageIndex>
116auto AdjacencyMatrixPrefix(Eigen::SparseCompressedBase<TDerivedA> const& A)
117{
118 using IndexVectorType = Eigen::Map<Eigen::Vector<TIndex, Eigen::Dynamic>>;
119 return Eigen::Map<IndexVectorType const>(A.outerIndexPtr(), A.outerSize() + 1);
120}
121
131template <
132 class TDerivedA,
133 class TScalar = typename TDerivedA::Scalar,
134 std::integral TIndex = typename TDerivedA::StorageIndex>
135auto AdjacencyMatrixIndices(Eigen::SparseCompressedBase<TDerivedA> const& A)
136{
137 using IndexVectorType = Eigen::Map<Eigen::Vector<TIndex, Eigen::Dynamic>>;
138 return Eigen::Map<IndexVectorType const>(A.innerIndexPtr(), A.nonZeros());
139}
140
150template <
151 class TDerivedA,
152 class TScalar = typename TDerivedA::Scalar,
153 std::integral TIndex = typename TDerivedA::StorageIndex>
154auto AdjacencyMatrixWeights(Eigen::SparseCompressedBase<TDerivedA> const& A)
155{
156 using WeightVectorType = Eigen::Map<Eigen::Vector<TScalar, Eigen::Dynamic>>;
157 return Eigen::Map<WeightVectorType const>(A.valuePtr(), A.nonZeros());
158}
159
171template <class TDerivedP, std::integral TIndex = typename TDerivedP::Scalar>
172auto MapToAdjacency(Eigen::DenseBase<TDerivedP> const& p, TIndex n = TIndex(-1))
173 -> std::tuple<Eigen::Vector<TIndex, Eigen::Dynamic>, Eigen::Vector<TIndex, Eigen::Dynamic>>
174{
175 if (n < 0)
176 n = p.maxCoeff() + TIndex(1);
177 auto s = common::Counts(p.begin(), p.end(), n);
178 auto ptr = common::CumSum(s);
179 auto adj = common::ArgSort(p.size(), [&](auto i, auto j) { return p(i) < p(j); });
180 return std::make_tuple(ptr, adj);
181}
182
192template <
193 class TDerivedA,
194 class TScalar = typename TDerivedA::Scalar,
195 std::integral TIndex = typename TDerivedA::StorageIndex>
196auto MatrixToAdjacency(Eigen::SparseCompressedBase<TDerivedA> const& A)
197{
198 return std::make_tuple(
201}
202
212template <
213 class TDerivedA,
214 class TScalar = typename TDerivedA::Scalar,
215 std::integral TIndex = typename TDerivedA::StorageIndex>
216auto MatrixToWeightedAdjacency(Eigen::SparseCompressedBase<TDerivedA> const& A)
217{
218 return std::make_tuple(
222}
223
232template <class TIndex = Index>
233auto ListOfListsToAdjacency(std::vector<std::vector<TIndex>> const& lil)
234{
235 auto n = static_cast<TIndex>(lil.size());
236 TIndex nEdges{0};
237 using IndexVectorType = Eigen::Vector<TIndex, Eigen::Dynamic>;
238 IndexVectorType ptr(n + TIndex(1));
239 ptr(0) = TIndex(0);
240 for (auto l = 0; l < n; ++l)
241 {
242 auto lStl = static_cast<std::size_t>(l);
243 auto nVerticesInPartition = static_cast<TIndex>(lil[lStl].size());
244 ptr(l + 1) = ptr(l) + nVerticesInPartition;
245 nEdges += nVerticesInPartition;
246 }
247 IndexVectorType adj(nEdges);
248 for (auto l = 0; l < n; ++l)
249 {
250 auto start = ptr(l);
251 auto end = ptr(l + 1);
252 auto lStl = static_cast<std::size_t>(l);
253 adj(Eigen::seqN(start, end - start)) = common::ToEigen(lil[lStl]);
254 }
255 return std::make_tuple(ptr, adj);
256}
257
270template <
271 class TDerivedPtr,
272 class TDerivedAdj,
273 class TIndex = typename TDerivedPtr::Scalar,
274 class Func>
275void ForEachEdge(Eigen::DenseBase<TDerivedPtr>& ptr, Eigen::DenseBase<TDerivedAdj>& adj, Func&& f)
276{
277 auto nVertices = ptr.size() - 1;
278 for (TIndex u = 0; u < nVertices; ++u)
279 {
280 auto uBegin = ptr(u);
281 auto uEnd = ptr(u + 1);
282 for (auto k = uBegin; k < uEnd; ++k)
283 {
284 auto v = adj(k);
285 f(u, v, k);
286 }
287 }
288}
289
302template <
303 class TDerivedPtr,
304 class TDerivedAdj,
305 class TIndex = typename TDerivedPtr::Scalar,
306 class Func>
308 Eigen::DenseBase<TDerivedPtr>& ptr,
309 Eigen::DenseBase<TDerivedAdj>& adj,
310 Func fShouldDeleteEdge)
311{
312 auto nPartitions = ptr.size() - 1;
313 using IndexVectorType = Eigen::Vector<TIndex, Eigen::Dynamic>;
314 IndexVectorType sizes(nPartitions);
315 sizes.setZero();
316 TIndex nEdges(0);
317 // Compress edges by discarding edges to remove
318 IndexVectorType adjTmp(adj.size());
319 IndexVectorType ptrTmp = ptr;
320 for (auto p = 0, kk = 0; p < nPartitions; ++p)
321 {
322 auto kBegin = ptr(p);
323 auto kEnd = ptr(p + TIndex(1));
324 sizes(p) = kEnd - kBegin;
325 for (auto k = kBegin; k < kEnd; ++k)
326 {
327 if (fShouldDeleteEdge(p, adj(k)))
328 {
329 --sizes(p);
330 }
331 else
332 {
333 adjTmp(kk) = adj(k);
334 ++kk;
335 }
336 }
337 nEdges += sizes(p);
338 ptrTmp(p + TIndex(1)) = ptrTmp(p) + sizes(p);
339 }
340 ptr = ptrTmp;
341 adj = adjTmp.head(nEdges);
342}
343
344} // namespace graph
345} // namespace pbat
346
347#endif // PBAT_GRAPH_ADJACENCY_H
Non-intrusive sorting.
Eigen adaptors for ranges.
auto Counts(auto begin, auto end, TIndex ncounts) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Counts the number of occurrences of each integer in a contiguous range.
Definition Indexing.h:57
auto CumSum(R &&sizes) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Cumulative sum of a range of integers.
Definition Indexing.h:34
auto ArgSort(TIndex n, FLess less) -> Eigen::Vector< TIndex, Eigen::Dynamic >
Computes the indices that would sort an array.
Definition ArgSort.h:32
auto ToEigen(R &&r) -> Eigen::Map< Eigen::Vector< std::ranges::range_value_t< R >, Eigen::Dynamic > const >
Map a range of scalars to an eigen vector of such scalars.
Definition Eigen.h:28
Definition Adjacency.h:24
Eigen::Triplet< TWeight, TIndex > WeightedEdge
Weighted edge (wrapper around Eigen triplet type)
Definition Adjacency.h:33
void ForEachEdge(Eigen::DenseBase< TDerivedPtr > &ptr, Eigen::DenseBase< TDerivedAdj > &adj, Func &&f)
Edge iteration over the adjacency list in compressed sparse format.
Definition Adjacency.h:275
auto AdjacencyMatrixFromEdges(TWeightedEdgeIterator begin, TWeightedEdgeIterator end, TIndex m=TIndex(-1), TIndex n=TIndex(-1)) -> Eigen::SparseMatrix< TScalar, Eigen::RowMajor, TIndex >
Construct adjacency matrix from edge/triplet list.
Definition Adjacency.h:70
auto ListOfListsToAdjacency(std::vector< std::vector< TIndex > > const &lil)
Construct adjacency list in compressed sparse format from an input adjacency list in list of lists fo...
Definition Adjacency.h:233
auto AdjacencyMatrixIndices(Eigen::SparseCompressedBase< TDerivedA > const &A)
Non-owning wrapper around the indices of a compressed sparse matrix.
Definition Adjacency.h:135
auto MatrixToWeightedAdjacency(Eigen::SparseCompressedBase< TDerivedA > const &A)
Construct adjacency list in compressed sparse format from an input adjacency matrix.
Definition Adjacency.h:216
auto MapToAdjacency(Eigen::DenseBase< TDerivedP > const &p, TIndex n=TIndex(-1)) -> std::tuple< Eigen::Vector< TIndex, Eigen::Dynamic >, Eigen::Vector< TIndex, Eigen::Dynamic > >
Construct adjacency list in compressed sparse format from a map p s.t. p(i) is the index of the verte...
Definition Adjacency.h:172
void RemoveEdges(Eigen::DenseBase< TDerivedPtr > &ptr, Eigen::DenseBase< TDerivedAdj > &adj, Func fShouldDeleteEdge)
In-place removal of edges from the adjacency list in compressed sparse format.
Definition Adjacency.h:307
auto AdjacencyMatrixWeights(Eigen::SparseCompressedBase< TDerivedA > const &A)
Non-owning wrapper around the weights of a compressed sparse matrix.
Definition Adjacency.h:154
auto MatrixToAdjacency(Eigen::SparseCompressedBase< TDerivedA > const &A)
Obtain the offset and indices arrays of an input adjacency matrix.
Definition Adjacency.h:196
auto AdjacencyMatrixPrefix(Eigen::SparseCompressedBase< TDerivedA > const &A)
Non-owning wrapper around the offset pointers of a compressed sparse matrix.
Definition Adjacency.h:116
The main namespace of the library.
Definition Aliases.h:15
Traits for WeightedEdge.
Definition Adjacency.h:42
std::remove_cvref_t< decltype(std::declval< TWeightedEdge >().value())> ScalarType
Scalar type of the graph edge weights.
Definition Adjacency.h:43
std::remove_cvref_t< decltype(std::declval< TWeightedEdge >().row())> IndexType
Definition Adjacency.h:45