mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-22 05:05:11 +00:00
array-unchecked: add runtime dimension support and array-compatible methods
The extends the previous unchecked support with the ability to determine the dimensions at runtime. This incurs a small performance hit when used (versus the compile-time fixed alternative), but is still considerably faster than the full checks on every call that happen with `.at()`/`.mutable_at()`.
This commit is contained in:
parent
423a49b8be
commit
773339f131
@ -340,12 +340,39 @@ To obtain the proxy from an ``array`` object, you must specify both the data
|
|||||||
type and number of dimensions as template arguments, such as ``auto r =
|
type and number of dimensions as template arguments, such as ``auto r =
|
||||||
myarray.mutable_unchecked<float, 2>()``.
|
myarray.mutable_unchecked<float, 2>()``.
|
||||||
|
|
||||||
|
If the number of dimensions is not known at compile time, you can omit the
|
||||||
|
dimensions template parameter (i.e. calling ``arr_t.unchecked()`` or
|
||||||
|
``arr.unchecked<T>()``. This will give you a proxy object that works in the
|
||||||
|
same way, but results in less optimizable code and thus a small efficiency
|
||||||
|
loss in tight loops.
|
||||||
|
|
||||||
Note that the returned proxy object directly references the array's data, and
|
Note that the returned proxy object directly references the array's data, and
|
||||||
only reads its shape, strides, and writeable flag when constructed. You must
|
only reads its shape, strides, and writeable flag when constructed. You must
|
||||||
take care to ensure that the referenced array is not destroyed or reshaped for
|
take care to ensure that the referenced array is not destroyed or reshaped for
|
||||||
the duration of the returned object, typically by limiting the scope of the
|
the duration of the returned object, typically by limiting the scope of the
|
||||||
returned instance.
|
returned instance.
|
||||||
|
|
||||||
|
The returned proxy object supports some of the same methods as ``py::array`` so
|
||||||
|
that it can be used as a drop-in replacement for some existing, index-checked
|
||||||
|
uses of ``py::array``:
|
||||||
|
|
||||||
|
- ``r.ndim()`` returns the number of dimensions
|
||||||
|
|
||||||
|
- ``r.data(1, 2, ...)`` and ``r.mutable_data(1, 2, ...)``` returns a pointer to
|
||||||
|
the ``const T`` or ``T`` data, respectively, at the given indices. The
|
||||||
|
latter is only available to proxies obtained via ``a.mutable_unchecked()``.
|
||||||
|
|
||||||
|
- ``itemsize()`` returns the size of an item in bytes, i.e. ``sizeof(T)``.
|
||||||
|
|
||||||
|
- ``ndim()`` returns the number of dimensions.
|
||||||
|
|
||||||
|
- ``shape(n)`` returns the size of dimension ``n``
|
||||||
|
|
||||||
|
- ``size()`` returns the total number of elements (i.e. the product of the shapes).
|
||||||
|
|
||||||
|
- ``nbytes()`` returns the number of bytes used by the referenced elements
|
||||||
|
(i.e. ``itemsize()`` times ``size()``).
|
||||||
|
|
||||||
.. seealso::
|
.. seealso::
|
||||||
|
|
||||||
The file :file:`tests/test_numpy_array.cpp` contains additional examples
|
The file :file:`tests/test_numpy_array.cpp` contains additional examples
|
||||||
|
@ -242,67 +242,107 @@ size_t byte_offset_unsafe(const Strides &strides, size_t i, Ix... index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Proxy class providing unsafe, unchecked const access to array data. This is constructed through
|
/** Proxy class providing unsafe, unchecked const access to array data. This is constructed through
|
||||||
* the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`.
|
* the `unchecked<T, N>()` method of `array` or the `unchecked<N>()` method of `array_t<T>`. `Dims`
|
||||||
|
* will be -1 for dimensions determined at runtime.
|
||||||
*/
|
*/
|
||||||
template <typename T, size_t Dims>
|
template <typename T, ssize_t Dims>
|
||||||
class unchecked_reference {
|
class unchecked_reference {
|
||||||
protected:
|
protected:
|
||||||
|
static constexpr bool Dynamic = Dims < 0;
|
||||||
const unsigned char *data_;
|
const unsigned char *data_;
|
||||||
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
|
// Storing the shape & strides in local variables (i.e. these arrays) allows the compiler to
|
||||||
// make large performance gains on big, nested loops.
|
// make large performance gains on big, nested loops, but requires compile-time dimensions
|
||||||
std::array<size_t, Dims> shape_, strides_;
|
conditional_t<Dynamic, const size_t *, std::array<size_t, (size_t) Dims>>
|
||||||
|
shape_, strides_;
|
||||||
|
const size_t dims_;
|
||||||
|
|
||||||
friend class pybind11::array;
|
friend class pybind11::array;
|
||||||
unchecked_reference(const void *data, const size_t *shape, const size_t *strides)
|
// Constructor for compile-time dimensions:
|
||||||
: data_{reinterpret_cast<const unsigned char *>(data)} {
|
template <bool Dyn = Dynamic>
|
||||||
for (size_t i = 0; i < Dims; i++) {
|
unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t<!Dyn, size_t>)
|
||||||
|
: data_{reinterpret_cast<const unsigned char *>(data)}, dims_{Dims} {
|
||||||
|
for (size_t i = 0; i < dims_; i++) {
|
||||||
shape_[i] = shape[i];
|
shape_[i] = shape[i];
|
||||||
strides_[i] = strides[i];
|
strides_[i] = strides[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Constructor for runtime dimensions:
|
||||||
|
template <bool Dyn = Dynamic>
|
||||||
|
unchecked_reference(const void *data, const size_t *shape, const size_t *strides, enable_if_t<Dyn, size_t> dims)
|
||||||
|
: data_{reinterpret_cast<const unsigned char *>(data)}, shape_{shape}, strides_{strides}, dims_{dims} {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Unchecked const reference access to data at the given indices. Omiting trailing indices
|
/** Unchecked const reference access to data at the given indices. For a compile-time known
|
||||||
* is equivalent to specifying them as 0.
|
* number of dimensions, this requires the correct number of arguments; for run-time
|
||||||
|
* dimensionality, this is not checked (and so is up to the caller to use safely).
|
||||||
*/
|
*/
|
||||||
template <typename... Ix> const T& operator()(Ix... index) const {
|
template <typename... Ix> const T &operator()(Ix... index) const {
|
||||||
static_assert(sizeof...(Ix) <= Dims, "Invalid number of indices for unchecked array reference");
|
static_assert(sizeof...(Ix) == Dims || Dynamic,
|
||||||
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, size_t{index}...));
|
"Invalid number of indices for unchecked array reference");
|
||||||
|
return *reinterpret_cast<const T *>(data_ + byte_offset_unsafe(strides_, size_t(index)...));
|
||||||
}
|
}
|
||||||
/** Unchecked const reference access to data; this operator only participates if the reference
|
/** Unchecked const reference access to data; this operator only participates if the reference
|
||||||
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
* is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
||||||
*/
|
*/
|
||||||
template <size_t D = Dims, typename = enable_if_t<D == 1>>
|
template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
||||||
const T &operator[](size_t index) const { return operator()(index); }
|
const T &operator[](size_t index) const { return operator()(index); }
|
||||||
|
|
||||||
|
/// Pointer access to the data at the given indices.
|
||||||
|
template <typename... Ix> const T *data(Ix... ix) const { return &operator()(size_t(ix)...); }
|
||||||
|
|
||||||
|
/// Returns the item size, i.e. sizeof(T)
|
||||||
|
constexpr static size_t itemsize() { return sizeof(T); }
|
||||||
|
|
||||||
/// Returns the shape (i.e. size) of dimension `dim`
|
/// Returns the shape (i.e. size) of dimension `dim`
|
||||||
size_t shape(size_t dim) const { return shape_[dim]; }
|
size_t shape(size_t dim) const { return shape_[dim]; }
|
||||||
|
|
||||||
/// Returns the number of dimensions of the array
|
/// Returns the number of dimensions of the array
|
||||||
constexpr static size_t ndim() { return Dims; }
|
size_t ndim() const { return dims_; }
|
||||||
|
|
||||||
|
/// Returns the total number of elements in the referenced array, i.e. the product of the shapes
|
||||||
|
template <bool Dyn = Dynamic>
|
||||||
|
enable_if_t<!Dyn, size_t> size() const {
|
||||||
|
return std::accumulate(shape_.begin(), shape_.end(), (size_t) 1, std::multiplies<size_t>());
|
||||||
|
}
|
||||||
|
template <bool Dyn = Dynamic>
|
||||||
|
enable_if_t<Dyn, size_t> size() const {
|
||||||
|
return std::accumulate(shape_, shape_ + ndim(), (size_t) 1, std::multiplies<size_t>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the total number of bytes used by the referenced data. Note that the actual span in
|
||||||
|
/// memory may be larger if the referenced array has non-contiguous strides (e.g. for a slice).
|
||||||
|
size_t nbytes() const {
|
||||||
|
return size() * itemsize();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, size_t Dims>
|
template <typename T, ssize_t Dims>
|
||||||
class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
|
class unchecked_mutable_reference : public unchecked_reference<T, Dims> {
|
||||||
friend class pybind11::array;
|
friend class pybind11::array;
|
||||||
using ConstBase = unchecked_reference<T, Dims>;
|
using ConstBase = unchecked_reference<T, Dims>;
|
||||||
using ConstBase::ConstBase;
|
using ConstBase::ConstBase;
|
||||||
|
using ConstBase::Dynamic;
|
||||||
public:
|
public:
|
||||||
/// Mutable, unchecked access to data at the given indices.
|
/// Mutable, unchecked access to data at the given indices.
|
||||||
template <typename... Ix> T& operator()(Ix... index) {
|
template <typename... Ix> T& operator()(Ix... index) {
|
||||||
static_assert(sizeof...(Ix) == Dims, "Invalid number of indices for unchecked array reference");
|
static_assert(sizeof...(Ix) == Dims || Dynamic,
|
||||||
|
"Invalid number of indices for unchecked array reference");
|
||||||
return const_cast<T &>(ConstBase::operator()(index...));
|
return const_cast<T &>(ConstBase::operator()(index...));
|
||||||
}
|
}
|
||||||
/** Mutable, unchecked access data at the given index; this operator only participates if the
|
/** Mutable, unchecked access data at the given index; this operator only participates if the
|
||||||
* reference is to a 1-dimensional array. When present, this is exactly equivalent to `obj(index)`.
|
* reference is to a 1-dimensional array (or has runtime dimensions). When present, this is
|
||||||
|
* exactly equivalent to `obj(index)`.
|
||||||
*/
|
*/
|
||||||
template <size_t D = Dims, typename = enable_if_t<D == 1>>
|
template <size_t D = Dims, typename = enable_if_t<D == 1 || Dynamic>>
|
||||||
T &operator[](size_t index) { return operator()(index); }
|
T &operator[](size_t index) { return operator()(index); }
|
||||||
|
|
||||||
|
/// Mutable pointer access to the data at the given indices.
|
||||||
|
template <typename... Ix> T *mutable_data(Ix... ix) { return &operator()(size_t(ix)...); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, size_t Dim>
|
template <typename T, size_t Dim>
|
||||||
struct type_caster<unchecked_reference<T, Dim>> {
|
struct type_caster<unchecked_reference<T, Dim>> {
|
||||||
static_assert(Dim == (size_t) -1 /* always fail */, "unchecked array proxy object is not castable");
|
static_assert(Dim == 0 && Dim > 0 /* always fail */, "unchecked array proxy object is not castable");
|
||||||
};
|
};
|
||||||
template <typename T, size_t Dim>
|
template <typename T, size_t Dim>
|
||||||
struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {};
|
struct type_caster<unchecked_mutable_reference<T, Dim>> : type_caster<unchecked_reference<T, Dim>> {};
|
||||||
@ -580,11 +620,11 @@ public:
|
|||||||
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
||||||
* and the caller must take care not to access invalid dimensions or dimension indices.
|
* and the caller must take care not to access invalid dimensions or dimension indices.
|
||||||
*/
|
*/
|
||||||
template <typename T, size_t Dims> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
|
template <typename T, ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
|
||||||
if (ndim() != Dims)
|
if (Dims >= 0 && ndim() != (size_t) Dims)
|
||||||
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
||||||
"; expected " + std::to_string(Dims));
|
"; expected " + std::to_string(Dims));
|
||||||
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides());
|
return detail::unchecked_mutable_reference<T, Dims>(mutable_data(), shape(), strides(), ndim());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a proxy object that provides const access to the array's data without bounds or
|
/** Returns a proxy object that provides const access to the array's data without bounds or
|
||||||
@ -593,11 +633,11 @@ public:
|
|||||||
* reshaped for the duration of the returned object, and the caller must take care not to access
|
* reshaped for the duration of the returned object, and the caller must take care not to access
|
||||||
* invalid dimensions or dimension indices.
|
* invalid dimensions or dimension indices.
|
||||||
*/
|
*/
|
||||||
template <typename T, size_t Dims> detail::unchecked_reference<T, Dims> unchecked() const {
|
template <typename T, ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const {
|
||||||
if (ndim() != Dims)
|
if (Dims >= 0 && ndim() != (size_t) Dims)
|
||||||
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
throw std::domain_error("array has incorrect number of dimensions: " + std::to_string(ndim()) +
|
||||||
"; expected " + std::to_string(Dims));
|
"; expected " + std::to_string(Dims));
|
||||||
return detail::unchecked_reference<T, Dims>(data(), shape(), strides());
|
return detail::unchecked_reference<T, Dims>(data(), shape(), strides(), ndim());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new view with all of the dimensions of length 1 removed
|
/// Return a new view with all of the dimensions of length 1 removed
|
||||||
@ -625,7 +665,7 @@ protected:
|
|||||||
|
|
||||||
template<typename... Ix> size_t byte_offset(Ix... index) const {
|
template<typename... Ix> size_t byte_offset(Ix... index) const {
|
||||||
check_dimensions(index...);
|
check_dimensions(index...);
|
||||||
return detail::byte_offset_unsafe(strides(), size_t{index}...);
|
return detail::byte_offset_unsafe(strides(), size_t(index)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_writeable() const {
|
void check_writeable() const {
|
||||||
@ -736,7 +776,7 @@ public:
|
|||||||
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
* care: the array must not be destroyed or reshaped for the duration of the returned object,
|
||||||
* and the caller must take care not to access invalid dimensions or dimension indices.
|
* and the caller must take care not to access invalid dimensions or dimension indices.
|
||||||
*/
|
*/
|
||||||
template <size_t Dims> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
|
template <ssize_t Dims = -1> detail::unchecked_mutable_reference<T, Dims> mutable_unchecked() {
|
||||||
return array::mutable_unchecked<T, Dims>();
|
return array::mutable_unchecked<T, Dims>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,7 +786,7 @@ public:
|
|||||||
* for the duration of the returned object, and the caller must take care not to access invalid
|
* for the duration of the returned object, and the caller must take care not to access invalid
|
||||||
* dimensions or dimension indices.
|
* dimensions or dimension indices.
|
||||||
*/
|
*/
|
||||||
template <size_t Dims> detail::unchecked_reference<T, Dims> unchecked() const {
|
template <ssize_t Dims = -1> detail::unchecked_reference<T, Dims> unchecked() const {
|
||||||
return array::unchecked<T, Dims>();
|
return array::unchecked<T, Dims>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,21 @@ template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(
|
|||||||
sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \
|
sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \
|
||||||
sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
|
sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
|
||||||
|
|
||||||
|
template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
|
||||||
|
if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
|
||||||
|
py::list l;
|
||||||
|
l.append(*r.data(0, 0));
|
||||||
|
l.append(*r2.mutable_data(0, 0));
|
||||||
|
l.append(r.data(0, 1) == r2.mutable_data(0, 1));
|
||||||
|
l.append(r.ndim());
|
||||||
|
l.append(r.itemsize());
|
||||||
|
l.append(r.shape(0));
|
||||||
|
l.append(r.shape(1));
|
||||||
|
l.append(r.size());
|
||||||
|
l.append(r.nbytes());
|
||||||
|
return l.release();
|
||||||
|
}
|
||||||
|
|
||||||
test_initializer numpy_array([](py::module &m) {
|
test_initializer numpy_array([](py::module &m) {
|
||||||
auto sm = m.def_submodule("array");
|
auto sm = m.def_submodule("array");
|
||||||
|
|
||||||
@ -191,6 +206,7 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
for (size_t j = 0; j < r.shape(1); j++)
|
for (size_t j = 0; j < r.shape(1); j++)
|
||||||
r(i, j) += v;
|
r(i, j) += v;
|
||||||
}, py::arg().noconvert(), py::arg());
|
}, py::arg().noconvert(), py::arg());
|
||||||
|
|
||||||
sm.def("proxy_init3", [](double start) {
|
sm.def("proxy_init3", [](double start) {
|
||||||
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
||||||
auto r = a.mutable_unchecked<3>();
|
auto r = a.mutable_unchecked<3>();
|
||||||
@ -216,4 +232,36 @@ test_initializer numpy_array([](py::module &m) {
|
|||||||
sumsq += r[i] * r(i); // Either notation works for a 1D array
|
sumsq += r[i] * r(i); // Either notation works for a 1D array
|
||||||
return sumsq;
|
return sumsq;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sm.def("proxy_auxiliaries2", [](py::array_t<double> a) {
|
||||||
|
auto r = a.unchecked<2>();
|
||||||
|
auto r2 = a.mutable_unchecked<2>();
|
||||||
|
return auxiliaries(r, r2);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Same as the above, but without a compile-time dimensions specification:
|
||||||
|
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) {
|
||||||
|
auto r = a.mutable_unchecked();
|
||||||
|
if (r.ndim() != 2) throw std::domain_error("error: ndim != 2");
|
||||||
|
for (size_t i = 0; i < r.shape(0); i++)
|
||||||
|
for (size_t j = 0; j < r.shape(1); j++)
|
||||||
|
r(i, j) += v;
|
||||||
|
}, py::arg().noconvert(), py::arg());
|
||||||
|
sm.def("proxy_init3_dyn", [](double start) {
|
||||||
|
py::array_t<double, py::array::c_style> a({ 3, 3, 3 });
|
||||||
|
auto r = a.mutable_unchecked();
|
||||||
|
if (r.ndim() != 3) throw std::domain_error("error: ndim != 3");
|
||||||
|
for (size_t i = 0; i < r.shape(0); i++)
|
||||||
|
for (size_t j = 0; j < r.shape(1); j++)
|
||||||
|
for (size_t k = 0; k < r.shape(2); k++)
|
||||||
|
r(i, j, k) = start++;
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
sm.def("proxy_auxiliaries2_dyn", [](py::array_t<double> a) {
|
||||||
|
return auxiliaries(a.unchecked(), a.mutable_unchecked());
|
||||||
|
});
|
||||||
|
|
||||||
|
sm.def("array_auxiliaries2", [](py::array_t<double> a) {
|
||||||
|
return auxiliaries(a, a);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -341,8 +341,9 @@ def test_greedy_string_overload(): # issue 685
|
|||||||
assert issue685(123) == "other"
|
assert issue685(123) == "other"
|
||||||
|
|
||||||
|
|
||||||
def test_array_unchecked(msg):
|
def test_array_unchecked_fixed_dims(msg):
|
||||||
from pybind11_tests.array import proxy_add2, proxy_init3F, proxy_init3, proxy_squared_L2_norm
|
from pybind11_tests.array import (proxy_add2, proxy_init3F, proxy_init3, proxy_squared_L2_norm,
|
||||||
|
proxy_auxiliaries2, array_auxiliaries2)
|
||||||
|
|
||||||
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
||||||
proxy_add2(z1, 10)
|
proxy_add2(z1, 10)
|
||||||
@ -359,3 +360,20 @@ def test_array_unchecked(msg):
|
|||||||
|
|
||||||
assert proxy_squared_L2_norm(np.array(range(6))) == 55
|
assert proxy_squared_L2_norm(np.array(range(6))) == 55
|
||||||
assert proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
|
assert proxy_squared_L2_norm(np.array(range(6), dtype="float64")) == 55
|
||||||
|
|
||||||
|
assert proxy_auxiliaries2(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
||||||
|
assert proxy_auxiliaries2(z1) == array_auxiliaries2(z1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_array_unchecked_dyn_dims(msg):
|
||||||
|
from pybind11_tests.array import (proxy_add2_dyn, proxy_init3_dyn, proxy_auxiliaries2_dyn,
|
||||||
|
array_auxiliaries2)
|
||||||
|
z1 = np.array([[1, 2], [3, 4]], dtype='float64')
|
||||||
|
proxy_add2_dyn(z1, 10)
|
||||||
|
assert np.all(z1 == [[11, 12], [13, 14]])
|
||||||
|
|
||||||
|
expect_c = np.ndarray(shape=(3, 3, 3), buffer=np.array(range(3, 30)), dtype='int')
|
||||||
|
assert np.all(proxy_init3_dyn(3.0) == expect_c)
|
||||||
|
|
||||||
|
assert proxy_auxiliaries2_dyn(z1) == [11, 11, True, 2, 8, 2, 2, 4, 32]
|
||||||
|
assert proxy_auxiliaries2_dyn(z1) == array_auxiliaries2(z1)
|
||||||
|
Loading…
Reference in New Issue
Block a user