KratosMultiphysics
KRATOS Multiphysics (Kratos) is a framework for building parallel, multi-disciplinary simulation software, aiming at modularity, extensibility, and high performance. Kratos is written in C++, and counts with an extensive Python interface.
sparse_graph.h
Go to the documentation of this file.
1 // | / |
2 // ' / __| _` | __| _ \ __|
3 // . \ | ( | | ( |\__ `
4 // _|\_\_| \__,_|\__|\___/ ____/
5 // Multi-Physics
6 //
7 // License: BSD License
8 // Kratos default license: kratos/license.txt
9 //
10 // Main authors: Riccardo Rossi
11 //
12 
13 #if !defined(KRATOS_SPARSE_GRAPH_H_INCLUDED )
14 #define KRATOS_SPARSE_GRAPH_H_INCLUDED
15 
16 
17 // System includes
18 #include <iostream>
19 #include <unordered_map>
20 #include <unordered_set>
21 
22 // External includes
23 #include <span/span.hpp>
24 
25 // Project includes
26 #include "includes/define.h"
29 #include "includes/serializer.h"
31 
32 namespace Kratos
33 {
36 
39 
43 
47 
51 
55 
57 //class to construct and store a matrix graph. Can be used to construct efficiently a CSR matrix (or other sparse matrix types)
58 
64 template<class TIndexType=std::size_t>
65 class SparseGraph final
66 {
67 public:
70  typedef TIndexType IndexType;
71  typedef std::map<IndexType, std::unordered_set<IndexType> > GraphType; //using a map since we need it ordered
72  typedef typename GraphType::const_iterator const_row_iterator;
73 
76 
80 
82  {
83  mpComm = &ParallelEnvironment::GetDataCommunicator("Serial"); //that's the only option
84  }
85 
88  {
89  mpComm = &ParallelEnvironment::GetDataCommunicator("Serial"); //thats the only option
90  }
91 
93  {
94  if(rComm.IsDistributed())
95  KRATOS_ERROR << "Attempting to construct a serial CsrMatrix with a distributed communicator" << std::endl;
96 
97  mpComm = &rComm;
98  }
99 
102 
104  SparseGraph(const SparseGraph& rOther)
105  :
106  mpComm(rOther.mpComm),
107  mGraph(rOther.mGraph)
108  {
109  }
110 
111  SparseGraph(const std::vector<IndexType>& rSingleVectorRepresentation)
112  {
113  AddFromSingleVectorRepresentation(rSingleVectorRepresentation);
114  }
115 
119  const DataCommunicator& GetComm() const
120  {
121  return *mpComm;
122  }
123 
124  const DataCommunicator* pGetComm() const
125  {
126  return mpComm;
127  }
128 
129  IndexType Size() const
130  {
131  if(!this->GetGraph().empty())
132  return (--(this->GetGraph().end()))->first + 1; //last key in the map + 1
133  return 0;
134  }
135 
136  bool IsEmpty() const
137  {
138  return mGraph.empty();
139  }
140 
141  bool Has(const IndexType I, const IndexType J) const
142  {
143  const auto& row_it = mGraph.find(I);
144  if(row_it != mGraph.end() ) {
145  if((row_it->second).find(J) != (row_it->second).end())
146  return true;
147  }
148  return false;
149  }
150 
151  const typename GraphType::mapped_type& operator[](const IndexType& Key) const
152  {
153  return (mGraph.find(Key))->second;
154  }
155 
156  void Clear()
157  {
158  mGraph.clear();
159  }
160 
161  void AddEntry(const IndexType RowIndex, const IndexType ColIndex)
162  {
163  mGraph[RowIndex].insert(ColIndex);
164  }
165 
166  template<class TContainerType>
167  void AddEntries(const IndexType RowIndex, const TContainerType& rColIndices)
168  {
169  mGraph[RowIndex].insert(rColIndices.begin(), rColIndices.end());
170  }
171 
172  template<class TIteratorType>
173  void AddEntries(const IndexType RowIndex,
174  const TIteratorType& rColBegin,
175  const TIteratorType& rColEnd
176  )
177  {
178  mGraph[RowIndex].insert(rColBegin, rColEnd);
179  }
180 
181  template<class TContainerType>
182  void AddEntries(const TContainerType& rIndices)
183  {
184  for(auto I : rIndices)
185  mGraph[I].insert(rIndices.begin(), rIndices.end());
186  }
187 
188  template<class TContainerType>
189  void AddEntries(const TContainerType& rRowIndices, const TContainerType& rColIndices)
190  {
191  for(auto I : rRowIndices)
192  AddEntries(I, rColIndices);
193  }
194 
195 
196  void AddEntries(SparseGraph& rOtherGraph)
197  {
198  for(const auto& item: rOtherGraph.GetGraph())
199  {
200  AddEntries(item.first, item.second);
201  }
202  }
203 
204  void Finalize()
205  {
206  }
207 
208  const GraphType& GetGraph() const{
209  return mGraph;
210  }
211 
212 
213  //note that this function is slightly less efficient than the span version below
214  template<class TVectorType=DenseVector<IndexType>>
216  TVectorType& rRowIndices,
217  TVectorType& rColIndices
218  ) const
219  {
220  IndexType* pRowIndicesData=nullptr;
221  IndexType RowIndicesDataSize=0;
222  IndexType* pColIndicesData=nullptr;
223  IndexType ColIndicesDataSize=0;
224  ExportCSRArrays(pRowIndicesData,RowIndicesDataSize,pColIndicesData,ColIndicesDataSize);
225  if(rRowIndices.size() != RowIndicesDataSize)
226  rRowIndices.resize(RowIndicesDataSize);
227  IndexPartition<IndexType>(RowIndicesDataSize).for_each(
228  [&](IndexType i){rRowIndices[i] = pRowIndicesData[i];}
229  );
230 
231  delete [] pRowIndicesData;
232  if(rColIndices.size() != ColIndicesDataSize)
233  rColIndices.resize(ColIndicesDataSize);
234  IndexPartition<IndexType>(ColIndicesDataSize).for_each(
235  [&](IndexType i){rColIndices[i] = pColIndicesData[i];}
236  );
237  delete [] pColIndicesData;
238 
239  return rRowIndices.size();
240  }
241 
243  Kratos::span<IndexType>& rRowIndices,
244  Kratos::span<IndexType>& rColIndices
245  ) const = delete;
246 
247  //NOTE this function will transfer ownership of pRowIndicesData and pColIndicesData to the caller
248  //hence the caller will be in charge of deleting that array
250  IndexType*& pRowIndicesData,
251  IndexType& rRowDataSize,
252  IndexType*& pColIndicesData,
253  IndexType& rColDataSize
254  ) const
255  {
256  //need to detect the number of rows this way since there may be gaps
257  IndexType nrows=this->Size();
258 
259  pRowIndicesData = new IndexType[nrows+1];
260  rRowDataSize = nrows+1;
261  Kratos::span<IndexType> row_indices(pRowIndicesData, nrows+1);
262 
263  //set it to zero in parallel to allow first touching
264  IndexPartition<IndexType>(row_indices.size()).for_each([&](IndexType i){
265  row_indices[i] = 0;
266  });
267 
268  //count the entries TODO: do the loop in parallel if possible
269  for(const auto& item : this->GetGraph())
270  {
271  row_indices[item.first+1] = item.second.size();
272  }
273 
274  //sum entries
275  for(int i = 1; i<static_cast<int>(row_indices.size()); ++i){
276  row_indices[i] += row_indices[i-1];
277  }
278 
279 
280  IndexType nnz = row_indices[nrows];
281  rColDataSize = nnz;
282  pColIndicesData = new IndexType[nnz];
283  Kratos::span<IndexType> col_indices(pColIndicesData, nnz);
284 
285  //set it to zero in parallel to allow first touching
286  IndexPartition<IndexType>(col_indices.size()).for_each([&](IndexType i){
287  col_indices[i] = 0;
288  });
289 
290  //count the entries TODO: do the loop in parallel if possible
291  for(const auto& item : this->GetGraph()){
292  IndexType start = row_indices[item.first];
293 
294  IndexType counter = 0;
295  for(auto index : item.second){
296  col_indices[start+counter] = index;
297  counter++;
298  }
299  }
300 
301  //reorder columns
302  IndexPartition<IndexType>(row_indices.size()-1).for_each([&](IndexType i){
303  std::sort(col_indices.begin()+row_indices[i], col_indices.begin()+row_indices[i+1]);
304  });
305  return nrows;
306  }
307 
308  //this function returns the Graph as a single vector
309  //in the form of
310  // RowIndex NumberOfEntriesInTheRow .... list of all Indices in the row
311  //every row is pushed back one after the other
312  std::vector<IndexType> ExportSingleVectorRepresentation() const
313  {
314  std::vector< IndexType > single_vector_representation;
315 
316  IndexType nrows = this->Size(); //note that the number of non zero rows may be different from this one
317  single_vector_representation.push_back(nrows);
318 
319  for(const auto& item : this->GetGraph()){
320  IndexType I = item.first;
321  single_vector_representation.push_back(I); //we store the index of the rows
322  single_vector_representation.push_back(item.second.size()); //the number of items in the row
323  for(auto J : item.second)
324  single_vector_representation.push_back(J); //the columns
325  }
326  return single_vector_representation;
327  }
328 
329  void AddFromSingleVectorRepresentation(const std::vector<IndexType>& rSingleVectorRepresentation)
330  {
331  //IndexType graph_size = rSingleVectorRepresentation[0];
332  //we actually do not need the graph_size since it will be reconstructed,
333  //however it is important that the graph_size is stored to make the single_vector
334  //representation also compatible with the sparse_contiguous_row_graph
335 
336  IndexType counter = 1;
337  while(counter < rSingleVectorRepresentation.size())
338  {
339  auto I = rSingleVectorRepresentation[counter++];
340  auto nrow = rSingleVectorRepresentation[counter++];
341  auto begin = &rSingleVectorRepresentation[counter];
342  AddEntries(I, begin, begin+nrow);
343  counter += nrow;
344  }
345  }
346 
349 
350 
351 
353 
354 
359  {
360  const_row_iterator map_iterator;
361  public:
362  using iterator_category = std::forward_iterator_tag;
363  using difference_type = std::ptrdiff_t;
364  using value_type = typename GraphType::value_type;
365  using pointer = typename GraphType::value_type*;
366  using reference = typename GraphType::value_type&;
367 
370  : map_iterator(it.map_iterator) {}
371  const_iterator_adaptor& operator++() { map_iterator++; return *this; }
374  { return map_iterator == rhs.map_iterator; }
376  { return map_iterator != rhs.map_iterator; }
377  //TODO: is it correct that the two following operators are the same?
378  const typename GraphType::mapped_type& operator*() const { return (map_iterator->second); }
379  const typename GraphType::mapped_type& operator->() const { return map_iterator->second; }
380  const_row_iterator& base() { return map_iterator; }
381  const_row_iterator const& base() const { return map_iterator; }
383  return map_iterator->first;
384  }
385  };
386 
388  {
389  return const_iterator_adaptor( mGraph.begin() );
390  }
392  {
393  return const_iterator_adaptor( mGraph.end() );
394  }
395 
396 
400 
401 
405 
407  std::string Info() const
408  {
409  std::stringstream buffer;
410  buffer << "SparseGraph" ;
411  return buffer.str();
412  }
413 
415  void PrintInfo(std::ostream& rOStream) const {rOStream << "SparseGraph";}
416 
418  void PrintData(std::ostream& rOStream) const {}
419 
423 
424 
426 
427 protected:
430 
431 
435 
436 
440 
441 
445 
446 
450 
451 
455 
456 
460 
461 
463 
464 private:
467 
468 
472  DataCommunicator* mpComm;
473  GraphType mGraph;
474 
475 
479  friend class Serializer;
480 
481  void save(Serializer& rSerializer) const
482  {
483  std::vector< IndexType > IJ = ExportSingleVectorRepresentation();
484  rSerializer.save("IJ",IJ);
485  }
486 
487  void load(Serializer& rSerializer)
488  {
489  std::vector< IndexType > IJ;
490  rSerializer.load("IJ",IJ);
492  }
493 
494 
498 
499 
500 
504 
505 
509 
510 
514 
516  SparseGraph& operator=(SparseGraph const& rOther) = delete;
517 
518 
520 
521 }; // Class SparseGraph
522 
524 
527 
528 
532 
533 
535 template<class TIndexType=std::size_t>
536 inline std::istream& operator >> (std::istream& rIStream,
537  SparseGraph<TIndexType>& rThis){
538  return rIStream;
539  }
540 
542 template<class TIndexType=std::size_t>
543 inline std::ostream& operator << (std::ostream& rOStream,
544  const SparseGraph<TIndexType>& rThis)
545 {
546  rThis.PrintInfo(rOStream);
547  rOStream << std::endl;
548  rThis.PrintData(rOStream);
549 
550  return rOStream;
551 }
553 
555 
556 } // namespace Kratos.
557 
558 #endif // KRATOS_SPARSE_GRAPH_H_INCLUDED defined
559 
560 
PeriodicInterfaceProcess & operator=(const PeriodicInterfaceProcess &)=delete
Serial (do-nothing) version of a wrapper class for MPI communication.
Definition: data_communicator.h:318
virtual bool IsDistributed() const
Check whether this DataCommunicator is aware of parallelism.
Definition: data_communicator.h:606
This class is useful for index iteration over containers.
Definition: parallel_utilities.h:451
void for_each(TUnaryFunction &&f)
Definition: parallel_utilities.h:514
static DataCommunicator & GetDataCommunicator(const std::string &rName)
Retrieve a registered DataCommunicator instance.
Definition: parallel_environment.cpp:26
The serialization consists in storing the state of an object into a storage format like data file or ...
Definition: serializer.h:123
void load(std::string const &rTag, TDataType &rObject)
Definition: serializer.h:207
void save(std::string const &rTag, std::array< TDataType, TDataSize > const &rObject)
Definition: serializer.h:545
Definition: sparse_graph.h:359
typename GraphType::value_type & reference
Definition: sparse_graph.h:366
std::ptrdiff_t difference_type
Definition: sparse_graph.h:363
IndexType GetRowIndex() const
Definition: sparse_graph.h:382
const_row_iterator & base()
Definition: sparse_graph.h:380
const GraphType::mapped_type & operator*() const
Definition: sparse_graph.h:378
const_iterator_adaptor(const const_iterator_adaptor &it)
Definition: sparse_graph.h:369
typename GraphType::value_type value_type
Definition: sparse_graph.h:364
typename GraphType::value_type * pointer
Definition: sparse_graph.h:365
const_iterator_adaptor & operator++()
Definition: sparse_graph.h:371
const GraphType::mapped_type & operator->() const
Definition: sparse_graph.h:379
bool operator!=(const const_iterator_adaptor &rhs) const
Definition: sparse_graph.h:375
const_row_iterator const & base() const
Definition: sparse_graph.h:381
const_iterator_adaptor operator++(int)
Definition: sparse_graph.h:372
bool operator==(const const_iterator_adaptor &rhs) const
Definition: sparse_graph.h:373
const_iterator_adaptor(const_row_iterator it)
Definition: sparse_graph.h:368
std::forward_iterator_tag iterator_category
Definition: sparse_graph.h:362
Short class definition.
Definition: sparse_graph.h:66
SparseGraph(DataCommunicator &rComm)
Definition: sparse_graph.h:92
IndexType ExportCSRArrays(TVectorType &rRowIndices, TVectorType &rColIndices) const
Definition: sparse_graph.h:215
TIndexType IndexType
Definition: sparse_graph.h:70
SparseGraph(IndexType N)
Definition: sparse_graph.h:81
bool IsEmpty() const
Definition: sparse_graph.h:136
void AddEntries(const TContainerType &rIndices)
Definition: sparse_graph.h:182
void Clear()
Definition: sparse_graph.h:156
const_iterator_adaptor begin() const
Definition: sparse_graph.h:387
const DataCommunicator & GetComm() const
Definition: sparse_graph.h:119
void AddEntries(const IndexType RowIndex, const TIteratorType &rColBegin, const TIteratorType &rColEnd)
Definition: sparse_graph.h:173
IndexType Size() const
Definition: sparse_graph.h:129
KRATOS_CLASS_POINTER_DEFINITION(SparseGraph)
Pointer definition of SparseGraph.
const GraphType & GetGraph() const
Definition: sparse_graph.h:208
std::vector< IndexType > ExportSingleVectorRepresentation() const
Definition: sparse_graph.h:312
void PrintData(std::ostream &rOStream) const
Print object's data.
Definition: sparse_graph.h:418
void AddEntries(const TContainerType &rRowIndices, const TContainerType &rColIndices)
Definition: sparse_graph.h:189
SparseGraph()
Default constructor.
Definition: sparse_graph.h:87
void PrintInfo(std::ostream &rOStream) const
Print information about this object.
Definition: sparse_graph.h:415
void AddEntries(const IndexType RowIndex, const TContainerType &rColIndices)
Definition: sparse_graph.h:167
IndexType ExportCSRArrays(Kratos::span< IndexType > &rRowIndices, Kratos::span< IndexType > &rColIndices) const =delete
void Finalize()
Definition: sparse_graph.h:204
~SparseGraph()
Destructor.
Definition: sparse_graph.h:101
SparseGraph(const std::vector< IndexType > &rSingleVectorRepresentation)
Definition: sparse_graph.h:111
void AddFromSingleVectorRepresentation(const std::vector< IndexType > &rSingleVectorRepresentation)
Definition: sparse_graph.h:329
void AddEntries(SparseGraph &rOtherGraph)
Definition: sparse_graph.h:196
const DataCommunicator * pGetComm() const
Definition: sparse_graph.h:124
GraphType::const_iterator const_row_iterator
Definition: sparse_graph.h:72
IndexType ExportCSRArrays(IndexType *&pRowIndicesData, IndexType &rRowDataSize, IndexType *&pColIndicesData, IndexType &rColDataSize) const
Definition: sparse_graph.h:249
bool Has(const IndexType I, const IndexType J) const
Definition: sparse_graph.h:141
std::string Info() const
Turn back information as a string.
Definition: sparse_graph.h:407
void AddEntry(const IndexType RowIndex, const IndexType ColIndex)
Definition: sparse_graph.h:161
const GraphType::mapped_type & operator[](const IndexType &Key) const
Definition: sparse_graph.h:151
const_iterator_adaptor end() const
Definition: sparse_graph.h:391
SparseGraph(const SparseGraph &rOther)
Copy constructor.
Definition: sparse_graph.h:104
std::map< IndexType, std::unordered_set< IndexType > > GraphType
Definition: sparse_graph.h:71
#define KRATOS_ERROR
Definition: exception.h:161
start
Definition: DEM_benchmarks.py:17
REF: G. R. Cowper, GAUSSIAN QUADRATURE FORMULAS FOR TRIANGLES.
Definition: mesh_condition.cpp:21
std::istream & operator>>(std::istream &rIStream, LinearMasterSlaveConstraint &rThis)
input stream function
std::ostream & operator<<(std::ostream &rOStream, const LinearMasterSlaveConstraint &rThis)
output stream function
Definition: linear_master_slave_constraint.h:432
rhs
Definition: generate_frictional_mortar_condition.py:297
tuple tmp
Definition: generate_total_lagrangian_mixed_volumetric_strain_element.py:98
def load(f)
Definition: ode_solve.py:307
int counter
Definition: script_THERMAL_CORRECT.py:218
J
Definition: sensitivityMatrix.py:58
N
Definition: sensitivityMatrix.py:29
integer i
Definition: TensorModule.f:17