Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numpy Deprecated Code Replacement #3126

Merged
merged 5 commits into from
Jan 18, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@
`decision_tree()` and `hoeffding_tree()` (#2971).

* Depend on `pkgbuild` for R bindings (#3081).

* Replaced Numpy deprecated code in Python bindings (#3126).

### mlpack 3.4.2
###### 2020-10-26
Expand Down
75 changes: 45 additions & 30 deletions src/mlpack/bindings/python/mlpack/arma_numpy.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ isWin = (platform.system() == "Windows")
cdef extern from "numpy/arrayobject.h":
void PyArray_ENABLEFLAGS(numpy.ndarray arr, int flags)
void PyArray_CLEARFLAGS(numpy.ndarray arr, int flags)
void* PyArray_DATA(numpy.ndarray arr)
numpy.npy_intp* PyArray_SHAPE(numpy.ndarray arr)
int PyArray_FLAGS(numpy.ndarray arr)

cdef extern from "<mlpack/bindings/python/mlpack/arma_util.hpp>":
void SetMemState[T](T& m, int state)
Expand All @@ -48,17 +51,19 @@ cdef arma.Mat[double]* numpy_to_mat_d(numpy.ndarray[numpy.double_t, ndim=2] X, \
"""
Convert a numpy ndarray to a matrix. The memory will still be owned by numpy.
"""
if not X.flags.c_contiguous or (not X.flags.owndata and not isWin):
cdef int flags = PyArray_FLAGS(X)
if not (flags & numpy.NPY_ARRAY_C_CONTIGUOUS) or \
(not (flags & numpy.NPY_ARRAY_OWNDATA) and not isWin):
# If needed, make a copy where we own the memory.
X = X.copy(order="C")
takeOwnership = True

cdef arma.Mat[double]* m = new arma.Mat[double](<double*> X.data, X.shape[1],\
X.shape[0], isWin, False)
cdef arma.Mat[double]* m = new arma.Mat[double](<double*> PyArray_DATA(X),
PyArray_SHAPE(X)[1], PyArray_SHAPE(X)[0], isWin, False)

# Take ownership of the memory, if we need to and we are not on Windows.
if takeOwnership and not isWin:
PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA)
PyArray_CLEARFLAGS(X, numpy.NPY_ARRAY_OWNDATA)
SetMemState[arma.Mat[double]](m[0], 0)

return m
Expand All @@ -68,18 +73,20 @@ cdef arma.Mat[size_t]* numpy_to_mat_s(numpy.ndarray[numpy.npy_intp, ndim=2] X, \
"""
Convert a numpy ndarray to a matrix. The memory will still be owned by numpy.
"""
if not X.flags.c_contiguous or (not X.flags.owndata and not isWin):
cdef int flags = PyArray_FLAGS(X)
if not (flags & numpy.NPY_ARRAY_C_CONTIGUOUS) or \
(not (flags & numpy.NPY_ARRAY_OWNDATA) and not isWin):
# If needed, make a copy where we own the memory, except on Windows where
# we never copy.
X = X.copy(order="C")
takeOwnership = True

cdef arma.Mat[size_t]* m = new arma.Mat[size_t](<size_t*> X.data, X.shape[1],
X.shape[0], isWin, False)
cdef arma.Mat[size_t]* m = new arma.Mat[size_t](<size_t*> PyArray_DATA(X),
PyArray_SHAPE(X)[1], PyArray_SHAPE(X)[0], isWin, False)

# Take ownership of the memory, if we need to.
if takeOwnership and not isWin:
PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA)
PyArray_CLEARFLAGS(X, numpy.NPY_ARRAY_OWNDATA)
SetMemState[arma.Mat[size_t]](m[0], 0)

return m
Expand All @@ -101,7 +108,7 @@ cdef numpy.ndarray[numpy.double_t, ndim=2] mat_to_numpy_d(arma.Mat[double]& X) \
# Transfer memory ownership, if needed.
if GetMemState[arma.Mat[double]](X) == 0 and not isWin:
SetMemState[arma.Mat[double]](X, 1)
PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA)
PyArray_ENABLEFLAGS(output, numpy.NPY_ARRAY_OWNDATA)

return output

Expand All @@ -122,7 +129,7 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=2] mat_to_numpy_s(arma.Mat[size_t]& X) \
# Transfer memory ownership, if needed.
if GetMemState[arma.Mat[size_t]](X) == 0 and not isWin:
SetMemState[arma.Mat[size_t]](X, 1)
PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA)
PyArray_ENABLEFLAGS(output, numpy.NPY_ARRAY_OWNDATA)

