Michele De Stefano's C++ Utilities
matrix_sparse.hpp
Go to the documentation of this file.
1 // matrix_sparse.hpp
2 //
3 // Copyright (c) 2009 - Michele De Stefano (micdestefano@users.sourceforge.net)
4 //
5 // Distributed under the MIT License (See accompanying file LICENSE)
6 
7 #ifndef MDS_UTILS_PYTHON_UBLAS_MATRIX_SPARSE_HPP_INCLUDED
8 #define MDS_UTILS_PYTHON_UBLAS_MATRIX_SPARSE_HPP_INCLUDED
9 
27 #include <mds_utils/python/ublas/detail/common.hpp>
31 #include <boost/numeric/ublas/matrix_sparse.hpp>
32 #include <boost/fusion/container/vector.hpp>
33 #include <boost/numeric/conversion/cast.hpp>
34 #include <algorithm>
35 #include <string>
36 
37 namespace mds_utils { namespace python { namespace ublas {
38 
40  namespace detail {
41 
42 template<class orientation_category>
43 struct scipy_sparse_mtx;
44 
45 template<>
46 struct scipy_sparse_mtx<boost::numeric::ublas::row_major_tag> {
47 
48  static const std::string name;
49 };
50 
51 const std::string scipy_sparse_mtx<boost::numeric::ublas::row_major_tag>::name("csr_matrix");
52 
53 template<>
54 struct scipy_sparse_mtx<boost::numeric::ublas::column_major_tag> {
55 
56  static const std::string name;
57 };
58 
59 const std::string scipy_sparse_mtx<boost::numeric::ublas::column_major_tag>::name("csc_matrix");
60 
61  } // detail
62 
64 
65 
66 
84 template<class M>
85 inline typename std::enable_if<
86  mds_utils::ublas::is_compressed_matrix<M>::value,M>::type
87  get(PyObject *po) {
88 
89  using namespace mds_utils::python::numpy;
90 
91  Obj module(PyImport_ImportModule("scipy.sparse"));
92 
93  module.get_ownership();
94 
95  Obj type_obj(module.attr(detail::scipy_sparse_mtx<
96  typename M::orientation_category>::name));
97 
98 
99  if (!PyType_Check(type_obj) ||
100  !PyObject_TypeCheck(po,
101  reinterpret_cast<PyTypeObject*>(static_cast<PyObject*>(type_obj)))) {
102 
103  throw std::invalid_argument(
104  "Cannot get a uBLAS compressed matrix from the given parameter.\n"
105  "Check the data type and the storage layout (i.e. csr or csc).");
106  }
107 
108  Obj o(po);
109 
110  Tuple shape(o.attr("shape"));
111 
112  Obj data(o.attr("data")),
113  indices(o.attr("indices")),
114  indptr(o.attr("indptr"));
115 
116  size_t
117  Nr(get<size_t>(shape[0])),
118  Nc(get<size_t>(shape[1])),
119  nnz(get<size_t>(o.attr("nnz")));
120 
121  if (Nr == 0 || Nc == 0) return M();
122 
123  M mout(Nr,Nc,nnz);
124 
126  it_data(reinterpret_cast<PyArrayObject*>(static_cast<PyObject*>(data))),
127  it_data_end(it_data,true);
129  it_inds(reinterpret_cast<PyArrayObject*>(static_cast<PyObject*>(indices))),
130  it_inds_end(it_inds,true),
131  it_indptr(reinterpret_cast<PyArrayObject*>(static_cast<PyObject*>(indptr))),
132  it_indptr_end(it_indptr,true);
133 
134  std::copy(it_data,it_data_end,mout.value_data().begin());
135  std::copy(it_inds,it_inds_end,mout.index2_data().begin());
136  std::copy(it_indptr,it_indptr_end,mout.index1_data().begin());
137 
138  mout.set_filled(len(indptr),len(data));
139 
140  return mout;
141 }
142 
143 
144 
158 template<class ublas_mat_T>
159 inline typename std::enable_if<
160  mds_utils::ublas::is_compressed_matrix<ublas_mat_T>::value,
161  PyObject*
162  >::type to_python(const ublas_mat_T& mat) {
163 
164  using namespace mds_utils::python::numpy;
165  namespace fus = boost::fusion;
166 
167  Obj module(PyImport_ImportModule("scipy.sparse"));
168 
169  module.get_ownership();
170 
171  Obj type_obj(module.attr(detail::scipy_sparse_mtx<
172  typename ublas_mat_T::orientation_category>::name));
173 
174  if (!PyType_Check(type_obj)) {
175 
176  throw std::runtime_error(
177  "Cannot create a " + detail::scipy_sparse_mtx<
178  typename ublas_mat_T::orientation_category>::name + " object.");
179  }
180 
181  int
182  flags(detail::numpy_flags<
183  typename ublas_mat_T::orientation_category>());
184 
185  npy_intp
186  data_dims[] = {boost::numeric_cast<npy_intp>(mat.filled2())},
187  indptr_dims[] = {boost::numeric_cast<npy_intp>(mat.filled1())},
188  mat_shape[] = {
189  boost::numeric_cast<npy_intp>(mat.size1()),
190  boost::numeric_cast<npy_intp>(mat.size2())
191  };
192 
193  PyObject
194  *pdata(PyArray_New(&PyArray_Type,1,data_dims,
196  typename ublas_mat_T::value_type>::typenum,
197  NULL,NULL,0,flags,NULL)),
198  *pindices(PyArray_New(&PyArray_Type,1,data_dims,
200  NULL,NULL,0,flags,NULL)),
201  *pindptr(PyArray_New(&PyArray_Type,1,indptr_dims,
203  NULL,NULL,0,flags,NULL));
204 
205  if (pdata == NULL) {
206  throw std::runtime_error("Could not create the data array.");
207  }
208  if (pindices == NULL) {
209  throw std::runtime_error("Could not create the indices array.");
210  }
211  if (pindptr == NULL) {
212  throw std::runtime_error("Could not create the indptr array.");
213  }
214 
216  it_data(reinterpret_cast<PyArrayObject*>(pdata));
217 
219  it_indices(reinterpret_cast<PyArrayObject*>(pindices)),
220  it_indptr(reinterpret_cast<PyArrayObject*>(pindptr));
221 
222  size_t k;
223  typename ublas_mat_T::index_array_type::const_iterator
224  mat_it_indices(mat.index2_data().begin()),
225  mat_it_indptr(mat.index1_data().begin());
226  typename ublas_mat_T::value_array_type::const_iterator
227  mat_it_data(mat.value_data().begin());
228 
229  for (k=0;k < *indptr_dims;++k,++mat_it_indptr,++it_indptr) {
230  *it_indptr = *mat_it_indptr;
231  }
232  for (k=0;k < *data_dims;++k,++mat_it_indices,++mat_it_data,++it_indices,++it_data) {
233  *it_indices = *mat_it_indices;
234  *it_data = *mat_it_data;
235  }
236 
237 
238  fus::vector<PyObject*,PyObject*,PyObject*>
239  mstruct(pdata,pindices,pindptr);
240 
241  Tuple
242  tup_mstruct,tup_sizes,tup_args;
243 
244  tup_mstruct.set(mstruct);
245  tup_sizes.set(mat_shape,mat_shape+2);
246 
247  fus::vector<Obj,Obj>
248  args(tup_mstruct,tup_sizes);
249 
250  tup_args.set(args);
251 
252  Obj out_mtx(type_obj(tup_args));
253 
254  return out_mtx.transfer();
255 }
256 
257 }}}
258 
259 #endif
Contains the wrapper for the NumPy iterator for ndarray objects.
Main namespace of all Michele De Stefano&#39;s C++ utilities.
Definition: endian.hpp:30
Contains utilities for the Boost uBLAS library.
Contains a wrapper class for the Python tuple datatype.
void get_ownership()
Used in place of incref, when the wrapped PyObject* was increfed already.
Definition: obj.hpp:380
size_t len(PyObject *o)
Retrieves the length of a sequence object.
Definition: sequence.hpp:54
Contains utilities for the creation of NumPy extensions.
virtual PyObject * transfer()
Returns the Python object with transferred ownership.
Definition: obj.hpp:350
void set(const seq_T &seq)
Sets a Python sequence from a Boost Fusion sequence.
Definition: sequence.hpp:296
ProxyAttr attr(const std::string &name)
Retrieves an attribute.
Definition: obj.hpp:407
Wraps a Python tuple.
Definition: tuple.hpp:49
std::enable_if< mds_utils::ublas::is_matrix< ublas_mat_T >::value, PyObject * >::type to_python(const ublas_mat_T &mat)
"To python" converter for Boost uBLAS matrices.
Definition: matrix.hpp:108
Provides traits for a specific C/C++ datatype.
Definition: traits.hpp:48
This is a simple wrapper around the PyObject* datatype.
Definition: obj.hpp:68