MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
table.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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 &table1,
28 const Table &table2, int offset)
29{
30 MFEM_ASSERT(table1.size == table2.size,
31 "Tables have different sizes can not merge.");
32 size = table1.size;
33
34 const int nnz = table1.I[size] + table2.I[size];
35 I.SetSize(size+1);
36 J.SetSize(nnz);
37
38 I[0] = 0;
39 Array<int> row;
40 for (int i = 0; i < size; i++)
41 {
42 I[i+1] = I[i];
43
44 table1.GetRow(i, row);
45 for (int r = 0; r < row.Size(); r++, I[i+1] ++)
46 {
47 J[ I[i+1] ] = row[r];
48 }
49
50 table2.GetRow(i, row);
51 for (int r = 0; r < row.Size(); r++, I[i+1] ++)
52 {
53 J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset : row[r] + offset;
54 }
55
56 }
57}
58
59Table::Table(const Table &table1,
60 const Table &table2, int offset2,
61 const Table &table3, int offset3)
62{
63 MFEM_ASSERT(table1.size == table2.size,
64 "Tables have different sizes can not merge.");
65 MFEM_ASSERT(table1.size == table3.size,
66 "Tables have different sizes can not merge.");
67 size = table1.size;
68
69 const int nnz = table1.I[size] + table2.I[size] + table3.I[size];
70 I.SetSize(size+1);
71 J.SetSize(nnz);
72
73 I[0] = 0;
74 Array<int> row;
75 for (int i = 0; i < size; i++)
76 {
77 I[i+1] = I[i];
78
79 table1.GetRow(i, row);
80 for (int r = 0; r < row.Size(); r++, I[i+1] ++)
81 {
82 J[ I[i+1] ] = row[r];
83 }
84
85 table2.GetRow(i, row);
86 for (int r = 0; r < row.Size(); r++, I[i+1] ++)
87 {
88 J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset2 : row[r] + offset2;
89 }
90
91 table3.GetRow(i, row);
92 for (int r = 0; r < row.Size(); r++, I[i+1] ++)
93 {
94 J[ I[i+1] ] = (row[r] < 0) ? row[r] - offset3 : row[r] + offset3;
95 }
96 }
97}
98
99Table::Table (int dim, int connections_per_row)
100{
101 int i, j, sum = dim * connections_per_row;
102
103 size = dim;
104 I.SetSize(size+1);
105 J.SetSize(sum);
106
107 I[0] = 0;
108 for (i = 1; i <= size; i++)
109 {
110 I[i] = I[i-1] + connections_per_row;
111 for (j = I[i-1]; j < I[i]; j++) { J[j] = -1; }
112 }
113}
114
115Table::Table(int nrows, int *partitioning)
116{
117 size = nrows;
118
119 I.SetSize(size+1);
120 J.SetSize(size);
121
122 for (int i = 0; i < size; i++)
123 {
124 I[i] = i;
125 J[i] = partitioning[i];
126 }
127 I[size] = size;
128}
129
130void Table::MakeI(int nrows)
131{
132 SetDims(nrows, 0);
133
134 for (int i = 0; i <= nrows; i++)
135 {
136 I[i] = 0;
137 }
138}
139
141{
142 int i, j, k;
143
144 for (k = i = 0; i < size; i++)
145 {
146 j = I[i], I[i] = k, k += j;
147 }
148
149 J.SetSize(I[size]=k);
150}
151
152void Table::AddConnections(int r, const int *c, int nc)
153{
154 int *jp = J+I[r];
155
156 for (int i = 0; i < nc; i++)
157 {
158 jp[i] = c[i];
159 }
160 I[r] += nc;
161}
162
164{
165 for (int i = size; i > 0; i--)
166 {
167 I[i] = I[i-1];
168 }
169 I[0] = 0;
170}
171
172void Table::SetSize(int dim, int connections_per_row)
173{
174 SetDims (dim, dim * connections_per_row);
175
176 if (size > 0)
177 {
178 I[0] = 0;
179 for (int i = 0, j = 0; i < size; i++)
180 {
181 int end = I[i] + connections_per_row;
182 I[i+1] = end;
183 for ( ; j < end; j++) { J[j] = -1; }
184 }
185 }
186}
187
188void Table::SetDims(int rows, int nnz)
189{
190 int j;
191
192 j = (I) ? (I[size]) : (0);
193 if (size != rows)
194 {
195 size = rows;
196 (rows >= 0) ? I.SetSize(rows+1) : I.DeleteAll();
197 }
198
199 if (j != nnz)
200 {
201 (nnz > 0) ? J.SetSize(nnz) : J.DeleteAll();
202 }
203
204 if (size >= 0)
205 {
206 I[0] = 0;
207 I[size] = nnz;
208 }
209}
210
211int Table::operator()(int i, int j) const
212{
213 if ( i>=size || i<0 )
214 {
215 return -1;
216 }
217
218 int k, end = I[i+1];
219 for (k = I[i]; k < end; k++)
220 {
221 if (J[k] == j)
222 {
223 return k;
224 }
225 else if (J[k] == -1)
226 {
227 return -1;
228 }
229 }
230 return -1;
231}
232
233void Table::GetRow(int i, Array<int> &row) const
234{
235 MFEM_ASSERT(i >= 0 && i < size, "Row index " << i << " is out of range [0,"
236 << size << ')');
237
238 HostReadJ();
239 HostReadI();
240
241 row.SetSize(RowSize(i));
242 row.Assign(GetRow(i));
243}
244
246{
247 for (int r = 0; r < size; r++)
248 {
249 std::sort(J + I[r], J + I[r+1]);
250 }
251}
252
253void Table::SetIJ(int *newI, int *newJ, int newsize)
254{
255 if (newsize >= 0)
256 {
257 size = newsize;
258 }
259 I.MakeRef(newI, size + 1, true);
260 J.MakeRef(newJ, I[size], true);
261}
262
263int Table::Push(int i, int j)
264{
265 MFEM_ASSERT(i >=0 &&
266 i<size, "Index out of bounds. i = " << i << " size " << size);
267
268 for (int k = I[i], end = I[i+1]; k < end; k++)
269 {
270 if (J[k] == j)
271 {
272 return k;
273 }
274 else if (J[k] == -1)
275 {
276 J[k] = j;
277 return k;
278 }
279 }
280
281 MFEM_ABORT("Reached end of loop unexpectedly: (i,j) = (" << i << ", " << j
282 << ")");
283
284 return -1;
285}
286
288{
289 int i, j, end, sum = 0, n = 0, newI = 0;
290
291 for (i=0; i<I[size]; i++)
292 {
293 if (J[i] != -1)
294 {
295 sum++;
296 }
297 }
298
299 if (sum != I[size])
300 {
301 Array<int> NewJ(sum);
302
303 for (i=0; i<size; i++)
304 {
305 end = I[i+1];
306 for (j=I[i]; j<end; j++)
307 {
308 if (J[j] == -1) { break; }
309 NewJ[ n++ ] = J[j];
310 }
311 I[i] = newI;
312 newI = n;
313 }
314 I[size] = sum;
315
316 mfem::Swap(J, NewJ);
317
318 MFEM_ASSERT(sum == n, "sum = " << sum << ", n = " << n);
319 }
320}
321
322void Table::MakeFromList(int nrows, const Array<Connection> &list)
323{
324 Clear();
325
326 size = nrows;
327 int nnz = list.Size();
328
329 I.SetSize(size+1);
330 J.SetSize(nnz);
331
332 for (int i = 0, k = 0; i <= size; i++)
333 {
334 I[i] = k;
335 while (k < nnz && list[k].from == i)
336 {
337 J[k] = list[k].to;
338 k++;
339 }
340 }
341}
342
343int Table::Width() const
344{
345 int width = -1, nnz = (size >= 0) ? I[size] : 0;
346 for (int k = 0; k < nnz; k++)
347 {
348 if (J[k] > width) { width = J[k]; }
349 }
350 return width + 1;
351}
352
353void Table::Print(std::ostream & os, int width) const
354{
355 int i, j;
356
357 for (i = 0; i < size; i++)
358 {
359 os << "[row " << i << "]\n";
360 for (j = I[i]; j < I[i+1]; j++)
361 {
362 os << setw(5) << J[j];
363 if ( !((j+1-I[i]) % width) )
364 {
365 os << '\n';
366 }
367 }
368 if ((j-I[i]) % width)
369 {
370 os << '\n';
371 }
372 }
373}
374
375void Table::PrintMatlab(std::ostream & os) const
376{
377 int i, j;
378
379 for (i = 0; i < size; i++)
380 {
381 for (j = I[i]; j < I[i+1]; j++)
382 {
383 os << i << " " << J[j] << " 1. \n";
384 }
385 }
386
387 os << flush;
388}
389
390void Table::Save(std::ostream &os) const
391{
392 os << size << '\n';
393
394 for (int i = 0; i <= size; i++)
395 {
396 os << I[i] << '\n';
397 }
398 for (int i = 0, nnz = I[size]; i < nnz; i++)
399 {
400 os << J[i] << '\n';
401 }
402}
403
404void Table::Load(std::istream &in)
405{
406 in >> size;
407 I.SetSize(size+1);
408 for (int i = 0; i <= size; i++)
409 {
410 in >> I[i];
411 }
412 int nnz = I[size];
413 J.SetSize(nnz);
414 for (int j = 0; j < nnz; j++)
415 {
416 in >> J[j];
417 }
418}
419
421{
422 I.DeleteAll();
423 J.DeleteAll();
424 size = -1;
425}
426
427void Table::Copy(Table & copy) const
428{
429 copy = *this;
430}
431
432void Table::Swap(Table & other)
433{
434 mfem::Swap(*this, other);
435}
436
437std::size_t Table::MemoryUsage() const
438{
439 if (size < 0 || I == NULL) { return 0; }
440 return (size+1 + I[size]) * sizeof(int);
441}
442
443void Transpose(const Table &A, Table &At, int ncols_A_)
444{
445 const int *i_A = A.GetI();
446 const int *j_A = A.GetJ();
447 const int nrows_A = A.Size();
448 const int ncols_A = (ncols_A_ < 0) ? A.Width() : ncols_A_;
449 const int nnz_A = i_A[nrows_A];
450
451 At.SetDims (ncols_A, nnz_A);
452
453 int *i_At = At.GetI();
454 int *j_At = At.GetJ();
455
456 for (int i = 0; i <= ncols_A; i++)
457 {
458 i_At[i] = 0;
459 }
460 for (int i = 0; i < nnz_A; i++)
461 {
462 i_At[j_A[i]+1]++;
463 }
464 for (int i = 1; i < ncols_A; i++)
465 {
466 i_At[i+1] += i_At[i];
467 }
468
469 for (int i = 0; i < nrows_A; i++)
470 {
471 for (int j = i_A[i]; j < i_A[i+1]; j++)
472 {
473 j_At[i_At[j_A[j]]++] = i;
474 }
475 }
476 for (int i = ncols_A; i > 0; i--)
477 {
478 i_At[i] = i_At[i-1];
479 }
480 i_At[0] = 0;
481}
482
484{
485 Table * At = new Table;
486 Transpose(A, *At);
487 return At;
488}
489
490void Transpose(const Array<int> &A, Table &At, int ncols_A_)
491{
492 At.MakeI((ncols_A_ < 0) ? (A.Max() + 1) : ncols_A_);
493 for (int i = 0; i < A.Size(); i++)
494 {
495 At.AddAColumnInRow(A[i]);
496 }
497 At.MakeJ();
498 for (int i = 0; i < A.Size(); i++)
499 {
500 At.AddConnection(A[i], i);
501 }
502 At.ShiftUpI();
503}
504
505void Mult(const Table &A, const Table &B, Table &C)
506{
507 int i, j, k, l, m;
508 const int *i_A = A.GetI();
509 const int *j_A = A.GetJ();
510 const int *i_B = B.GetI();
511 const int *j_B = B.GetJ();
512 const int nrows_A = A.Size();
513 const int nrows_B = B.Size();
514 const int ncols_A = A.Width();
515 const int ncols_B = B.Width();
516
517 MFEM_VERIFY( ncols_A <= nrows_B, "Table size mismatch: ncols_A = " << ncols_A
518 << ", nrows_B = " << nrows_B);
519
520 Array<int> B_marker (ncols_B);
521
522 for (i = 0; i < ncols_B; i++)
523 {
524 B_marker[i] = -1;
525 }
526
527 int counter = 0;
528 for (i = 0; i < nrows_A; i++)
529 {
530 for (j = i_A[i]; j < i_A[i+1]; j++)
531 {
532 k = j_A[j];
533 for (l = i_B[k]; l < i_B[k+1]; l++)
534 {
535 m = j_B[l];
536 if (B_marker[m] != i)
537 {
538 B_marker[m] = i;
539 counter++;
540 }
541 }
542 }
543 }
544
545 C.SetDims (nrows_A, counter);
546
547 for (i = 0; i < ncols_B; i++)
548 {
549 B_marker[i] = -1;
550 }
551
552 int *i_C = C.GetI();
553 int *j_C = C.GetJ();
554 counter = 0;
555 for (i = 0; i < nrows_A; i++)
556 {
557 i_C[i] = counter;
558 for (j = i_A[i]; j < i_A[i+1]; j++)
559 {
560 k = j_A[j];
561 for (l = i_B[k]; l < i_B[k+1]; l++)
562 {
563 m = j_B[l];
564 if (B_marker[m] != i)
565 {
566 B_marker[m] = i;
567 j_C[counter] = m;
568 counter++;
569 }
570 }
571 }
572 }
573}
574
575
576Table * Mult(const Table &A, const Table &B)
577{
578 Table * C = new Table;
579 Mult(A,B,*C);
580 return C;
581}
582
583STable::STable(int dim, int connections_per_row) :
584 Table(dim, connections_per_row)
585{}
586
587int STable::operator()(int i, int j) const
588{
589 if (i < j)
590 {
591 return Table::operator()(i,j);
592 }
593 else
594 {
595 return Table::operator()(j,i);
596 }
597}
598
599int STable::Push( int i, int j )
600{
601 if (i < j)
602 {
603 return Table::Push(i, j);
604 }
605 else
606 {
607 return Table::Push(j, i);
608 }
609}
610
611
613{
614 Rows = new Node*[nrows];
615 for (int i = 0; i < nrows; i++)
616 {
617 Rows[i] = NULL;
618 }
619 NumRows = nrows;
620 NumEntries = 0;
621}
622
623int DSTable::Push_(int r, int c)
624{
625 MFEM_ASSERT(r >= 0 && r < NumRows,
626 "Row out of bounds: r = " << r << ", NumRows = " << NumRows);
627 Node *n;
628 for (n = Rows[r]; n != NULL; n = n->Prev)
629 {
630 if (n->Column == c)
631 {
632 return (n->Index);
633 }
634 }
635#ifdef MFEM_USE_MEMALLOC
636 n = NodesMem.Alloc ();
637#else
638 n = new Node;
639#endif
640 n->Column = c;
641 n->Index = NumEntries;
642 n->Prev = Rows[r];
643 Rows[r] = n;
644 return (NumEntries++);
645}
646
647int DSTable::Index(int r, int c) const
648{
649 MFEM_ASSERT( r>=0, "Row index must be non-negative, not "<<r);
650 if (r >= NumRows)
651 {
652 return (-1);
653 }
654 for (Node *n = Rows[r]; n != NULL; n = n->Prev)
655 {
656 if (n->Column == c)
657 {
658 return (n->Index);
659 }
660 }
661 return (-1);
662}
663
665{
666#ifdef MFEM_USE_MEMALLOC
667 // NodesMem.Clear(); // this is done implicitly
668#else
669 for (int i = 0; i < NumRows; i++)
670 {
671 Node *na, *nb = Rows[i];
672 while (nb != NULL)
673 {
674 na = nb;
675 nb = nb->Prev;
676 delete na;
677 }
678 }
679#endif
680 delete [] Rows;
681}
682
683}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:69
void Assign(const T *)
Copy data from a pointer. 'Size()' elements are copied.
Definition array.hpp:1112
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:1053
void DeleteAll()
Delete the whole array.
Definition array.hpp:1033
DSTable(int nrows)
Definition table.cpp:612
int Push(int i, int j)
Definition table.cpp:599
STable(int dim, int connections_per_row=3)
Creates table with fixed number of connections.
Definition table.cpp:583
int operator()(int i, int j) const
Definition table.cpp:587
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
Definition table.hpp:43
void Save(std::ostream &out) const
Definition table.cpp:390
int size
The number of TYPE I elements.
Definition table.hpp:45
const int * HostReadI() const
Definition table.hpp:140
int * GetJ()
Definition table.hpp:128
Array< int > J
The length of the J array is equal to the number of connections between TYPE I and TYPE II elements.
Definition table.hpp:55
void AddConnections(int r, const int *c, int nc)
Definition table.cpp:152
void PrintMatlab(std::ostream &out) const
Definition table.cpp:375
void Swap(Table &other)
Definition table.cpp:432
int RowSize(int i) const
Definition table.hpp:122
void Load(std::istream &in)
Definition table.cpp:404
int operator()(int i, int j) const
Returns index of the connection between element i of TYPE I and element j of TYPE II.
Definition table.cpp:211
void ShiftUpI()
Definition table.cpp:163
void Clear()
Definition table.cpp:420
void SetSize(int dim, int connections_per_row)
Set the size and the number of connections for the table.
Definition table.cpp:172
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition table.cpp:233
int Push(int i, int j)
Establish connection between element i and element j in the table.
Definition table.cpp:263
void AddConnection(int r, int c)
Definition table.hpp:89
Array< int > I
The length of the I array is 'size + 1',.
Definition table.hpp:51
void Finalize()
Finalize the table initialization.
Definition table.cpp:287
void MakeI(int nrows)
Definition table.cpp:130
void Print(std::ostream &out=mfem::out, int width=4) const
Prints the table to the stream out.
Definition table.cpp:353
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:253
const int * HostReadJ() const
Definition table.hpp:147
Table()
Creates an empty table.
Definition table.hpp:61
int Size() const
Returns the number of TYPE I elements.
Definition table.hpp:103
int Width() const
Returns the number of TYPE II elements (after Finalize() is called).
Definition table.cpp:343
std::size_t MemoryUsage() const
Definition table.cpp:437
void MakeFromList(int nrows, const Array< Connection > &list)
Create the table from a list of connections {(from, to)}, where 'from' is a TYPE I index and 'to' is ...
Definition table.cpp:322
void Copy(Table &copy) const
Definition table.cpp:427
void MakeJ()
Definition table.cpp:140
int * GetI()
Definition table.hpp:127
void AddAColumnInRow(int r)
Definition table.hpp:86
void SortRows()
Sort the column (TYPE II) indices in each row.
Definition table.cpp:245
void SetDims(int rows, int nnz)
Set the rows and the number of all connections for the table.
Definition table.cpp:188
int dim
Definition ex24.cpp:53
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
void Swap(T &a, T &b)
Swap objects of type T. The operation is performed using the most specialized swap function from the ...
Definition array.hpp:738