Files
mfem/general/table.hpp
T

264 lines
8.6 KiB
C++

// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_TABLE
#define MFEM_TABLE
// Data types for Table.
#include "mem_alloc.hpp"
#include "array.hpp"
#include "globals.hpp"
#include <ostream>
#include <istream>
namespace mfem
{
/// Helper struct for defining a connectivity table, see Table::MakeFromList.
struct Connection
{
int from, to;
Connection() = default;
Connection(int from, int to) : from(from), to(to) {}
bool operator== (const Connection &rhs) const
{ return (from == rhs.from) && (to == rhs.to); }
bool operator< (const Connection &rhs) const
{ return (from == rhs.from) ? (to < rhs.to) : (from < rhs.from); }
};
/** Data type Table. Table stores the connectivity of elements of TYPE I
to elements of TYPE II, for example, it may be Element-To-Face
connectivity table, etc. */
class Table
{
protected:
/// size is the number of TYPE I elements.
int size;
/** Arrays for the connectivity information in the CSR storage.
I is of size "size+1", J is of size the number of connections
between TYPE I to TYPE II elements (actually stored I[size]). */
Memory<int> I, J;
public:
/// Creates an empty table
Table() { size = -1; I.Reset(); J.Reset(); }
/// Copy constructor
Table(const Table &);
/// Assignment operator: deep copy
Table& operator=(const Table &rhs);
/// Create a table with an upper limit for the number of connections.
explicit Table (int dim, int connections_per_row = 3);
/** Create a table from a list of connections, see MakeFromList(). */
Table(int nrows, Array<Connection> &list) : size(-1)
{ I.Reset(); J.Reset(); MakeFromList(nrows, list); }
/** Create a table with one entry per row with column indices given
by 'partitioning'. */
Table (int nrows, int *partitioning);
/// Next 7 methods are used together with the default constructor
void MakeI (int nrows);
void AddAColumnInRow (int r) { I[r]++; }
void AddColumnsInRow (int r, int ncol) { I[r] += ncol; }
void MakeJ();
void AddConnection (int r, int c) { J[I[r]++] = c; }
void AddConnections (int r, const int *c, int nc);
void ShiftUpI();
/// Set the size and the number of connections for the table.
void SetSize(int dim, int connections_per_row);
/** Set the rows and the number of all connections for the table.
Does NOT initialize the whole array I ! (I[0]=0 and I[rows]=nnz only) */
void SetDims(int rows, int nnz);
/// Returns the number of TYPE I elements.
inline int Size() const { return size; }
/** Returns the number of connections in the table. If Finalize() is
not called, it returns the number of possible connections established
by the used constructor. Otherwise, it is exactly the number of
established connections before calling Finalize(). */
inline int Size_of_connections() const { return I[size]; }
/** Returns index of the connection between element i of TYPE I and
element j of TYPE II. If there is no connection between element i
and element j established in the table, then the return value is -1. */
int operator() (int i, int j) const;
/// Return row i in array row (the Table must be finalized)
void GetRow(int i, Array<int> &row) const;
int RowSize(int i) const { return I[i+1]-I[i]; }
const int *GetRow(int i) const { return J+I[i]; }
int *GetRow(int i) { return J+I[i]; }
int *GetI() { return I; }
int *GetJ() { return J; }
const int *GetI() const { return I; }
const int *GetJ() const { return J; }
Memory<int> &GetIMemory() { return I; }
Memory<int> &GetJMemory() { return J; }
const Memory<int> &GetIMemory() const { return I; }
const Memory<int> &GetJMemory() const { return J; }
/// @brief Sort the column (TYPE II) indices in each row.
void SortRows();
/// Replace the #I and #J arrays with the given @a newI and @a newJ arrays.
/** If @a newsize < 0, then the size of the Table is not modified. */
void SetIJ(int *newI, int *newJ, int newsize = -1);
/** Establish connection between element i and element j in the table.
The return value is the index of the connection. It returns -1 if it
fails to establish the connection. Possibilities are there is not
enough memory on row i to establish connection to j, an attempt to
establish new connection after calling Finalize(). */
int Push( int i, int j );
/** Finalize the table initialization. The function may be called
only once, after the table has been initialized, in order to compress
array J (by getting rid of -1's in array J). Calling this function
will "freeze" the table and function Push will work no more.
Note: The table is functional even without calling Finalize(). */
void Finalize();
/** Create the table from a list of connections {(from, to)}, where 'from'
is a TYPE I index and 'to' is a TYPE II index. The list is assumed to be
sorted and free of duplicities, i.e., you need to call Array::Sort and
Array::Unique before calling this method. */
void MakeFromList(int nrows, const Array<Connection> &list);
/// Returns the number of TYPE II elements (after Finalize() is called).
int Width() const;
/// Call this if data has been stolen.
void LoseData() { size = -1; I.Reset(); J.Reset(); }
/// Prints the table to stream out.
void Print(std::ostream & out = mfem::out, int width = 4) const;
void PrintMatlab(std::ostream & out) const;
void Save(std::ostream &out) const;
void Load(std::istream &in);
void Copy(Table & copy) const;
void Swap(Table & other);
void Clear();
long MemoryUsage() const;
/// Destroys Table.
~Table();
};
/// Specialization of the template function Swap<> for class Table
template <> inline void Swap<Table>(Table &a, Table &b)
{
a.Swap(b);
}
/// Transpose a Table
void Transpose (const Table &A, Table &At, int _ncols_A = -1);
Table * Transpose (const Table &A);
/// Transpose an Array<int>
void Transpose(const Array<int> &A, Table &At, int _ncols_A = -1);
/// C = A * B (as boolean matrices)
void Mult (const Table &A, const Table &B, Table &C);
Table * Mult (const Table &A, const Table &B);
/** Data type STable. STable is similar to Table, but it's for symmetric
connectivity, i.e. TYPE I is equivalent to TYPE II. In the first
dimension we put the elements with smaller index. */
class STable : public Table
{
public:
/// Creates table with fixed number of connections.
STable (int dim, int connections_per_row = 3);
/** Returns index of the connection between element i of TYPE I and
element j of TYPE II. If there is no connection between element i
and element j established in the table, then the return value is -1. */
int operator() (int i, int j) const;
/** Establish connection between element i and element j in the table.
The return value is the index of the connection. It returns -1 if it
fails to establish the connection. Possibilities are there is not
enough memory on row i to establish connection to j, an attempt to
establish new connection after calling Finalize(). */
int Push( int i, int j );
/// Destroys STable.
~STable() {}
};
class DSTable
{
private:
class Node
{
public:
Node *Prev;
int Column, Index;
};
int NumRows, NumEntries;
Node **Rows;
#ifdef MFEM_USE_MEMALLOC
MemAlloc <Node, 1024> NodesMem;
#endif
int Push_(int r, int c);
int Index(int r, int c) const;
public:
DSTable(int nrows);
int NumberOfRows() const { return (NumRows); }
int NumberOfEntries() const { return (NumEntries); }
int Push(int a, int b)
{ return ((a <= b) ? Push_(a, b) : Push_(b, a)); }
int operator()(int a, int b) const
{ return ((a <= b) ? Index(a, b) : Index(b, a)); }
~DSTable();
class RowIterator
{
private:
Node *n;
public:
RowIterator (const DSTable &t, int r) { n = t.Rows[r]; }
int operator!() { return (n != NULL); }
void operator++() { n = n->Prev; }
int Column() { return (n->Column); }
int Index() { return (n->Index); }
void SetIndex(int new_idx) { n->Index = new_idx; }
};
};
}
#endif