return output

Expand All @@ -132,18 +139,20 @@ cdef arma.Row[double]* numpy_to_row_d(numpy.ndarray[numpy.double_t, ndim=1] X, \
Convert a numpy one-dimensional ndarray to a row. The memory will still be
owned by numpy.
"""
if not X.flags.c_contiguous or (not X.flags.owndata and not isWin):
cdef int flags = PyArray_FLAGS(X)
if not (flags & numpy.NPY_ARRAY_C_CONTIGUOUS) or \
(not (flags & numpy.NPY_ARRAY_OWNDATA) and not isWin):
# If needed, make a copy where we own the memory, except on Windows where
# we never copy.
X = X.copy(order="C")
takeOwnership = True

cdef arma.Row[double]* m = new arma.Row[double](<double*> X.data, X.shape[0],
isWin, False)
cdef arma.Row[double]* m = new arma.Row[double](<double*> PyArray_DATA(X),
PyArray_SHAPE(X)[0], isWin, False)

# Transfer memory ownership, if needed.
if takeOwnership and not isWin:
PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA)
PyArray_CLEARFLAGS(X, numpy.NPY_ARRAY_OWNDATA)
SetMemState[arma.Row[double]](m[0], 0)

return m
Expand All @@ -154,18 +163,20 @@ cdef arma.Row[size_t]* numpy_to_row_s(numpy.ndarray[numpy.npy_intp, ndim=1] X, \
Convert a numpy one-dimensional ndarray to a row. The memory will still be
owned by numpy.
"""
if not X.flags.c_contiguous or (not X.flags.owndata and not isWin):
cdef int flags = PyArray_FLAGS(X)
if not (flags & numpy.NPY_ARRAY_C_CONTIGUOUS) or \
(not (flags & numpy.NPY_ARRAY_OWNDATA) and not isWin):
# If needed, make a copy where we own the memory, except on Windows where
# we never copy.
X = X.copy(order="C")
takeOwnership = True

cdef arma.Row[size_t]* m = new arma.Row[size_t](<size_t*> X.data, X.shape[0],
isWin, False)
cdef arma.Row[size_t]* m = new arma.Row[size_t](<size_t*> PyArray_DATA(X),
PyArray_SHAPE(X)[0], isWin, False)

# Transfer memory ownership, if needed.
if takeOwnership and not isWin:
PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA)
PyArray_CLEARFLAGS(X, numpy.NPY_ARRAY_OWNDATA)
SetMemState[arma.Row[size_t]](m[0], 0)

return m
Expand All @@ -185,7 +196,7 @@ cdef numpy.ndarray[numpy.double_t, ndim=1] row_to_numpy_d(arma.Row[double]& X) \
# Transfer memory ownership, if needed.
if GetMemState[arma.Row[double]](X) == 0 and not isWin:
SetMemState[arma.Row[double]](X, 1)
PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA)
PyArray_ENABLEFLAGS(output, numpy.NPY_ARRAY_OWNDATA)

return output

Expand All @@ -205,7 +216,7 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=1] row_to_numpy_s(arma.Row[size_t]& X) \
# Transfer memory ownership, if needed.
if GetMemState[arma.Row[size_t]](X) == 0 and not isWin:
SetMemState[arma.Row[size_t]](X, 1)
PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA)
PyArray_ENABLEFLAGS(output, numpy.NPY_ARRAY_OWNDATA)

