MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
table.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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
19#include <iostream>
20#include <iomanip>
21
22namespace mfem
23{
24
25using namespace std;
26
27Table::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
50Table::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
66Table::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
81void 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
104void 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
124void 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
140void 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
165int 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
187void 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 HostReadJ();
193 HostReadI();
194
195 row.SetSize(RowSize(i));
196 row.Assign(GetRow(i));
197}
198
200{
201 for (int r = 0; r < size; r++)
202 {
203 std::sort(J + I[r], J + I[r+1]);
204 }
205}
206
207void Table::SetIJ(int *newI, int *newJ, int newsize)
208{
209 I.Delete();
210 J.Delete();
211 if (newsize >= 0)
212 {
213 size = newsize;
214 }
215 I.Wrap(newI, size+1, true);
216 J.Wrap(newJ, I[size], true);
217}
218
219int Table::Push(int i, int j)
220{
221 MFEM_ASSERT(i >=0 &&
222 i<size, "Index out of bounds. i = " << i << " size " << size);
223
224 for (int k = I[i], end = I[i+1]; k < end; k++)
225 {
226 if (J[k] == j)
227 {
228 return k;
229 }
230 else if (J[k] == -1)
231 {
232 J[k] = j;
233 return k;
234 }
235 }
236
237 MFEM_ABORT("Reached end of loop unexpectedly: (i,j) = (" << i << ", " << j
238 << ")");
239
240 return -1;
241}
242
244{
245 int i, j, end, sum = 0, n = 0, newI = 0;
246
247 for (i=0; i<I[size]; i++)
248 {
249 if (J[i] != -1)
250 {
251 sum++;
252 }
253 }
254
255 if (sum != I[size])
256 {
257 int *NewJ = Memory<int>(sum);
258
259 for (i=0; i<size; i++)
260 {
261 end = I[i+1];
262 for (j=I[i]; j<end; j++)
263 {
264 if (J[j] == -1) { break; }
265 NewJ[ n++ ] = J[j];
266 }
267 I[i] = newI;
268 newI = n;
269 }
270 I[size] = sum;
271
272 J.Delete();
273
274 J.Wrap(NewJ, sum, true);
275
276 MFEM_ASSERT(sum == n, "sum = " << sum << ", n = " << n);
277 }
278}
279
280void Table::MakeFromList(int nrows, const Array<Connection> &list)
281{
282 Clear();
283
284 size = nrows;
285 int nnz = list.Size();
286
287 I.New(size+1);
288 J.New(nnz);
289
290 for (int i = 0, k = 0; i <= size; i++)
291 {
292 I[i] = k;
293 while (k < nnz && list[k].from == i)
294 {
295 J[k] = list[k].to;
296 k++;
297 }
298 }
299}
300
301int Table::Width() const
302{
303 int width = -1, nnz = (size >= 0) ? I[size] : 0;
304 for (int k = 0; k < nnz; k++)
305 {
306 if (J[k] > width) { width = J[k]; }
307 }
308 return width + 1;
309}
310
311void Table::Print(std::ostream & os, int width) const
312{
313 int i, j;
314
315 for (i = 0; i < size; i++)
316 {
317 os << "[row " << i << "]\n";
318 for (j = I[i]; j < I[i+1]; j++)
319 {
320 os << setw(5) << J[j];
321 if ( !((j+1-I[i]) % width) )
322 {
323 os << '\n';
324 }
325 }
326 if ((j-I[i]) % width)
327 {
328 os << '\n';
329 }
330 }
331}
332
333void Table::PrintMatlab(std::ostream & os) const
334{
335 int i, j;
336
337 for (i = 0; i < size; i++)
338 {
339 for (j = I[i]; j < I[i+1]; j++)
340 {
341 os << i << " " << J[j] << " 1. \n";
342 }
343 }
344
345 os << flush;
346}
347
348void Table::Save(std::ostream &os) const
349{
350 os << size << '\n';
351
352 for (int i = 0; i <= size; i++)
353 {
354 os << I[i] << '\n';
355 }
356 for (int i = 0, nnz = I[size]; i < nnz; i++)
357 {
358 os << J[i] << '\n';
359 }
360}
361
362void Table::Load(std::istream &in)
363{
364 I.Delete();
365 J.Delete();
366
367 in >> size;
368 I.New(size+1);
369 for (int i = 0; i <= size; i++)
370 {
371 in >> I[i];
372 }
373 int nnz = I[size];
374 J.New(nnz);
375 for (int j = 0; j < nnz; j++)
376 {
377 in >> J[j];
378 }
379}
380
382{
383 I.Delete();
384 J.Delete();
385 size = -1;
386 I.Reset();
387 J.Reset();
388}
389
390void Table::Copy(Table & copy) const
391{
392 copy = *this;
393}
394
395void Table::Swap(Table & other)
396{
397 mfem::Swap(size, other.size);
398 mfem::Swap(I, other.I);
399 mfem::Swap(J, other.J);
400}
401
402std::size_t Table::MemoryUsage() const
403{
404 if (size < 0 || I == NULL) { return 0; }
405 return (size+1 + I[size]) * sizeof(int);
406}
407
409{
410 I.Delete();
411 J.Delete();
412}
413
414void Transpose (const Table &A, Table &At, int ncols_A_)
415{
416 const int *i_A = A.GetI();
417 const int *j_A = A.GetJ();
418 const int nrows_A = A.Size();
419 const int ncols_A = (ncols_A_ < 0) ? A.Width() : ncols_A_;
420 const int nnz_A = i_A[nrows_A];
421
422 At.SetDims (ncols_A, nnz_A);
423
424 int *i_At = At.GetI();
425 int *j_At = At.GetJ();
426
427 for (int i = 0; i <= ncols_A; i++)
428 {
429 i_At[i] = 0;
430 }
431 for (int i = 0; i < nnz_A; i++)
432 {
433 i_At[j_A[i]+1]++;
434 }
435 for (int i = 1; i < ncols_A; i++)
436 {
437 i_At[i+1] += i_At[i];
438 }
439
440 for (int i = 0; i < nrows_A; i++)
441 {
442 for (int j = i_A[i]; j < i_A[i+1]; j++)
443 {
444 j_At[i_At[j_A[j]]++] = i;
445 }
446 }
447 for (int i = ncols_A; i > 0; i--)
448 {
449 i_At[i] = i_At[i-1];
450 }
451 i_At[0] = 0;
452}
453
455{
456 Table * At = new Table;
457 Transpose(A, *At);
458 return At;
459}
460
461void Transpose(const Array<int> &A, Table &At, int ncols_A_)
462{
463 At.MakeI((ncols_A_ < 0) ? (A.Max() + 1) : ncols_A_);
464 for (int i = 0; i < A.Size(); i++)
465 {
466 At.AddAColumnInRow(A[i]);
467 }
468 At.MakeJ();
469 for (int i = 0; i < A.Size(); i++)
470 {
471 At.AddConnection(A[i], i);
472 }
473 At.ShiftUpI();
474}
475
476void Mult (const Table &A, const Table &B, Table &C)
477{
478 int i, j, k, l, m;
479 const int *i_A = A.GetI();
480 const int *j_A = A.GetJ();
481 const int *i_B = B.GetI();
482 const int *j_B = B.GetJ();
483 const int nrows_A = A.Size();
484 const int nrows_B = B.Size();
485 const int ncols_A = A.Width();
486 const int ncols_B = B.Width();
487
488 MFEM_VERIFY( ncols_A <= nrows_B, "Table size mismatch: ncols_A = " << ncols_A
489 << ", nrows_B = " << nrows_B);
490
491 Array<int> B_marker (ncols_B);
492
493 for (i = 0; i < ncols_B; i++)
494 {
495 B_marker[i] = -1;
496 }
497
498 int counter = 0;
499 for (i = 0; i < nrows_A; i++)
500 {
501 for (j = i_A[i]; j < i_A[i+1]; j++)
502 {
503 k = j_A[j];
504 for (l = i_B[k]; l < i_B[k+1]; l++)
505 {
506 m = j_B[l];
507 if (B_marker[m] != i)
508 {
509 B_marker[m] = i;
510 counter++;
511 }
512 }
513 }
514 }
515
516 C.SetDims (nrows_A, counter);
517
518 for (i = 0; i < ncols_B; i++)
519 {
520 B_marker[i] = -1;
521 }
522
523 int *i_C = C.GetI();
524 int *j_C = C.GetJ();
525 counter = 0;
526 for (i = 0; i < nrows_A; i++)
527 {
528 i_C[i] = counter;
529 for (j = i_A[i]; j < i_A[i+1]; j++)
530 {
531 k = j_A[j];
532 for (l = i_B[k]; l < i_B[k+1]; l++)
533 {
534 m = j_B[l];
535 if (B_marker[m] != i)
536 {
537 B_marker[m] = i;
538 j_C[counter] = m;
539 counter++;
540 }
541 }
542 }
543 }
544}
545
546
547Table * Mult (const Table &A, const Table &B)
548{
549 Table * C = new Table;
550 Mult(A,B,*C);
551 return C;
552}
553
554STable::STable (int dim, int connections_per_row) :
555 Table(dim, connections_per_row)
556{}
557
558int STable::operator() (int i, int j) const
559{
560 if (i < j)
561 {
562 return Table::operator()(i,j);
563 }
564 else
565 {
566 return Table::operator()(j,i);
567 }
568}
569
570int STable::Push( int i, int j )
571{
572 if (i < j)
573 {
574 return Table::Push(i, j);
575 }
576 else
577 {
578 return Table::Push(j, i);
579 }
580}
581
582
584{
585 Rows = new Node*[nrows];
586 for (int i = 0; i < nrows; i++)
587 {
588 Rows[i] = NULL;
589 }
590 NumRows = nrows;
591 NumEntries = 0;
592}
593
594int DSTable::Push_(int r, int c)
595{
596 MFEM_ASSERT(r >= 0 && r < NumRows,
597 "Row out of bounds: r = " << r << ", NumRows = " << NumRows);
598 Node *n;
599 for (n = Rows[r]; n != NULL; n = n->Prev)
600 {
601 if (n->Column == c)
602 {
603 return (n->Index);
604 }
605 }
606#ifdef MFEM_USE_MEMALLOC
607 n = NodesMem.Alloc ();
608#else
609 n = new Node;
610#endif
611 n->Column = c;
612 n->Index = NumEntries;
613 n->Prev = Rows[r];
614 Rows[r] = n;
615 return (NumEntries++);
616}
617
618int DSTable::Index(int r, int c) const
619{
620 MFEM_ASSERT( r>=0, "Row index must be non-negative, not "<<r);
621 if (r >= NumRows)
622 {
623 return (-1);
624 }
625 for (Node *n = Rows[r]; n != NULL; n = n->Prev)
626 {
627 if (n->Column == c)
628 {
629 return (n->Index);
630 }
631 }
632 return (-1);
633}
634
636{
637#ifdef MFEM_USE_MEMALLOC
638 // NodesMem.Clear(); // this is done implicitly
639#else
640 for (int i = 0; i < NumRows; i++)
641 {
642 Node *na, *nb = Rows[i];
643 while (nb != NULL)
644 {
645 na = nb;
646 nb = nb->Prev;
647 delete na;
648 }
649 }
650#endif
651 delete [] Rows;
652}
653
654}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
void Assign(const T *)
Copy data from a pointer. 'Size()' elements are copied.
Definition array.hpp:925
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:697
int Size() const
Return the logical size of the array.
Definition array.hpp:144
DSTable(int nrows)
Definition table.cpp:583
Class used by MFEM to store pointers to host and/or device memory.
MemoryType GetMemoryType() const
Return a MemoryType that is currently valid. If both the host and the device pointers are currently v...
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
void Reset()
Reset the memory to be empty, ensuring that Delete() will be a no-op.
void Wrap(T *ptr, int size, bool own)
Wrap an externally allocated host pointer, ptr with the current host memory type returned by MemoryMa...
void Delete()
Delete the owned pointers and reset the Memory object.
void New(int size)
Allocate host memory for size entries with the current host memory type returned by MemoryManager::Ge...
int Push(int i, int j)
Definition table.cpp:570
STable(int dim, int connections_per_row=3)
Creates table with fixed number of connections.
Definition table.cpp:554
int operator()(int i, int j) const
Definition table.cpp:558
Table & operator=(const Table &rhs)
Assignment operator: deep copy.
Definition table.cpp:40
void Save(std::ostream &out) const
Definition table.cpp:348
int size
size is the number of TYPE I elements.
Definition table.hpp:47
const int * HostReadI() const
Definition table.hpp:129
~Table()
Destroys Table.
Definition table.cpp:408
int * GetJ()
Definition table.hpp:114
void AddConnections(int r, const int *c, int nc)
Definition table.cpp:104
void PrintMatlab(std::ostream &out) const
Definition table.cpp:333
void Swap(Table &other)
Definition table.cpp:395
int RowSize(int i) const
Definition table.hpp:108
void Load(std::istream &in)
Definition table.cpp:362
int operator()(int i, int j) const
Definition table.cpp:165
void ShiftUpI()
Definition table.cpp:115
void Clear()
Definition table.cpp:381
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition table.cpp:124
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:219
void AddConnection(int r, int c)
Definition table.hpp:80
void Finalize()
Definition table.cpp:243
void MakeI(int nrows)
Next 7 methods are used together with the default constructor.
Definition table.cpp:81
void Print(std::ostream &out=mfem::out, int width=4) const
Prints the table to stream out.
Definition table.cpp:311
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:207
const int * HostReadJ() const
Definition table.hpp:142
Table()
Creates an empty table.
Definition table.hpp:56
int Size() const
Returns the number of TYPE I elements.
Definition table.hpp:92
int Width() const
Returns the number of TYPE II elements (after Finalize() is called).
Definition table.cpp:301
std::size_t MemoryUsage() const
Definition table.cpp:402
void MakeFromList(int nrows, const Array< Connection > &list)
Definition table.cpp:280
void Copy(Table &copy) const
Definition table.cpp:390
void MakeJ()
Definition table.cpp:91
Memory< int > J
Definition table.hpp:52
Memory< int > I
Definition table.hpp:52
int * GetI()
Definition table.hpp:113
void AddAColumnInRow(int r)
Definition table.hpp:77
void SortRows()
Sort the column (TYPE II) indices in each row.
Definition table.cpp:199
void SetDims(int rows, int nnz)
Definition table.cpp:140
int dim
Definition ex24.cpp:53
void Swap(Array< T > &, Array< T > &)
Definition array.hpp:648
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:476
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:414