LvArray
PyCRSMatrix.hpp
Go to the documentation of this file.
1 /*
2  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3  * Copyright (c) 2019, Lawrence Livermore National Security, LLC.
4  *
5  * Produced at the Lawrence Livermore National Laboratory
6  *
7  * LLNL-CODE-746361
8  *
9  * All rights reserved. See COPYRIGHT for details.
10  *
11  * This file is part of the GEOSX Simulation Framework.
12  *
13  * GEOSX is a free software; you can redistribute it and/or modify it under
14  * the terms of the GNU Lesser General Public License (as published by the
15  * Free Software Foundation) version 2.1 dated February 1999.
16  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17  */
18 
23 #pragma once
24 
25 // Source includes
27 #include "numpyHelpers.hpp"
28 #include "../CRSMatrix.hpp"
29 #include "../Macros.hpp"
30 #include "../limits.hpp"
31 #include "../output.hpp"
32 
33 // TPL includes
34 #include <RAJA/RAJA.hpp>
35 
36 // System includes
37 #include <string>
38 #include <memory>
39 #include <typeindex>
40 
41 namespace LvArray
42 {
43 namespace python
44 {
45 namespace internal
46 {
47 
53 {
54 public:
55 
59  virtual ~PyCRSMatrixWrapperBase() = default;
60 
65  virtual int getAccessLevel() const
66  { return m_accessLevel; }
67 
73  virtual void setAccessLevel( int const accessLevel, int const memorySpace ) = 0;
74 
79  virtual std::string repr() const = 0;
80 
85  virtual std::type_index columnType() const = 0;
86 
91  virtual std::type_index entryType() const = 0;
92 
98  virtual long long numRows() const = 0;
99 
105  virtual long long numColumns() const = 0;
106 
111  virtual bool isCompressed() const = 0;
112 
119  virtual PyObject * getColumns( long long const row ) const = 0;
120 
127  virtual PyObject * getEntries( long long const row ) const = 0;
128 
133  virtual std::array< PyObject *, 3 > getEntriesColumnsAndOffsets() const = 0;
134 
142  virtual void resize( long long const numRows,
143  long long const numCols,
144  long long const initialRowCapacity ) = 0;
145 
150  virtual void compress() = 0;
151 
161  virtual long long insertNonZeros( long long const row,
162  void const * const cols,
163  void const * const entries,
164  long long const numCols ) = 0;
165 
174  virtual long long removeNonZeros( long long const row,
175  void const * const cols,
176  long long const numCols ) = 0;
177 
186  virtual void addToRow( long long const row,
187  void const * const cols,
188  void const * const vals,
189  long long const numCols ) const = 0;
190 
191 protected:
192 
197  m_accessLevel( static_cast< int >( LvArray::python::PyModify::READ_ONLY ) )
198  {}
199 
202 };
203 
214 template< typename T,
215  typename COL_TYPE,
216  typename INDEX_TYPE,
217  template< typename > class BUFFER_TYPE >
219 {
220 public:
221 
228  m_matrix( matrix )
229  {}
230 
232  virtual ~PyCRSMatrixWrapper() = default;
233 
235  virtual std::string repr() const final override
236  { return system::demangleType< CRSMatrix< T, COL_TYPE, INDEX_TYPE, BUFFER_TYPE > >(); }
237 
239  virtual std::type_index columnType() const final override
240  { return typeid( COL_TYPE ); }
241 
243  virtual std::type_index entryType() const final override
244  { return typeid( T ); }
245 
247  virtual long long numRows() const final override
248  { return m_matrix.numRows(); }
249 
251  virtual long long numColumns() const final override
252  { return m_matrix.numColumns(); }
253 
255  virtual bool isCompressed() const final override
256  {
257  #if defined(USE_OPENMP)
258  using EXEC_POLICY = RAJA::omp_parallel_for_exec;
259  using REDUCE_POLICY = RAJA::omp_reduce;
260  #else
261  using EXEC_POLICY = RAJA::loop_exec;
262  using REDUCE_POLICY = RAJA::seq_reduce;
263  #endif
264 
265  RAJA::ReduceBitAnd< REDUCE_POLICY, bool > compressed( true );
266 
267  RAJA::forall< EXEC_POLICY >( RAJA::TypedRangeSegment< INDEX_TYPE >( 0, m_matrix.numRows() ),
268  [compressed, this] ( INDEX_TYPE const row )
269  {
270  compressed &= m_matrix.numNonZeros( row ) == m_matrix.nonZeroCapacity( row );
271  }
272  );
273 
274  return compressed.get();
275  }
276 
278  virtual PyObject * getColumns( long long const row ) const final override
279  {
280  INDEX_TYPE const convertedRow = integerConversion< INDEX_TYPE >( row );
281  COL_TYPE const * const columns = m_matrix.getColumns( convertedRow );
282  INDEX_TYPE const nnz = m_matrix.numNonZeros( convertedRow );
283  constexpr INDEX_TYPE unitStride = 1;
284  return createNumPyArray( columns, false, 1, &nnz, &unitStride );
285  }
286 
288  virtual PyObject * getEntries( long long const row ) const final override
289  {
290  INDEX_TYPE const convertedRow = integerConversion< INDEX_TYPE >( row );
291  T * const entries = m_matrix.getEntries( convertedRow );
292  INDEX_TYPE const nnz = m_matrix.numNonZeros( convertedRow );
293  constexpr INDEX_TYPE unitStride = 1;
294  return createNumPyArray( entries, getAccessLevel(), 1, &nnz, &unitStride );
295  }
296 
298  virtual std::array< PyObject *, 3 > getEntriesColumnsAndOffsets() const final override
299  {
300  T * const entries = m_matrix.getEntries( 0 );
301  COL_TYPE const * const columns = m_matrix.getColumns( 0 );
302  INDEX_TYPE const * const offsets = m_matrix.getOffsets();
303 
304  INDEX_TYPE const numNonZeros = offsets[ m_matrix.numRows() ]; // size of columns and entries
305  INDEX_TYPE offsetSize = m_matrix.numRows() + 1;
306  constexpr INDEX_TYPE unitStride = 1;
307  return { createNumPyArray( entries, getAccessLevel() >= static_cast< int >( LvArray::python::PyModify::MODIFIABLE ), 1, &numNonZeros, &unitStride ),
308  createNumPyArray( columns, false, 1, &numNonZeros, &unitStride ),
309  createNumPyArray( offsets, false, 1, &offsetSize, &unitStride ) };
310  }
311 
313  virtual void setAccessLevel( int const accessLevel, int const memorySpace ) final override
314  {
315  LVARRAY_UNUSED_VARIABLE( memorySpace );
316  if( accessLevel >= static_cast< int >( LvArray::python::PyModify::RESIZEABLE ) )
317  {
318  // touch
319  }
320  m_accessLevel = accessLevel;
321  }
322 
324  virtual void resize( long long const numRows,
325  long long const numCols,
326  long long const initialRowCapacity ) final override
327  {
328  INDEX_TYPE const convertedNumRows = integerConversion< INDEX_TYPE >( numRows );
329  INDEX_TYPE const convertedNumCols = integerConversion< INDEX_TYPE >( numCols );
330  INDEX_TYPE const convertedCapacity = integerConversion< INDEX_TYPE >( initialRowCapacity );
331  m_matrix.resize( convertedNumRows, convertedNumCols, convertedCapacity );
332  }
333 
335  virtual void compress() final override
336  { m_matrix.compress(); }
337 
339  virtual long long insertNonZeros( long long const row,
340  void const * const cols,
341  void const * const entries,
342  long long const numCols ) final override
343  {
344  INDEX_TYPE const convertedRow = integerConversion< INDEX_TYPE >( row );
345  COL_TYPE const * const castedCols = reinterpret_cast< COL_TYPE const * >( cols );
346  T const * const castedEntries = reinterpret_cast< T const * >( entries );
347  INDEX_TYPE const convertedNumCols = integerConversion< INDEX_TYPE >( numCols );
348  return integerConversion< long long >( m_matrix.insertNonZeros( convertedRow, castedCols, castedEntries, convertedNumCols ) );
349  }
350 
352  virtual long long removeNonZeros( long long const row,
353  void const * const cols,
354  long long const numCols ) final override
355  {
356  INDEX_TYPE const convertedRow = integerConversion< INDEX_TYPE >( row );
357  COL_TYPE const * const castedCols = reinterpret_cast< COL_TYPE const * >( cols );
358  INDEX_TYPE const convertedNumCols = integerConversion< INDEX_TYPE >( numCols );
359  return integerConversion< long long >( m_matrix.removeNonZeros( convertedRow, castedCols, convertedNumCols ) );
360  }
361 
363  virtual void addToRow( long long const row,
364  void const * const cols,
365  void const * const vals,
366  long long const numCols ) const final override
367  {
368  INDEX_TYPE const convertedRow = integerConversion< INDEX_TYPE >( row );
369  COL_TYPE const * const castedCols = reinterpret_cast< COL_TYPE const * >( cols );
370  T const * const castedVals = reinterpret_cast< T const * >( vals );
371  INDEX_TYPE const convertedNumCols = integerConversion< INDEX_TYPE >( numCols );
372  return m_matrix.template addToRowBinarySearchUnsorted< RAJA::seq_atomic >( convertedRow,
373  castedCols,
374  castedVals,
375  convertedNumCols );
376  }
377 
378 private:
381 };
382 
388 PyObject * create( std::unique_ptr< internal::PyCRSMatrixWrapperBase > && matrix );
389 
390 } // namespace internal
391 
403 template< typename T,
404  typename COL_TYPE,
405  typename INDEX_TYPE,
406  template< typename > class BUFFER_TYPE >
407 std::enable_if_t< internal::canExportToNumpy< T >, PyObject * >
409 {
410  auto tmp = std::make_unique< internal::PyCRSMatrixWrapper< T, COL_TYPE, INDEX_TYPE, BUFFER_TYPE > >( matrix );
411  return internal::create( std::move( tmp ) );
412 }
413 
418 PyTypeObject * getPyCRSMatrixType();
419 
420 } // namespace python
421 } // namespace LvArray
#define LVARRAY_UNUSED_VARIABLE(X)
Mark X as an unused variable, used to silence compiler warnings.
Definition: Macros.hpp:51
std::enable_if_t< internal::canExportToNumpy< T >, PyObject *> create(T &value)
Create a NumPy 1D array of length 1 containing the scalar value.
Definition: numpyHelpers.hpp:147
PyModify
An enumeration of the various access policies for Python objects.
Definition: pythonHelpers.hpp:131
std::enable_if_t< internal::canExportToNumpy< T >, PyObject *> create(CRSMatrix< T, COL_TYPE, INDEX_TYPE, BUFFER_TYPE > &matrix)
Create a Python object corresponding to matrix.
Definition: PyCRSMatrix.hpp:408
virtual long long insertNonZeros(long long const row, void const *const cols, void const *const entries, long long const numCols)=0
Insert new non zero entries into a row.
virtual std::string repr() const =0
Return a string representing the underlying CRSMatrix type.
virtual void resize(long long const numRows, long long const numCols, long long const initialRowCapacity)=0
Resize the matrix.
virtual PyObject * getColumns(long long const row) const final override
Return a 1D NumPy array of the columns for row.
Definition: PyCRSMatrix.hpp:278
PyCRSMatrixWrapperBase()
Construct an empty PyCRSMatrixWrapperBase.
Definition: PyCRSMatrix.hpp:196
virtual ~PyCRSMatrixWrapperBase()=default
Default destructor.
virtual std::array< PyObject *, 3 > getEntriesColumnsAndOffsets() const =0
Return 3 1D NumPy arrays of the entries, columns and offsets that comprise the matrix.
virtual std::string repr() const final override
Return a string representing the underlying CRSMatrix type.
Definition: PyCRSMatrix.hpp:235
virtual PyObject * getEntries(long long const row) const =0
Return a 1D NumPy array of the entries for row.
virtual PyObject * getColumns(long long const row) const =0
Return a 1D NumPy array of the columns for row.
virtual std::type_index columnType() const final override
Return the type of the columns.
Definition: PyCRSMatrix.hpp:239
virtual long long numColumns() const =0
Return the number of columns in the matrix.
virtual void setAccessLevel(int const accessLevel, int const memorySpace) final override
Set the access level for the matrix.
Definition: PyCRSMatrix.hpp:313
PyCRSMatrixWrapper(CRSMatrix< T, COL_TYPE, INDEX_TYPE, BUFFER_TYPE > &matrix)
Construct a new Python wrapper around matrix.
Definition: PyCRSMatrix.hpp:226
virtual long long removeNonZeros(long long const row, void const *const cols, long long const numCols)=0
Remove non zero entries from a row.
virtual void addToRow(long long const row, void const *const cols, void const *const vals, long long const numCols) const final override
Add to existing entries in a row.
Definition: PyCRSMatrix.hpp:363
Forward declarations of Python Objects.
virtual long long numRows() const final override
Return the number of rows in the matrix.
Definition: PyCRSMatrix.hpp:247
int m_accessLevel
access level for the matrix.
Definition: PyCRSMatrix.hpp:201
PyTypeObject * getPyCRSMatrixType()
Return the Python type for the CRSMatrix.
virtual void compress() final override
Compress the matrix so that there is no extra space between the rows.
Definition: PyCRSMatrix.hpp:335
The top level namespace.
Definition: Array.hpp:24
Contains methods to help with conversion to python objects.
virtual std::type_index columnType() const =0
Return the type of the columns.
virtual long long removeNonZeros(long long const row, void const *const cols, long long const numCols) final override
Remove non zero entries from a row.
Definition: PyCRSMatrix.hpp:352
Provides a concrete implementation of PyCRSMatrixWrapperBase.
Definition: PyCRSMatrix.hpp:218
virtual long long numColumns() const final override
Return the number of columns in the matrix.
Definition: PyCRSMatrix.hpp:251
Provides a virtual Python wrapper around a CRSMatrix.
Definition: PyCRSMatrix.hpp:52
virtual std::type_index entryType() const =0
Return the type of the entries.
virtual bool isCompressed() const =0
Return true iff the matrix is compressed (no extra space between the rows).
CRSMatrix< T, COL_TYPE, INDEX_TYPE, BUFFER_TYPE > & m_matrix
The CRSMatrix to wrap.
Definition: PyCRSMatrix.hpp:380
virtual bool isCompressed() const final override
Return true iff the matrix is compressed (no extra space between the rows).
Definition: PyCRSMatrix.hpp:255
virtual PyObject * getEntries(long long const row) const final override
Return a 1D NumPy array of the entries for row.
Definition: PyCRSMatrix.hpp:288
virtual long long numRows() const =0
Return the number of rows in the matrix.
virtual std::array< PyObject *, 3 > getEntriesColumnsAndOffsets() const final override
Return 3 1D NumPy arrays of the entries, columns and offsets that comprise the matrix.
Definition: PyCRSMatrix.hpp:298
virtual void addToRow(long long const row, void const *const cols, void const *const vals, long long const numCols) const =0
Add to existing entries in a row.
virtual int getAccessLevel() const
Return the access level for the matrix.
Definition: PyCRSMatrix.hpp:65
virtual void setAccessLevel(int const accessLevel, int const memorySpace)=0
Set the access level for the matrix.
virtual std::type_index entryType() const final override
Return the type of the entries.
Definition: PyCRSMatrix.hpp:243
virtual long long insertNonZeros(long long const row, void const *const cols, void const *const entries, long long const numCols) final override
Insert new non zero entries into a row.
Definition: PyCRSMatrix.hpp:339
virtual void resize(long long const numRows, long long const numCols, long long const initialRowCapacity) final override
Resize the matrix.
Definition: PyCRSMatrix.hpp:324
This class implements a compressed row storage matrix.
Definition: CRSMatrix.hpp:35
virtual void compress()=0
Compress the matrix so that there is no extra space between the rows.
std::enable_if_t< internal::canExportToNumpy< T >, PyObject *> createNumPyArray(T *const data, bool const modify, int const ndim, INDEX_TYPE const *const dimsPtr, INDEX_TYPE const *const stridesPtr)
Return a NumPy ndarray view of data.
Definition: numpyHelpers.hpp:107