Skip to content

Commit 803f214

Browse files
jameshcorbettcorbett5
authored andcommitted
Adds an optional python extension module.
1 parent 40d464e commit 803f214

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+7449
-292
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
docs/doxygen/LvArrayConfig.hpp
66
uberenv_libs
77
spack-*.txt
8+
*__pycache__

RELEASE_NOTES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ Version vxx.yy.zz -- Release date 20yy-mm-dd
22
============================================
33

44
* New features:
5+
* Added various tensorOps functions.
6+
* Added a Python interface to most container classes.
57

68
* API Changes:
79
* You will now get a compilation error when performing certain undefined operations on rvalues, for example calling `toView` on an `Array` rvalue.
810

911
* Build changes/improvements:
1012

1113
* Bug fixes:
12-
* Fixed indexing bug that produced a compilation error with GCC 10.
14+
* Fixed an indexing bug that produced a compilation error with GCC 10.
1315
* Fixed a memory leak in `CRSMatrix::assimilate`.
1416
* Fixed a memory leak in `ArrayOfArraysView::free` with non-trivially destructable values.
1517
* Fixed a compilation error with GCC 9.

cmake/SetupTPL.cmake

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,19 @@ else()
9090
message(STATUS "Not using caliper.")
9191
endif()
9292

93-
set(thirdPartyLibs ${thirdPartyLibs} CACHE STRING "")
93+
################################
94+
# Python
95+
################################
96+
if ( ENABLE_PYLVARRAY )
97+
message( STATUS "Python3_EXECUTABLE=${Python3_EXECUTABLE}" )
98+
find_package( Python3 REQUIRED
99+
COMPONENTS Development NumPy )
100+
101+
message( STATUS "Python3_INCLUDE_DIRS = ${Python3_INCLUDE_DIRS}" )
102+
message( STATUS "Python3_LIBRARY_DIRS = ${Python3_LIBRARY_DIRS}" )
103+
message( STATUS "Python3_NumPy_INCLUDE_DIRS = ${Python3_NumPy_INCLUDE_DIRS}" )
104+
105+
set( thirdPartyLibs ${thirdPartyLibs} Python3::Python Python3::NumPy )
106+
endif()
107+
108+
set( thirdPartyLibs ${thirdPartyLibs} CACHE STRING "" )

docs/doxygen/Doxyfile.in

Lines changed: 220 additions & 84 deletions
Large diffs are not rendered by default.

docs/sphinx/conf.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import os
1616
import sys
1717
import shutil
18-
# sys.path.insert(0, os.path.abspath('.'))
1918

2019
# Call doxygen in ReadtheDocs
2120
read_the_docs_build = os.environ.get('READTHEDOCS', None) == 'True'
@@ -75,7 +74,7 @@
7574
# ones.
7675
extensions = [
7776
# 'sphinx.ext.mathjax'
78-
'sphinx.ext.imgmath'
77+
'sphinx.ext.imgmath',
7978
]
8079

8180
# Add any paths that contain templates here, relative to this directory.
@@ -121,7 +120,7 @@
121120
html_theme = 'sphinx_rtd_theme'
122121
html_theme_options = {}
123122
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
124-
123+
125124
# The name for this set of Sphinx documents. If None, it defaults to
126125
# "<project> v<release> documentation".
127126
#html_title = None
@@ -259,7 +258,7 @@
259258
imgmath_image_format='svg'
260259
imgmath_font_size=14
261260
#####################################################
262-
# add LaTeX macros
261+
# add LaTeX macros
263262

264263
# f = open('docs/sphinx/latex_macros.sty')
265264

