Sequential Quantum Gate Decomposer  v1.9.6
Powerful decomposition of general unitarias into one- and two-qubit gates gates
gates_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 gates_Wrapper.cpp
24 \brief Python interface to expose Squander gates to Python
25 */
26 
27 #define PY_SSIZE_T_CLEAN
28 
29 
30 #include <Python.h>
31 #include "structmember.h"
32 #include "Gate.h"
33 #include "CU.h"
34 #include "CH.h"
35 #include "CNOT.h"
36 #include "CZ.h"
37 #include "CRY.h"
38 #include "CRX.h"
39 #include "CRZ.h"
40 #include "CP.h"
41 #include "H.h"
42 #include "RX.h"
43 #include "RY.h"
44 #include "RZ.h"
45 #include "SX.h"
46 #include "SYC.h"
47 #include "U1.h"
48 #include "U2.h"
49 #include "U3.h"
50 #include "X.h"
51 #include "Y.h"
52 #include "Z.h"
53 #include "S.h"
54 #include "SDG.h"
55 #include "T.h"
56 #include "Tdg.h"
57 #include "R.h"
58 #include "CR.h"
59 #include "CROT.h"
60 #include "CCX.h"
61 #include "SWAP.h"
62 #include "CSWAP.h"
63 #include "numpy_interface.h"
64 #include "RXX.h"
65 #include "RYY.h"
66 #include "RZZ.h"
67 #include "SXdg.h"
68 
70 
74 typedef struct {
75  PyObject_HEAD
78 } Gate_Wrapper;
79 
80 
81 
82 
83 template<typename GateT>
85  GateT* gate = new GateT( qbit_num, target_qbit );
86  return static_cast<Gate*>( gate );
87 }
88 
89 template<typename GateT>
91  GateT* gate = new GateT( qbit_num );
92  return static_cast<Gate*>( gate );
93 }
94 
95 
96 template<typename GateT>
98 
99  GateT* gate = new GateT( qbit_num, target_qbit, control_qbit );
100  return static_cast<Gate*>( gate );
101 
102 }
103 
104 template<typename GateT>
105 Gate* create_multi_target_gate( int qbit_num, const std::vector<int>& target_qbits ) {
106 
107  GateT* gate = new GateT( qbit_num, target_qbits );
108  return static_cast<Gate*>( gate );
109 
110 }
111 
112 template<typename GateT>
113 Gate* create_multi_qubit_gate( int qbit_num, int target_qbit, const std::vector<int>& control_qbits ) {
114 
115  GateT* gate = new GateT( qbit_num, target_qbit, control_qbits );
116  return static_cast<Gate*>( gate );
117 
118 }
119 
120 template<typename GateT>
121 Gate* create_multi_target_controlled_gate( int qbit_num, const std::vector<int>& target_qbits, const std::vector<int>& control_qbits ) {
122 
123  GateT* gate = new GateT( qbit_num, target_qbits, control_qbits );
124  return static_cast<Gate*>( gate );
125 
126 }
127 
128 
129 
134 static void
136 {
137  if( self->gate != NULL ) {
138  delete( self->gate );
139  self->gate = NULL;
140  }
141 
142  Py_TYPE(self)->tp_free((PyObject *) self);
143 }
144 
145 
150 static PyObject *
151  generic_Gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
152 {
153 
154  static char *kwlist[] = {(char*)"qbit_num", NULL};
155  int qbit_num = -1;
156 
157 
158  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &qbit_num)) {
159  std::string err( "Unable to parse arguments");
160  PyErr_SetString(PyExc_Exception, err.c_str());
161  return NULL;
162  }
163 
164  if (qbit_num == -1){
165  PyErr_SetString(PyExc_ValueError, "Qubit_num must be set!");
166  return NULL;
167  }
168 
169 
170  Gate_Wrapper *self;
171  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
172  if (self != NULL) {
173  self->gate = new Gate( qbit_num );
174  }
175 
176 
177  return (PyObject *) self;
178 }
179 
180 
181 
188 template<typename GateT>
189 static PyObject *
190  Gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
191 {
192 
193  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbit", NULL};
194  int qbit_num = -1;
195  int target_qbit = -1;
196 
197  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist, &qbit_num, &target_qbit)) {
198  std::string err( "Unable to parse arguments");
199  PyErr_SetString(PyExc_Exception, err.c_str());
200  return NULL;
201  }
202 
203  if (qbit_num == -1 || target_qbit == -1){
204  PyErr_SetString(PyExc_ValueError, "Qubit_num and target_qubit all must be set!");
205  return NULL;
206  }
207 
208  if (qbit_num <= target_qbit ){
209  PyErr_SetString(PyExc_ValueError, "Target_qubit cannot be larger or equal than qubit_num!");
210  return NULL;
211  }
212  Gate_Wrapper *self;
213  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
214  if (self != NULL) {
215  self->gate = create_gate<GateT>( qbit_num, target_qbit );
216  }
217 
218 
219  return (PyObject *) self;
220 }
221 
228 template<typename GateT>
229 static PyObject *
230  qbit_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
231 {
232  static char *kwlist[] = {(char*)"qbit_num", NULL};
233  int qbit_num = -1;
234 
235  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &qbit_num)) {
236  std::string err( "Unable to parse arguments");
237  PyErr_SetString(PyExc_Exception, err.c_str());
238  return NULL;
239  }
240 
241  if (qbit_num == -1){
242  PyErr_SetString(PyExc_ValueError, "Qubit_num must be set!");
243  return NULL;
244  }
245 
246  Gate_Wrapper *self;
247  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
248  if (self != NULL) {
249  self->gate = create_qbit_gate<GateT>( qbit_num );
250  }
251 
252  return (PyObject *) self;
253 }
254 
255 
262 template<typename GateT>
263 static PyObject *
264  controlled_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
265 {
266  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbit", (char*)"control_qbit", NULL};
267  int qbit_num = -1;
268  int target_qbit = -1;
269  int control_qbit = -1;
270 
271 
272  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iii", kwlist, &qbit_num, &target_qbit, &control_qbit)) {
273  std::string err( "Unable to parse arguments");
274  PyErr_SetString(PyExc_Exception, err.c_str());
275  return NULL;
276  }
277 
278  if ((qbit_num == -1 || target_qbit == -1) || control_qbit == -1){
279  PyErr_SetString(PyExc_ValueError, "Qubit_num, target_qubit and control_qubit all must be set!");
280  return NULL;
281  }
282 
283  if (qbit_num <= target_qbit || qbit_num <= control_qbit ){
284  PyErr_SetString(PyExc_ValueError, "Target_qubit or control_qbit cannot be larger or equal than qubit_num!");
285  return NULL;
286  }
287 
288  Gate_Wrapper *self;
289  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
290  if (self != NULL) {
291  self->gate = create_controlled_gate<GateT>( qbit_num, target_qbit, control_qbit );
292  }
293 
294  return (PyObject *) self;
295 
296 }
297 
304 template<typename GateT>
305 static PyObject *
307 {
308  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbit", (char*)"control_qbits", NULL};
309  int qbit_num = -1;
310  int target_qbit = -1;
311  PyObject* control_qbits_py = NULL;
312 
313  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiO", kwlist, &qbit_num, &target_qbit, &control_qbits_py)) {
314  std::string err("Unable to parse arguments");
315  PyErr_SetString(PyExc_Exception, err.c_str());
316  return NULL;
317  }
318 
319  if (qbit_num == -1 || target_qbit == -1 || control_qbits_py == NULL) {
320  PyErr_SetString(PyExc_ValueError, "qbit_num, target_qbit, and control_qbits must be provided!");
321  return NULL;
322  }
323 
324  if (target_qbit >= qbit_num) {
325  PyErr_SetString(PyExc_ValueError, "Target qubit index out of range!");
326  return NULL;
327  }
328 
329  // Convert Python list to C++ vector
330  if (!PyList_Check(control_qbits_py)) {
331  PyErr_SetString(PyExc_TypeError, "control_qbits must be a list!");
332  return NULL;
333  }
334 
335  std::vector<int> control_qbits;
336  Py_ssize_t list_size = PyList_Size(control_qbits_py);
337  for (Py_ssize_t i = 0; i < list_size; i++) {
338  PyObject* item = PyList_GetItem(control_qbits_py, i);
339  if (!PyLong_Check(item)) {
340  PyErr_SetString(PyExc_TypeError, "control_qbits must contain integers!");
341  return NULL;
342  }
343  int qbit = PyLong_AsLong(item);
344  if (qbit >= qbit_num) {
345  PyErr_SetString(PyExc_ValueError, "Control qubit index out of range!");
346  return NULL;
347  }
348  control_qbits.push_back(qbit);
349  }
350 
351  Gate_Wrapper *self;
352  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
353  if (self != NULL) {
354  self->gate = create_multi_qubit_gate<GateT>(qbit_num, target_qbit, control_qbits);
355  }
356 
357  return (PyObject *) self;
358 }
359 
366 template<typename GateT>
367 static PyObject *
369 {
370  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbits", NULL};
371  int qbit_num = -1;
372  PyObject* target_qbits_py = NULL;
373 
374  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, &qbit_num, &target_qbits_py)) {
375  std::string err("Unable to parse arguments");
376  PyErr_SetString(PyExc_Exception, err.c_str());
377  return NULL;
378  }
379 
380  if (qbit_num == -1 || target_qbits_py == NULL) {
381  PyErr_SetString(PyExc_ValueError, "qbit_num and target_qbits must be provided!");
382  return NULL;
383  }
384 
385  // Convert Python list to C++ vector
386  if (!PyList_Check(target_qbits_py)) {
387  PyErr_SetString(PyExc_TypeError, "target_qbits must be a list!");
388  return NULL;
389  }
390 
391  std::vector<int> target_qbits;
392  Py_ssize_t target_size = PyList_Size(target_qbits_py);
393  for (Py_ssize_t i = 0; i < target_size; i++) {
394  PyObject* item = PyList_GetItem(target_qbits_py, i);
395  if (!PyLong_Check(item)) {
396  PyErr_SetString(PyExc_TypeError, "target_qbits must contain integers!");
397  return NULL;
398  }
399  int qbit = PyLong_AsLong(item);
400  if (qbit >= qbit_num) {
401  PyErr_SetString(PyExc_ValueError, "Target qubit index out of range!");
402  return NULL;
403  }
404  target_qbits.push_back(qbit);
405  }
406 
407  Gate_Wrapper *self;
408  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
409  if (self != NULL) {
410  self->gate = create_multi_target_gate<GateT>(qbit_num, target_qbits);
411  }
412 
413  return (PyObject *) self;
414 }
415 
422 template<typename GateT>
423 static PyObject *
425 {
426  static char *kwlist[] = {(char*)"qbit_num", (char*)"target_qbits", (char*)"control_qbits", NULL};
427  int qbit_num = -1;
428  PyObject* target_qbits_py = NULL;
429  PyObject* control_qbits_py = NULL;
430 
431  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iOO", kwlist, &qbit_num, &target_qbits_py, &control_qbits_py)) {
432  std::string err("Unable to parse arguments");
433  PyErr_SetString(PyExc_Exception, err.c_str());
434  return NULL;
435  }
436 
437  if (qbit_num == -1 || target_qbits_py == NULL || control_qbits_py == NULL) {
438  PyErr_SetString(PyExc_ValueError, "qbit_num, target_qbits, and control_qbits must be provided!");
439  return NULL;
440  }
441 
442  // Convert Python lists to C++ vectors
443  if (!PyList_Check(target_qbits_py) || !PyList_Check(control_qbits_py)) {
444  PyErr_SetString(PyExc_TypeError, "target_qbits and control_qbits must be lists!");
445  return NULL;
446  }
447 
448  std::vector<int> target_qbits;
449  Py_ssize_t target_size = PyList_Size(target_qbits_py);
450  for (Py_ssize_t i = 0; i < target_size; i++) {
451  PyObject* item = PyList_GetItem(target_qbits_py, i);
452  if (!PyLong_Check(item)) {
453  PyErr_SetString(PyExc_TypeError, "target_qbits must contain integers!");
454  return NULL;
455  }
456  int qbit = PyLong_AsLong(item);
457  if (qbit >= qbit_num) {
458  PyErr_SetString(PyExc_ValueError, "Target qubit index out of range!");
459  return NULL;
460  }
461  target_qbits.push_back(qbit);
462  }
463 
464  std::vector<int> control_qbits;
465  Py_ssize_t control_size = PyList_Size(control_qbits_py);
466  for (Py_ssize_t i = 0; i < control_size; i++) {
467  PyObject* item = PyList_GetItem(control_qbits_py, i);
468  if (!PyLong_Check(item)) {
469  PyErr_SetString(PyExc_TypeError, "control_qbits must contain integers!");
470  return NULL;
471  }
472  int qbit = PyLong_AsLong(item);
473  if (qbit >= qbit_num) {
474  PyErr_SetString(PyExc_ValueError, "Control qubit index out of range!");
475  return NULL;
476  }
477  control_qbits.push_back(qbit);
478  }
479 
480  Gate_Wrapper *self;
481  self = (Gate_Wrapper *) type->tp_alloc(type, 0);
482  if (self != NULL) {
483  self->gate = create_multi_target_controlled_gate<GateT>(qbit_num, target_qbits, control_qbits);
484  }
485 
486  return (PyObject *) self;
487 }
488 
489 
496 static int
497  Gate_Wrapper_init(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
498 {
499 
500 
501 
502  return 0;
503 }
504 
505 
506 
507 
508 
509 
510 
515 static PyObject *
516 Gate_Wrapper_get_Matrix( Gate_Wrapper *self, PyObject *args, PyObject *kwds ) {
517 
518  static char *kwlist[] = {(char*)"parameters", (char*)"is_f32", NULL};
519 
520  PyObject* parameters_obj = NULL;
521  PyArrayObject * parameters_arr = NULL;
522  int is_f32 = 0;
523 
524 
525  // parsing input arguments
526  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Op", kwlist, &parameters_obj, &is_f32 )) {
527  std::string err( "Unable to parse keyword arguments");
528  PyErr_SetString(PyExc_Exception, err.c_str());
529  return NULL;
530  }
531 
532  try {
533  Gate* gate = self->gate;
534 
535  if (is_f32) {
536  Matrix_float gate_mtx;
537 
538  if (parameters_obj != NULL) {
539  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF(parameters_obj, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY);
540  if (parameters_arr == NULL) {
541  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float32 when is_f32=True");
542  return NULL;
543  }
544  }
545 
546  if (gate->get_parameter_num() == 0) {
547 
548  if (parameters_arr != NULL) {
549  PyErr_SetString(PyExc_Exception, "The gate contains no parameters to set, but parameter array was given as input");
550  Py_DECREF(parameters_arr);
551  return NULL;
552  }
553 
554  // No-parameter gate: use apply_to on identity (existing path)
555  const int matrix_size = 1 << gate->get_qbit_num();
556  gate_mtx = Matrix_float(matrix_size, matrix_size);
557  for (int idx = 0; idx < gate_mtx.size(); idx++) {
558  gate_mtx[idx].real = 0.0f;
559  gate_mtx[idx].imag = 0.0f;
560  }
561  for (int idx = 0; idx < matrix_size; idx++) {
562  gate_mtx[idx * gate_mtx.stride + idx].real = 1.0f;
563  }
564  gate->apply_to(gate_mtx, 0);
565 
566  }
567  else if (gate->get_parameter_num() > 0) {
568 
569  if (parameters_arr == NULL) {
570  PyErr_SetString(PyExc_Exception, "The gate has free parameters to set, but no parameter array was given as input");
571  return NULL;
572  }
573 
574  Matrix_real_float&& parameters_mtx = numpy2matrix_real_float(parameters_arr);
575  // Use get_matrix so it never calls apply_to internally
576  gate_mtx = gate->get_matrix(parameters_mtx, 1);
577 
578  Py_DECREF(parameters_arr);
579 
580  }
581  else {
582  std::string err( "The number of parameters in a gate is set to a negative value");
583  PyErr_SetString(PyExc_Exception, err.c_str());
584  if (parameters_arr != NULL) {
585  Py_DECREF(parameters_arr);
586  }
587  return NULL;
588  }
589 
590 
591  gate_mtx.set_owner(false);
592  PyObject *gate_mtx_py = matrix_float_to_numpy( gate_mtx );
593  return gate_mtx_py;
594  }
595 
596  Matrix gate_mtx;
597 
598  if (parameters_obj != NULL) {
599  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF(parameters_obj, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
600  if (parameters_arr == NULL) {
601  PyErr_SetString(PyExc_TypeError, "Parameter vector should be real typed and array-like");
602  return NULL;
603  }
604  }
605 
606  if( gate->get_parameter_num() == 0 ) {
607 
608  if( parameters_arr != NULL ) {
609  PyErr_SetString(PyExc_Exception, "The gate contains no parameters to set, but parameter array was given as input");
610  Py_DECREF(parameters_arr);
611  return NULL;
612  }
613 
614  int parallel = 1;
615  gate_mtx = gate->get_matrix( parallel );
616 
617  }
618  else if( gate->get_parameter_num() > 0 ) {
619 
620  if( parameters_arr == NULL ) {
621  PyErr_SetString(PyExc_Exception, "The gate has free parameters to set, but no parameter array was given as input");
622  return NULL;
623  }
624 
625  // get the C++ wrapper around the input data
626  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
627  int parallel = 1;
628  gate_mtx = self->gate->get_matrix( parameters_mtx, parallel );
629 
630  Py_DECREF(parameters_arr);
631 
632 
633  }
634  else {
635  std::string err( "The number of parameters in a gate is set to a negative value");
636  PyErr_SetString(PyExc_Exception, err.c_str());
637  if (parameters_arr != NULL) {
638  Py_DECREF(parameters_arr);
639  }
640  return NULL;
641 
642  }
643 
644 
645  // convert to numpy array
646  gate_mtx.set_owner(false);
647  PyObject *gate_mtx_py = matrix_to_numpy( gate_mtx );
648 
649 
650  return gate_mtx_py;
651  }
652  catch (const std::string& err) {
653  if (parameters_arr != NULL) {
654  Py_DECREF(parameters_arr);
655  }
656  PyErr_SetString(PyExc_RuntimeError, err.c_str());
657  return NULL;
658  }
659  catch (const std::exception& err) {
660  if (parameters_arr != NULL) {
661  Py_DECREF(parameters_arr);
662  }
663  PyErr_SetString(PyExc_RuntimeError, err.what());
664  return NULL;
665  }
666  catch(...) {
667  if (parameters_arr != NULL) {
668  Py_DECREF(parameters_arr);
669  }
670  PyErr_SetString(PyExc_RuntimeError, "Unknown error in Gate_Wrapper_get_Matrix");
671  return NULL;
672  }
673 }
674 
675 
679 static PyObject *
681 
682  static char *kwlist[] = {(char*)"unitary", (char*)"parameters", (char*)"is_f32", NULL};
683 
684  PyArrayObject * input = NULL;
685  PyArrayObject * parameters_arr = NULL;
686  int is_f32 = 0;
687 
688  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Op", kwlist, &input, &parameters_arr, &is_f32 )) {
689  std::string err( "Unable to parse keyword arguments");
690  PyErr_SetString(PyExc_Exception, err.c_str());
691  return NULL;
692  }
693 
694  Gate* gate = self->gate;
695  const int param_count = gate->get_parameter_num();
696  bool release_parameters_arr = false;
697 
698  if ( input == NULL ) {
699  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
700  return NULL;
701  }
702 
703  if (param_count == 0 && parameters_arr != NULL) {
704  PyErr_SetString(PyExc_Exception, "The gate contains no parameters to set, but parameter array was given as input");
705  return NULL;
706  }
707 
708  if (is_f32) {
709  if ( PyArray_TYPE(input) != NPY_COMPLEX64 ) {
710  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex64 when is_f32=True");
711  return NULL;
712  }
713  }
714  else {
715  if ( PyArray_TYPE(input) != NPY_COMPLEX128 ) {
716  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex128 when is_f32=False");
717  return NULL;
718  }
719  }
720 
721  if ( !PyArray_IS_C_CONTIGUOUS(input) ) {
722  PyErr_SetString(PyExc_Exception, "input state/matrix is not memory contiguous");
723  return NULL;
724  }
725 
726  if (is_f32) {
727 
728  Matrix_float input_mtx = numpy2matrix_float(input);
729 
730  try {
731  if (param_count == 0) {
732  gate->apply_from_right(input_mtx);
733  }
734  else if (param_count > 0) {
735  if( parameters_arr == NULL ) {
736  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
737  PyErr_SetString(PyExc_Exception, err.c_str());
738  return NULL;
739  }
740 
741  if ( PyArray_TYPE(parameters_arr) != NPY_FLOAT32 ) {
742  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float32 when is_f32=True");
743  return NULL;
744  }
745 
746  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
747  Py_INCREF(parameters_arr);
748  }
749  else {
750  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY);
751  }
752 
753  if (parameters_arr == NULL) {
754  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous float32 numpy array");
755  return NULL;
756  }
757  release_parameters_arr = true;
758 
759  Matrix_real_float&& parameters_mtx = numpy2matrix_real_float( parameters_arr );
760  gate->apply_from_right(parameters_mtx, input_mtx);
761 
762  Py_DECREF(parameters_arr);
763  }
764  else {
765  PyErr_SetString(PyExc_ValueError, "The number of parameters in a gate is set to a negative value");
766  return NULL;
767  }
768  }
769  catch (const std::string& err) {
770  if (release_parameters_arr) {
771  Py_DECREF(parameters_arr);
772  }
773  PyErr_SetString(PyExc_RuntimeError, err.c_str());
774  return NULL;
775  }
776  catch(...) {
777  if (release_parameters_arr) {
778  Py_DECREF(parameters_arr);
779  }
780  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate operation");
781  return NULL;
782  }
783 
784  if (input_mtx.data != PyArray_DATA(input)) {
785  memcpy(PyArray_DATA(input), input_mtx.data, input_mtx.size() * sizeof(QGD_Complex8));
786  }
787 
788  return Py_BuildValue("i", 0);
789  }
790 
791  Matrix input_mtx = numpy2matrix(input);
792 
793  try {
794  if (param_count == 0) {
795  gate->apply_from_right(input_mtx);
796  }
797  else if (param_count > 0) {
798  if( parameters_arr == NULL ) {
799  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
800  PyErr_SetString(PyExc_Exception, err.c_str());
801  return NULL;
802  }
803 
804  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
805  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float64 when is_f32=False");
806  return NULL;
807  }
808 
809  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
810  Py_INCREF(parameters_arr);
811  }
812  else {
813  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
814  }
815 
816  if (parameters_arr == NULL) {
817  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous double numpy array");
818  return NULL;
819  }
820  release_parameters_arr = true;
821 
822  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
823  gate->apply_from_right(parameters_mtx, input_mtx);
824 
825  Py_DECREF(parameters_arr);
826  }
827  else {
828  PyErr_SetString(PyExc_ValueError, "The number of parameters in a gate is set to a negative value");
829  return NULL;
830  }
831  }
832  catch (const std::string& err) {
833  if (release_parameters_arr) {
834  Py_DECREF(parameters_arr);
835  }
836  PyErr_SetString(PyExc_RuntimeError, err.c_str());
837  return NULL;
838  }
839  catch(...) {
840  if (release_parameters_arr) {
841  Py_DECREF(parameters_arr);
842  }
843  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate operation");
844  return NULL;
845  }
846 
847  if (input_mtx.data != PyArray_DATA(input)) {
848  memcpy(PyArray_DATA(input), input_mtx.data, input_mtx.size() * sizeof(QGD_Complex16));
849  }
850 
851  return Py_BuildValue("i", 0);
852 }
853 
854 
858 static PyObject *
860 
861  static char *kwlist[] = {(char*)"inputs", (char*)"parameters", (char*)"parallel", (char*)"is_f32", NULL};
862 
863  PyObject * inputs_obj = NULL;
864  PyArrayObject * parameters_arr = NULL;
865  int parallel = 1;
866  int is_f32 = 0;
867 
868  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oip", kwlist, &inputs_obj, &parameters_arr, &parallel, &is_f32 )) {
869  std::string err( "Unable to parse keyword arguments");
870  PyErr_SetString(PyExc_Exception, err.c_str());
871  return NULL;
872  }
873 
874  if ( inputs_obj == NULL ) {
875  PyErr_SetString(PyExc_Exception, "Input list was not given");
876  return NULL;
877  }
878 
879  PyObject* seq = PySequence_Fast(inputs_obj, "inputs must be a sequence of numpy arrays");
880  if (seq == NULL) {
881  return NULL;
882  }
883 
884  Gate* gate = self->gate;
885  const int param_count = gate->get_parameter_num();
886  bool release_parameters_arr = false;
887 
888  try {
889  if (is_f32) {
890  Matrix_real_float parameters_mtx;
891 
892  if (param_count > 0) {
893  if( parameters_arr == NULL ) {
894  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
895  Py_DECREF(seq);
896  PyErr_SetString(PyExc_Exception, err.c_str());
897  return NULL;
898  }
899 
900  if ( PyArray_TYPE(parameters_arr) != NPY_FLOAT32 ) {
901  Py_DECREF(seq);
902  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float32 when is_f32=True");
903  return NULL;
904  }
905 
906  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
907  Py_INCREF(parameters_arr);
908  }
909  else {
910  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY);
911  }
912 
913  if (parameters_arr == NULL) {
914  Py_DECREF(seq);
915  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous float32 numpy array");
916  return NULL;
917  }
918  release_parameters_arr = true;
919  parameters_mtx = numpy2matrix_real_float(parameters_arr);
920  }
921 
922  const Py_ssize_t n = PySequence_Fast_GET_SIZE(seq);
923  PyObject** items = PySequence_Fast_ITEMS(seq);
924  for (Py_ssize_t idx = 0; idx < n; idx++) {
925  PyObject* item = items[idx];
926  if (!PyArray_Check(item)) {
927  Py_DECREF(seq);
928  if (release_parameters_arr) {
929  Py_DECREF(parameters_arr);
930  }
931  PyErr_SetString(PyExc_TypeError, "All inputs should be numpy arrays");
932  return NULL;
933  }
934 
935  PyArrayObject* input = (PyArrayObject*)item;
936  if ( PyArray_TYPE(input) != NPY_COMPLEX64 ) {
937  Py_DECREF(seq);
938  if (release_parameters_arr) {
939  Py_DECREF(parameters_arr);
940  }
941  PyErr_SetString(PyExc_TypeError, "All inputs should be complex64 when is_f32=True");
942  return NULL;
943  }
944 
945  if ( !PyArray_IS_C_CONTIGUOUS(input) ) {
946  Py_DECREF(seq);
947  if (release_parameters_arr) {
948  Py_DECREF(parameters_arr);
949  }
950  PyErr_SetString(PyExc_TypeError, "All inputs should be C-contiguous");
951  return NULL;
952  }
953 
954  Matrix_float input_mtx = numpy2matrix_float(input);
955  if (param_count == 0) {
956  gate->apply_to(input_mtx, parallel);
957  }
958  else if (param_count > 0) {
959  gate->apply_to(parameters_mtx, input_mtx, parallel);
960  }
961  else {
962  Py_DECREF(seq);
963  if (release_parameters_arr) {
964  Py_DECREF(parameters_arr);
965  }
966  PyErr_SetString(PyExc_ValueError, "The number of parameters in a gate is set to a negative value");
967  return NULL;
968  }
969 
970  if (input_mtx.data != PyArray_DATA(input)) {
971  memcpy(PyArray_DATA(input), input_mtx.data, input_mtx.size() * sizeof(QGD_Complex8));
972  }
973  }
974  }
975  else {
976  Matrix_real parameters_mtx;
977 
978  if (param_count > 0) {
979  if( parameters_arr == NULL ) {
980  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
981  Py_DECREF(seq);
982  PyErr_SetString(PyExc_Exception, err.c_str());
983  return NULL;
984  }
985 
986  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
987  Py_DECREF(seq);
988  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float64 when is_f32=False");
989  return NULL;
990  }
991 
992  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
993  Py_INCREF(parameters_arr);
994  }
995  else {
996  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
997  }
998 
999  if (parameters_arr == NULL) {
1000  Py_DECREF(seq);
1001  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous double numpy array");
1002  return NULL;
1003  }
1004  release_parameters_arr = true;
1005  parameters_mtx = numpy2matrix_real(parameters_arr);
1006  }
1007 
1008  const Py_ssize_t n = PySequence_Fast_GET_SIZE(seq);
1009  PyObject** items = PySequence_Fast_ITEMS(seq);
1010  for (Py_ssize_t idx = 0; idx < n; idx++) {
1011  PyObject* item = items[idx];
1012  if (!PyArray_Check(item)) {
1013  Py_DECREF(seq);
1014  if (release_parameters_arr) {
1015  Py_DECREF(parameters_arr);
1016  }
1017  PyErr_SetString(PyExc_TypeError, "All inputs should be numpy arrays");
1018  return NULL;
1019  }
1020 
1021  PyArrayObject* input = (PyArrayObject*)item;
1022  if ( PyArray_TYPE(input) != NPY_COMPLEX128 ) {
1023  Py_DECREF(seq);
1024  if (release_parameters_arr) {
1025  Py_DECREF(parameters_arr);
1026  }
1027  PyErr_SetString(PyExc_TypeError, "All inputs should be complex128 when is_f32=False");
1028  return NULL;
1029  }
1030 
1031  if ( !PyArray_IS_C_CONTIGUOUS(input) ) {
1032  Py_DECREF(seq);
1033  if (release_parameters_arr) {
1034  Py_DECREF(parameters_arr);
1035  }
1036  PyErr_SetString(PyExc_TypeError, "All inputs should be C-contiguous");
1037  return NULL;
1038  }
1039 
1040  Matrix input_mtx = numpy2matrix(input);
1041  if (param_count == 0) {
1042  gate->apply_to(input_mtx, parallel);
1043  }
1044  else if (param_count > 0) {
1045  gate->apply_to(parameters_mtx, input_mtx, parallel);
1046  }
1047  else {
1048  Py_DECREF(seq);
1049  if (release_parameters_arr) {
1050  Py_DECREF(parameters_arr);
1051  }
1052  PyErr_SetString(PyExc_ValueError, "The number of parameters in a gate is set to a negative value");
1053  return NULL;
1054  }
1055 
1056  if (input_mtx.data != PyArray_DATA(input)) {
1057  memcpy(PyArray_DATA(input), input_mtx.data, input_mtx.size() * sizeof(QGD_Complex16));
1058  }
1059  }
1060  }
1061 
1062  Py_DECREF(seq);
1063  if (release_parameters_arr) {
1064  Py_DECREF(parameters_arr);
1065  }
1066  return Py_BuildValue("i", 0);
1067  }
1068  catch (const std::string& err) {
1069  Py_DECREF(seq);
1070  if (release_parameters_arr) {
1071  Py_DECREF(parameters_arr);
1072  }
1073  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1074  return NULL;
1075  }
1076  catch(...) {
1077  Py_DECREF(seq);
1078  if (release_parameters_arr) {
1079  Py_DECREF(parameters_arr);
1080  }
1081  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate operation");
1082  return NULL;
1083  }
1084 }
1085 
1086 
1087 
1091 static PyObject *
1092 Gate_Wrapper_Wrapper_apply_to( Gate_Wrapper *self, PyObject *args, PyObject *kwds ) {
1093 
1094  static char *kwlist[] = {(char*)"unitary", (char*)"parameters", (char*)"parallel", (char*)"is_f32", NULL};
1095 
1096  PyArrayObject * input = NULL;
1097  PyArrayObject * parameters_arr = NULL;
1098  int parallel = 1;
1099  int is_f32 = 0;
1100 
1101  // parsing input arguments
1102  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oip", kwlist, &input, &parameters_arr, &parallel, &is_f32 )) {
1103  std::string err( "Unable to parse keyword arguments");
1104  PyErr_SetString(PyExc_Exception, err.c_str());
1105  return NULL;
1106  }
1107 
1108  // Check if input matrix is provided
1109  if ( input == NULL ) {
1110  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1111  return NULL;
1112  }
1113 
1114  if (is_f32) {
1115  if ( PyArray_TYPE(input) != NPY_COMPLEX64 ) {
1116  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex64 when is_f32=True");
1117  return NULL;
1118  }
1119  }
1120  else {
1121  if ( PyArray_TYPE(input) != NPY_COMPLEX128 ) {
1122  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex128 when is_f32=False");
1123  return NULL;
1124  }
1125  }
1126 
1127  // test C-style contiguous memory allocation of the array
1128  if ( !PyArray_IS_C_CONTIGUOUS(input) ) {
1129  PyErr_SetString(PyExc_Exception, "input state/matrix is not memory contiguous");
1130  return NULL;
1131  }
1132 
1133  Gate* gate = self->gate;
1134 
1135  const int param_count = gate->get_parameter_num();
1136  bool release_parameters_arr = false;
1137 
1138  if (is_f32) {
1139 
1140  Matrix_float input_mtx = numpy2matrix_float(input);
1141 
1142  try {
1143  if (param_count == 0) {
1144  gate->apply_to(input_mtx, parallel);
1145  }
1146  else if (param_count > 0) {
1147  if( parameters_arr == NULL ) {
1148  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
1149  PyErr_SetString(PyExc_Exception, err.c_str());
1150  return NULL;
1151  }
1152 
1153  if ( PyArray_TYPE(parameters_arr) != NPY_FLOAT32 ) {
1154  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float32 when is_f32=True");
1155  return NULL;
1156  }
1157 
1158  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1159  Py_INCREF(parameters_arr);
1160  }
1161  else {
1162  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY);
1163  }
1164 
1165  if (parameters_arr == NULL) {
1166  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous float32 numpy array");
1167  return NULL;
1168  }
1169  release_parameters_arr = true;
1170 
1171  Matrix_real_float&& parameters_mtx = numpy2matrix_real_float( parameters_arr );
1172  gate->apply_to(parameters_mtx, input_mtx, parallel);
1173 
1174  Py_DECREF(parameters_arr);
1175  }
1176  else {
1177  PyErr_SetString(PyExc_ValueError, "The number of parameters in a gate is set to a negative value");
1178  return NULL;
1179  }
1180  }
1181  catch (const std::string& err) {
1182  if (release_parameters_arr) {
1183  Py_DECREF(parameters_arr);
1184  }
1185  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1186  return NULL;
1187  }
1188  catch(...) {
1189  if (release_parameters_arr) {
1190  Py_DECREF(parameters_arr);
1191  }
1192  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate operation");
1193  return NULL;
1194  }
1195 
1196  if (input_mtx.data != PyArray_DATA(input)) {
1197  memcpy(PyArray_DATA(input), input_mtx.data, input_mtx.size() * sizeof(QGD_Complex8));
1198  }
1199 
1200  return Py_BuildValue("i", 0);
1201  }
1202 
1203  Matrix input_mtx = numpy2matrix(input);
1204 
1205  try {
1206  if (param_count == 0) {
1207  gate->apply_to(input_mtx, parallel);
1208  }
1209  else if (param_count > 0) {
1210  if( parameters_arr == NULL ) {
1211  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
1212  PyErr_SetString(PyExc_Exception, err.c_str());
1213  return NULL;
1214  }
1215 
1216  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
1217  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float64 when is_f32=False");
1218  return NULL;
1219  }
1220 
1221  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1222  Py_INCREF(parameters_arr);
1223  }
1224  else {
1225  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1226  }
1227 
1228  if (parameters_arr == NULL) {
1229  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous double numpy array");
1230  return NULL;
1231  }
1232  release_parameters_arr = true;
1233 
1234  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1235 
1236  gate->apply_to(parameters_mtx, input_mtx, parallel);
1237 
1238  Py_DECREF(parameters_arr);
1239  }
1240  else {
1241  PyErr_SetString(PyExc_ValueError, "The number of parameters in a gate is set to a negative value");
1242  return NULL;
1243  }
1244  }
1245  catch (const std::string& err) {
1246  if (release_parameters_arr) {
1247  Py_DECREF(parameters_arr);
1248  }
1249  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1250  return NULL;
1251  }
1252  catch(...) {
1253  if (release_parameters_arr) {
1254  Py_DECREF(parameters_arr);
1255  }
1256  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate operation");
1257  return NULL;
1258  }
1259 
1260  if (input_mtx.data != PyArray_DATA(input)) {
1261  memcpy(PyArray_DATA(input), input_mtx.data, input_mtx.size() * sizeof(QGD_Complex16));
1262  }
1263 
1264  return Py_BuildValue("i", 0);
1265 }
1266 
1267 
1272 static void
1274  Matrix* m = static_cast<Matrix*>( PyCapsule_GetPointer(cap, "squander.matrix_owner") );
1275  delete m;
1276 }
1277 
1281 static void
1283  Matrix_float* m = static_cast<Matrix_float*>( PyCapsule_GetPointer(cap, "squander.matrix_float_owner") );
1284  delete m;
1285 }
1286 
1290 static PyObject *
1292 
1293  static char *kwlist[] = {(char*)"unitary", (char*)"parameters", (char*)"parallel", (char*)"is_f32", NULL};
1294 
1295  PyArrayObject * input = NULL;
1296  PyArrayObject * parameters_arr = NULL;
1297  int parallel = 1;
1298  int is_f32 = 0;
1299 
1300  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oip", kwlist, &input, &parameters_arr, &parallel, &is_f32 )) {
1301  std::string err( "Unable to parse keyword arguments");
1302  PyErr_SetString(PyExc_Exception, err.c_str());
1303  return NULL;
1304  }
1305 
1306  if ( input == NULL ) {
1307  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1308  return NULL;
1309  }
1310 
1311  if (is_f32) {
1312  if ( PyArray_TYPE(input) != NPY_COMPLEX64 ) {
1313  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex64 when is_f32=True");
1314  return NULL;
1315  }
1316  }
1317  else {
1318  if ( PyArray_TYPE(input) != NPY_COMPLEX128 ) {
1319  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex128 when is_f32=False");
1320  return NULL;
1321  }
1322  }
1323 
1324  if ( !PyArray_IS_C_CONTIGUOUS(input) ) {
1325  PyErr_SetString(PyExc_Exception, "input state/matrix is not memory contiguous");
1326  return NULL;
1327  }
1328 
1329  Gate* gate = self->gate;
1330  const int param_count = gate->get_parameter_num();
1331  bool release_parameters_arr = false;
1332 
1333  if (is_f32) {
1334 
1335  Matrix_float input_mtx = numpy2matrix_float(input);
1336 
1337  try {
1338  if (param_count > 0) {
1339  if( parameters_arr == NULL ) {
1340  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
1341  PyErr_SetString(PyExc_Exception, err.c_str());
1342  return NULL;
1343  }
1344 
1345  if ( PyArray_TYPE(parameters_arr) != NPY_FLOAT32 ) {
1346  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float32 when is_f32=True");
1347  return NULL;
1348  }
1349 
1350  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1351  Py_INCREF(parameters_arr);
1352  }
1353  else {
1354  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY);
1355  }
1356 
1357  if (parameters_arr == NULL) {
1358  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous float32 numpy array");
1359  return NULL;
1360  }
1361  release_parameters_arr = true;
1362  }
1363  Matrix_real_float parameters_mtx;
1364  parameters_mtx = numpy2matrix_real_float(parameters_arr);
1365 
1366  std::vector<Matrix_float> derivs;
1367  derivs = gate->apply_derivate_to(parameters_mtx, input_mtx, parallel);
1368 
1369  PyObject* deriv_list = PyList_New((Py_ssize_t)derivs.size());
1370  if (deriv_list == NULL) {
1371  if (release_parameters_arr) {
1372  Py_DECREF(parameters_arr);
1373  }
1374  return NULL;
1375  }
1376 
1377  for (Py_ssize_t idx = 0; idx < (Py_ssize_t)derivs.size(); ++idx) {
1378  // Heap-allocate a Matrix_float that owns the derivative data.
1379  // The numpy array will hold a capsule referencing it; when the numpy
1380  // array is freed, the capsule destructor calls delete, which decrements
1381  // the reference count and eventually calls scalable_aligned_free.
1382  Matrix_float* owned = new Matrix_float(derivs[(size_t)idx]);
1383  PyObject* cap = PyCapsule_New(
1384  owned, "squander.matrix_float_owner",
1386  if (cap == NULL) {
1387  delete owned;
1388  Py_DECREF(deriv_list);
1389  if (release_parameters_arr) {
1390  Py_DECREF(parameters_arr);
1391  }
1392  return NULL;
1393  }
1394  npy_intp shape[2] = { (npy_intp)owned->rows, (npy_intp)owned->cols };
1395  // Derivative matrices always have stride==cols (copied from contiguous input).
1396  PyObject* deriv_py = PyArray_SimpleNewFromData(
1397  2, shape, NPY_COMPLEX64, owned->get_data());
1398  if (deriv_py == NULL) {
1399  Py_DECREF(cap); // also deletes owned via destructor
1400  Py_DECREF(deriv_list);
1401  if (release_parameters_arr) {
1402  Py_DECREF(parameters_arr);
1403  }
1404  return NULL;
1405  }
1406  // Transfer data ownership to the numpy array via the capsule.
1407  PyArray_SetBaseObject((PyArrayObject*)deriv_py, cap);
1408  PyList_SET_ITEM(deriv_list, idx, deriv_py);
1409  }
1410 
1411  if (release_parameters_arr) {
1412  Py_DECREF(parameters_arr);
1413  }
1414  return deriv_list;
1415  }
1416  catch (const std::string& err) {
1417  if (release_parameters_arr) {
1418  Py_DECREF(parameters_arr);
1419  }
1420  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1421  return NULL;
1422  }
1423  catch(...) {
1424  if (release_parameters_arr) {
1425  Py_DECREF(parameters_arr);
1426  }
1427  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate derivative operation");
1428  return NULL;
1429  }
1430  }
1431 
1432  Matrix input_mtx = numpy2matrix(input);
1433 
1434  try {
1435  if (param_count > 0) {
1436  if( parameters_arr == NULL ) {
1437  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
1438  PyErr_SetString(PyExc_Exception, err.c_str());
1439  return NULL;
1440  }
1441 
1442  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
1443  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float64 when is_f32=False");
1444  return NULL;
1445  }
1446 
1447  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1448  Py_INCREF(parameters_arr);
1449  }
1450  else {
1451  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1452  }
1453 
1454  if (parameters_arr == NULL) {
1455  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous double numpy array");
1456  return NULL;
1457  }
1458  release_parameters_arr = true;
1459  }
1460  Matrix_real parameters_mtx;
1461  parameters_mtx = numpy2matrix_real(parameters_arr);
1462 
1463  std::vector<Matrix> derivs;
1464  derivs = gate->apply_derivate_to(parameters_mtx, input_mtx, parallel);
1465 
1466  PyObject* deriv_list = PyList_New((Py_ssize_t)derivs.size());
1467  if (deriv_list == NULL) {
1468  if (release_parameters_arr) {
1469  Py_DECREF(parameters_arr);
1470  }
1471  return NULL;
1472  }
1473 
1474  for (Py_ssize_t idx = 0; idx < (Py_ssize_t)derivs.size(); ++idx) {
1475  // Heap-allocate a Matrix that owns the derivative data.
1476  // The numpy array will hold a capsule referencing it; when the numpy
1477  // array is freed, the capsule destructor calls delete, which decrements
1478  // the reference count and eventually calls scalable_aligned_free.
1479  Matrix* owned = new Matrix(derivs[(size_t)idx]);
1480  PyObject* cap = PyCapsule_New(
1481  owned, "squander.matrix_owner",
1483  if (cap == NULL) {
1484  delete owned;
1485  Py_DECREF(deriv_list);
1486  if (release_parameters_arr) {
1487  Py_DECREF(parameters_arr);
1488  }
1489  return NULL;
1490  }
1491  npy_intp shape[2] = { (npy_intp)owned->rows, (npy_intp)owned->cols };
1492  // Derivative matrices always have stride==cols (copied from contiguous input).
1493  PyObject* deriv_py = PyArray_SimpleNewFromData(
1494  2, shape, NPY_COMPLEX128, owned->get_data());
1495  if (deriv_py == NULL) {
1496  Py_DECREF(cap); // also deletes owned via destructor
1497  Py_DECREF(deriv_list);
1498  if (release_parameters_arr) {
1499  Py_DECREF(parameters_arr);
1500  }
1501  return NULL;
1502  }
1503  // Transfer data ownership to the numpy array via the capsule.
1504  PyArray_SetBaseObject((PyArrayObject*)deriv_py, cap);
1505  PyList_SET_ITEM(deriv_list, idx, deriv_py);
1506  }
1507 
1508  if (release_parameters_arr) {
1509  Py_DECREF(parameters_arr);
1510  }
1511  return deriv_list;
1512  }
1513  catch (const std::string& err) {
1514  if (release_parameters_arr) {
1515  Py_DECREF(parameters_arr);
1516  }
1517  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1518  return NULL;
1519  }
1520  catch(...) {
1521  if (release_parameters_arr) {
1522  Py_DECREF(parameters_arr);
1523  }
1524  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate derivative operation");
1525  return NULL;
1526  }
1527 }
1528 
1529 
1534 static PyObject *
1536 
1537  static char *kwlist[] = {(char*)"unitary", (char*)"parameters", (char*)"parallel", (char*)"is_f32", NULL};
1538 
1539  PyArrayObject * input = NULL;
1540  PyArrayObject * parameters_arr = NULL;
1541  int parallel = 1;
1542  int is_f32 = 0;
1543 
1544  if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oip", kwlist, &input, &parameters_arr, &parallel, &is_f32 )) {
1545  std::string err( "Unable to parse keyword arguments");
1546  PyErr_SetString(PyExc_Exception, err.c_str());
1547  return NULL;
1548  }
1549 
1550  if ( input == NULL ) {
1551  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1552  return NULL;
1553  }
1554 
1555  if (is_f32) {
1556  if ( PyArray_TYPE(input) != NPY_COMPLEX64 ) {
1557  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex64 when is_f32=True");
1558  return NULL;
1559  }
1560  }
1561  else {
1562  if ( PyArray_TYPE(input) != NPY_COMPLEX128 ) {
1563  PyErr_SetString(PyExc_TypeError, "input matrix or state should be complex128 when is_f32=False");
1564  return NULL;
1565  }
1566  }
1567 
1568  if ( !PyArray_IS_C_CONTIGUOUS(input) ) {
1569  PyErr_SetString(PyExc_Exception, "input state/matrix is not memory contiguous");
1570  return NULL;
1571  }
1572 
1573  Gate* gate = self->gate;
1574  const int param_count = gate->get_parameter_num();
1575  bool release_parameters_arr = false;
1576 
1577  if (is_f32) {
1578 
1579  Matrix_float input_mtx = numpy2matrix_float(input);
1580 
1581  try {
1582  Matrix_real_float parameters_mtx(0, 0);
1583 
1584  if (param_count > 0) {
1585  if( parameters_arr == NULL ) {
1586  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
1587  PyErr_SetString(PyExc_Exception, err.c_str());
1588  return NULL;
1589  }
1590 
1591  if ( PyArray_TYPE(parameters_arr) != NPY_FLOAT32 ) {
1592  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float32 when is_f32=True");
1593  return NULL;
1594  }
1595 
1596  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1597  Py_INCREF(parameters_arr);
1598  }
1599  else {
1600  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_FLOAT32, NPY_ARRAY_IN_ARRAY);
1601  }
1602 
1603  if (parameters_arr == NULL) {
1604  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous float32 numpy array");
1605  return NULL;
1606  }
1607  release_parameters_arr = true;
1608  parameters_mtx = numpy2matrix_real_float(parameters_arr);
1609  }
1610 
1611  std::vector<Matrix_float> combined = gate->apply_to_combined(parameters_mtx, input_mtx, parallel);
1612 
1613  PyObject* combined_list = PyList_New((Py_ssize_t)combined.size());
1614  if (combined_list == NULL) {
1615  if (release_parameters_arr) {
1616  Py_DECREF(parameters_arr);
1617  }
1618  return NULL;
1619  }
1620 
1621  for (Py_ssize_t idx = 0; idx < (Py_ssize_t)combined.size(); ++idx) {
1622  Matrix_float* owned = new Matrix_float(combined[(size_t)idx]);
1623  PyObject* cap = PyCapsule_New(
1624  owned, "squander.matrix_float_owner",
1626  if (cap == NULL) {
1627  delete owned;
1628  Py_DECREF(combined_list);
1629  if (release_parameters_arr) {
1630  Py_DECREF(parameters_arr);
1631  }
1632  return NULL;
1633  }
1634  npy_intp shape[2] = { (npy_intp)owned->rows, (npy_intp)owned->cols };
1635  PyObject* out_py = PyArray_SimpleNewFromData(
1636  2, shape, NPY_COMPLEX64, owned->get_data());
1637  if (out_py == NULL) {
1638  Py_DECREF(cap);
1639  Py_DECREF(combined_list);
1640  if (release_parameters_arr) {
1641  Py_DECREF(parameters_arr);
1642  }
1643  return NULL;
1644  }
1645  PyArray_SetBaseObject((PyArrayObject*)out_py, cap);
1646  PyList_SET_ITEM(combined_list, idx, out_py);
1647  }
1648 
1649  if (release_parameters_arr) {
1650  Py_DECREF(parameters_arr);
1651  }
1652  return combined_list;
1653  }
1654  catch (const std::string& err) {
1655  if (release_parameters_arr) {
1656  Py_DECREF(parameters_arr);
1657  }
1658  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1659  return NULL;
1660  }
1661  catch(...) {
1662  if (release_parameters_arr) {
1663  Py_DECREF(parameters_arr);
1664  }
1665  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate combined operation");
1666  return NULL;
1667  }
1668  }
1669 
1670  Matrix input_mtx = numpy2matrix(input);
1671 
1672  try {
1673  Matrix_real parameters_mtx(0, 0);
1674 
1675  if (param_count > 0) {
1676  if( parameters_arr == NULL ) {
1677  std::string err( "The gate has free parameters to set, but no parameter array was given as input");
1678  PyErr_SetString(PyExc_Exception, err.c_str());
1679  return NULL;
1680  }
1681 
1682  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
1683  PyErr_SetString(PyExc_TypeError, "Parameter vector should be float64 when is_f32=False");
1684  return NULL;
1685  }
1686 
1687  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1688  Py_INCREF(parameters_arr);
1689  }
1690  else {
1691  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1692  }
1693 
1694  if (parameters_arr == NULL) {
1695  PyErr_SetString(PyExc_TypeError, "Failed to cast parameters to a contiguous double numpy array");
1696  return NULL;
1697  }
1698  release_parameters_arr = true;
1699  parameters_mtx = numpy2matrix_real(parameters_arr);
1700  }
1701 
1702  std::vector<Matrix> combined = gate->apply_to_combined(parameters_mtx, input_mtx, parallel);
1703 
1704  PyObject* combined_list = PyList_New((Py_ssize_t)combined.size());
1705  if (combined_list == NULL) {
1706  if (release_parameters_arr) {
1707  Py_DECREF(parameters_arr);
1708  }
1709  return NULL;
1710  }
1711 
1712  for (Py_ssize_t idx = 0; idx < (Py_ssize_t)combined.size(); ++idx) {
1713  Matrix* owned = new Matrix(combined[(size_t)idx]);
1714  PyObject* cap = PyCapsule_New(
1715  owned, "squander.matrix_owner",
1717  if (cap == NULL) {
1718  delete owned;
1719  Py_DECREF(combined_list);
1720  if (release_parameters_arr) {
1721  Py_DECREF(parameters_arr);
1722  }
1723  return NULL;
1724  }
1725  npy_intp shape[2] = { (npy_intp)owned->rows, (npy_intp)owned->cols };
1726  PyObject* out_py = PyArray_SimpleNewFromData(
1727  2, shape, NPY_COMPLEX128, owned->get_data());
1728  if (out_py == NULL) {
1729  Py_DECREF(cap);
1730  Py_DECREF(combined_list);
1731  if (release_parameters_arr) {
1732  Py_DECREF(parameters_arr);
1733  }
1734  return NULL;
1735  }
1736  PyArray_SetBaseObject((PyArrayObject*)out_py, cap);
1737  PyList_SET_ITEM(combined_list, idx, out_py);
1738  }
1739 
1740  if (release_parameters_arr) {
1741  Py_DECREF(parameters_arr);
1742  }
1743  return combined_list;
1744  }
1745  catch (const std::string& err) {
1746  if (release_parameters_arr) {
1747  Py_DECREF(parameters_arr);
1748  }
1749  PyErr_SetString(PyExc_RuntimeError, err.c_str());
1750  return NULL;
1751  }
1752  catch(...) {
1753  if (release_parameters_arr) {
1754  Py_DECREF(parameters_arr);
1755  }
1756  PyErr_SetString(PyExc_RuntimeError, "Unknown error in gate combined operation");
1757  return NULL;
1758  }
1759 }
1760 
1761 
1762 
1771 static PyObject *
1772 Gate_Wrapper_get_Gate_Kernel( Gate_Wrapper *self, PyObject *args, PyObject *kwds) {
1773 
1774 
1775  static char *kwlist[] = {(char*)"ThetaOver2", (char*)"Phi", (char*)"Lambda", NULL};
1776 
1777  double ThetaOver2;
1778  double Phi;
1779  double Lambda;
1780 
1781 
1782  try {
1783  ThetaOver2 = 0.0;
1784  Phi = 0.0;
1785  Lambda = 0.0;
1786  }
1787  catch (std::string err) {
1788  PyErr_SetString(PyExc_Exception, err.c_str());
1789  return NULL;
1790  }
1791  catch(...) {
1792  std::string err( "Invalid pointer to gate class");
1793  PyErr_SetString(PyExc_Exception, err.c_str());
1794  return NULL;
1795  }
1796 
1797  // parsing input arguments
1798  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ddd", kwlist, &ThetaOver2, &Phi, &Lambda )) {
1799  std::string err( "Unable to parse keyword arguments");
1800  PyErr_SetString(PyExc_Exception, err.c_str());
1801  return NULL;
1802  }
1803 
1804 
1805  Matrix CH_1qbit_;
1806 
1807  // create QGD version of the input matrix
1808  Gate* gate = self->gate;
1809 
1810  if( gate->get_parameter_num() == 0 ) {
1811  Matrix_real empty_params(0, 0);
1812  CH_1qbit_ = gate->gate_kernel(empty_params);
1813  }
1814  else if( gate->get_parameter_num() > 0 ) {
1815  CH_1qbit_ = Gate::calc_one_qubit_u3(ThetaOver2, Phi, Lambda);
1816  }
1817  else {
1818  std::string err( "The number of parameters in a gate is set to a negative value");
1819  PyErr_SetString(PyExc_Exception, err.c_str());
1820  return NULL;
1821 
1822  }
1823 
1824 
1825  PyObject *CH_1qbit = matrix_to_numpy( CH_1qbit_ );
1826 
1827  return CH_1qbit;
1828 
1829 
1830 }
1831 
1832 
1833 
1838 static PyObject *
1840 
1841  int parameter_num;
1842 
1843  try {
1844  parameter_num = self->gate->get_parameter_num();
1845  }
1846  catch (std::string err) {
1847  PyErr_SetString(PyExc_Exception, err.c_str());
1848  return NULL;
1849  }
1850  catch(...) {
1851  std::string err( "Invalid pointer to gate class");
1852  PyErr_SetString(PyExc_Exception, err.c_str());
1853  return NULL;
1854  }
1855 
1856 
1857  return Py_BuildValue("i", parameter_num);
1858 
1859 }
1860 
1861 
1862 
1867 static PyObject *
1869 
1870  int start_index;
1871 
1872  try {
1873  start_index = self->gate->get_parameter_start_idx();
1874  }
1875  catch (std::string err) {
1876  PyErr_SetString(PyExc_Exception, err.c_str());
1877  return NULL;
1878  }
1879  catch(...) {
1880  std::string err( "Invalid pointer to gate class");
1881  PyErr_SetString(PyExc_Exception, err.c_str());
1882  return NULL;
1883  }
1884 
1885  return Py_BuildValue("i", start_index);
1886 
1887 }
1888 
1889 
1890 
1891 
1896 static PyObject *
1898 
1899  int target_qbit;
1900 
1901  try {
1902  target_qbit = self->gate->get_target_qbit();
1903  }
1904  catch (std::string err) {
1905  PyErr_SetString(PyExc_Exception, err.c_str());
1906  return NULL;
1907  }
1908  catch(...) {
1909  std::string err( "Invalid pointer to gate class");
1910  PyErr_SetString(PyExc_Exception, err.c_str());
1911  return NULL;
1912  }
1913 
1914  return Py_BuildValue("i", target_qbit);
1915 
1916 }
1917 
1922 static PyObject *
1924 
1925  int control_qbit;
1926 
1927  try {
1928  control_qbit = self->gate->get_control_qbit();
1929  }
1930  catch (std::string err) {
1931  PyErr_SetString(PyExc_Exception, err.c_str());
1932  return NULL;
1933  }
1934  catch(...) {
1935  std::string err( "Invalid pointer to gate class");
1936  PyErr_SetString(PyExc_Exception, err.c_str());
1937  return NULL;
1938  }
1939 
1940  return Py_BuildValue("i", control_qbit);
1941 
1942 }
1943 
1947 static PyObject *
1949 
1950  int target_qbit_in = -1;
1951  if (!PyArg_ParseTuple(args, "|i", &target_qbit_in )) {
1952  std::string err( "Unable to parse arguments");
1953  return NULL;
1954  }
1955 
1956  try{
1957  self->gate->set_target_qbit(target_qbit_in);
1958  }
1959  catch (std::string err) {
1960  PyErr_SetString(PyExc_Exception, err.c_str());
1961  return NULL;
1962  }
1963  catch(...) {
1964  std::string err( "Invalid pointer to circuit class");
1965  PyErr_SetString(PyExc_Exception, err.c_str());
1966  return NULL;
1967  }
1968 
1969 
1970  return Py_BuildValue("i", 0);
1971 
1972 }
1973 
1977 static PyObject *
1979 
1980  int control_qbit_in = -1;
1981  if (!PyArg_ParseTuple(args, "|i", &control_qbit_in )) {
1982  std::string err( "Unable to parse arguments");
1983  return NULL;
1984  }
1985 
1986  try{
1987  self->gate->set_control_qbit(control_qbit_in);
1988  }
1989  catch (std::string err) {
1990  PyErr_SetString(PyExc_Exception, err.c_str());
1991  return NULL;
1992  }
1993  catch(...) {
1994  std::string err( "Invalid pointer to circuit class");
1995  PyErr_SetString(PyExc_Exception, err.c_str());
1996  return NULL;
1997  }
1998 
1999 
2000 
2001  return Py_BuildValue("i", 0);
2002 
2003 }
2004 
2005 
2010 static PyObject *
2012 
2013  std::vector<int> target_qbits;
2014 
2015  try {
2016  target_qbits = self->gate->get_target_qbits();
2017  }
2018  catch (std::string err) {
2019  PyErr_SetString(PyExc_Exception, err.c_str());
2020  return NULL;
2021  }
2022  catch(...) {
2023  std::string err( "Invalid pointer to gate class");
2024  PyErr_SetString(PyExc_Exception, err.c_str());
2025  return NULL;
2026  }
2027 
2028  PyObject* target_qbits_py = PyList_New((Py_ssize_t)target_qbits.size());
2029  for (size_t i = 0; i < target_qbits.size(); i++) {
2030  PyList_SetItem(target_qbits_py, (Py_ssize_t)i, Py_BuildValue("i", target_qbits[i]));
2031  }
2032 
2033  return target_qbits_py;
2034 
2035 }
2036 
2041 static PyObject *
2043 
2044  std::vector<int> control_qbits;
2045 
2046  try {
2047  control_qbits = self->gate->get_control_qbits();
2048  }
2049  catch (std::string err) {
2050  PyErr_SetString(PyExc_Exception, err.c_str());
2051  return NULL;
2052  }
2053  catch(...) {
2054  std::string err( "Invalid pointer to gate class");
2055  PyErr_SetString(PyExc_Exception, err.c_str());
2056  return NULL;
2057  }
2058 
2059  PyObject* control_qbits_py = PyList_New((Py_ssize_t)control_qbits.size());
2060  for (size_t i = 0; i < control_qbits.size(); i++) {
2061  PyList_SetItem(control_qbits_py, (Py_ssize_t)i, Py_BuildValue("i", control_qbits[i]));
2062  }
2063 
2064  return control_qbits_py;
2065 
2066 }
2067 
2071 static PyObject *
2073 
2074  PyObject* target_qbits_py = NULL;
2075  if (!PyArg_ParseTuple(args, "O", &target_qbits_py)) {
2076  std::string err( "Unable to parse arguments");
2077  PyErr_SetString(PyExc_Exception, err.c_str());
2078  return NULL;
2079  }
2080 
2081  if (!PyList_Check(target_qbits_py)) {
2082  PyErr_SetString(PyExc_TypeError, "target_qbits must be a list!");
2083  return NULL;
2084  }
2085 
2086  std::vector<int> target_qbits;
2087  Py_ssize_t list_size = PyList_Size(target_qbits_py);
2088  for (Py_ssize_t i = 0; i < list_size; i++) {
2089  PyObject* item = PyList_GetItem(target_qbits_py, i);
2090  if (!PyLong_Check(item)) {
2091  PyErr_SetString(PyExc_TypeError, "target_qbits must contain integers!");
2092  return NULL;
2093  }
2094  target_qbits.push_back(PyLong_AsLong(item));
2095  }
2096 
2097  try{
2098  self->gate->set_target_qbits(target_qbits);
2099  }
2100  catch (std::string err) {
2101  PyErr_SetString(PyExc_Exception, err.c_str());
2102  return NULL;
2103  }
2104  catch(...) {
2105  std::string err( "Invalid pointer to gate class");
2106  PyErr_SetString(PyExc_Exception, err.c_str());
2107  return NULL;
2108  }
2109 
2110  return Py_BuildValue("i", 0);
2111 
2112 }
2113 
2117 static PyObject *
2119 
2120  PyObject* control_qbits_py = NULL;
2121  if (!PyArg_ParseTuple(args, "O", &control_qbits_py)) {
2122  std::string err( "Unable to parse arguments");
2123  PyErr_SetString(PyExc_Exception, err.c_str());
2124  return NULL;
2125  }
2126 
2127  if (!PyList_Check(control_qbits_py)) {
2128  PyErr_SetString(PyExc_TypeError, "control_qbits must be a list!");
2129  return NULL;
2130  }
2131 
2132  std::vector<int> control_qbits;
2133  Py_ssize_t list_size = PyList_Size(control_qbits_py);
2134  for (Py_ssize_t i = 0; i < list_size; i++) {
2135  PyObject* item = PyList_GetItem(control_qbits_py, i);
2136  if (!PyLong_Check(item)) {
2137  PyErr_SetString(PyExc_TypeError, "control_qbits must contain integers!");
2138  return NULL;
2139  }
2140  control_qbits.push_back(PyLong_AsLong(item));
2141  }
2142 
2143  try{
2144  self->gate->set_control_qbits(control_qbits);
2145  }
2146  catch (std::string err) {
2147  PyErr_SetString(PyExc_Exception, err.c_str());
2148  return NULL;
2149  }
2150  catch(...) {
2151  std::string err( "Invalid pointer to gate class");
2152  PyErr_SetString(PyExc_Exception, err.c_str());
2153  return NULL;
2154  }
2155 
2156  return Py_BuildValue("i", 0);
2157 
2158 }
2159 
2164 static PyObject *
2166 
2167  std::vector<int> involved_qbits;
2168 
2169  try {
2170  involved_qbits = self->gate->get_involved_qubits();
2171  }
2172  catch (std::string err) {
2173  PyErr_SetString(PyExc_Exception, err.c_str());
2174  return NULL;
2175  }
2176  catch(...) {
2177  std::string err( "Invalid pointer to gate class");
2178  PyErr_SetString(PyExc_Exception, err.c_str());
2179  return NULL;
2180  }
2181 
2182  PyObject* involved_qbits_py = PyList_New((Py_ssize_t)involved_qbits.size());
2183  for (size_t i = 0; i < involved_qbits.size(); i++) {
2184  PyList_SetItem(involved_qbits_py, (Py_ssize_t)i, Py_BuildValue("i", involved_qbits[i]));
2185  }
2186 
2187  return involved_qbits_py;
2188 
2189 }
2190 
2191 
2196 static PyObject *
2198 
2199  PyArrayObject * parameters_arr = NULL;
2200 
2201 
2202  // parsing input arguments
2203  if (!PyArg_ParseTuple(args, "O", &parameters_arr )) {
2204  PyErr_SetString(PyExc_ValueError, "Unable to parse arguments");
2205  return NULL;
2206  }
2207 
2208  if( parameters_arr == NULL ) {
2209  PyErr_SetString(PyExc_ValueError, "Missing input parameter array");
2210  return NULL;
2211  }
2212 
2213  if (PyArray_TYPE(parameters_arr) != NPY_DOUBLE) {
2214  PyErr_SetString(PyExc_TypeError, "Parameter array must contain double values");
2215  return NULL;
2216  }
2217 
2218  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
2219  Py_INCREF(parameters_arr);
2220  }
2221  else {
2222  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
2223  }
2224 
2225  if (parameters_arr == NULL) {
2226  PyErr_SetString(PyExc_TypeError, "Failed to cast parameter array to contiguous double format");
2227  return NULL;
2228  }
2229 
2230  // get the C++ wrapper around the data
2231  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
2232 
2233  Matrix_real extracted_parameters;
2234 
2235  try {
2236  extracted_parameters = self->gate->extract_parameters( parameters_mtx );
2237  }
2238  catch (std::string err) {
2239  Py_DECREF(parameters_arr);
2240  PyErr_SetString(PyExc_Exception, err.c_str());
2241  return NULL;
2242  }
2243  catch(...) {
2244  Py_DECREF(parameters_arr);
2245  std::string err( "Invalid pointer to circuit class");
2246  PyErr_SetString(PyExc_Exception, err.c_str());
2247  return NULL;
2248  }
2249 
2250 
2251  // convert to numpy array
2252  extracted_parameters.set_owner(false);
2253  PyObject *extracted_parameters_py = matrix_real_to_numpy( extracted_parameters );
2254  if (extracted_parameters_py == NULL) {
2255  Py_DECREF(parameters_arr);
2256  return NULL;
2257  }
2258 
2259  // flatten the extracted array
2260  npy_intp param_num = (npy_intp)extracted_parameters.size();
2261  PyArray_Dims new_shape;
2262  new_shape.ptr = &param_num;
2263  new_shape.len = 1;
2264 
2265  PyObject *extracted_parameters_py_flatten = PyArray_Newshape( (PyArrayObject*)extracted_parameters_py, &new_shape, NPY_CORDER);
2266  Py_DECREF(extracted_parameters_py);
2267  if (extracted_parameters_py_flatten == NULL) {
2268  Py_DECREF(parameters_arr);
2269  return NULL;
2270  }
2271 
2272  Py_DECREF(parameters_arr);
2273  return extracted_parameters_py_flatten;
2274 }
2275 
2276 
2277 
2278 
2283 static PyObject *
2285 
2286  std::string name;
2287  try {
2288  name = self->gate->get_name();
2289  }
2290  catch (std::string err) {
2291  PyErr_SetString(PyExc_Exception, err.c_str());
2292  return NULL;
2293  }
2294  catch(...) {
2295  std::string err( "Invalid pointer to circuit class");
2296  PyErr_SetString(PyExc_Exception, err.c_str());
2297  return NULL;
2298  }
2299 
2300  return PyUnicode_FromString(name.c_str());
2301 }
2302 
2303 
2304 
2308 static PyObject *
2310 
2311  PyObject* gate_state = PyDict_New();
2312 
2313  if( gate_state == NULL ) {
2314  std::string err( "Failed to create dictionary");
2315  PyErr_SetString(PyExc_Exception, err.c_str());
2316  return NULL;
2317  }
2318 
2319 
2320  PyObject* val = Py_BuildValue("i", self->gate->get_type() );
2321  if (val == NULL || PyDict_SetItemString(gate_state, "type", val) != 0) {
2322  Py_XDECREF(val);
2323  Py_DECREF(gate_state);
2324  return NULL;
2325  }
2326  Py_DECREF(val);
2327 
2328  val = Py_BuildValue("i", self->gate->get_qbit_num() );
2329  if (val == NULL || PyDict_SetItemString(gate_state, "qbit_num", val) != 0) {
2330  Py_XDECREF(val);
2331  Py_DECREF(gate_state);
2332  return NULL;
2333  }
2334  Py_DECREF(val);
2335 
2336  val = Py_BuildValue("i", self->gate->get_target_qbit() );
2337  if (val == NULL || PyDict_SetItemString(gate_state, "target_qbit", val) != 0) {
2338  Py_XDECREF(val);
2339  Py_DECREF(gate_state);
2340  return NULL;
2341  }
2342  Py_DECREF(val);
2343 
2344  val = Py_BuildValue("i", self->gate->get_control_qbit() );
2345  if (val == NULL || PyDict_SetItemString(gate_state, "control_qbit", val) != 0) {
2346  Py_XDECREF(val);
2347  Py_DECREF(gate_state);
2348  return NULL;
2349  }
2350  Py_DECREF(val);
2351 
2352  // Serialize target_qbits vector
2353  std::vector<int> target_qbits = self->gate->get_target_qbits();
2354  PyObject* target_qbits_py = PyList_New((Py_ssize_t)target_qbits.size());
2355  if (target_qbits_py == NULL) {
2356  Py_DECREF(gate_state);
2357  return NULL;
2358  }
2359  for (size_t i = 0; i < target_qbits.size(); i++) {
2360  PyObject* item = Py_BuildValue("i", target_qbits[i]);
2361  if (item == NULL || PyList_SetItem(target_qbits_py, (Py_ssize_t)i, item) != 0) {
2362  Py_XDECREF(item);
2363  Py_DECREF(target_qbits_py);
2364  Py_DECREF(gate_state);
2365  return NULL;
2366  }
2367  }
2368  if (PyDict_SetItemString(gate_state, "target_qbits", target_qbits_py) != 0) {
2369  Py_DECREF(target_qbits_py);
2370  Py_DECREF(gate_state);
2371  return NULL;
2372  }
2373  Py_DECREF(target_qbits_py);
2374 
2375  // Serialize control_qbits vector
2376  std::vector<int> control_qbits = self->gate->get_control_qbits();
2377  PyObject* control_qbits_py = PyList_New((Py_ssize_t)control_qbits.size());
2378  if (control_qbits_py == NULL) {
2379  Py_DECREF(gate_state);
2380  return NULL;
2381  }
2382  for (size_t i = 0; i < control_qbits.size(); i++) {
2383  PyObject* item = Py_BuildValue("i", control_qbits[i]);
2384  if (item == NULL || PyList_SetItem(control_qbits_py, (Py_ssize_t)i, item) != 0) {
2385  Py_XDECREF(item);
2386  Py_DECREF(control_qbits_py);
2387  Py_DECREF(gate_state);
2388  return NULL;
2389  }
2390  }
2391  if (PyDict_SetItemString(gate_state, "control_qbits", control_qbits_py) != 0) {
2392  Py_DECREF(control_qbits_py);
2393  Py_DECREF(gate_state);
2394  return NULL;
2395  }
2396  Py_DECREF(control_qbits_py);
2397 
2398  if (self->gate->get_type() == GENERAL_OPERATION) {
2399  try {
2400  Matrix gate_mtx = self->gate->get_matrix();
2401  gate_mtx.set_owner(false);
2402  PyObject* gate_mtx_py = matrix_to_numpy(gate_mtx);
2403  if (gate_mtx_py == NULL) {
2404  Py_DECREF(gate_state);
2405  return NULL;
2406  }
2407  if (PyDict_SetItemString(gate_state, "matrix", gate_mtx_py) != 0) {
2408  Py_DECREF(gate_mtx_py);
2409  Py_DECREF(gate_state);
2410  return NULL;
2411  }
2412  Py_DECREF(gate_mtx_py);
2413  }
2414  catch (std::string err) {
2415  PyErr_SetString(PyExc_Exception, err.c_str());
2416  Py_DECREF(gate_state);
2417  return NULL;
2418  }
2419  catch (...) {
2420  PyErr_SetString(PyExc_Exception, "Failed to serialize GENERAL_OPERATION matrix");
2421  Py_DECREF(gate_state);
2422  return NULL;
2423  }
2424  }
2425 
2426  return gate_state;
2427 
2428 }
2429 
2430 
2431 
2432 
2433 
2437 static PyObject *
2439 
2440 
2441  PyObject* gate_state = NULL;
2442 
2443 
2444  // parsing input arguments
2445  if (!PyArg_ParseTuple(args, "O", &gate_state )) {
2446  PyErr_SetString(PyExc_ValueError, "Unable to parse arguments");
2447  return NULL;
2448  }
2449 
2450  if( !PyDict_Check( gate_state ) ) {
2451  std::string err( "Gate state should be given by a dictionary");
2452  PyErr_SetString(PyExc_Exception, err.c_str());
2453  return NULL;
2454  }
2455 
2456  PyObject* qbit_num_key = Py_BuildValue( "s", "qbit_num" );
2457  if ( PyDict_Contains(gate_state, qbit_num_key) == 0 ) {
2458  std::string err( "Gate state should contain the number of qubits");
2459  PyErr_SetString(PyExc_Exception, err.c_str());
2460 
2461  Py_DECREF( qbit_num_key );
2462  return NULL;
2463  }
2464  PyObject* qbit_num_py = PyDict_GetItem(gate_state, qbit_num_key); // borrowed reference
2465  Py_DECREF( qbit_num_key );
2466 
2467 
2468  PyObject* target_qbit_key = Py_BuildValue( "s", "target_qbit" );
2469  if ( PyDict_Contains(gate_state, target_qbit_key) == 0 ) {
2470  std::string err( "Gate state should contain a target qubit");
2471  PyErr_SetString(PyExc_Exception, err.c_str());
2472 
2473  Py_DECREF( target_qbit_key );
2474  return NULL;
2475  }
2476  PyObject* target_qbit_py = PyDict_GetItem(gate_state, target_qbit_key); // borrowed reference
2477  Py_DECREF( target_qbit_key );
2478 
2479 
2480  PyObject* control_qbit_key = Py_BuildValue( "s", "control_qbit" );
2481  if ( PyDict_Contains(gate_state, control_qbit_key) == 0 ) {
2482  std::string err( "Gate state should contain a control qubit (-1 for gates with no control qubits)");
2483  PyErr_SetString(PyExc_Exception, err.c_str());
2484 
2485  Py_DECREF( control_qbit_key );
2486  return NULL;
2487  }
2488  PyObject* control_qbit_py = PyDict_GetItem(gate_state, control_qbit_key); // borrowed reference
2489  Py_DECREF( control_qbit_key );
2490 
2491 
2492 
2493 
2494 
2495  PyObject* type_key = Py_BuildValue( "s", "type" );
2496  if ( PyDict_Contains(gate_state, type_key) == 0 ) {
2497  std::string err( "Gate state should contain a type ID (see gate.h for the gate type IDs)");
2498  PyErr_SetString(PyExc_Exception, err.c_str());
2499 
2500  Py_DECREF( type_key );
2501  return NULL;
2502  }
2503  PyObject* type_py = PyDict_GetItem(gate_state, type_key); // borrowed reference
2504  Py_DECREF( type_key );
2505 
2506 
2507 
2508  int qbit_num = (int)PyLong_AsLong( qbit_num_py );
2509  int target_qbit = (int)PyLong_AsLong( target_qbit_py );
2510  int control_qbit = (int)PyLong_AsLong( control_qbit_py );
2511  int gate_type = (int)PyLong_AsLong( type_py );
2512 
2513  // Extract target_qbits vector if present
2514  std::vector<int> target_qbits;
2515  PyObject* target_qbits_key = Py_BuildValue( "s", "target_qbits" );
2516  if ( PyDict_Contains(gate_state, target_qbits_key) == 1 ) {
2517  PyObject* target_qbits_py = PyDict_GetItem(gate_state, target_qbits_key); // borrowed reference
2518  if (PyList_Check(target_qbits_py)) {
2519  Py_ssize_t list_size = PyList_Size(target_qbits_py);
2520  for (Py_ssize_t i = 0; i < list_size; i++) {
2521  PyObject* item = PyList_GetItem(target_qbits_py, i);
2522  if (PyLong_Check(item)) {
2523  target_qbits.push_back(PyLong_AsLong(item));
2524  }
2525  }
2526  }
2527  }
2528  Py_DECREF( target_qbits_key );
2529 
2530  // Extract control_qbits vector if present
2531  std::vector<int> control_qbits;
2532  PyObject* control_qbits_key = Py_BuildValue( "s", "control_qbits" );
2533  if ( PyDict_Contains(gate_state, control_qbits_key) == 1 ) {
2534  PyObject* control_qbits_py = PyDict_GetItem(gate_state, control_qbits_key); // borrowed reference
2535  if (PyList_Check(control_qbits_py)) {
2536  Py_ssize_t list_size = PyList_Size(control_qbits_py);
2537  for (Py_ssize_t i = 0; i < list_size; i++) {
2538  PyObject* item = PyList_GetItem(control_qbits_py, i);
2539  if (PyLong_Check(item)) {
2540  control_qbits.push_back(PyLong_AsLong(item));
2541  }
2542  }
2543  }
2544  }
2545  Py_DECREF( control_qbits_key );
2546 
2547  Gate* gate = NULL;
2548 
2549  switch (gate_type) {
2550  case CNOT_OPERATION: {
2551  gate = create_controlled_gate<CNOT>( qbit_num, target_qbit, control_qbit );
2552  break;
2553  }
2554  case CZ_OPERATION:
2555  {
2556  gate = create_controlled_gate<CZ>( qbit_num, target_qbit, control_qbit );
2557  break;
2558  }
2559  case CH_OPERATION: {
2560  gate = create_controlled_gate<CH>( qbit_num, target_qbit, control_qbit );
2561  break;
2562  }
2563  case SYC_OPERATION: {
2564  gate = create_controlled_gate<SYC>( qbit_num, target_qbit, control_qbit );
2565  break;
2566  }
2567  case X_OPERATION: {
2568  gate = create_gate<X>( qbit_num, target_qbit );
2569  break;
2570  }
2571  case Y_OPERATION: {
2572  gate = create_gate<Y>( qbit_num, target_qbit );
2573  break;
2574  }
2575  case Z_OPERATION: {
2576  gate = create_gate<Z>( qbit_num, target_qbit );
2577  break;
2578  }
2579  case S_OPERATION: {
2580  gate = create_gate<S>( qbit_num, target_qbit );
2581  break;
2582  }
2583  case SDG_OPERATION: {
2584  gate = create_gate<SDG>( qbit_num, target_qbit );
2585  break;
2586  }
2587  case SX_OPERATION: {
2588  gate = create_gate<SX>( qbit_num, target_qbit );
2589  break;
2590  }
2591  case SXDG_OPERATION: {
2592  gate = create_gate<SXdg>( qbit_num, target_qbit );
2593  break;
2594  }
2595  case T_OPERATION: {
2596  gate = create_gate<T>( qbit_num, target_qbit );
2597  break;
2598  }
2599  case TDG_OPERATION: {
2600  gate = create_gate<Tdg>( qbit_num, target_qbit );
2601  break;
2602  }
2603  case H_OPERATION: {
2604  gate = create_gate<H>( qbit_num, target_qbit );
2605  break;
2606  }
2607  case U1_OPERATION: {
2608  gate = create_gate<U1>( qbit_num, target_qbit );
2609  break;
2610  }
2611  case U2_OPERATION: {
2612  gate = create_gate<U2>( qbit_num, target_qbit );
2613  break;
2614  }
2615  case U3_OPERATION: {
2616  gate = create_gate<U3>( qbit_num, target_qbit );
2617  break;
2618  }
2619  case CU_OPERATION: {
2620  gate = create_controlled_gate<CU>( qbit_num, target_qbit, control_qbit );
2621  break;
2622  }
2623  case R_OPERATION: {
2624  gate = create_gate<R>( qbit_num, target_qbit );
2625  break;
2626  }
2627  case RX_OPERATION: {
2628  gate = create_gate<RX>( qbit_num, target_qbit );
2629  break;
2630  }
2631  case RY_OPERATION: {
2632  gate = create_gate<RY>( qbit_num, target_qbit );
2633  break;
2634  }
2635  case CRX_OPERATION: {
2636  gate = create_controlled_gate<CRX>( qbit_num, target_qbit, control_qbit );
2637  break;
2638  }
2639  case CRZ_OPERATION: {
2640  gate = create_controlled_gate<CRZ>( qbit_num, target_qbit, control_qbit );
2641  break;
2642  }
2643  case CP_OPERATION: {
2644  gate = create_controlled_gate<CP>( qbit_num, target_qbit, control_qbit );
2645  break;
2646  }
2647  case CRY_OPERATION: {
2648  gate = create_controlled_gate<CRY>( qbit_num, target_qbit, control_qbit );
2649  break;
2650  }
2651  case CROT_OPERATION: {
2652  gate = create_controlled_gate<CROT>( qbit_num, target_qbit, control_qbit );
2653  break;
2654  }
2655  case CR_OPERATION: {
2656  gate = create_controlled_gate<CR>( qbit_num, target_qbit, control_qbit );
2657  break;
2658  }
2659  case RXX_OPERATION: {
2660  if (!target_qbits.empty()) {
2661  // Use vector-based constructor
2662  gate = create_multi_target_gate<RXX>( qbit_num, target_qbits );
2663  } else {
2664  // Legacy: convert old format (target_qbit, control_qbit) to vector format
2665  std::vector<int> swap_targets = {target_qbit, control_qbit};
2666  gate = create_multi_target_gate<RXX>( qbit_num, swap_targets );
2667  }
2668  break;
2669  }
2670  case RYY_OPERATION: {
2671  if (!target_qbits.empty()) {
2672  // Use vector-based constructor
2673  gate = create_multi_target_gate<RYY>( qbit_num, target_qbits );
2674  } else {
2675  // Legacy: convert old format (target_qbit, control_qbit) to vector format
2676  std::vector<int> swap_targets = {target_qbit, control_qbit};
2677  gate = create_multi_target_gate<RYY>( qbit_num, swap_targets );
2678  }
2679  break;
2680  }
2681  case RZZ_OPERATION: {
2682  if (!target_qbits.empty()) {
2683  // Use vector-based constructor
2684  gate = create_multi_target_gate<RZZ>( qbit_num, target_qbits );
2685  } else {
2686  // Legacy: convert old format (target_qbit, control_qbit) to vector format
2687  std::vector<int> swap_targets = {target_qbit, control_qbit};
2688  gate = create_multi_target_gate<RZZ>( qbit_num, swap_targets );
2689  }
2690  break;
2691  }
2692  case SWAP_OPERATION: {
2693  if (!target_qbits.empty()) {
2694  // Use vector-based constructor
2695  gate = create_multi_target_gate<SWAP>( qbit_num, target_qbits );
2696  } else {
2697  // Legacy: convert old format (target_qbit, control_qbit) to vector format
2698  std::vector<int> swap_targets = {target_qbit, control_qbit};
2699  gate = create_multi_target_gate<SWAP>( qbit_num, swap_targets );
2700  }
2701  break;
2702  }
2703  case CCX_OPERATION: {
2704  if (!control_qbits.empty()) {
2705  // Use vector-based constructor
2706  gate = create_multi_qubit_gate<CCX>( qbit_num, target_qbit, control_qbits );
2707  } else {
2708  std::string err( "CCX gate requires control_qbits vector");
2709  PyErr_SetString(PyExc_Exception, err.c_str());
2710  return NULL;
2711  }
2712  break;
2713  }
2714  case CSWAP_OPERATION: {
2715  if (!target_qbits.empty() && !control_qbits.empty()) {
2716  // Use vector-based constructor
2717  gate = create_multi_target_controlled_gate<CSWAP>( qbit_num, target_qbits, control_qbits );
2718  } else {
2719  std::string err( "CSWAP gate requires both target_qbits and control_qbits vectors");
2720  PyErr_SetString(PyExc_Exception, err.c_str());
2721  return NULL;
2722  }
2723  break;
2724  }
2725  case RZ_OPERATION: {
2726  gate = create_gate<RZ>( qbit_num, target_qbit );
2727  break;
2728  }
2729  case BLOCK_OPERATION: {
2730  std::string err( "Unsupported gate type: block operation");
2731  PyErr_SetString(PyExc_Exception, err.c_str());
2732  return NULL;
2733  }
2734  case GENERAL_OPERATION: {
2735  gate = new Gate(qbit_num);
2736 
2737  PyObject* matrix_key = Py_BuildValue("s", "matrix");
2738  if (PyDict_Contains(gate_state, matrix_key) == 0) {
2739  Py_DECREF(matrix_key);
2740  std::string err("GENERAL_OPERATION gate state should contain a matrix");
2741  PyErr_SetString(PyExc_Exception, err.c_str());
2742  delete gate;
2743  return NULL;
2744  }
2745 
2746  PyObject* matrix_obj = PyDict_GetItem(gate_state, matrix_key); // borrowed
2747  Py_DECREF(matrix_key);
2748 
2749  PyArrayObject* matrix_arr = (PyArrayObject*)PyArray_FROM_OTF(matrix_obj, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
2750  if (matrix_arr == NULL) {
2751  delete gate;
2752  return NULL;
2753  }
2754 
2755  Matrix gate_matrix = numpy2matrix(matrix_arr);
2756  gate->set_matrix(gate_matrix);
2757  Py_DECREF(matrix_arr);
2758 
2759  if (!target_qbits.empty()) {
2760  gate->set_target_qbits(target_qbits);
2761  } else if (target_qbit >= 0) {
2762  gate->set_target_qbit(target_qbit);
2763  }
2764 
2765  if (!control_qbits.empty()) {
2766  gate->set_control_qbits(control_qbits);
2767  } else if (control_qbit >= 0) {
2768  gate->set_control_qbit(control_qbit);
2769  }
2770 
2771  break;
2772  }
2773  default:
2774  std::string err( "Unsupported gate type");
2775  PyErr_SetString(PyExc_Exception, err.c_str());
2776  return NULL;
2777  }
2778  try {
2779  delete( self->gate );
2780  self->gate = gate;
2781  }
2782  catch (std::string err) {
2783  PyErr_SetString(PyExc_Exception, err.c_str());
2784  return NULL;
2785  }
2786  catch(...) {
2787  std::string err( "Invalid pointer to circuit class");
2788  PyErr_SetString(PyExc_Exception, err.c_str());
2789  return NULL;
2790  }
2791 
2792 
2793  return Py_BuildValue("");
2794 
2795 }
2796 
2797 extern "C"
2798 {
2799 
2803 #define GATE_WRAPPER_BASE_METHODS \
2804  {"get_Matrix", (PyCFunction) Gate_Wrapper_get_Matrix, METH_VARARGS | METH_KEYWORDS, \
2805  "Method to get the matrix representation of the gate." \
2806  }, \
2807  {"apply_to", (PyCFunction) Gate_Wrapper_Wrapper_apply_to, METH_VARARGS | METH_KEYWORDS, \
2808  "Call to apply the gate on an input state/matrix." \
2809  }, \
2810  {"apply_derivate_to", (PyCFunction) Gate_Wrapper_Wrapper_apply_derivate_to, METH_VARARGS | METH_KEYWORDS, \
2811  "Call to evaluate derivatives of the gate action on an input state/matrix." \
2812  }, \
2813  {"apply_to_combined", (PyCFunction) Gate_Wrapper_Wrapper_apply_to_combined, METH_VARARGS | METH_KEYWORDS, \
2814  "Call to evaluate forward gate action and all derivatives in one call." \
2815  }, \
2816  {"apply_from_right", (PyCFunction) Gate_Wrapper_Wrapper_apply_from_right, METH_VARARGS | METH_KEYWORDS, \
2817  "Call to apply the gate from right side on an input state/matrix." \
2818  }, \
2819  {"apply_to_list", (PyCFunction) Gate_Wrapper_Wrapper_apply_to_list, METH_VARARGS | METH_KEYWORDS, \
2820  "Call to apply the gate on a list of input states/matrices." \
2821  }, \
2822  {"get_Gate_Kernel", (PyCFunction) Gate_Wrapper_get_Gate_Kernel, METH_VARARGS | METH_KEYWORDS, \
2823  "Call to calculate the gate matrix acting on a single qbit space." \
2824  }, \
2825  {"get_Parameter_Num", (PyCFunction) Gate_Wrapper_get_Parameter_Num, METH_NOARGS, \
2826  "Call to get the number of free parameters in the gate." \
2827  }, \
2828  {"get_Parameter_Start_Index", (PyCFunction) Gate_Wrapper_get_Parameter_Start_Index, METH_NOARGS, \
2829  "Call to get the starting index of the parameters in the parameter array corresponding to the circuit in which the current gate is incorporated." \
2830  }, \
2831  {"get_Target_Qbit", (PyCFunction) Gate_Wrapper_get_Target_Qbit, METH_NOARGS, \
2832  "Call to get the target qbit." \
2833  }, \
2834  {"get_Control_Qbit", (PyCFunction) Gate_Wrapper_get_Control_Qbit, METH_NOARGS, \
2835  "Call to get the control qbit (returns with -1 if no control qbit is used in the gate)." \
2836  }, \
2837  {"get_Target_Qbits", (PyCFunction) Gate_Wrapper_get_Target_Qbits, METH_NOARGS, \
2838  "Call to get the target qubits as a list." \
2839  }, \
2840  {"get_Control_Qbits", (PyCFunction) Gate_Wrapper_get_Control_Qbits, METH_NOARGS, \
2841  "Call to get the control qubits as a list." \
2842  }, \
2843  {"set_Target_Qbit", (PyCFunction) Gate_Wrapper_set_Target_Qbit, METH_VARARGS, \
2844  "Call to set the target qubits from a list." \
2845  }, \
2846  {"set_Control_Qbit", (PyCFunction) Gate_Wrapper_set_Control_Qbit, METH_VARARGS, \
2847  "Call to set the control qubits from a list." \
2848  }, \
2849  {"set_Target_Qbits", (PyCFunction) Gate_Wrapper_set_Target_Qbits, METH_VARARGS, \
2850  "Call to set the target qubits from a list." \
2851  }, \
2852  {"set_Control_Qbits", (PyCFunction) Gate_Wrapper_set_Control_Qbits, METH_VARARGS, \
2853  "Call to set the control qubits from a list." \
2854  }, \
2855  {"get_Involved_Qbits", (PyCFunction) Gate_Wrapper_get_Involved_Qbits, METH_NOARGS, \
2856  "Call to get the target qubits as a list." \
2857  }, \
2858  {"Extract_Parameters", (PyCFunction) Gate_Wrapper_Extract_Parameters, METH_VARARGS, \
2859  "Call to extract the paramaters corresponding to the gate, from a parameter array associated to the circuit in which the gate is embedded." \
2860  }, \
2861  {"get_Name", (PyCFunction) Gate_Wrapper_get_Name, METH_NOARGS, \
2862  "Method to get the name label of the gate" \
2863  }
2864 
2865 static PyMethodDef Gate_Wrapper_methods[] = {
2867  ,
2868  {"__getstate__", (PyCFunction) Gate_Wrapper_getstate, METH_NOARGS,
2869  "Method to extract the stored quantum gate in a human-readable data serialized and pickle-able format"
2870  },
2871  {"__setstate__", (PyCFunction) Gate_Wrapper_setstate, METH_VARARGS,
2872  "Call to set the state of quantum gate from a human-readable data serialized and pickle-able format"
2873  },
2874  {NULL} /* Sentinel */
2875 };
2876 
2877 
2881 static PyMemberDef Gate_Wrapper_members[] = {
2882  {NULL} /* Sentinel */
2883 };
2884 
2885 
2887 
2888 
2890 
2891  //PyVarObject tt = { PyVarObject_HEAD_INIT(NULL, 0) };
2892 
2893  ob_base.ob_size = 0;
2894  tp_name = "Gate";
2895  tp_basicsize = sizeof(Gate_Wrapper);
2896  tp_dealloc = (destructor) Gate_Wrapper_dealloc;
2897  tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
2898  tp_doc = "Object to represent python binding for a generic base gate of the Squander package.";
2899  tp_methods = Gate_Wrapper_methods;
2900  tp_members = Gate_Wrapper_members;
2901  tp_init = (initproc) Gate_Wrapper_init;
2902  tp_new = generic_Gate_Wrapper_new;
2903  }
2904 
2905 
2906 };
2907 
2909 
2910 
2911 #define gate_wrapper_type_template(gate_name, wrapper_new) \
2912 struct gate_name##_Wrapper_Type : Gate_Wrapper_Type_tmp { \
2913  gate_name##_Wrapper_Type() { \
2914  tp_name = #gate_name; \
2915  tp_doc = "Object to represent python binding for a " #gate_name " gate of the Squander package."; \
2916  tp_new = (newfunc) wrapper_new< gate_name>; \
2917  tp_base = &Gate_Wrapper_Type; \
2918  } \
2919 }; \
2920 static gate_name##_Wrapper_Type gate_name##_Wrapper_Type_ins;
2921 
2922 
2923 
2926  tp_name = "SWAP";
2927  tp_doc = "Object to represent python binding for a SWAP gate of the Squander package.";
2928  tp_new = (newfunc) multi_target_gate_Wrapper_new<SWAP>;
2929  tp_base = &Gate_Wrapper_Type;
2930  }
2931 
2932 };
2934 
2937  tp_name = "RXX";
2938  tp_doc = "Object to represent python binding for a RXX gate of the Squander package.";
2939  tp_new = (newfunc) multi_target_gate_Wrapper_new<RXX>;
2940  tp_base = &Gate_Wrapper_Type;
2941  }
2942 
2943 };
2945 
2948  tp_name = "RYY";
2949  tp_doc = "Object to represent python binding for a RYY gate of the Squander package.";
2950  tp_new = (newfunc) multi_target_gate_Wrapper_new<RYY>;
2951  tp_base = &Gate_Wrapper_Type;
2952  }
2953 
2954 };
2956 
2959  tp_name = "RZZ";
2960  tp_doc = "Object to represent python binding for a RZZ gate of the Squander package.";
2961  tp_new = (newfunc) multi_target_gate_Wrapper_new<RZZ>;
2962  tp_base = &Gate_Wrapper_Type;
2963  }
2964 
2965 };
2967 
2968 
2971  tp_name = "CCX";
2972  tp_doc = "Object to represent python binding for a CCX gate of the Squander package.";
2973  tp_new = (newfunc) multi_control_gate_Wrapper_new<CCX>;
2974  tp_base = &Gate_Wrapper_Type;
2975  }
2976 
2977 };
2979 
2982  tp_name = "CSWAP";
2983  tp_doc = "Object to represent python binding for a CSWAP gate of the Squander package.";
2984  tp_new = (newfunc) multi_target_controlled_gate_Wrapper_new<CSWAP>;
2985  tp_base = &Gate_Wrapper_Type;
2986  }
2987 
2988 };
2990 
2992 
2994 
2996 
2998 
3000 
3002 
3004 
3006 
3008 
3010 
3012 
3014 
3016 
3018 
3020 
3022 
3024 
3026 
3028 
3030 
3032 
3034 
3036 
3038 
3040 
3042 
3044 
3046 
3047 
3048 
3049 
3051 
3052 
3053 
3054 
3058 static PyModuleDef gates_Wrapper_Module = {
3059  PyModuleDef_HEAD_INIT,
3060  "gates_Wrapper",
3061  "Python binding for gates implemented in Squander C++",
3062  -1,
3063 };
3064 
3065 #define Py_INCREF_template(gate_name) \
3066  Py_INCREF(&gate_name##_Wrapper_Type_ins); \
3067  if (PyModule_AddObject(m, #gate_name, (PyObject *) &gate_name##_Wrapper_Type_ins) < 0) { \
3068  Py_DECREF(&gate_name##_Wrapper_Type_ins); \
3069  Py_DECREF(m); \
3070  return NULL; \
3071  }
3072 
3076 PyMODINIT_FUNC
3078 {
3079 
3080  // initialize Numpy API
3081  import_array();
3082 
3083 
3084  PyObject * m= PyModule_Create(& gates_Wrapper_Module);
3085  if (m == NULL)
3086  return NULL;
3087 
3088 
3089  if (PyType_Ready(&Gate_Wrapper_Type) < 0 ||
3090  PyType_Ready(&CH_Wrapper_Type_ins) < 0 ||
3091  PyType_Ready(&CNOT_Wrapper_Type_ins) < 0 ||
3092  PyType_Ready(&CZ_Wrapper_Type_ins) < 0 ||
3093  PyType_Ready(&CRY_Wrapper_Type_ins) < 0 ||
3094  PyType_Ready(&CRX_Wrapper_Type_ins) < 0 ||
3095  PyType_Ready(&CRZ_Wrapper_Type_ins) < 0 ||
3096  PyType_Ready(&CP_Wrapper_Type_ins) < 0 ||
3097  PyType_Ready(&H_Wrapper_Type_ins) < 0 ||
3098  PyType_Ready(&RX_Wrapper_Type_ins) < 0 ||
3099  PyType_Ready(&RXX_Wrapper_Type_ins) < 0 ||
3100  PyType_Ready(&RYY_Wrapper_Type_ins) < 0 ||
3101  PyType_Ready(&RZZ_Wrapper_Type_ins) < 0 ||
3102  PyType_Ready(&RY_Wrapper_Type_ins) < 0 ||
3103  PyType_Ready(&RZ_Wrapper_Type_ins) < 0 ||
3104  PyType_Ready(&SX_Wrapper_Type_ins) < 0 ||
3105  PyType_Ready(&SXdg_Wrapper_Type_ins) < 0 ||
3106  PyType_Ready(&SYC_Wrapper_Type_ins) < 0 ||
3107  PyType_Ready(&U1_Wrapper_Type_ins) < 0 ||
3108  PyType_Ready(&U2_Wrapper_Type_ins) < 0 ||
3109  PyType_Ready(&U3_Wrapper_Type_ins) < 0 ||
3110  PyType_Ready(&CU_Wrapper_Type_ins) < 0 ||
3111  PyType_Ready(&X_Wrapper_Type_ins) < 0 ||
3112  PyType_Ready(&Y_Wrapper_Type_ins) < 0 ||
3113  PyType_Ready(&Z_Wrapper_Type_ins) < 0 ||
3114  PyType_Ready(&S_Wrapper_Type_ins) < 0 ||
3115  PyType_Ready(&SDG_Wrapper_Type_ins) < 0 ||
3116  PyType_Ready(&T_Wrapper_Type_ins) < 0 ||
3117  PyType_Ready(&Tdg_Wrapper_Type_ins) < 0 ||
3118  PyType_Ready(&CR_Wrapper_Type_ins) < 0 ||
3119  PyType_Ready(&CROT_Wrapper_Type_ins) < 0 ||
3120  PyType_Ready(&CCX_Wrapper_Type_ins) < 0 ||
3121  PyType_Ready(&SWAP_Wrapper_Type_ins) < 0 ||
3122  PyType_Ready(&CSWAP_Wrapper_Type_ins) < 0 ||
3123  PyType_Ready(&R_Wrapper_Type_ins) < 0 ) {
3124 
3125  Py_DECREF(m);
3126  return NULL;
3127  }
3128 
3129 
3130  Py_INCREF(&Gate_Wrapper_Type);
3131  if (PyModule_AddObject(m, "Gate", (PyObject *) & Gate_Wrapper_Type) < 0) {
3132  Py_DECREF(& Gate_Wrapper_Type);
3133  Py_DECREF(m);
3134  return NULL;
3135  }
3136 
3137 
3139 
3141 
3143 
3145 
3147 
3149 
3151 
3153 
3155 
3157 
3159 
3161 
3163 
3165 
3167 
3169 
3171 
3173 
3175 
3177 
3179 
3181 
3183 
3185 
3186  Py_INCREF(&SDG_Wrapper_Type_ins);
3187  if (PyModule_AddObject(m, "Sdg", (PyObject *) & SDG_Wrapper_Type_ins) < 0) {
3188  Py_DECREF(& SDG_Wrapper_Type_ins);
3189  Py_DECREF(m);
3190  return NULL;
3191  }
3192 
3193  Py_INCREF(&SXdg_Wrapper_Type_ins);
3194  if (PyModule_AddObject(m, "SXdg", (PyObject *) & SXdg_Wrapper_Type_ins) < 0) {
3195  Py_DECREF(& SXdg_Wrapper_Type_ins);
3196  Py_DECREF(m);
3197  return NULL;
3198  }
3199 
3201 
3202  Py_INCREF(&Tdg_Wrapper_Type_ins);
3203  if (PyModule_AddObject(m, "Tdg", (PyObject *) & Tdg_Wrapper_Type_ins) < 0) {
3204  Py_DECREF(& Tdg_Wrapper_Type_ins);
3205  Py_DECREF(m);
3206  return NULL;
3207  }
3208 
3210 
3212 
3214 
3216 
3218 
3220 
3221  return m;
3222 }
3223 
3224 
3225 
3226 }
static PyObject * Gate_Wrapper_set_Control_Qbit(Gate_Wrapper *self, PyObject *args)
Call to set the target qbit.
Copyright (C) Miklos Maroti, 2021 SPDX-License-Identifier: Apache-2.0.
Definition: U3.h:19
Definition: X.h:11
static PyObject * Gate_Wrapper_getstate(Gate_Wrapper *self)
Method to extract the stored quantum gate in a human-readable data serialized and pickle-able format...
Gate * create_multi_target_controlled_gate(int qbit_num, const std::vector< int > &target_qbits, const std::vector< int > &control_qbits)
Header file for a class representing a CSWAP (Controlled SWAP) operation.
static PyObject * Gate_Wrapper_set_Target_Qbits(Gate_Wrapper *self, PyObject *args)
Call to set the target qubits from a Python list.
A class representing a RXX gate.
Definition: RXX.h:34
Header file for a class representing a CP gate.
Gate * create_controlled_gate(int qbit_num, int target_qbit, int control_qbit)
parameter_num
[set adaptive gate structure]
static PyObject * multi_target_controlled_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Generic wrapper for multi-target controlled gates (e.g., CSWAP)
Header file for a class for the representation of general gate operations.
void set_control_qbits(const std::vector< int > &control_qbits_in)
Call to set the control qubits for the gate operation.
Definition: Gate.cpp:1097
Class to store single-precision real arrays and properties.
A class representing a CCX (Toffoli) operation.
Definition: CCX.h:35
Definition: U2.h:11
Header file for a class representing a controlled Z rotation gate.
#define GATE_WRAPPER_BASE_METHODS
Structure containing metadata about the methods of class qgd_U3.
PyMODINIT_FUNC PyInit_gates_Wrapper(void)
Method called when the Python module is initialized.
Definition: S.h:11
static PyObject * generic_Gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_CH_Wrapper is allocated.
Gate * create_multi_target_gate(int qbit_num, const std::vector< int > &target_qbits)
static PyObject * Gate_Wrapper_Wrapper_apply_to_combined(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Call to evaluate forward gate action and all derivatives in one call.
A class representing a controlled RX gate.
Definition: CRX.h:35
A class representing a CP gate.
Definition: CP.h:35
static PyObject * Gate_Wrapper_Wrapper_apply_to_list(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Call to apply the gate operation on a list of input states or matrices.
static PyObject * Gate_Wrapper_get_Involved_Qbits(Gate_Wrapper *self)
Call to get the target qubits vector.
static PyObject * Gate_Wrapper_get_Matrix(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Call te extract t he matric representation of the gate.
virtual std::vector< Matrix > apply_derivate_to(Matrix_real &parameters_mtx_in, Matrix &input, int parallel)
Call to evaluate the derivate of the circuit on an inout with respect to all of the free parameters...
Definition: Gate.cpp:784
static PyObject * Gate_Wrapper_Extract_Parameters(Gate_Wrapper *self, PyObject *args)
Call to extract the paramaters corresponding to the gate, from a parameter array associated to the ci...
int stride
The column stride of the array. (The array elements in one row are a_0, a_1, ... a_{cols-1}, 0, 0, 0, 0. The number of zeros is stride-cols)
Definition: matrix_base.hpp:46
Header file for a class representing a controlled rotation gate around the Y axis.
PyObject_HEAD Gate * gate
Pointer to the C++ class of the CH gate.
return Py_BuildValue("i", 0)
static PyModuleDef gates_Wrapper_Module
Structure containing metadata about the module.
Matrix_real numpy2matrix_real(PyArrayObject *arr)
Call to create a PIC matrix_real representation of a numpy array.
Structure type representing single-precision complex numbers.
Definition: QGDTypes.h:46
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 PyObject * Gate_Wrapper_get_Gate_Kernel(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Calculate the matrix of a U3 gate gate corresponding to the given parameters acting on a single qbit ...
Header file for a class representing a CH operation.
Header file for a class representing a controlled X rotation gate.
Header file for a class representing a SWAP operation.
static SWAP_Wrapper_Type SWAP_Wrapper_Type_ins
#define Py_INCREF_template(gate_name)
static PyObject * Gate_Wrapper_get_Parameter_Num(Gate_Wrapper *self)
Call to get the number of free parameters in the gate.
PyObject * matrix_real_to_numpy(Matrix_real &mtx)
Call to make a numpy array from an instance of matrix class.
Definition: Tdg.h:11
A class representing a SWAP operation.
Definition: SWAP.h:35
Definition: U1.h:11
U3 RX RZ H Y SX S T CNOT CH SYC CRZ PyObject PyObject * kwds
static PyObject * Gate_Wrapper_Wrapper_apply_derivate_to(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Call to evaluate derivatives of the gate action on an input state or matrix.
static PyObject * Gate_Wrapper_get_Parameter_Start_Index(Gate_Wrapper *self)
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
Matrix_real_float numpy2matrix_real_float(PyArrayObject *arr)
Call to create a PIC matrix_real_float representation of a numpy array.
Header file for a class representing a CCX (Toffoli) operation.
scalar * get_data() const
Call to get the pointer to the stored data.
static Matrix calc_one_qubit_u3(double ThetaOver2=0.0, double Phi=0.0, double Lambda=0.0)
Build a 2x2 U3 kernel from angles (theta/2, phi, lambda).
Definition: Gate.cpp:2650
static PyObject * Gate_Wrapper_set_Control_Qbits(Gate_Wrapper *self, PyObject *args)
Call to set the control qubits from a Python list.
static PyObject * controlled_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of a controlled gate class is initialized.
Class representing a RZZ gate.
static void matrix_owner_capsule_destruct(PyObject *cap)
Capsule destructor: calls delete on a heap-allocated Matrix, which correctly decrements the reference...
static void matrix_float_owner_capsule_destruct(PyObject *cap)
Capsule destructor for heap-allocated Matrix_float.
A class representing a RYY gate.
Definition: RYY.h:34
virtual Matrix get_matrix(Matrix_real &parameters, int parallel)
Call to retrieve the gate matrix.
Definition: Gate.cpp:269
static void Gate_Wrapper_dealloc(Gate_Wrapper *self)
Method called when a python instance of the class Gate_Wrapper is destroyed.
A class representing a CROT gate.
Definition: CROT.h:38
static PyObject * Gate_Wrapper_get_Target_Qbits(Gate_Wrapper *self)
Call to get the target qubits vector.
A class representing a CZ operation.
Definition: CZ.h:36
Header file for a class representing a CNOT operation.
static PyObject * Gate_Wrapper_get_Target_Qbit(Gate_Wrapper *self)
Call to get the target qbit.
Definition: Z.h:11
Definition: RZ.h:11
static PyObject * Gate_Wrapper_set_Target_Qbit(Gate_Wrapper *self, PyObject *args)
Call to set the target qbit.
A class representing a CRY gate.
Definition: CRY.h:37
virtual void apply_from_right(Matrix &input)
Call to apply the gate on the input array/matrix by input*Gate.
Definition: Gate.cpp:919
U3 RX RZ H Y SX S T CNOT CH SYC CRZ PyObject * args
int rows
The number of rows.
Definition: matrix_base.hpp:42
A class representing a CH operation.
Definition: CH.h:36
int cols
The number of columns.
Definition: matrix_base.hpp:44
Definition: CU.h:11
matrix_size
[load Umtx]
Definition: example.py:58
static PyObject * Gate_Wrapper_setstate(Gate_Wrapper *self, PyObject *args)
Call to set the state of quantum gate from a human-readable data serialized and pickle-able format...
static RZZ_Wrapper_Type RZZ_Wrapper_Type_ins
static PyObject * multi_control_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Generic wrapper for single-target multi-control gates (e.g., CCX)
static int Gate_Wrapper_init(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of a non-controlled gate class is initialized.
static Gate_Wrapper_Type_tmp Gate_Wrapper_Type
void set_control_qbit(int control_qbit_in)
Call to set the control qubit for the gate operation.
Definition: Gate.cpp:1054
Header file for a class representing a CZ operation.
static PyObject * qbit_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of a qbit-only gate class is initialized.
void set_target_qbit(int target_qbit_in)
Call to set the target qubit for the gate operation.
Definition: Gate.cpp:1076
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...
A class representing a RZZ gate.
Definition: RZZ.h:34
Structure type representing complex numbers in the SQUANDER package.
Definition: QGDTypes.h:38
A class representing a CNOT operation.
Definition: CNOT.h:35
void set_matrix(Matrix input)
Call to set the stored matrix in the operation.
Definition: Gate.cpp:1036
static PyObject * Gate_Wrapper_Wrapper_apply_to(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Call to apply the gate operation on an input state or matrix.
Double-precision complex matrix (float64).
Definition: matrix.h:38
Definition: H.h:11
Definition: Y.h:11
Definition: RY.h:11
int size() const
Call to get the number of the allocated elements.
#define gate_wrapper_type_template(gate_name, wrapper_new)
Gate * create_qbit_gate(int qbit_num)
Matrix_float numpy2matrix_float(PyArrayObject *arr)
Call to create a PIC matrix_float representation of a numpy array.
static PyObject * Gate_Wrapper_get_Name(Gate_Wrapper *self)
Extract the optimized parameters.
A class representing a controlled RZ gate.
Definition: CRZ.h:35
A class representing a CRY gate.
Definition: CR.h:37
virtual int get_parameter_num()
Call to get the number of free parameters.
Definition: Gate.cpp:1324
static PyObject * Gate_Wrapper_get_Control_Qbit(Gate_Wrapper *self)
Call to get the control qbit (returns with -1 if no control qbit is used in the gate) ...
Gate * create_gate(int qbit_num, int target_qbit)
virtual Matrix gate_kernel(const Matrix_real &precomputed_sincos)
Compute the gate kernel matrix from precomputed trigonometric values.
Definition: Gate.cpp:2546
Single-precision complex matrix (float32).
Definition: matrix_float.h:41
virtual std::vector< Matrix > apply_to_combined(Matrix_real &parameters_mtx_in, Matrix &input, int parallel)
Combined forward + derivative application with shared precomputed trig cache.
Definition: Gate.cpp:816
Definition: R.h:11
static RYY_Wrapper_Type RYY_Wrapper_Type_ins
Type definition of the Gate_Wrapper Python class of the gates module.
Base class for the representation of general gate operations.
Definition: Gate.h:86
Definition: SXdg.h:11
PyObject * matrix_float_to_numpy(Matrix_float &mtx)
Call to make a numpy array from an instance of matrix_float class.
void set_target_qbits(const std::vector< int > &target_qbits_in)
Call to set the target qubits for the gate operation.
Definition: Gate.cpp:1116
static PyMethodDef Gate_Wrapper_methods[]
Header file for a class representing a controlled rotation gate around the Y axis.
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a PIC matrix representation of a numpy array.
A class representing a SYC operation.
Definition: SYC.h:36
static PyObject * multi_target_gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Generic wrapper for multi-target gates without control (e.g., SWAP)
static PyMemberDef Gate_Wrapper_members[]
Structure containing metadata about the members of class qgd_CH_Wrapper.
Definition: SX.h:11
static PyObject * Gate_Wrapper_Wrapper_apply_from_right(Gate_Wrapper *self, PyObject *args, PyObject *kwds)
Call to apply the gate operation from the right side on an input state or matrix. ...
int get_qbit_num()
Call to get the number of qubits composing the unitary.
Definition: Gate.cpp:1342
gate_type
Type definition of operation types (also generalized for decomposition classes derived from the class...
Definition: Gate.h:39
Gate * create_multi_qubit_gate(int qbit_num, int target_qbit, const std::vector< int > &control_qbits)
Definition: T.h:11
Definition: RX.h:11
virtual void apply_to(Matrix &input, int parallel)
Call to apply the gate on the input array/matrix.
Definition: Gate.cpp:433
static CCX_Wrapper_Type CCX_Wrapper_Type_ins
static CSWAP_Wrapper_Type CSWAP_Wrapper_Type_ins
PyObject * matrix_to_numpy(Matrix &mtx)
Call to make a numpy array from an instance of matrix class.
Definition: SDG.h:11
static PyObject * Gate_Wrapper_get_Control_Qbits(Gate_Wrapper *self)
Call to get the control qubits vector.
static RXX_Wrapper_Type RXX_Wrapper_Type_ins
PyObject * target_qbits_py
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:41
static PyObject * Gate_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of a non-controlled gate class is initialized.
A class representing a CSWAP (Controlled SWAP) operation.
Definition: CSWAP.h:35
Class representing a RYY gate.
Header file for a class representing a Sycamore gate.