return output

Expand All @@ -215,18 +226,20 @@ cdef arma.Col[double]* numpy_to_col_d(numpy.ndarray[numpy.double_t, ndim=1] X, \
Convert a numpy one-dimensional ndarray to a column vector. The memory will
still be owned by numpy.
"""
if not X.flags.c_contiguous or (not X.flags.owndata and not isWin):
cdef int flags = PyArray_FLAGS(X)
if not (flags & numpy.NPY_ARRAY_C_CONTIGUOUS) or \
(not (flags & numpy.NPY_ARRAY_OWNDATA) and not isWin):
# If needed, make a copy where we own the memory, except on Windows where
# we never copy.
X = X.copy(order="C")
takeOwnership = True

cdef arma.Col[double]* m = new arma.Col[double](<double*> X.data, X.shape[0],
isWin, False)
cdef arma.Col[double]* m = new arma.Col[double](<double*> PyArray_DATA(X),
PyArray_SHAPE(X)[0], isWin, False)

# Transfer memory ownership, if needed.
if takeOwnership and not isWin:
PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA)
PyArray_CLEARFLAGS(X, numpy.NPY_ARRAY_OWNDATA)
SetMemState[arma.Col[double]](m[0], 0)

return m
Expand All @@ -237,18 +250,20 @@ cdef arma.Col[size_t]* numpy_to_col_s(numpy.ndarray[numpy.npy_intp, ndim=1] X, \
Convert a numpy one-dimensional ndarray to a column vector. The memory will
still be owned by numpy.
"""
if not X.flags.c_contiguous or (not X.flags.owndata and not isWin):
cdef int flags = PyArray_FLAGS(X)
if not (flags & numpy.NPY_ARRAY_C_CONTIGUOUS) or \
(not (flags & numpy.NPY_ARRAY_OWNDATA) and not isWin):
# If needed, make a copy where we own the memory, except on Windows where
# we never copy.
X = X.copy(order="C")
takeOwnership = True

cdef arma.Col[size_t]* m = new arma.Col[size_t](<size_t*> X.data, X.shape[0],
isWin, False)
cdef arma.Col[size_t]* m = new arma.Col[size_t](<size_t*> PyArray_DATA(X),
PyArray_SHAPE(X)[0], isWin, False)

# Transfer memory ownership, if needed.
if takeOwnership and not isWin:
PyArray_CLEARFLAGS(X, numpy.NPY_OWNDATA)
PyArray_CLEARFLAGS(X, numpy.NPY_ARRAY_OWNDATA)
SetMemState[arma.Col[size_t]](m[0], 0)

return m
Expand All @@ -268,7 +283,7 @@ cdef numpy.ndarray[numpy.double_t, ndim=1] col_to_numpy_d(arma.Col[double]& X) \
# Transfer memory ownership, if needed.
if GetMemState[arma.Col[double]](X) == 0 and not isWin:
SetMemState[arma.Col[double]](X, 1)
PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA)
PyArray_ENABLEFLAGS(output, numpy.NPY_ARRAY_OWNDATA)

return output

Expand All @@ -287,6 +302,6 @@ cdef numpy.ndarray[numpy.npy_intp, ndim=1] col_to_numpy_s(arma.Col[size_t]& X) \
# Transfer memory ownership, if needed.
if GetMemState[arma.Col[size_t]](X) == 0 and not isWin:
SetMemState[arma.Col[size_t]](X, 1)
PyArray_ENABLEFLAGS(output, numpy.NPY_OWNDATA)
PyArray_ENABLEFLAGS(output, numpy.NPY_ARRAY_OWNDATA)