docs/sphinx/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ The ``LvArray`` containers were designed specifically to integrate with `RAJA <h
3939
developmentAids
4040
testing
4141
benchmarks
42+
python/index
4243

4344
Doxygen
4445
=======

docs/sphinx/python/index.rst

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
.. _pylvarray:
2+
3+
:mod:`pylvarray` --- LvArray in Python
4+
======================================
5+
6+
.. py:module:: pylvarray
7+
:synopsis: Manipulate LvArray objects in Python
8+
9+
Many of the LvArray classes can be accessed and manipulated from Python.
10+
However, they cannot be created from Python.
11+
12+
.. warning::
13+
The ``pylvarray`` module provides plenty of opportunites to crash Python.
14+
See the Segmentation Faults section below.
15+
16+
Only Python 3 is supported.
17+
18+
Module Constants
19+
----------------
20+
21+
Space Constants
22+
^^^^^^^^^^^^^^^
23+
24+
The following constants are used to set the space in which an LvArray object lives.
25+
The object ``pylvarray.GPU`` will only be defined if it is a
26+
valid space for the current system.
27+
28+
.. py:data:: pylvarray.CPU
29+
.. py:data:: pylvarray.GPU
30+
31+
Permissions Constants
32+
^^^^^^^^^^^^^^^^^^^^^
33+
34+
The following constants are used to set permissions for an array instance.
35+
36+
.. py:data:: pylvarray.READ_ONLY
37+
38+
No modification of the underlying data is allowed.
39+
40+
.. py:data:: pylvarray.MODIFIABLE
41+
42+
Allows Numpy views to be modified, but the object itself cannot be resized
43+
(or otherwise have its buffer reallocated, such as by inserting new elements).
44+
45+
.. py:data:: pylvarray.RESIZEABLE
46+
47+
Allows Numpy views to be modified, and the object
48+
to be resized.
49+
50+
Module Classes
51+
--------------
52+
53+
All of the objects documented below have an attribute, ``dtype``,
54+
which returns the ``numpy.dtype`` of the object's data, and therefore
55+
the datatype of any Numpy view of the object.
56+
57+
Array and SortedArray
58+
^^^^^^^^^^^^^^^^^^^^^
59+
60+
.. py:class:: pylvarray.Array
61+
62+
Represents an LvArray::Array, a multidimensional array.
63+
64+
.. py:method:: get_single_parameter_resize_index()
65+
66+
.. py:method:: set_single_parameter_resize_index(dim)
67+
68+
Set the dimension resized by a call to ``resize()``.
69+
70+
.. py:method:: resize(new_size)
71+
72+
Resize the array in the default dimension to ``new_size``.
73+
74+
.. py:method:: resize_all(new_dims)
75+
76+
Resize all the dimensions of the array in-place, discarding values.
77+
78+
.. py:method:: to_numpy()
79+
80+
Return a Numpy view of the array.
81+
82+
.. py:method:: set_access_level(new_level)
83+
84+
Set read/modify/resize permissions for the instance.
85+
86+
.. py:method:: get_access_level()
87+
88+
Return the read/modify/resize permissions for the instance.
89+
90+
.. py:class:: pylvarray.SortedArray
91+
92+
Represents an LvArray::SortedArray, a one-dimensional sorted array.
93+
94+
.. py:method:: to_numpy()
95+
96+
Return a read-only Numpy view of the array.
97+
98+
.. py:method:: set_access_level(new_level)
99+
100+
Set read/modify/resize permissions for the instance.
101+
102+
.. py:method:: get_access_level()
103+
104+
Return the read/modify/resize permissions for the instance.
105+
106+
.. py:method:: insert(values)
107+
108+
Insert one or more values into the array.
109+
The object passed in will be converted to a 1D numpy array of the same dtype
110+
as the underlying instance, raising an exception if the conversion cannot be made safely.
111+
112+
.. py:method:: remove(values)
113+
114+
Remove one or more values from the array.
115+
The object passed in will be converted to a 1D numpy array of the same dtype
116+
as the underlying instance, raising an exception if the conversion cannot be made safely.
117+
118+
ArrayOfArrays and ArrayOfSets
119+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
120+
121+
.. py:class:: pylvarray.ArrayOfArrays
122+
123+
Represents an LvArray::ArrayOfArrays, a two-dimensional ragged array.
124+
125+
Supports Python's `sequence protocol
126+
<https://docs.python.org/3/library/collections.abc.html#collections.abc.Sequence>`_,
127+
with the addition of deleting subarrays with ``del arr[i]`` syntax.
128+
An array fetched with ``[]`` is returned as a Numpy view.
129+
The built-in ``len()`` function will return the number of arrays in the instance.
130+
Iterating over an instance will yield a Numpy view of each array.
131+
132+
.. py:method:: set_access_level(new_level)
133+
134+
Set read/modify/resize permissions for the instance.
135+
136+
.. py:method:: get_access_level()
137+
138+
Return the read/modify/resize permissions for the instance.
139+
140+
.. py:method:: insert(index, values)
141+
142+
Insert a new array consisting of ``values`` at the given index.
143+
144+
.. py:method:: insert_into(index, subindex, values)
145+
146+
Insert ``values`` into the subarray given by ``index`` at position ``subindex``.
147+
``values`` will be converted to a 1D numpy array of the same dtype
148+
as the underlying instance, raising an exception if the conversion cannot be made safely.
149+
150+
.. py:method:: erase_from(index, subindex)
151+
152+
Remove the value at ``subindex`` in the subarray ``index``.
153+
154+
*Conceptually* equivalent to ``del array_of_sets[index][subindex]``.
155+
156+
157+
.. py:class:: pylvarray.ArrayOfSets
158+
159+
Represents an LvArray::ArrayOfSets, a collection of sets.
160+
161+
Behaves very similarly to the ``ArrayOfArrays``, with differences
162+
outlined below.
163+
164+
.. py:method:: set_access_level(new_level)
165+
166+
Set read/modify/resize permissions for the instance.
167+
168+
.. py:method:: get_access_level()
169+
170+
Return the read/modify/resize permissions for the instance.
171+
172+
.. py:method:: insert(position, capacity=0)
173+
174+
Insert a new set with a given capacity at ``position``.
175+
176+
.. py:method:: insert_into(set_index, values)
177+
178+
Insert values into a specific set.
179+
180+
``values`` will be converted to a 1D numpy array of the same dtype
181+
as the underlying instance, raising an exception if the conversion cannot be made safely.
182+
183+
.. py:method:: erase_from(set_index, values)
184+
185+
Remove values from a specific set.
186+
187+
``values`` will be converted to a 1D numpy array of the same dtype
188+
as the underlying instance, raising an exception if the conversion cannot be made safely.
189+
190+
CRSMatrix
191+
^^^^^^^^^
192+
193+
.. py:class:: pylvarray.CRSMatrix
194+
195+
Represents an LvArray::CRSMatrix, a sparse matrix.
196+
197+
.. py:method:: to_scipy()
198+
199+
Return a scipy.sparse.csr_matrix representing the matrix.
200+
201+
Note that many methods of ``scipy.sparse.csr_matrix`` will,
202+
without raising an exception, generate deep copies of the
203+
LvArray::CRSMatrix's data. For instance, assigning a new
204+
value to an element in the ``csr_matrix`` may or may not modify the
205+
``CRSMatrix`` data. Other ``csr_matrix`` methods will raise
206+
exceptions---for instance, when resizing. It is therefore in your
207+
best interest to be very careful about what methods and operations
208+
you perform on the ``crs_matrix``. To be safe, do not attempt to modify
209+
the matrix at all.
210+
211+
.. py:method:: set_access_level(new_level)
212+
213+
Set read/modify/resize permissions for the instance.
214+
215+
.. py:method:: get_access_level()
216+
217+
Return the read/modify/resize permissions for the instance.
218+
219+
.. py:method:: num_rows()
220+
221+
Return the number of rows in the matrix.
222+
223+
.. py:method:: num_columns()
224+
225+
Return the number of columns in the matrix.
226+
227+
.. py:method:: get_entries(row)
228+
229+
Return a Numpy array representing the entries in the given row.
230+
231+
.. py:method:: resize(num_rows, num_cols, initial_row_capacity=0)
232+
233+
Set the dimensions of the matrix, and the row capacity for
234+
any newly-created rows.
235+
236+
.. py:method:: compress()
237+
238+
Compress the matrix.
239+
240+
.. py:method:: insert_nonzeros(row, columns, entries)
241+
242+
Insert new nonzero entries to the matrix.
243+
244+
``columns`` and ``entries`` should be iterables of equal length; both
245+
will be converted to Numpy arrays and a ``TypeError`` will be raised
246+
if the conversion cannot be made safely.
247+
248+
.. py:method:: remove_nonzeros(row, columns)
249+
250+
Remove nonzero entries from the matrix.
251+
252+
``columns`` should be an iterable identifying the columns of
253+
the given row to remove nonzero entries from. It will be
254+
converted to a Numpy array and a ``TypeError`` will be raised
255+
if the conversion cannot be made safely.
256+
257+
.. py:method:: add_to_row(row, columns, values)
258+
259+
Add values to already-existing entries in a row.
260+
261+
``columns`` and ``values`` should be iterables of equal length; both
262+
will be converted to Numpy arrays and a ``TypeError`` will be raised
263+
if the conversion cannot be made safely.
264+
265+
Segmentation Faults
266+
-------------------
267+
Improper use of this module and associated programs can easily cause Python to crash.
268+
There are two main causes of crashes.
269+
270+
Stale Numpy Views
271+
^^^^^^^^^^^^^^^^^
272+
The ``pylvarray`` classes provide various ways to get Numpy views of
273+
their data. However, those views are only valid as long as the
274+
LvArray object's buffer is not reallocated. The buffer may be reallocated
275+
by invoking methods (the ones that require
276+
the ``RESIZEABLE`` permission) or by calls into a C++ program with access
277+
to the underlying C++ LvArray object.
278+
279+
.. code:: python
280+
281+
view = my_array.to_numpy()
282+
my_array.resize(1000)
283+
print(view) # segfault
284+
285+
Destroyed LvArray C++ objects
286+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
287+
As mentioned earlier, the classes defined in this
288+
module cannot be created in Python; some external C++
289+
program/library must create an LvArray object in C++, then create a
290+
``pylvarray`` view of it. However, the Python view will only be
291+
valid as long as the underlying LvArray C++ object is kept around. If
292+
that is destroyed, the Python object will be left holding an invalid
293+
pointer and subsequent attempts to use the Python object will cause
294+
undefined behavior. The only way to avoid this is to know under what
295+
circumstances the external C++ program/library will destroy
296+
LvArray objects. To be safe, however, do not hold onto ``pylvarray``
297+
object references after calling functions that have access to the underlying
298+
``LvArray`` objects.
299+
300+
.. toctree::
301+
:maxdepth: 2
302+
:caption: Contents:
303+
304+
Indices and tables
305+
==================
306+
307+
* :ref:`genindex`
308+
* :ref:`modindex`
309+
* :ref:`search`
310+

0 commit comments

Comments
 (0)