Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
numpy_interface.cpp
Go to the documentation of this file.
1 /*
2 Copyright 2020 Peter Rakyta, Ph.D.
3 
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7 
8  http://www.apache.org/licenses/LICENSE-2.0
9 
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 
16 */
17 
18 #include <Python.h>
19 #include <numpy/arrayobject.h>
20 #include "matrix.h"
21 #include "matrix_real.h"
22 
23 
28 void capsule_cleanup(PyObject* capsule) {
29 
30  void *memory = PyCapsule_GetPointer(capsule, NULL);
31  // I'm going to assume your memory needs to be freed with free().
32  // If it needs different cleanup, perform whatever that cleanup is
33  // instead of calling free().
34  scalable_aligned_free(memory);
35 
36 
37 }
38 
39 
40 
41 
49 PyObject* array_from_ptr(void * ptr, int dim, npy_intp* shape, int np_type) {
50 
51  if (PyArray_API == NULL) {
52  import_array();
53  }
54 
55 
56  // create numpy array
57  PyObject* arr = PyArray_SimpleNewFromData(dim, shape, np_type, ptr);
58 
59  // set memory keeper for the numpy array
60  PyObject *capsule = PyCapsule_New(ptr, NULL, capsule_cleanup);
61  PyArray_SetBaseObject((PyArrayObject *) arr, capsule);
62 
63  return arr;
64 
65 }
66 
67 
68 
73 PyObject* matrix_to_numpy( Matrix &mtx ) {
74  // initialize Numpy API
75  import_array();
76 
77 
78  npy_intp shape[2];
79  shape[0] = (npy_intp) mtx.rows;
80  shape[1] = (npy_intp) mtx.cols;
81 
82  QGD_Complex16* data = mtx.get_data();
83  return array_from_ptr( (void*) data, 2, shape, NPY_COMPLEX128);
84 
85 
86 }
87 
88 
89 
94 PyObject* matrix_real_to_numpy( Matrix_real &mtx ) {
95  // initialize Numpy API
96  import_array();
97 
98  npy_intp shape[2];
99 
100  // TODO: this logic should be implemented on higher level of API logic in the interfaces.
101  // fix this issue after redesigning the decomposition interfaces
102  int dims;
103  if ( mtx.rows == 1 ) {
104  dims = 1;
105  shape[0] = mtx.cols;
106  }
107  else if ( mtx.cols == 1 ) {
108  dims = 1;
109  shape[0] = mtx.rows;
110  }
111  else {
112  dims = 2;
113  shape[0] = (npy_intp) mtx.rows;
114  shape[1] = (npy_intp) mtx.cols;
115  }
116 
117  double* data = mtx.get_data();
118  return array_from_ptr( (void*) data, dims, shape, NPY_DOUBLE);
119 
120 
121 }
122 
123 
124 
130  // initialize Numpy API
131  import_array();
132 
133 
134  npy_intp shape[2];
135  shape[0] = (npy_intp) mtx.rows;
136  shape[1] = (npy_intp) mtx.cols;
137 
138  int8_t* data = mtx.get_data();
139  return array_from_ptr( (void*) data, 2, shape, NPY_INT8);
140 
141 
142 }
143 
144 
145 
146 
150 Matrix
151 numpy2matrix(PyArrayObject* arr) {
152 
153  if ( (PyObject*)arr == Py_None ) {
154  return Matrix(0,0);
155  }
156 
157 #ifdef DEBUG
158  // test C-style contiguous memory allocation of the arrays
159  // in production this case has to be handled outside
160  assert( PyArray_IS_C_CONTIGUOUS(arr) && "array is not memory contiguous" );
161 #endif
162 
163  // get the pointer to the data stored in the input matrices
164  QGD_Complex16* data = (QGD_Complex16*)PyArray_DATA(arr);
165 
166  // get the dimensions of the array self->C
167  int dim_num = PyArray_NDIM( arr );
168  npy_intp* dims = PyArray_DIMS(arr);
169 
170  // create PIC version of the input matrices
171  if (dim_num == 2) {
172  Matrix mtx = Matrix(data, dims[0], dims[1]);
173  return mtx;
174  }
175  else if (dim_num == 1) {
176  Matrix mtx = Matrix(data, dims[0], 1);
177  return mtx;
178  }
179  else {
180  std::string err( "numpy2matrix: Wrong matrix dimension was given");
181  throw err;
182  }
183 
184 
185 
186 }
187 
188 
193 numpy2matrix_real(PyArrayObject* arr) {
194 
195 
196  if ( (PyObject*)arr == Py_None ) {
197  return Matrix_real(0,0);
198  }
199 
200 #ifdef DEBUG
201  // test C-style contiguous memory allocation of the arrays
202  // in production this case has to be handled outside
203  assert( PyArray_IS_C_CONTIGUOUS(arr) && "array is not memory contiguous" );
204 #endif
205 
206  // get the pointer to the data stored in the input matrices
207  double *data = (double *)PyArray_DATA(arr);
208 
209  // get the dimensions of the array self->C
210  int dim_num = PyArray_NDIM( arr );
211  npy_intp* dims = PyArray_DIMS(arr);
212 
213  // create PIC version of the input matrices
214  if (dim_num == 2) {
215  Matrix_real mtx = Matrix_real(data, dims[0], dims[1]);
216  return mtx;
217  }
218  else if (dim_num == 1) {
219  Matrix_real mtx = Matrix_real(data, dims[0], 1);
220  return mtx;
221  }
222  else {
223  std::string err( "numpy2matrix: Wrong matrix dimension was given");
224  throw err;
225  }
226 
227 
228 
229 }
230 
231 
232 
233 
234 
data
load the unitary from file
Definition: example.py:51
scalar * get_data() const
Call to get the pointer to the stored data.
PyObject * matrix_int8_to_numpy(matrix_base< int8_t > &mtx)
Call to make a numpy array from an instance of matrix_base<int8_t> class.
Base Class to store data of arrays and its properties.
Definition: matrix_base.hpp:38
int rows
The number of rows.
Definition: matrix_base.hpp:42
int cols
The number of columns.
Definition: matrix_base.hpp:44
PyObject * matrix_to_numpy(Matrix &mtx)
Call to make a numpy array from an instance of matrix class.
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a matrix representation of a numpy array.
Header file of complex array storage array with automatic and thread safe reference counting...
Structure type representing complex numbers in the SQUANDER package.
Definition: QGDTypes.h:38
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
Matrix_real numpy2matrix_real(PyArrayObject *arr)
Call to create a PIC matrix_real representation of a numpy array.
PyObject * matrix_real_to_numpy(Matrix_real &mtx)
Call to make a numpy array from an instance of matrix class.
void capsule_cleanup(PyObject *capsule)
Method to cleanup the memory when the python object becomes released.
PyObject * array_from_ptr(void *ptr, int dim, npy_intp *shape, int np_type)
Call to make a numpy array from data stored via void pointer.
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39