return output
13 changes: 10 additions & 3 deletions src/mlpack/bindings/python/print_input_processing.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,20 +454,25 @@ void PrintInputProcessing(

/** We want to generate code like the following:
*
* cdef extern from "numpy/arrayobject.h":
* void* PyArray_DATA(np.ndarray arr)
* if param_name is not None:
* param_name_tuple = to_matrix_with_info(param_name)
* if len(param_name_tuple[0].shape) < 2:
* param_name_tuple[0].shape = (param_name_tuple[0].size,)
* param_name_mat = arma_numpy.numpy_to_matrix_d(param_name_tuple[0])
* SetParamWithInfo[mat](p, \<const string\> 'param_name',
* dereference(param_name_mat), &param_name_tuple[1][0])
* dereference(param_name_mat),
* \<const cbool*\> PyArray_DATA(param_name_dims))
* p.SetPassed(\<const string\> 'param_name')
*/
std::cout << prefix << "cdef np.ndarray " << d.name << "_dims" << std::endl;
std::cout << prefix << "# Detect if the parameter was passed; set if so."
<< std::endl;
if (!d.required)
{
std::cout << prefix << "cdef extern from \"numpy/arrayobject.h\":" << std::endl;
std::cout << prefix << " void* PyArray_DATA(np.ndarray arr)" << std::endl;
std::cout << prefix << "if " << d.name << " is not None:" << std::endl;
std::cout << prefix << " " << d.name << "_tuple = to_matrix_with_info("
<< d.name << ", dtype=np.double, copy=p.Has('copy_all_inputs'))"
Expand All @@ -482,13 +487,15 @@ void PrintInputProcessing(
<< "_tuple[2]" << std::endl;
std::cout << prefix << " SetParamWithInfo[arma.Mat[double]](p, <const "
<< "string> '" << d.name << "', dereference(" << d.name << "_mat), "
<< "<const cbool*> " << d.name << "_dims.data)" << std::endl;
<< "<const cbool*> PyArray_DATA(" << d.name << "_dims))" << std::endl;
std::cout << prefix << " p.SetPassed(<const string> '" << d.name
<< "')" << std::endl;
std::cout << prefix << " del " << d.name << "_mat" << std::endl;
}
else
{
std::cout << prefix << "cdef extern from \"numpy/arrayobject.h\":" << std::endl;
std::cout << prefix << " void* PyArray_DATA(np.ndarray arr)" << std::endl;
std::cout << prefix << d.name << "_tuple = to_matrix_with_info(" << d.name
<< ", dtype=np.double, copy=p.Has('copy_all_inputs'))"
<< std::endl;
Expand All @@ -502,7 +509,7 @@ void PrintInputProcessing(
<< std::endl;
std::cout << prefix << "SetParamWithInfo[arma.Mat[double]](p, <const "
<< "string> '" << d.name << "', dereference(" << d.name << "_mat), "
<< "<const cbool*> " << d.name << "_dims.data)" << std::endl;
<< "<const cbool*> PyArray_DATA(" << d.name << "_dims))" << std::endl;
std::cout << prefix << "p.SetPassed(<const string> '" << d.name << "')"
<< std::endl;
std::cout << prefix << "del " << d.name << "_mat" << std::endl;
Expand Down
2 changes: 2 additions & 0 deletions src/mlpack/bindings/python/setup.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ else:
# CMAKE_CXX_FLAGS seems to have an extra space.
extra_compile_args=extra_args,
extra_link_args=extra_link_args,
define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
undef_macros=[] if len("${DISABLE_CFLAGS}") == 0 \
else '${DISABLE_CFLAGS}'.split(' ')) \
for name in pyxs if name == module]
Expand All @@ -96,6 +97,7 @@ else:
# CMAKE_CXX_FLAGS seems to have an extra space.
extra_compile_args=extra_args,
extra_link_args=extra_link_args,
define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')],
undef_macros=[] if len("${DISABLE_CFLAGS}") == 0 \
else '${DISABLE_CFLAGS}'.split(' ')) \
for name in pyxs]
Expand Down