Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_R_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_RX_Wrapper.cpp
24 \brief Python interface for the RX gate class
25 */
26 
27 #define PY_SSIZE_T_CLEAN
28 
29 
30 #include <Python.h>
31 #include "structmember.h"
32 #include "R.h"
33 #include "numpy_interface.h"
34 
35 
36 
37 
41 typedef struct {
42  PyObject_HEAD
44  R* gate;
46 
47 
53 R*
55 
56  return new R( qbit_num, target_qbit );
57 }
58 
59 
64 void
65 release_R( R* 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 RX gate
87  release_R( self->gate );
88 
89  Py_TYPE(self)->tp_free((PyObject *) self);
90 }
91 
92 
97 static PyObject *
98 qgd_R_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
99 {
100  qgd_R_Wrapper *self;
101  self = (qgd_R_Wrapper *) type->tp_alloc(type, 0);
102  if (self != NULL) {}
103  return (PyObject *) self;
104 }
105 
106 
113 static int
114 qgd_R_Wrapper_init(qgd_R_Wrapper *self, PyObject *args, PyObject *kwds)
115 {
116  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbit", NULL};
117  int qbit_num = -1;
118  int target_qbit = -1;
119 
120  if (PyArray_API == NULL) {
121  import_array();
122  }
123 
124  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
125  &qbit_num, &target_qbit))
126  return -1;
127 
128  if (qbit_num != -1 && target_qbit != -1) {
129  self->gate = create_R( qbit_num, target_qbit );
130  }
131  return 0;
132 }
133 
138 static PyObject *
139 qgd_R_Wrapper_get_Matrix( qgd_R_Wrapper *self, PyObject *args ) {
140 
141  PyArrayObject * parameters_arr = NULL;
142 
143 
144  // parsing input arguments
145  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
146  return Py_BuildValue("i", -1);
147 
148 
149  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
150  Py_INCREF(parameters_arr);
151  }
152  else {
153  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
154  }
155 
156 
157  // get the C++ wrapper around the data
158  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
159 
160  int parallel = 1;
161  Matrix R_mtx = self->gate->get_matrix( parameters_mtx, parallel );
162 
163  // convert to numpy array
164  R_mtx.set_owner(false);
165  PyObject *R_py = matrix_to_numpy( R_mtx );
166 
167 
168  Py_DECREF(parameters_arr);
169 
170  return R_py;
171 }
172 
173 
174 
178 static PyObject *
179 qgd_R_Wrapper_apply_to( qgd_R_Wrapper *self, PyObject *args ) {
180 
181  PyArrayObject * parameters_arr = NULL;
182  PyArrayObject * unitary_arg = NULL;
183 
184 
185 
186  // parsing input arguments
187  if (!PyArg_ParseTuple(args, "|OO", &parameters_arr, &unitary_arg ))
188  return Py_BuildValue("i", -1);
189 
190  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
191  Py_INCREF(parameters_arr);
192  }
193  else {
194  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
195  }
196 
197  // get the C++ wrapper around the data
198  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
199 
200  // convert python object array to numpy C API array
201  if ( unitary_arg == NULL ) {
202  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
203  return NULL;
204  }
205 
206  PyArrayObject* unitary = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)unitary_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
207 
208  // test C-style contiguous memory allocation of the array
209  if ( !PyArray_IS_C_CONTIGUOUS(unitary) ) {
210  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
211  return NULL;
212  }
213 
214  // create QGD version of the input matrix
215  Matrix unitary_mtx = numpy2matrix(unitary);
216 
217  int parallel = 1;
218  self->gate->apply_to( parameters_mtx, unitary_mtx, parallel );
219 
220  if (unitary_mtx.data != PyArray_DATA(unitary)) {
221  memcpy(PyArray_DATA(unitary), unitary_mtx.data, unitary_mtx.size() * sizeof(QGD_Complex16));
222  }
223 
224  Py_DECREF(parameters_arr);
225  Py_DECREF(unitary);
226 
227  return Py_BuildValue("i", 0);
228 }
229 
238 static PyObject *
240 
241  double ThetaOver2,Phi;
242 
243  // parsing input arguments
244  if (!PyArg_ParseTuple(args, "|dd", &ThetaOver2,&Phi ))
245  return Py_BuildValue("i", -1);
246 
247 
248  // create QGD version of the input matrix
249 
250  double phi0 = Phi-M_PI/2;
251  double lambda0 = -1.*Phi + M_PI/2;
252 
253  Matrix R_1qbit_ = self->gate->calc_one_qubit_u3(ThetaOver2, phi0, lambda0 );
254 
255  PyObject *R_1qbit = matrix_to_numpy( R_1qbit_ );
256 
257  return R_1qbit;
258 
259 }
260 
261 
262 
267 static PyObject *
269 
270  int parameter_num = self->gate->get_parameter_num();
271 
272  return Py_BuildValue("i", parameter_num);
273 
274 }
275 
280 static PyObject *
282 
283  int start_index = self->gate->get_parameter_start_idx();
284 
285  return Py_BuildValue("i", start_index);
286 
287 }
288 
289 
290 
295 static PyObject *
297 
298  int target_qbit = self->gate->get_target_qbit();
299 
300  return Py_BuildValue("i", target_qbit);
301 
302 }
303 
308 static PyObject *
310 
311  int control_qbit = self->gate->get_control_qbit();
312 
313  return Py_BuildValue("i", control_qbit);
314 
315 }
316 
320 static PyObject *
322  int target_qbit_in = -1;
323  if (!PyArg_ParseTuple(args, "|i", &target_qbit_in ))
324  return Py_BuildValue("i", -1);
325  self->gate->set_target_qbit(target_qbit_in);
326 
327  return Py_BuildValue("i", 0);
328 
329 }
330 
334 static PyObject *
336 
337  PyArrayObject * parameters_arr = NULL;
338 
339 
340  // parsing input arguments
341  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
342  return Py_BuildValue("i", -1);
343 
344 
345  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
346  Py_INCREF(parameters_arr);
347  }
348  else {
349  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
350  }
351 
352  // get the C++ wrapper around the data
353  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
354 
355 
356 
357  Matrix_real extracted_parameters;
358 
359  try {
360  extracted_parameters = self->gate->extract_parameters( parameters_mtx );
361  }
362  catch (std::string err) {
363  PyErr_SetString(PyExc_Exception, err.c_str());
364  return NULL;
365  }
366  catch(...) {
367  std::string err( "Invalid pointer to circuit class");
368  PyErr_SetString(PyExc_Exception, err.c_str());
369  return NULL;
370  }
371 
372 
373  // convert to numpy array
374  extracted_parameters.set_owner(false);
375  PyObject *extracted_parameters_py = matrix_real_to_numpy( extracted_parameters );
376 
377 
378  return extracted_parameters_py;
379 }
380 
381 
382 
386 static PyMemberDef qgd_R_Wrapper_members[] = {
387  {NULL} /* Sentinel */
388 };
389 
390 
394 static PyMethodDef qgd_R_Wrapper_methods[] = {
395  {"get_Matrix", (PyCFunction) qgd_R_Wrapper_get_Matrix, METH_VARARGS,
396  "Method to get the matrix of the operation."
397  },
398  {"apply_to", (PyCFunction) qgd_R_Wrapper_apply_to, METH_VARARGS,
399  "Call to apply the gate on the input matrix."
400  },
401  {"get_Gate_Kernel", (PyCFunction) qgd_R_Wrapper_get_Gate_Kernel, METH_VARARGS,
402  "Call to calculate the gate matrix acting on a single qbit space."
403  },
404  {"get_Parameter_Num", (PyCFunction) qgd_R_Wrapper_get_Parameter_Num, METH_NOARGS,
405  "Call to get the number of free parameters in the gate."
406  },
407  {"get_Parameter_Start_Index", (PyCFunction) qgd_R_Wrapper_get_Parameter_Start_Index, METH_NOARGS,
408  "Call to get the starting index of the parameters in the parameter array corresponding to the circuit in which the current gate is incorporated."
409  },
410  {"get_Target_Qbit", (PyCFunction) qgd_R_Wrapper_get_Target_Qbit, METH_NOARGS,
411  "Call to get the target qbit."
412  },
413  {"get_Control_Qbit", (PyCFunction) qgd_R_Wrapper_get_Control_Qbit, METH_NOARGS,
414  "Call to get the control qbit (returns with -1 if no control qbit is used in the gate)."
415  },
416  {"set_Target_Qbit", (PyCFunction) qgd_R_Wrapper_set_Target_Qbit, METH_VARARGS,
417  "Call to set the target qbit."
418  },
419  {"Extract_Parameters", (PyCFunction) qgd_R_Wrapper_Extract_Parameters, METH_VARARGS,
420  "Call to extract the paramaters corresponding to the gate, from a parameter array associated to the circuit in which the gate is embedded."
421  },
422  {NULL} /* Sentinel */
423 };
424 
425 
430  PyVarObject_HEAD_INIT(NULL, 0)
431  "qgd_R_Wrapper.qgd_R_Wrapper", /*tp_name*/
432  sizeof(qgd_R_Wrapper), /*tp_basicsize*/
433  0, /*tp_itemsize*/
434  (destructor) qgd_R_Wrapper_dealloc, /*tp_dealloc*/
435  #if PY_VERSION_HEX < 0x030800b4
436  0, /*tp_print*/
437  #endif
438  #if PY_VERSION_HEX >= 0x030800b4
439  0, /*tp_vectorcall_offset*/
440  #endif
441  0, /*tp_getattr*/
442  0, /*tp_setattr*/
443  #if PY_MAJOR_VERSION < 3
444  0, /*tp_compare*/
445  #endif
446  #if PY_MAJOR_VERSION >= 3
447  0, /*tp_as_async*/
448  #endif
449  0, /*tp_repr*/
450  0, /*tp_as_number*/
451  0, /*tp_as_sequence*/
452  0, /*tp_as_mapping*/
453  0, /*tp_hash*/
454  0, /*tp_call*/
455  0, /*tp_str*/
456  0, /*tp_getattro*/
457  0, /*tp_setattro*/
458  0, /*tp_as_buffer*/
459  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
460  "Object to represent a R gate of the QGD package.", /*tp_doc*/
461  0, /*tp_traverse*/
462  0, /*tp_clear*/
463  0, /*tp_richcompare*/
464  0, /*tp_weaklistoffset*/
465  0, /*tp_iter*/
466  0, /*tp_iternext*/
467  qgd_R_Wrapper_methods, /*tp_methods*/
468  qgd_R_Wrapper_members, /*tp_members*/
469  0, /*tp_getset*/
470  0, /*tp_base*/
471  0, /*tp_dict*/
472  0, /*tp_descr_get*/
473  0, /*tp_descr_set*/
474  0, /*tp_dictoffset*/
475  (initproc) qgd_R_Wrapper_init, /*tp_init*/
476  0, /*tp_alloc*/
477  qgd_R_Wrapper_new, /*tp_new*/
478  0, /*tp_free*/
479  0, /*tp_is_gc*/
480  0, /*tp_bases*/
481  0, /*tp_mro*/
482  0, /*tp_cache*/
483  0, /*tp_subclasses*/
484  0, /*tp_weaklist*/
485  0, /*tp_del*/
486  0, /*tp_version_tag*/
487  #if PY_VERSION_HEX >= 0x030400a1
488  0, /*tp_finalize*/
489  #endif
490  #if PY_VERSION_HEX >= 0x030800b1
491  0, /*tp_vectorcall*/
492  #endif
493  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
494  0, /*tp_print*/
495  #endif
496 };
497 
498 
502 static PyModuleDef qgd_R_Wrapper_Module = {
503  PyModuleDef_HEAD_INIT,
504  "qgd_R_Wrapper",
505  "Python binding for QGD R gate",
506  -1,
507 };
508 
509 
513 PyMODINIT_FUNC
515 {
516 
517  // initialize Numpy API
518  import_array();
519 
520  PyObject *m;
521  if (PyType_Ready(& qgd_R_Wrapper_Type) < 0)
522  return NULL;
523 
524  m = PyModule_Create(& qgd_R_Wrapper_Module);
525  if (m == NULL)
526  return NULL;
527 
528  Py_INCREF(& qgd_R_Wrapper_Type);
529  if (PyModule_AddObject(m, "qgd_R_Wrapper", (PyObject *) & qgd_R_Wrapper_Type) < 0) {
530  Py_DECREF(& qgd_R_Wrapper_Type);
531  Py_DECREF(m);
532  return NULL;
533  }
534 
535  return m;
536 }
537 
538 
539 
540 
541 }
R * create_R(int qbit_num, int target_qbit)
Creates an instance of class N_Qubit_Decomposition and return with a pointer pointing to the class in...
parameter_num
[set adaptive gate structure]
Header file for a class representing a rotation gate around the X axis.
static PyMemberDef qgd_R_Wrapper_members[]
Structure containing metadata about the members of class qgd_RX_Wrapper.
static PyModuleDef qgd_R_Wrapper_Module
Structure containing metadata about the module.
Type definition of the qgd_RX_Wrapper Python class of the qgd_RX_Wrapper module.
static PyMethodDef qgd_R_Wrapper_methods[]
Structure containing metadata about the methods of class qgd_RX_Wrapper.
static void qgd_R_Wrapper_dealloc(qgd_R_Wrapper *self)
Method called when a python instance of the class qgd_RX_Wrapper is destroyed.
static PyObject * qgd_R_Wrapper_apply_to(qgd_R_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.
static PyObject * qgd_R_Wrapper_get_Parameter_Num(qgd_R_Wrapper *self)
Call to get the number of free parameters in the gate.
scalar * data
pointer to the stored data
Definition: matrix_base.hpp:48
void release_R(R *instance)
Call to deallocate an instance of N_Qubit_Decomposition class.
PyObject * matrix_real_to_numpy(Matrix_real &mtx)
Call to make a numpy array from an instance of matrix class.
static PyObject * qgd_R_Wrapper_get_Control_Qbit(qgd_R_Wrapper *self)
Call to get the control qbit (returns with -1 if no control qbit is used in the gate) ...
static PyObject * qgd_R_Wrapper_get_Matrix(qgd_R_Wrapper *self, PyObject *args)
Extract the optimized parameters.
static PyObject * qgd_R_Wrapper_set_Target_Qbit(qgd_R_Wrapper *self, PyObject *args)
Call to set the target qbit.
PyMODINIT_FUNC PyInit_qgd_R_Wrapper(void)
Method called when the Python module is initialized.
static PyObject * qgd_R_Wrapper_get_Gate_Kernel(qgd_R_Wrapper *self, PyObject *args)
Calculate the matrix of a U3 gate gate corresponding to the given parameters acting on a single qbit ...
static PyObject * qgd_R_Wrapper_get_Target_Qbit(qgd_R_Wrapper *self)
Call to get the target qbit.
PyObject_HEAD R * gate
Pointer to the C++ class of the RX gate.
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
static int qgd_R_Wrapper_init(qgd_R_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_RX_Wrapper is initialized.
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
static PyObject * qgd_R_Wrapper_Extract_Parameters(qgd_R_Wrapper *self, PyObject *args)
Call to extract the paramaters corresponding to the gate, from a parameter array associated to the ci...
int size() const
Call to get the number of the allocated elements.
static PyTypeObject qgd_R_Wrapper_Type
A structure describing the type of the class qgd_RX_Wrapper.
static PyObject * qgd_R_Wrapper_get_Parameter_Start_Index(qgd_R_Wrapper *self)
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
A class representing a U3 gate.
Definition: R.h:36
static PyObject * qgd_R_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_RX_Wrapper is allocated.
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a PIC matrix representation of a numpy array.
PyObject * matrix_to_numpy(Matrix &mtx)
Call to make a numpy array from an instance of matrix class.
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39