Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_CROT_Wrapper.cpp
Go to the documentation of this file.
1 /*
2 Created on Fri Jun 26 14:42:56 2020
3 Copyright 2020 Peter Rakyta, Ph.D.
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see http://www.gnu.org/licenses/.
19 
20 @author: Peter Rakyta, Ph.D.
21 */
22 /*
23 \file qgd_CROT_Wrapper.cpp
24 \brief Python interface for the CROT gate class
25 */
26 
27 #define PY_SSIZE_T_CLEAN
28 
29 
30 #include <Python.h>
31 #include "structmember.h"
32 #include "CROT.h"
33 #include "numpy_interface.h"
34 
35 
36 
37 
41 typedef struct {
42  PyObject_HEAD
44  CROT* gate;
46 
47 
53 CROT*
54 create_CROT( int qbit_num, int target_qbit, int control_qbit, crot_type subtype_in ) {
55 
56  return new CROT( qbit_num, target_qbit, control_qbit, subtype_in );
57 }
58 
59 
64 void
65 release_CROT( CROT* instance ) {
66  delete instance;
67  return;
68 }
69 
70 
71 
72 
73 
74 extern "C"
75 {
76 
77 
82 static void
84 {
85 
86  // release the RY gate
87  release_CROT( self->gate );
88 
89  Py_TYPE(self)->tp_free((PyObject *) self);
90 }
91 
92 
97 static PyObject *
98 qgd_CROT_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
99 {
100  qgd_CROT_Wrapper *self;
101  self = (qgd_CROT_Wrapper *) type->tp_alloc(type, 0);
102  if (self != NULL) {}
103  return (PyObject *) self;
104 }
105 
106 
113 static int
114 qgd_CROT_Wrapper_init(qgd_CROT_Wrapper *self, PyObject *args, PyObject *kwds)
115 {
116  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbit", (char*)"control_qbit", (char*) "subtype",NULL};
117  int qbit_num = -1;
118  int target_qbit = -1;
119  int control_qbit = -1;
120  PyObject* subtype_arg = NULL;
121 
122  if (PyArray_API == NULL) {
123  import_array();
124  }
125 
126  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiiO", kwlist,
127  &qbit_num, &target_qbit, &control_qbit,&subtype_arg))
128  return -1;
129  PyObject* subtype_string = PyObject_Str(subtype_arg);
130  PyObject* subtype_string_unicode = PyUnicode_AsEncodedString(subtype_string, "utf-8", "~E~");
131  const char* subtype_C = PyBytes_AS_STRING(subtype_string_unicode);
132  crot_type qgd_subtype;
133  if ( strcmp("control_r", subtype_C) == 0 || strcmp("CONTROL_R", subtype_C) == 0) {
134  qgd_subtype = CONTROL_R;
135  }
136  else if ( strcmp("control_opposite", subtype_C)==0 || strcmp("CONTROL_OPPOSITE", subtype_C)==0) {
137  qgd_subtype = CONTROL_OPPOSITE;
138  }
139  else if ( strcmp("control_independent", subtype_C)==0 || strcmp("CONTROL_INDEPENDENT", subtype_C)==0) {
140  qgd_subtype = CONTROL_INDEPENDENT;
141  }
142  if (qbit_num != -1 && target_qbit != -1) {
143  self->gate = create_CROT( qbit_num, target_qbit, control_qbit,qgd_subtype );
144  }
145  return 0;
146 }
147 
148 
149 
150 
154 static PyObject *
155 qgd_CROT_Wrapper_apply_to( qgd_CROT_Wrapper *self, PyObject *args ) {
156 
157  PyArrayObject * parameters_arr = NULL;
158  PyArrayObject * unitary_arg = NULL;
159 
160 
161 
162  // parsing input arguments
163  if (!PyArg_ParseTuple(args, "|OO", &parameters_arr, &unitary_arg ))
164  return Py_BuildValue("i", -1);
165 
166  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
167  Py_INCREF(parameters_arr);
168  }
169  else {
170  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
171  }
172 
173  // get the C++ wrapper around the data
174  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
175 
176  // convert python object array to numpy C API array
177  if ( unitary_arg == NULL ) {
178  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
179  return NULL;
180  }
181 
182  PyArrayObject* unitary = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)unitary_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
183 
184  // test C-style contiguous memory allocation of the array
185  if ( !PyArray_IS_C_CONTIGUOUS(unitary) ) {
186  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
187  return NULL;
188  }
189 
190  // create QGD version of the input matrix
191  Matrix unitary_mtx = numpy2matrix(unitary);
192 
193  int parallel = 1;
194  self->gate->apply_to( parameters_mtx, unitary_mtx, parallel );
195 
196  if (unitary_mtx.data != PyArray_DATA(unitary)) {
197  memcpy(PyArray_DATA(unitary), unitary_mtx.data, unitary_mtx.size() * sizeof(QGD_Complex16));
198  }
199 
200  Py_DECREF(parameters_arr);
201  Py_DECREF(unitary);
202 
203  return Py_BuildValue("i", 0);
204 }
205 
206 
207 
212 static PyObject *
214 
215  int parameter_num = self->gate->get_parameter_num();
216 
217  return Py_BuildValue("i", parameter_num);
218 
219 }
220 
225 static PyObject *
227 
228  int start_index = self->gate->get_parameter_start_idx();
229 
230  return Py_BuildValue("i", start_index);
231 
232 }
233 
234 
239 static PyObject *
241 
242  int target_qbit = self->gate->get_target_qbit();
243 
244  return Py_BuildValue("i", target_qbit);
245 
246 }
247 
252 static PyObject *
254 
255  int control_qbit = self->gate->get_control_qbit();
256 
257  return Py_BuildValue("i", control_qbit);
258 
259 }
260 
264 static PyObject *
266  int target_qbit_in = -1;
267  if (!PyArg_ParseTuple(args, "|i", &target_qbit_in ))
268  return Py_BuildValue("i", -1);
269  self->gate->set_target_qbit(target_qbit_in);
270 
271  return Py_BuildValue("i", 0);
272 
273 }
274 
278 static PyObject *
280  int control_qbit_in = -1;
281  if (!PyArg_ParseTuple(args, "|i", &control_qbit_in ))
282  return Py_BuildValue("i", -1);
283  self->gate->set_control_qbit(control_qbit_in);
284 
285  return Py_BuildValue("i", 0);
286 
287 }
291 static PyObject *
293 
294  PyArrayObject * parameters_arr = NULL;
295 
296 
297  // parsing input arguments
298  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
299  return Py_BuildValue("i", -1);
300 
301 
302  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
303  Py_INCREF(parameters_arr);
304  }
305  else {
306  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
307  }
308 
309  // get the C++ wrapper around the data
310  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
311 
312 
313 
314  Matrix_real extracted_parameters;
315 
316  try {
317  extracted_parameters = self->gate->extract_parameters( parameters_mtx );
318  }
319  catch (std::string err) {
320  PyErr_SetString(PyExc_Exception, err.c_str());
321  return NULL;
322  }
323  catch(...) {
324  std::string err( "Invalid pointer to circuit class");
325  PyErr_SetString(PyExc_Exception, err.c_str());
326  return NULL;
327  }
328 
329 
330  // convert to numpy array
331  extracted_parameters.set_owner(false);
332  PyObject *extracted_parameters_py = matrix_real_to_numpy( extracted_parameters );
333 
334 
335  return extracted_parameters_py;
336 }
337 
338 
342 static PyMemberDef qgd_CROT_Wrapper_members[] = {
343  {NULL} /* Sentinel */
344 };
345 
346 
350 static PyMethodDef qgd_CROT_Wrapper_methods[] = {
351  {"apply_to", (PyCFunction) qgd_CROT_Wrapper_apply_to, METH_VARARGS,
352  "Call to apply the gate on the input matrix."
353  },
354  {"get_Parameter_Num", (PyCFunction) qgd_CROT_Wrapper_get_Parameter_Num, METH_NOARGS,
355  "Call to get the number of free parameters in the gate."
356  },
357  {"get_Parameter_Start_Index", (PyCFunction) qgd_CROT_Wrapper_get_Parameter_Start_Index, METH_NOARGS,
358  "Call to get the starting index of the parameters in the parameter array corresponding to the circuit in which the current gate is incorporated."
359  },
360  {"get_Target_Qbit", (PyCFunction) qgd_CROT_Wrapper_get_Target_Qbit, METH_NOARGS,
361  "Call to get the target qbit."
362  },
363  {"get_Control_Qbit", (PyCFunction) qgd_CROT_Wrapper_get_Control_Qbit, METH_NOARGS,
364  "Call to get the control qbit (returns with -1 if no control qbit is used in the gate)."
365  },
366  {"set_Target_Qbit", (PyCFunction) qgd_CROT_Wrapper_set_Target_Qbit, METH_VARARGS,
367  "Call to set the target qbit."
368  },
369  {"set_Control_Qbit", (PyCFunction) qgd_CROT_Wrapper_set_Control_Qbit, METH_VARARGS,
370  "Call to set the control qbit."
371  },
372  {"Extract_Parameters", (PyCFunction) qgd_CROT_Wrapper_Extract_Parameters, METH_VARARGS,
373  "Call to extract the paramaters corresponding to the gate, from a parameter array associated to the circuit in which the gate is embedded."
374  },
375  {NULL} /* Sentinel */
376 };
377 
378 
383  PyVarObject_HEAD_INIT(NULL, 0)
384  "qgd_CROT_Wrapper.qgd_CROT_Wrapper", /*tp_name*/
385  sizeof(qgd_CROT_Wrapper), /*tp_basicsize*/
386  0, /*tp_itemsize*/
387  (destructor) qgd_CROT_Wrapper_dealloc, /*tp_dealloc*/
388  #if PY_VERSION_HEX < 0x030800b4
389  0, /*tp_print*/
390  #endif
391  #if PY_VERSION_HEX >= 0x030800b4
392  0, /*tp_vectorcall_offset*/
393  #endif
394  0, /*tp_getattr*/
395  0, /*tp_setattr*/
396  #if PY_MAJOR_VERSION < 3
397  0, /*tp_compare*/
398  #endif
399  #if PY_MAJOR_VERSION >= 3
400  0, /*tp_as_async*/
401  #endif
402  0, /*tp_repr*/
403  0, /*tp_as_number*/
404  0, /*tp_as_sequence*/
405  0, /*tp_as_mapping*/
406  0, /*tp_hash*/
407  0, /*tp_call*/
408  0, /*tp_str*/
409  0, /*tp_getattro*/
410  0, /*tp_setattro*/
411  0, /*tp_as_buffer*/
412  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
413  "Object to represent a RY gate of the QGD package.", /*tp_doc*/
414  0, /*tp_traverse*/
415  0, /*tp_clear*/
416  0, /*tp_richcompare*/
417  0, /*tp_weaklistoffset*/
418  0, /*tp_iter*/
419  0, /*tp_iternext*/
420  qgd_CROT_Wrapper_methods, /*tp_methods*/
421  qgd_CROT_Wrapper_members, /*tp_members*/
422  0, /*tp_getset*/
423  0, /*tp_base*/
424  0, /*tp_dict*/
425  0, /*tp_descr_get*/
426  0, /*tp_descr_set*/
427  0, /*tp_dictoffset*/
428  (initproc) qgd_CROT_Wrapper_init, /*tp_init*/
429  0, /*tp_alloc*/
430  qgd_CROT_Wrapper_new, /*tp_new*/
431  0, /*tp_free*/
432  0, /*tp_is_gc*/
433  0, /*tp_bases*/
434  0, /*tp_mro*/
435  0, /*tp_cache*/
436  0, /*tp_subclasses*/
437  0, /*tp_weaklist*/
438  0, /*tp_del*/
439  0, /*tp_version_tag*/
440  #if PY_VERSION_HEX >= 0x030400a1
441  0, /*tp_finalize*/
442  #endif
443  #if PY_VERSION_HEX >= 0x030800b1
444  0, /*tp_vectorcall*/
445  #endif
446  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
447  0, /*tp_print*/
448  #endif
449 };
450 
451 
455 static PyModuleDef qgd_CROT_Wrapper_Module = {
456  PyModuleDef_HEAD_INIT,
457  "qgd_CROT_Wrapper",
458  "Python binding for QGD RY gate",
459  -1,
460 };
461 
462 
466 PyMODINIT_FUNC
468 {
469  // initialize Numpy API
470  import_array();
471 
472  PyObject *m;
473  if (PyType_Ready(& qgd_CROT_Wrapper_Type) < 0)
474  return NULL;
475 
476  m = PyModule_Create(& qgd_CROT_Wrapper_Module);
477  if (m == NULL)
478  return NULL;
479 
480  Py_INCREF(& qgd_CROT_Wrapper_Type);
481  if (PyModule_AddObject(m, "qgd_CROT_Wrapper", (PyObject *) & qgd_CROT_Wrapper_Type) < 0) {
482  Py_DECREF(& qgd_CROT_Wrapper_Type);
483  Py_DECREF(m);
484  return NULL;
485  }
486 
487  return m;
488 }
489 
490 
491 
492 
493 }
parameter_num
[set adaptive gate structure]
void release_CROT(CROT *instance)
Call to deallocate an instance of N_Qubit_Decomposition class.
static void qgd_CROT_Wrapper_dealloc(qgd_CROT_Wrapper *self)
Method called when a python instance of the class qgd_CROT_Wrapper is destroyed.
static int qgd_CROT_Wrapper_init(qgd_CROT_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_CROT_Wrapper is initialized.
static PyModuleDef qgd_CROT_Wrapper_Module
Structure containing metadata about the module.
static PyObject * qgd_CROT_Wrapper_apply_to(qgd_CROT_Wrapper *self, PyObject *args)
Call to apply the gate operation on the inut matrix.
Matrix_real numpy2matrix_real(PyArrayObject *arr)
Call to create a PIC matrix_real representation of a numpy array.
Header file for a class representing a controlled rotation gate around the Y axis.
scalar * data
pointer to the stored data
Definition: matrix_base.hpp:48
static PyMemberDef qgd_CROT_Wrapper_members[]
Structure containing metadata about the members of class qgd_CROT_Wrapper.
static PyObject * qgd_CROT_Wrapper_set_Control_Qbit(qgd_CROT_Wrapper *self, PyObject *args)
Call to set the target qbit.
PyObject * matrix_real_to_numpy(Matrix_real &mtx)
Call to make a numpy array from an instance of matrix class.
A class representing a CROT gate.
Definition: CROT.h:39
static PyObject * qgd_CROT_Wrapper_get_Parameter_Num(qgd_CROT_Wrapper *self)
Call to get the number of free parameters in the gate.
static PyObject * qgd_CROT_Wrapper_Extract_Parameters(qgd_CROT_Wrapper *self, PyObject *args)
Call to extract the paramaters corresponding to the gate, from a parameter array associated to the ci...
static PyTypeObject qgd_CROT_Wrapper_Type
A structure describing the type of the class qgd_CROT_Wrapper.
void set_owner(bool owner_in)
Call to set the current class instance to be (or not to be) the owner of the stored data array...
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
int size() const
Call to get the number of the allocated elements.
CROT * create_CROT(int qbit_num, int target_qbit, int control_qbit, crot_type subtype_in)
Creates an instance of class N_Qubit_Decomposition and return with a pointer pointing to the class in...
static PyObject * qgd_CROT_Wrapper_get_Control_Qbit(qgd_CROT_Wrapper *self)
Call to get the control qbit (returns with -1 if no control qbit is used in the gate) ...
static PyObject * qgd_CROT_Wrapper_get_Target_Qbit(qgd_CROT_Wrapper *self)
Call to get the target qbit.
PyMODINIT_FUNC PyInit_qgd_CROT_Wrapper(void)
Method called when the Python module is initialized.
static PyObject * qgd_CROT_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_CROT_Wrapper is allocated.
Type definition of the qgd_CROT Python class of the qgd_CROT module.
static PyObject * qgd_CROT_Wrapper_get_Parameter_Start_Index(qgd_CROT_Wrapper *self)
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
static PyObject * qgd_CROT_Wrapper_set_Target_Qbit(qgd_CROT_Wrapper *self, PyObject *args)
Call to set the target qbit.
Definition: CROT.h:34
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a PIC matrix representation of a numpy array.
static PyMethodDef qgd_CROT_Wrapper_methods[]
Structure containing metadata about the methods of class qgd_CROT_Wrapper.
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
crot_type
Definition: CROT.h:34