MFEM  v4.4.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
table.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2022, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 
12 // Implementation of data types Table.
13 
14 #include "array.hpp"
15 #include "table.hpp"
16 #include "error.hpp"
17 
18 #include "../general/mem_manager.hpp"
19 #include <iostream>
20 #include <iomanip>
21 
22 namespace mfem
23 {
24 
25 using namespace std;
26 
27 Table::Table(const Table &table)
28 {
29  size = table.size;
30  if (size >= 0)
31  {
32  const int nnz = table.I[size];
33  I.New(size+1, table.I.GetMemoryType());
34  J.New(nnz, table.J.GetMemoryType());
35  I.CopyFrom(table.I, size+1);
36  J.CopyFrom(table.J, nnz);
37  }
38 }
39 
41 {
42  Clear();
43 
44  Table copy(rhs);
45  Swap(copy);
46 
47  return *this;
48 }
49 
50 Table::Table (int dim, int connections_per_row)
51 {
52  int i, j, sum = dim * connections_per_row;
53 
54  size = dim;
55  I.New(size+1);
56  J.New(sum);
57 
58  I[0] = 0;
59  for (i = 1; i <= size; i++)
60  {
61  I[i] = I[i-1] + connections_per_row;
62  for (j = I[i-1]; j < I[i]; j++) { J[j] = -1; }
63  }
64 }
65 
66 Table::Table (int nrows, int *partitioning)
67 {
68  size = nrows;
69 
70  I.New(size+1);
71  J.New(size);
72 
73  for (int i = 0; i < size; i++)
74  {
75  I[i] = i;
76  J[i] = partitioning[i];
77  }
78  I[size] = size;
79 }
80 
81 void Table::MakeI (int nrows)
82 {
83  SetDims (nrows, 0);
84 
85  for (int i = 0; i <= nrows; i++)
86  {
87  I[i] = 0;
88  }
89 }
90 
92 {
93  int i, j, k;
94 
95  for (k = i = 0; i < size; i++)
96  {
97  j = I[i], I[i] = k, k += j;
98  }
99 
100  J.Delete();
101  J.New(I[size]=k);
102 }
103 
104 void Table::AddConnections (int r, const int *c, int nc)
105 {
106  int *jp = J+I[r];
107 
108  for (int i = 0; i < nc; i++)
109  {
110  jp[i] = c[i];
111  }
112  I[r] += nc;
113 }
114 
116 {
117  for (int i = size; i > 0; i--)
118  {
119  I[i] = I[i-1];
120  }
121  I[0] = 0;
122 }
123 
124 void Table::SetSize(int dim, int connections_per_row)
125 {
126  SetDims (dim, dim * connections_per_row);
127 
128  if (size > 0)
129  {
130  I[0] = 0;
131  for (int i = 0, j = 0; i < size; i++)
132  {
133  int end = I[i] + connections_per_row;
134  I[i+1] = end;
135  for ( ; j < end; j++) { J[j] = -1; }
136  }
137  }
138 }
139 
140 void Table::SetDims(int rows, int nnz)
141 {
142  int j;
143 
144  j = (I) ? (I[size]) : (0);
145  if (size != rows)
146  {
147  size = rows;
148  I.Delete();
149  (rows >= 0) ? I.New(rows+1) : I.Reset();
150  }
151 
152  if (j != nnz)
153  {
154  J.Delete();
155  (nnz > 0) ? J.New(nnz) : J.Reset();
156  }
157 
158  if (size >= 0)
159  {
160  I[0] = 0;
161  I[size] = nnz;
162  }
163 }
164 
165 int Table::operator() (int i, int j) const
166 {
167  if ( i>=size || i<0 )
168  {
169  return -1;
170  }
171 
172  int k, end = I[i+1];
173  for (k = I[i]; k < end; k++)
174  {
175  if (J[k] == j)
176  {
177  return k;
178  }
179  else if (J[k] == -1)
180  {
181  return -1;
182  }
183  }
184  return -1;
185 }
186 
187 void Table::GetRow(int i, Array<int> &row) const
188 {
189  MFEM_ASSERT(i >= 0 && i < size, "Row index " << i << " is out of range [0,"
190  << size << ')');
191 
192  row.SetSize(RowSize(i));
193  row.Assign(GetRow(i));
194 }
195 
197 {
198  for (int r = 0; r < size; r++)
199  {
200  std::sort(J + I[r], J + I[r+1]);
201  }
202 }
203 
204 void Table::SetIJ(int *newI, int *newJ, int newsize)
205 {
206  I.Delete();
207  J.Delete();
208  if (newsize >= 0)
209  {
210  size = newsize;
211  }
212  I.Wrap(newI, size+1, true);
213  J.Wrap(newJ, I[size], true);
214 }
215 
216 int Table::Push(int i, int j)
217 {
218  MFEM_ASSERT( i >=0 && i<size, "Index out of bounds. i = "<<i);
219 
220  for (int k = I[i], end = I[i+1]; k < end; k++)
221  {
222  if (J[k] == j)
223  {
224  return k;
225  }
226  else if (J[k] == -1)
227  {
228  J[k] = j;
229  return k;
230  }
231  }
232 
233  MFEM_ABORT("Reached end of loop unexpectedly: (i,j) = (" << i << ", " << j
234  << ")");
235 
236  return -1;
237 }
238 
240 {
241  int i, j, end, sum = 0, n = 0, newI = 0;
242 
243  for (i=0; i<I[size]; i++)
244  {
245  if (J[i] != -1)
246  {
247  sum++;
248  }
249  }
250 
251  if (sum != I[size])
252  {
253  int *NewJ = Memory<int>(sum);
254 
255  for (i=0; i<size; i++)
256  {
257  end = I[i+1];
258  for (j=I[i]; j<end; j++)
259  {
260  if (J[j] == -1) { break; }
261  NewJ[ n++ ] = J[j];
262  }
263  I[i] = newI;
264  newI = n;
265  }
266  I[size] = sum;
267 
268  J.Delete();
269 
270  J.Wrap(NewJ, sum, true);
271 
272  MFEM_ASSERT(sum == n, "sum = " << sum << ", n = " << n);
273  }
274 }
275 
276 void Table::MakeFromList(int nrows, const Array<Connection> &list)
277 {
278  Clear();
279 
280  size = nrows;
281  int nnz = list.Size();
282 
283  I.New(size+1);
284  J.New(nnz);
285 
286  for (int i = 0, k = 0; i <= size; i++)
287  {
288  I[i] = k;
289  while (k < nnz && list[k].from == i)
290  {
291  J[k] = list[k].to;
292  k++;
293  }
294  }
295 }
296 
297 int Table::Width() const
298 {
299  int width = -1, nnz = (size >= 0) ? I[size] : 0;
300  for (int k = 0; k < nnz; k++)
301  {
302  if (J[k] > width) { width = J[k]; }
303  }
304  return width + 1;
305 }
306 
307 void Table::Print(std::ostream & os, int width) const
308 {
309  int i, j;
310 
311  for (i = 0; i < size; i++)
312  {
313  os << "[row " << i << "]\n";
314  for (j = I[i]; j < I[i+1]; j++)
315  {
316  os << setw(5) << J[j];
317  if ( !((j+1-I[i]) % width) )
318  {
319  os << '\n';
320  }
321  }
322  if ((j-I[i]) % width)
323  {
324  os << '\n';
325  }
326  }
327 }
328 
329 void Table::PrintMatlab(std::ostream & os) const
330 {
331  int i, j;
332 
333  for (i = 0; i < size; i++)
334  {
335  for (j = I[i]; j < I[i+1]; j++)
336  {
337  os << i << " " << J[j] << " 1. \n";
338  }
339  }
340 
341  os << flush;
342 }
343 
344 void Table::Save(std::ostream &os) const
345 {
346  os << size << '\n';
347 
348  for (int i = 0; i <= size; i++)
349  {
350  os << I[i] << '\n';
351  }
352  for (int i = 0, nnz = I[size]; i < nnz; i++)
353  {
354  os << J[i] << '\n';
355  }
356 }
357 
358 void Table::Load(std::istream &in)
359 {
360  I.Delete();
361  J.Delete();
362 
363  in >> size;
364  I.New(size+1);
365  for (int i = 0; i <= size; i++)
366  {
367  in >> I[i];
368  }
369  int nnz = I[size];
370  J.New(nnz);
371  for (int j = 0; j < nnz; j++)
372  {
373  in >> J[j];
374  }
375 }
376 
378 {
379  I.Delete();
380  J.Delete();
381  size = -1;
382  I.Reset();
383  J.Reset();
384 }
385 
386 void Table::Copy(Table & copy) const
387 {
388  copy = *this;
389 }
390 
391 void Table::Swap(Table & other)
392 {
393  mfem::Swap(size, other.size);
394  mfem::Swap(I, other.I);
395  mfem::Swap(J, other.J);
396 }
397 
398 long Table::MemoryUsage() const
399 {
400  if (size < 0 || I == NULL) { return 0; }
401  return (size+1 + I[size]) * sizeof(int);
402 }
403 
405 {
406  I.Delete();
407  J.Delete();
408 }
409 
410 void Transpose (const Table &A, Table &At, int ncols_A_)
411 {
412  const int *i_A = A.GetI();
413  const int *j_A = A.GetJ();
414  const int nrows_A = A.Size();
415  const int ncols_A = (ncols_A_ < 0) ? A.Width() : ncols_A_;
416  const int nnz_A = i_A[nrows_A];
417 
418  At.SetDims (ncols_A, nnz_A);
419 
420  int *i_At = At.GetI();
421  int *j_At = At.GetJ();
422 
423  for (int i = 0; i <= ncols_A; i++)
424  {
425  i_At[i] = 0;
426  }
427  for (int i = 0; i < nnz_A; i++)
428  {
429  i_At[j_A[i]+1]++;
430  }
431  for (int i = 1; i < ncols_A; i++)
432  {
433  i_At[i+1] += i_At[i];
434  }
435 
436  for (int i = 0; i < nrows_A; i++)
437  {
438  for (int j = i_A[i]; j < i_A[i+1]; j++)
439  {
440  j_At[i_At[j_A[j]]++] = i;
441  }
442  }
443  for (int i = ncols_A; i > 0; i--)
444  {
445  i_At[i] = i_At[i-1];
446  }
447  i_At[0] = 0;
448 }
449 
450 Table * Transpose(const Table &A)
451 {
452  Table * At = new Table;
453  Transpose(A, *At);
454  return At;
455 }
456 
457 void Transpose(const Array<int> &A, Table &At, int ncols_A_)
458 {
459  At.MakeI((ncols_A_ < 0) ? (A.Max() + 1) : ncols_A_);
460  for (int i = 0; i < A.Size(); i++)
461  {
462  At.AddAColumnInRow(A[i]);
463  }
464  At.MakeJ();
465  for (int i = 0; i < A.Size(); i++)
466  {
467  At.AddConnection(A[i], i);
468  }
469  At.ShiftUpI();
470 }
471 
472 void Mult (const Table &A, const Table &B, Table &C)
473 {
474  int i, j, k, l, m;
475  const int *i_A = A.GetI();
476  const int *j_A = A.GetJ();
477  const int *i_B = B.GetI();
478  const int *j_B = B.GetJ();
479  const int nrows_A = A.Size();
480  const int nrows_B = B.Size();
481  const int ncols_A = A.Width();
482  const int ncols_B = B.Width();
483 
484  MFEM_VERIFY( ncols_A <= nrows_B, "Table size mismatch: ncols_A = " << ncols_A
485  << ", nrows_B = " << nrows_B);
486 
487  Array<int> B_marker (ncols_B);
488 
489  for (i = 0; i < ncols_B; i++)
490  {
491  B_marker[i] = -1;
492  }
493 
494  int counter = 0;
495  for (i = 0; i < nrows_A; i++)
496  {
497  for (j = i_A[i]; j < i_A[i+1]; j++)
498  {
499  k = j_A[j];
500  for (l = i_B[k]; l < i_B[k+1]; l++)
501  {
502  m = j_B[l];
503  if (B_marker[m] != i)
504  {
505  B_marker[m] = i;
506  counter++;
507  }
508  }
509  }
510  }
511 
512  C.SetDims (nrows_A, counter);
513 
514  for (i = 0; i < ncols_B; i++)
515  {
516  B_marker[i] = -1;
517  }
518 
519  int *i_C = C.GetI();
520  int *j_C = C.GetJ();
521  counter = 0;
522  for (i = 0; i < nrows_A; i++)
523  {
524  i_C[i] = counter;
525  for (j = i_A[i]; j < i_A[i+1]; j++)
526  {
527  k = j_A[j];
528  for (l = i_B[k]; l < i_B[k+1]; l++)
529  {
530  m = j_B[l];
531  if (B_marker[m] != i)
532  {
533  B_marker[m] = i;
534  j_C[counter] = m;
535  counter++;
536  }
537  }
538  }
539  }
540 }
541 
542 
543 Table * Mult (const Table &A, const Table &B)
544 {
545  Table * C = new Table;
546  Mult(A,B,*C);
547  return C;
548 }
549 
550 STable::STable (int dim, int connections_per_row) :
551  Table(dim, connections_per_row)
552 {}
553 
554 int STable::operator() (int i, int j) const
555 {
556  if (i < j)
557  {
558  return Table::operator()(i,j);
559  }
560  else
561  {
562  return Table::operator()(j,i);
563  }
564 }
565 
566 int STable::Push( int i, int j )
567 {
568  if (i < j)
569  {
570  return Table::Push(i, j);
571  }
572  else
573  {
574  return Table::Push(j, i);
575  }
576 }
577 
578 
580 {
581  Rows = new Node*[nrows];
582  for (int i = 0; i < nrows; i++)
583  {
584  Rows[i] = NULL;
585  }
586  NumRows = nrows;
587  NumEntries = 0;
588 }
589 
590 int DSTable::Push_(int r, int c)
591 {
592  MFEM_ASSERT(r >= 0 && r < NumRows,
593  "Row out of bounds: r = " << r << ", NumRows = " << NumRows);
594  Node *n;
595  for (n = Rows[r]; n != NULL; n = n->Prev)
596  {
597  if (n->Column == c)
598  {
599  return (n->Index);
600  }
601  }
602 #ifdef MFEM_USE_MEMALLOC
603  n = NodesMem.Alloc ();
604 #else
605  n = new Node;
606 #endif
607  n->Column = c;
608  n->Index = NumEntries;
609  n->Prev = Rows[r];
610  Rows[r] = n;
611  return (NumEntries++);
612 }
613 
614 int DSTable::Index(int r, int c) const
615 {
616  MFEM_ASSERT( r>=0, "Row index must be non-negative, not "<<r);
617  if (r >= NumRows)
618  {
619  return (-1);
620  }
621  for (Node *n = Rows[r]; n != NULL; n = n->Prev)
622  {
623  if (n->Column == c)
624  {
625  return (n->Index);
626  }
627  }
628  return (-1);
629 }
630 
632 {
633 #ifdef MFEM_USE_MEMALLOC
634  // NodesMem.Clear(); // this is done implicitly
635 #else
636  for (int i = 0; i < NumRows; i++)
637  {
638  Node *na, *nb = Rows[i];
639  while (nb != NULL)
640  {
641  na = nb;
642  nb = nb->Prev;
643  delete na;
644  }
645  }
646 #endif
647  delete [] Rows;
648 }
649 
650 }
Elem * Alloc()
Definition: mem_alloc.hpp:166
int Size() const
Return the logical size of the array.
Definition: array.hpp:138
int Push(int i, int j)
Definition: table.cpp:216
int * GetJ()
Definition: table.hpp:114
Memory< int > I
Definition: table.hpp:52
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition: table.cpp:124
int operator()(int i, int j) const
Definition: table.cpp:165
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition: table.cpp:81
void SortRows()
Sort the column (TYPE II) indices in each row.
Definition: table.cpp:196
void Delete()
Delete the owned pointers and reset the Memory object.
void Swap(Table &other)
Definition: table.cpp:391
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:472
void SetDims(int rows, int nnz)
Definition: table.cpp:140
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
int Push(int i, int j)
Definition: table.cpp:566
void Save(std::ostream &out) const
Definition: table.cpp:344
void AddConnections(int r, const int *c, int nc)
Definition: table.cpp:104
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
int Width() const
Returns the number of TYPE II elements (after Finalize() is called).
Definition: table.cpp:297
int operator()(int i, int j) const
Definition: table.cpp:554
void Print(std::ostream &out=mfem::out, int width=4) const
Prints the table to stream out.
Definition: table.cpp:307
void MakeFromList(int nrows, const Array< Connection > &list)
Definition: table.cpp:276
Table & operator=(const Table &rhs)
Assignment operator: deep copy.
Definition: table.cpp:40
void Clear()
Definition: table.cpp:377
void AddConnection(int r, int c)
Definition: table.hpp:80
T Max() const
Find the maximal element in the array, using the comparison operator &lt; for class T.
Definition: array.cpp:68
long MemoryUsage() const
Definition: table.cpp:398
void Assign(const T *)
Copy data from a pointer. &#39;Size()&#39; elements are copied.
Definition: array.hpp:900
int Size() const
Returns the number of TYPE I elements.
Definition: table.hpp:92
void PrintMatlab(std::ostream &out) const
Definition: table.cpp:329
STable(int dim, int connections_per_row=3)
Creates table with fixed number of connections.
Definition: table.cpp:550
void Swap(Array< T > &, Array< T > &)
Definition: array.hpp:630
Memory< int > J
Definition: table.hpp:52
void Finalize()
Definition: table.cpp:239
int size
size is the number of TYPE I elements.
Definition: table.hpp:47
void AddAColumnInRow(int r)
Definition: table.hpp:77
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:679
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition: table.cpp:410
void ShiftUpI()
Definition: table.cpp:115
void Load(std::istream &in)
Definition: table.cpp:358
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
~Table()
Destroys Table.
Definition: table.cpp:404
void SetIJ(int *newI, int *newJ, int newsize=-1)
Replace the I and J arrays with the given newI and newJ arrays.
Definition: table.cpp:204
void MakeJ()
Definition: table.cpp:91
int dim
Definition: ex24.cpp:53
int * GetI()
Definition: table.hpp:113
void Copy(Table &copy) const
Definition: table.cpp:386
DSTable(int nrows)
Definition: table.cpp:579
Table()
Creates an empty table.
Definition: table.hpp:56