| 230 | } |
| 231 | |
| 232 | Status TensorToNdarray(const std::shared_ptr<Tensor>& tensor, PyObject* base, |
| 233 | PyObject** out) { |
| 234 | int type_num = 0; |
| 235 | RETURN_NOT_OK(GetNumPyType(*tensor->type(), &type_num)); |
| 236 | PyArray_Descr* dtype = PyArray_DescrNewFromType(type_num); |
| 237 | RETURN_IF_PYERROR(); |
| 238 | |
| 239 | const int ndim = tensor->ndim(); |
| 240 | std::vector<npy_intp> npy_shape(ndim); |
| 241 | std::vector<npy_intp> npy_strides(ndim); |
| 242 | |
| 243 | for (int i = 0; i < ndim; ++i) { |
| 244 | npy_shape[i] = tensor->shape()[i]; |
| 245 | npy_strides[i] = tensor->strides()[i]; |
| 246 | } |
| 247 | |
| 248 | const void* immutable_data = nullptr; |
| 249 | if (tensor->data()) { |
| 250 | immutable_data = tensor->data()->data(); |
| 251 | } |
| 252 | |
| 253 | // Remove const =( |
| 254 | void* mutable_data = const_cast<void*>(immutable_data); |
| 255 | |
| 256 | int array_flags = 0; |
| 257 | if (tensor->is_row_major()) { |
| 258 | array_flags |= NPY_ARRAY_C_CONTIGUOUS; |
| 259 | } |
| 260 | if (tensor->is_column_major()) { |
| 261 | array_flags |= NPY_ARRAY_F_CONTIGUOUS; |
| 262 | } |
| 263 | if (tensor->is_mutable()) { |
| 264 | array_flags |= NPY_ARRAY_WRITEABLE; |
| 265 | } |
| 266 | |
| 267 | PyObject* result = |
| 268 | PyArray_NewFromDescr(&PyArray_Type, dtype, ndim, npy_shape.data(), |
| 269 | npy_strides.data(), mutable_data, array_flags, nullptr); |
| 270 | RETURN_IF_PYERROR(); |
| 271 | |
| 272 | if (base == Py_None || base == nullptr) { |
| 273 | base = py::wrap_tensor(tensor); |
| 274 | } else { |
| 275 | Py_XINCREF(base); |
| 276 | } |
| 277 | PyArray_SetBaseObject(reinterpret_cast<PyArrayObject*>(result), base); |
| 278 | *out = result; |
| 279 | return Status::OK(); |
| 280 | } |
| 281 | |
| 282 | // Wrap the dense data of a sparse tensor in a ndarray |
| 283 | static Status SparseTensorDataToNdarray(const SparseTensor& sparse_tensor, |
no test coverage detected