Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_Circuit_Wrapper.cpp
Go to the documentation of this file.
1 /*
2 Created on Fri Jun 26 14:42:56 2020
3 Copyright 2020 Peter Rakyta, Ph.D.
4 
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8 
9  http://www.apache.org/licenses/LICENSE-2.0
10 
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see http://www.gnu.org/licenses/.
19 
20 @author: Peter Rakyta, Ph.D.
21 */
22 /*
23 \file qgd_Operation_BLock.cpp
24 \brief Python interface for the Gates_block class
25 */
26 
27 #define PY_SSIZE_T_CLEAN
28 
29 #include <Python.h>
30 #include "structmember.h"
31 #include "Gates_block.h"
32 #include "CZ.h"
33 #include "CH.h"
34 #include "CNOT.h"
35 #include "U1.h"
36 #include "U2.h"
37 #include "U3.h"
38 #include "RX.h"
39 #include "R.h"
40 #include "RY.h"
41 #include "CRY.h"
42 #include "CROT.h"
43 #include "RZ.h"
44 #include "H.h"
45 #include "X.h"
46 #include "Y.h"
47 #include "Z.h"
48 #include "SX.h"
49 #include "SYC.h"
50 #include "UN.h"
51 #include "ON.h"
52 #include "Adaptive.h"
53 #include "Composite.h"
54 
55 #include "numpy_interface.h"
56 
57 #ifdef __DFE__
58 #include <numpy/arrayobject.h>
59 #include "numpy_interface.h"
60 #endif
61 
65 typedef struct {
66  PyObject_HEAD
70 
74 typedef struct {
75  PyObject_HEAD
78 } qgd_Gate;
79 
83 typedef struct qgd_Circuit_Wrapper {
84  PyObject_HEAD
88 
96  return new Gates_block(qbit_num);
97 }
98 
103 void
105  delete instance;
106  return;
107 }
108 
109 
110 
111 
112 
113 extern "C"
114 {
115 
120 static void
122 {
123 
124  // deallocate the instance of class N_Qubit_Decomposition
125  release_Circuit( self->circuit );
126 
127  Py_TYPE(self)->tp_free((PyObject *) self);
128 }
129 
134 static PyObject *
135 qgd_Circuit_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
136 {
137 
138  // The tuple of expected keywords
139  static char *kwlist[] = {(char*)"qbit_num", NULL};
140 
141  // initiate variables for input arguments
142  int qbit_num = 0;
143 
144  // parsing input arguments
145  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &qbit_num)) {
146  std::string err( "Unable to parse arguments");
147  PyErr_SetString(PyExc_Exception, err.c_str());
148  return NULL;
149  }
150 
151  qgd_Circuit_Wrapper *self;
152  self = (qgd_Circuit_Wrapper *) type->tp_alloc(type, 0);
153 
154  if (self != NULL) {
155  self->circuit = create_Circuit( qbit_num );
156  }
157 
158  return (PyObject *) self;
159 }
160 
161 
169 static int
170 qgd_Circuit_Wrapper_init(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
171 {
172  return 0;
173 }
174 
175 
179 static PyMemberDef qgd_Circuit_Wrapper_Members[] = {
180  {NULL} /* Sentinel */
181 };
182 
183 
184 
191 static PyObject *
192 qgd_Circuit_Wrapper_add_U1(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
193 {
194  // The tuple of expected keywords
195  static char *kwlist[] = {(char*)"target_qbit", NULL};
196 
197  // initiate variables for input arguments
198  int target_qbit = -1;
199 
200  // parsing input arguments
201  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
202  &target_qbit))
203  return Py_BuildValue("i", -1);
204 
205  // adding U1 gate to the end of the gate structure
206  if (target_qbit != -1 ) {
207  self->circuit->add_u1(target_qbit);
208  }
209 
210  return Py_BuildValue("i", 0);
211 }
212 
213 
214 
221 static PyObject *
222 qgd_Circuit_Wrapper_add_U2(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
223 {
224  // The tuple of expected keywords
225  static char *kwlist[] = {(char*)"target_qbit", NULL};
226 
227  // initiate variables for input arguments
228  int target_qbit = -1;
229 
230  // parsing input arguments
231  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
232  &target_qbit))
233  return Py_BuildValue("i", -1);
234 
235  // adding U2 gate to the end of the gate structure
236  if (target_qbit != -1 ) {
237  self->circuit->add_u2(target_qbit);
238  }
239 
240  return Py_BuildValue("i", 0);
241 }
242 
243 
244 
251 static PyObject *
252 qgd_Circuit_Wrapper_add_U3(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
253 {
254 
255  // The tuple of expected keywords
256  static char *kwlist[] = {(char*)"target_qbit", NULL};
257 
258  // initiate variables for input arguments
259  int target_qbit = -1;
260 
261  // parsing input arguments
262  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
263  &target_qbit))
264  return Py_BuildValue("i", -1);
265 
266  // adding U3 gate to the end of the gate structure
267  if (target_qbit != -1 ) {
268  self->circuit->add_u3(target_qbit);
269  }
270 
271  return Py_BuildValue("i", 0);
272 }
273 
274 
275 
282 static PyObject *
283 qgd_Circuit_Wrapper_add_RX(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
284 {
285 
286  // The tuple of expected keywords
287  static char *kwlist[] = {(char*)"target_qbit", NULL};
288 
289  // initiate variables for input arguments
290  int target_qbit = -1;
291 
292  // parsing input arguments
293  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
294  &target_qbit))
295  return Py_BuildValue("i", -1);
296 
297  // adding U3 gate to the end of the gate structure
298  if (target_qbit != -1 ) {
299  self->circuit->add_rx(target_qbit);
300  }
301 
302  return Py_BuildValue("i", 0);
303 
304 }
305 
306 
307 
314 static PyObject *
315 qgd_Circuit_Wrapper_add_R(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
316 {
317 
318  // The tuple of expected keywords
319  static char *kwlist[] = {(char*)"target_qbit", NULL};
320 
321  // initiate variables for input arguments
322  int target_qbit = -1;
323 
324  // parsing input arguments
325  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
326  &target_qbit))
327  return Py_BuildValue("i", -1);
328 
329  // adding U3 gate to the end of the gate structure
330  if (target_qbit != -1 ) {
331  self->circuit->add_r(target_qbit);
332  }
333 
334  return Py_BuildValue("i", 0);
335 
336 }
337 
338 
339 
346 static PyObject *
347 qgd_Circuit_Wrapper_add_RY(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
348 {
349 
350  // The tuple of expected keywords
351  static char *kwlist[] = {(char*)"target_qbit", NULL};
352 
353  // initiate variables for input arguments
354  int target_qbit = -1;
355 
356  // parsing input arguments
357  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
358  &target_qbit))
359  return Py_BuildValue("i", -1);
360 
361  // adding U3 gate to the end of the gate structure
362  if (target_qbit != -1 ) {
363  self->circuit->add_ry(target_qbit);
364  }
365 
366  return Py_BuildValue("i", 0);
367 
368 }
369 
370 
371 
378 static PyObject *
379 qgd_Circuit_Wrapper_add_RZ(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
380 {
381 
382  // The tuple of expected keywords
383  static char *kwlist[] = {(char*)"target_qbit", NULL};
384 
385  // initiate variables for input arguments
386  int target_qbit = -1;
387 
388  // parsing input arguments
389  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
390  &target_qbit))
391  return Py_BuildValue("i", -1);
392 
393  // adding U3 gate to the end of the gate structure
394  if (target_qbit != -1 ) {
395  self->circuit->add_rz(target_qbit);
396  }
397 
398  return Py_BuildValue("i", 0);
399 
400 }
401 
402 
403 
410 static PyObject *
411 qgd_Circuit_Wrapper_add_CNOT(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
412 {
413 
414  // The tuple of expected keywords
415  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
416 
417  // initiate variables for input arguments
418  int target_qbit = -1;
419  int control_qbit = -1;
420 
421  // parsing input arguments
422  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
423  &target_qbit, &control_qbit))
424  return Py_BuildValue("i", -1);
425 
426 
427  // adding CNOT gate to the end of the gate structure
428  if (target_qbit != -1 ) {
429  self->circuit->add_cnot(target_qbit, control_qbit);
430  }
431 
432  return Py_BuildValue("i", 0);
433 
434 }
435 
436 
437 
444 static PyObject *
445 qgd_Circuit_Wrapper_add_CZ(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
446 {
447 
448  // The tuple of expected keywords
449  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
450 
451  // initiate variables for input arguments
452  int target_qbit = -1;
453  int control_qbit = -1;
454 
455  // parsing input arguments
456  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
457  &target_qbit, &control_qbit))
458  return Py_BuildValue("i", -1);
459 
460 
461  // adding CZ gate to the end of the gate structure
462  if (target_qbit != -1 ) {
463  self->circuit->add_cz(target_qbit, control_qbit);
464  }
465 
466  return Py_BuildValue("i", 0);
467 
468 }
469 
470 
471 
478 static PyObject *
479 qgd_Circuit_Wrapper_add_CH(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
480 {
481 
482  // The tuple of expected keywords
483  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
484 
485  // initiate variables for input arguments
486  int target_qbit = -1;
487  int control_qbit = -1;
488 
489  // parsing input arguments
490  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
491  &target_qbit, &control_qbit))
492  return Py_BuildValue("i", -1);
493 
494 
495  // adding CZ gate to the end of the gate structure
496  if (target_qbit != -1 ) {
497  self->circuit->add_ch(target_qbit, control_qbit);
498  }
499 
500  return Py_BuildValue("i", 0);
501 
502 }
503 
504 
505 
512 static PyObject *
513 qgd_Circuit_Wrapper_add_SYC(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
514 {
515 
516  // The tuple of expected keywords
517  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
518 
519  // initiate variables for input arguments
520  int target_qbit = -1;
521  int control_qbit = -1;
522 
523  // parsing input arguments
524  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
525  &target_qbit, &control_qbit))
526  return Py_BuildValue("i", -1);
527 
528 
529  // adding Sycamore gate to the end of the gate structure
530  if (target_qbit != -1 ) {
531  self->circuit->add_syc(target_qbit, control_qbit);
532  }
533 
534  return Py_BuildValue("i", 0);
535 
536 }
537 
538 
539 
546 static PyObject *
547 qgd_Circuit_Wrapper_add_H(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
548 {
549 
550  // The tuple of expected keywords
551  static char *kwlist[] = {(char*)"target_qbit", NULL};
552 
553  // initiate variables for input arguments
554  int target_qbit = -1;
555 
556  // parsing input arguments
557  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
558  &target_qbit))
559  return Py_BuildValue("i", -1);
560 
561 
562  // adding X gate to the end of the gate structure
563  if (target_qbit != -1 ) {
564  self->circuit->add_h(target_qbit);
565  }
566 
567  return Py_BuildValue("i", 0);
568 
569 }
570 
571 
572 
579 static PyObject *
580 qgd_Circuit_Wrapper_add_X(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
581 {
582 
583  // The tuple of expected keywords
584  static char *kwlist[] = {(char*)"target_qbit", NULL};
585 
586  // initiate variables for input arguments
587  int target_qbit = -1;
588 
589  // parsing input arguments
590  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
591  &target_qbit))
592  return Py_BuildValue("i", -1);
593 
594 
595  // adding X gate to the end of the gate structure
596  if (target_qbit != -1 ) {
597  self->circuit->add_x(target_qbit);
598  }
599 
600  return Py_BuildValue("i", 0);
601 
602 }
603 
604 
605 
612 static PyObject *
613 qgd_Circuit_Wrapper_add_Y(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
614 {
615 
616  // The tuple of expected keywords
617  static char *kwlist[] = {(char*)"target_qbit", NULL};
618 
619  // initiate variables for input arguments
620  int target_qbit = -1;
621 
622  // parsing input arguments
623  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
624  &target_qbit))
625  return Py_BuildValue("i", -1);
626 
627 
628  // adding X gate to the end of the gate structure
629  if (target_qbit != -1 ) {
630  self->circuit->add_y(target_qbit);
631  }
632 
633  return Py_BuildValue("i", 0);
634 
635 }
636 
637 
638 
645 static PyObject *
646 qgd_Circuit_Wrapper_add_Z(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
647 {
648 
649  // The tuple of expected keywords
650  static char *kwlist[] = {(char*)"target_qbit", NULL};
651 
652  // initiate variables for input arguments
653  int target_qbit = -1;
654 
655  // parsing input arguments
656  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
657  &target_qbit))
658  return Py_BuildValue("i", -1);
659 
660 
661  // adding X gate to the end of the gate structure
662  if (target_qbit != -1 ) {
663  self->circuit->add_z(target_qbit);
664  }
665 
666  return Py_BuildValue("i", 0);
667 
668 }
669 
670 
671 
678 static PyObject *
679 qgd_Circuit_Wrapper_add_SX(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
680 {
681 
682  // The tuple of expected keywords
683  static char *kwlist[] = {(char*)"target_qbit", NULL};
684 
685  // initiate variables for input arguments
686  int target_qbit = -1;
687 
688  // parsing input arguments
689  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
690  &target_qbit))
691  return Py_BuildValue("i", -1);
692 
693 
694  // adding SX gate to the end of the gate structure
695  if (target_qbit != -1 ) {
696  self->circuit->add_sx(target_qbit);
697  }
698 
699  return Py_BuildValue("i", 0);
700 
701 }
702 
703 
704 
711 static PyObject *
712 qgd_Circuit_Wrapper_add_T(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
713 {
714 
715  // The tuple of expected keywords
716  static char *kwlist[] = {(char*)"target_qbit", NULL};
717 
718  // initiate variables for input arguments
719  int target_qbit = -1;
720 
721  // parsing input arguments
722  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
723  &target_qbit))
724  return Py_BuildValue("i", -1);
725 
726 
727  // adding T gate to the end of the gate structure
728  if (target_qbit != -1 ) {
729  self->circuit->add_t(target_qbit);
730  }
731 
732  return Py_BuildValue("i", 0);
733 
734 }
735 
736 
737 
744 static PyObject *
745 qgd_Circuit_Wrapper_add_Tdg(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
746 {
747 
748  // The tuple of expected keywords
749  static char *kwlist[] = {(char*)"target_qbit", NULL};
750 
751  // initiate variables for input arguments
752  int target_qbit = -1;
753 
754  // parsing input arguments
755  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
756  &target_qbit))
757  return Py_BuildValue("i", -1);
758 
759 
760  // adding Tdg gate to the end of the gate structure
761  if (target_qbit != -1 ) {
762  self->circuit->add_tdg(target_qbit);
763  }
764 
765  return Py_BuildValue("i", 0);
766 
767 }
768 
769 
770 
777 static PyObject *
778 qgd_Circuit_Wrapper_add_CRY(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
779 {
780 
781  // The tuple of expected keywords
782  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
783 
784  // initiate variables for input arguments
785  int target_qbit = -1;
786  int control_qbit = -1;
787 
788  // parsing input arguments
789  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
790  &target_qbit, &control_qbit))
791  return Py_BuildValue("i", -1);
792 
793  // adding U3 gate to the end of the gate structure
794  if (target_qbit != -1 ) {
795  self->circuit->add_cry(target_qbit, control_qbit);
796  }
797 
798  return Py_BuildValue("i", 0);
799 
800 }
801 
802 
809 static PyObject *
810 qgd_Circuit_Wrapper_add_CROT(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
811 {
812 
813  // The tuple of expected keywords
814  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit",(char*)"crot_type", NULL};
815 
816  // initiate variables for input arguments
817  int target_qbit = -1;
818  int control_qbit = -1;
819  PyObject* subtype_arg = NULL;
820  // parsing input arguments
821  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iiO", kwlist,
822  &target_qbit, &control_qbit,&subtype_arg))
823  return Py_BuildValue("i", -1);
824  PyObject* subtype_string = PyObject_Str(subtype_arg);
825  PyObject* subtype_string_unicode = PyUnicode_AsEncodedString(subtype_string, "utf-8", "~E~");
826  const char* subtype_C = PyBytes_AS_STRING(subtype_string_unicode);
827  crot_type qgd_subtype;
828  if ( strcmp("control_r", subtype_C) == 0 || strcmp("CONTROL_R", subtype_C) == 0) {
829  qgd_subtype = CONTROL_R;
830  }
831  else if ( strcmp("control_opposite", subtype_C)==0 || strcmp("CONTROL_OPPOSITE", subtype_C)==0) {
832  qgd_subtype = CONTROL_OPPOSITE;
833  }
834  else if ( strcmp("control_independent", subtype_C)==0 || strcmp("CONTROL_INDEPENDENT", subtype_C)==0) {
835  qgd_subtype = CONTROL_INDEPENDENT;
836  }
837  // adding U3 gate to the end of the gate structure
838  if (target_qbit != -1 ) {
839  self->circuit->add_crot(target_qbit, control_qbit,qgd_subtype);
840  }
841 
842  return Py_BuildValue("i", 0);
843 
844 }
845 
846 
847 
854 static PyObject *
855 qgd_Circuit_Wrapper_add_adaptive(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
856 {
857 
858  // The tuple of expected keywords
859  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
860 
861  // initiate variables for input arguments
862  int target_qbit = -1;
863  int control_qbit = -1;
864 
865  // parsing input arguments
866  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
867  &target_qbit, &control_qbit))
868  return Py_BuildValue("i", -1);
869 
870  // adding U3 gate to the end of the gate structure
871  if (target_qbit != -1 ) {
872  self->circuit->add_adaptive(target_qbit, control_qbit);
873  }
874 
875  return Py_BuildValue("i", 0);
876 
877 }
878 
879 
880 
887 static PyObject *
889 {
890 
891  // initiate variables for input arguments
892  PyObject *Py_Circuit;
893 
894  // parsing input arguments
895  if (!PyArg_ParseTuple(args, "|O",
896  &Py_Circuit))
897  return Py_BuildValue("i", -1);
898 
899 
900  qgd_Circuit_Wrapper* qgd_op_block = (qgd_Circuit_Wrapper*) Py_Circuit;
901 
902 
903  // adding general gate to the end of the gate structure
904  self->circuit->add_gate( static_cast<Gate*>( qgd_op_block->circuit->clone() ) );
905 
906  return Py_BuildValue("i", 0);
907 
908 }
909 
910 #ifdef __DFE__
911 
912 static PyObject*
913 DFEgateQGD_to_Python(DFEgate_kernel_type* DFEgates, int gatesNum)
914 {
915  PyObject* o = PyList_New(0);
916  for (int i = 0; i < gatesNum; i++) {
917  PyList_Append(o, Py_BuildValue("iiibbbb", DFEgates[i].ThetaOver2, DFEgates[i].Phi,
918  DFEgates[i].Lambda, DFEgates[i].target_qbit, DFEgates[i].control_qbit,
919  DFEgates[i].gate_type, DFEgates[i].metadata));
920  }
921  delete [] DFEgates;
922  return o;
923 }
924 
925 static DFEgate_kernel_type*
926 DFEgatePython_to_QGD(PyObject* obj)
927 {
928  Py_ssize_t gatesNum = PyList_Size(obj); //assert type is list
929  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gatesNum];
930  for (Py_ssize_t i = 0; i < gatesNum; i++) {
931  PyObject* t = PyList_GetItem(obj, i);
932  //assert type is tuple and PyTuple_Size(t) == 7
933  DFEgates[i].ThetaOver2 = PyLong_AsLong(PyTuple_GetItem(t, 0));
934  DFEgates[i].Phi = PyLong_AsLong(PyTuple_GetItem(t, 1));
935  DFEgates[i].Lambda = PyLong_AsLong(PyTuple_GetItem(t, 2));
936  DFEgates[i].target_qbit = PyLong_AsLong(PyTuple_GetItem(t, 3));
937  DFEgates[i].control_qbit = PyLong_AsLong(PyTuple_GetItem(t, 4));
938  DFEgates[i].gate_type = PyLong_AsLong(PyTuple_GetItem(t, 5));
939  DFEgates[i].metadata = PyLong_AsLong(PyTuple_GetItem(t, 6));
940  }
941  return DFEgates;
942 }
943 
944 static PyObject *
945 qgd_Circuit_Wrapper_convert_to_DFE_gates_with_derivates(qgd_Circuit_Wrapper *self, PyObject *args)
946 {
947  bool only_derivates = false;
948  PyArrayObject* parameters_mtx_np = NULL;
949 
950  if (!PyArg_ParseTuple(args, "|Ob",
951  &parameters_mtx_np, &only_derivates))
952  return Py_BuildValue("");
953 
954  if ( parameters_mtx_np == NULL ) {
955  return Py_BuildValue("");
956  }
957 
958  PyArrayObject* parameters_mtx = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)parameters_mtx_np, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
959 
960  // test C-style contiguous memory allocation of the array
961  if ( !PyArray_IS_C_CONTIGUOUS(parameters_mtx) ) {
962  std::cout << "parameters_mtx is not memory contiguous" << std::endl;
963  }
964 
965  // create QGD version of the parameters_mtx
966  Matrix_real parameters_mtx_mtx = numpy2matrix_real(parameters_mtx);
967 
968  int gatesNum = -1, gateSetNum = -1, redundantGateSets = -1;
969  DFEgate_kernel_type* ret = self->circuit->convert_to_DFE_gates_with_derivates(parameters_mtx_mtx, gatesNum, gateSetNum, redundantGateSets, only_derivates);
970  return Py_BuildValue("Oii", DFEgateQGD_to_Python(ret, gatesNum), gateSetNum, redundantGateSets);
971 }
972 
973 static PyObject *
974 qgd_Circuit_Wrapper_adjust_parameters_for_derivation(qgd_Circuit_Wrapper *self, PyObject *args)
975 {
976  int gatesNum = -1;
977  PyObject* dfegates = NULL;
978  if (!PyArg_ParseTuple(args, "|Oi",
979  &dfegates, &gatesNum))
980  return Py_BuildValue("");
981  int gate_idx = -1, gate_set_index = -1;
982  DFEgate_kernel_type* dfegates_qgd = DFEgatePython_to_QGD(dfegates);
983  self->circuit->adjust_parameters_for_derivation(dfegates_qgd, gatesNum, gate_idx, gate_set_index);
984  return Py_BuildValue("Oii", DFEgateQGD_to_Python(dfegates_qgd, gatesNum), gate_idx, gate_set_index);
985 }
986 
987 /*static PyObject *
988 qgd_Circuit_Wrapper_convert_to_DFE_gates(qgd_Circuit_Wrapper *self, PyObject *args)
989 {
990  PyObject* parameters_mtx_np = NULL;
991  if (!PyArg_ParseTuple(args, "|O",
992  &parameters_mtx_np))
993  return Py_BuildValue("");
994 
995  if ( parameters_mtx_np == NULL ) return Py_BuildValue("");
996  PyObject* parameters_mtx = PyArray_FROM_OTF(parameters_mtx_np, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
997 
998  // test C-style contiguous memory allocation of the array
999  if ( !PyArray_IS_C_CONTIGUOUS(parameters_mtx) ) {
1000  std::cout << "parameters_mtx is not memory contiguous" << std::endl;
1001  }
1002 
1003  // create QGD version of the parameters_mtx
1004  Matrix_real parameters_mtx_mtx = numpy2matrix_real(parameters_mtx);
1005 
1006  int gatesNum = -1;
1007  DFEgate_kernel_type* ret = self->circuit->convert_to_DFE_gates(parameters_mtx_mtx, gatesNum);
1008  return DFEgateQGD_to_Python(ret, gatesNum);
1009 }*/
1010 
1011 static PyObject *
1012 qgd_Circuit_Wrapper_convert_to_DFE_gates(qgd_Circuit_Wrapper *self, PyObject *args)
1013 {
1014  int start_index = -1;
1015  PyArrayObject* parameters_mtx_np = NULL;
1016  PyObject* dfegates = NULL;
1017 
1018  if (!PyArg_ParseTuple(args, "|OOi",
1019  &parameters_mtx_np, &dfegates, &start_index))
1020  return Py_BuildValue("");
1021 
1022 
1023  if ( parameters_mtx_np == NULL ) {
1024  return Py_BuildValue("");
1025  }
1026 
1027  PyArrayObject* parameters_mtx = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)parameters_mtx_np, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1028 
1029  // test C-style contiguous memory allocation of the array
1030  if ( !PyArray_IS_C_CONTIGUOUS(parameters_mtx) ) {
1031  std::cout << "parameters_mtx is not memory contiguous" << std::endl;
1032  }
1033 
1034  // create QGD version of the parameters_mtx
1035  Matrix_real parameters_mtx_mtx = numpy2matrix_real(parameters_mtx);
1036  DFEgate_kernel_type* dfegates_qgd = DFEgatePython_to_QGD(dfegates);
1037 
1038  Py_ssize_t gatesNum = PyList_Size(dfegates);
1039 
1040  self->circuit->convert_to_DFE_gates(parameters_mtx_mtx, dfegates_qgd, start_index);
1041 
1042  return DFEgateQGD_to_Python(dfegates_qgd, gatesNum);
1043 }
1044 
1045 #endif
1046 
1051 static PyObject *
1053 
1054  PyArrayObject * parameters_arr = NULL;
1055 
1056 
1057  // parsing input arguments
1058  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
1059  return Py_BuildValue("i", -1);
1060 
1061 
1062  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1063  Py_INCREF(parameters_arr);
1064  }
1065  else {
1066  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1067  }
1068 
1069 
1070  // get the C++ wrapper around the data
1071  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1072 
1073 
1074  Matrix mtx = self->circuit->get_matrix( parameters_mtx );
1075 
1076  // convert to numpy array
1077  mtx.set_owner(false);
1078  PyObject *mtx_py = matrix_to_numpy( mtx );
1079 
1080 
1081  Py_DECREF(parameters_arr);
1082 
1083  return mtx_py;
1084 }
1085 
1086 
1087 
1091 static PyObject *
1093 
1094  int parameter_num = self->circuit->get_parameter_num();
1095 
1096  return Py_BuildValue("i", parameter_num);
1097 }
1098 
1099 
1100 
1104 static PyObject *
1105 qgd_Circuit_Wrapper_apply_to( qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds ) {
1106 
1107  PyArrayObject * parameters_arr = NULL;
1108  PyArrayObject * unitary_arg = NULL;
1109 
1110  int parallel = 1;
1111 
1112  static char *kwlist[] = {(char*)"", (char*)"", (char*)"parallel", NULL};
1113 
1114 
1115  // parsing input arguments
1116  if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i", kwlist, &parameters_arr, &unitary_arg, &parallel )) {
1117  PyErr_SetString(PyExc_Exception, "Unable to parse input");
1118  return NULL;
1119  }
1120 
1121 
1122 
1123  if ( unitary_arg == NULL ) {
1124  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1125  return NULL;
1126  }
1127 
1128 
1129  if ( parameters_arr == NULL ) {
1130  PyErr_SetString(PyExc_Exception, "Parameters were not given");
1131  return NULL;
1132  }
1133 
1134 
1135 
1136  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
1137  PyErr_SetString(PyExc_Exception, "Parameter vector should be real typed");
1138  return NULL;
1139  }
1140 
1141 
1142  if ( PyArray_TYPE(unitary_arg) != NPY_COMPLEX128 ) {
1143  PyErr_SetString(PyExc_Exception, "input matrix or state should be complex typed");
1144  return NULL;
1145  }
1146 
1147 
1148  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1149  Py_INCREF(parameters_arr);
1150  }
1151  else {
1152  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1153  }
1154 
1155  // get the C++ wrapper around the data
1156  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1157 
1158 
1159 
1160  PyArrayObject* unitary = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)unitary_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1161 
1162  // test C-style contiguous memory allocation of the array
1163  if ( !PyArray_IS_C_CONTIGUOUS(unitary) ) {
1164  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
1165  return NULL;
1166  }
1167 
1168 
1169  // create QGD version of the input matrix
1170  Matrix unitary_mtx = numpy2matrix(unitary);
1171 
1172  try {
1173  self->circuit->apply_to( parameters_mtx, unitary_mtx, parallel );
1174  }
1175  catch (std::string err) {
1176 
1177  Py_DECREF(parameters_arr);
1178  Py_DECREF(unitary);
1179 
1180  PyErr_SetString(PyExc_Exception, err.c_str());
1181  return NULL;
1182  }
1183  catch(...) {
1184 
1185  Py_DECREF(parameters_arr);
1186  Py_DECREF(unitary);
1187 
1188  std::string err( "Invalid pointer to circuit class");
1189  PyErr_SetString(PyExc_Exception, err.c_str());
1190  return NULL;
1191  }
1192 
1193  if (unitary_mtx.data != PyArray_DATA(unitary)) {
1194  memcpy(PyArray_DATA(unitary), unitary_mtx.data, unitary_mtx.size() * sizeof(QGD_Complex16));
1195  }
1196 
1197  Py_DECREF(parameters_arr);
1198  Py_DECREF(unitary);
1199 
1200  return Py_BuildValue("i", 0);
1201 }
1202 
1203 
1204 
1208 static PyObject *
1210 {
1211 
1212 
1213  PyArrayObject * parameters_arr = NULL;
1214  PyArrayObject * input_state_arg = NULL;
1215  PyObject * qubit_list_arg = NULL;
1216 
1217 
1218  // parsing input arguments
1219  if (!PyArg_ParseTuple(args, "|OOO", &parameters_arr, &input_state_arg, &qubit_list_arg ))
1220  return Py_BuildValue("i", -1);
1221 
1222 
1223  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1224  Py_INCREF(parameters_arr);
1225  }
1226  else {
1227  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1228  }
1229 
1230  // get the C++ wrapper around the data
1231  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1232 
1233 
1234  // convert python object array to numpy C API array
1235  if ( input_state_arg == NULL ) {
1236  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1237  return NULL;
1238  }
1239 
1240  PyArrayObject* input_state = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)input_state_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1241 
1242  // test C-style contiguous memory allocation of the array
1243  if ( !PyArray_IS_C_CONTIGUOUS(input_state) ) {
1244  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
1245  return NULL;
1246  }
1247 
1248 
1249 
1250 
1251  // create QGD version of the input matrix
1252  Matrix input_state_mtx = numpy2matrix(input_state);
1253 
1254 
1255  // check input argument qbit_list
1256  if ( qubit_list_arg == NULL || (!PyList_Check( qubit_list_arg )) ) {
1257  PyErr_SetString(PyExc_Exception, "qubit_list should be a list");
1258  return NULL;
1259  }
1260 
1261  Py_ssize_t reduced_qbit_num = PyList_Size( qubit_list_arg );
1262 
1263  matrix_base<int> qbit_list_mtx( (int)reduced_qbit_num, 1);
1264  for ( int idx=0; idx<reduced_qbit_num; idx++ ) {
1265 
1266  PyObject* item = PyList_GET_ITEM( qubit_list_arg, idx );
1267  qbit_list_mtx[idx] = (int) PyLong_AsLong( item );
1268 
1269  }
1270 
1271 
1272  double entropy = -1;
1273 
1274 
1275  try {
1276  entropy = self->circuit->get_second_Renyi_entropy( parameters_mtx, input_state_mtx, qbit_list_mtx );
1277  }
1278  catch (std::string err) {
1279  PyErr_SetString(PyExc_Exception, err.c_str());
1280  return NULL;
1281  }
1282  catch(...) {
1283  std::string err( "Invalid pointer to circuit class");
1284  PyErr_SetString(PyExc_Exception, err.c_str());
1285  return NULL;
1286  }
1287 
1288 
1289  Py_DECREF(parameters_arr);
1290  Py_DECREF(input_state);
1291 
1292 
1293 
1294  PyObject* p = Py_BuildValue("d", entropy);
1295 
1296  return p;
1297 }
1298 
1299 
1300 
1304 static PyObject *
1306 
1307  int qbit_num = 0;
1308 
1309  try {
1310  qbit_num = self->circuit->get_qbit_num();
1311  }
1312  catch (std::string err) {
1313  PyErr_SetString(PyExc_Exception, err.c_str());
1314  std::cout << err << std::endl;
1315  return NULL;
1316  }
1317  catch(...) {
1318  std::string err( "Invalid pointer to circuit class");
1319  PyErr_SetString(PyExc_Exception, err.c_str());
1320  return NULL;
1321  }
1322 
1323 
1324  return Py_BuildValue("i", qbit_num );
1325 
1326 }
1327 
1328 
1329 
1330 
1334 static PyObject *
1336 
1337  int qbit_num = 0;
1338 
1339  // parsing input arguments
1340  if (!PyArg_ParseTuple(args, "|i", &qbit_num )) {
1341  std::string err( "Unable to parse arguments");
1342  PyErr_SetString(PyExc_Exception, err.c_str());
1343  return NULL;
1344  }
1345 
1346 
1347  try {
1348  self->circuit->set_qbit_num( qbit_num );
1349  }
1350  catch (std::string err) {
1351  PyErr_SetString(PyExc_Exception, err.c_str());
1352  std::cout << err << std::endl;
1353  return NULL;
1354  }
1355  catch(...) {
1356  std::string err( "Invalid pointer to circuit class");
1357  PyErr_SetString(PyExc_Exception, err.c_str());
1358  return NULL;
1359  }
1360 
1361 
1362  return Py_None;
1363 
1364 }
1365 
1366 
1367 
1371 static PyObject *
1373 
1374  PyObject* ret = PyList_New(0);
1375 
1376  try {
1377  std::vector<int>&& qbits = self->circuit->get_involved_qubits();
1378  for (int idx = 0; idx < qbits.size(); idx++) {
1379  PyList_Append(ret, Py_BuildValue("i", qbits[idx] ) );
1380  }
1381 
1382  }
1383  catch (std::string err) {
1384  PyErr_SetString(PyExc_Exception, err.c_str());
1385  std::cout << err << std::endl;
1386  return NULL;
1387  }
1388  catch(...) {
1389  std::string err( "Invalid pointer to circuit class");
1390  PyErr_SetString(PyExc_Exception, err.c_str());
1391  return NULL;
1392  }
1393 
1394 
1395  return Py_BuildValue("O", ret );
1396 
1397 }
1398 
1399 
1400 
1404 static PyObject *
1406 
1407 
1408  PyObject* qbit_map_arg = NULL;
1409  int qbit_num = 0;
1410 
1411 
1412  // parsing input arguments
1413  if (!PyArg_ParseTuple(args, "|Oi", &qbit_map_arg, &qbit_num ))
1414  return Py_BuildValue("i", -1);
1415 
1416 
1417  // parse qbit map and create C++ version of the map
1418 
1419  bool is_dict = PyDict_Check( qbit_map_arg );
1420  if (!is_dict) {
1421  printf("Qubit map object must be a python dictionary!\n");
1422  return Py_BuildValue("i", -1);
1423  }
1424 
1425  // integer type config metadata utilized during the optimization
1426  std::map<int, int> qbit_map;
1427 
1428 
1429  // keys and values of the config dict (borrowed references)
1430  PyObject *key, *value;
1431  Py_ssize_t pos = 0;
1432 
1433  while (PyDict_Next(qbit_map_arg, &pos, &key, &value)) {
1434 
1435 
1436  if ( PyLong_Check( value ) && PyLong_Check( key ) ) {
1437  int key_Cpp = (int)PyLong_AsLongLong( key );
1438  qbit_map[ key_Cpp ] = (int)PyLong_AsLongLong( value );
1439  }
1440  else {
1441  std::string err( "Key and value in the qbit_map should be integers");
1442  PyErr_SetString(PyExc_Exception, err.c_str());
1443  return NULL;
1444  }
1445 
1446  }
1447 
1448 
1449  Gates_block* remapped_circuit = NULL;
1450 
1451  try {
1452  remapped_circuit = self->circuit->create_remapped_circuit( qbit_map, qbit_num);
1453 
1454  }
1455  catch (std::string err) {
1456  PyErr_SetString(PyExc_Exception, err.c_str());
1457  std::cout << err << std::endl;
1458  return NULL;
1459  }
1460  catch(...) {
1461  std::string err( "Invalid pointer to circuit class");
1462  PyErr_SetString(PyExc_Exception, err.c_str());
1463  return NULL;
1464  }
1465 
1466 
1467 
1468  // import gate operation modules
1469  PyObject* qgd_circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
1470 
1471  if ( qgd_circuit == NULL ) {
1472  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
1473  return NULL;
1474  }
1475 
1476  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_circuit );
1477 
1478  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1479  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
1480 
1481  PyObject* circuit_input = Py_BuildValue("(O)", Py_BuildValue("i", qbit_num) );
1482  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
1483 
1484 
1485  // replace dummy data with real gate data
1486  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
1487 
1488  delete( py_circuit_C->circuit );
1489  py_circuit_C->circuit = remapped_circuit;
1490 
1491  Py_DECREF( qgd_circuit );
1492  Py_DECREF( circuit_input );
1493 
1494 
1495  return py_circuit;
1496 
1497 }
1498 
1499 
1500 
1501 
1508 static PyObject *
1510 
1511 
1512  Gate* gate = circuit->get_gate( idx );
1513 
1514  // create dummy gate parameters to instantiate dummy object, which are then filled up with valid data
1515  PyObject* qbit_num = Py_BuildValue("i", gate->get_qbit_num() );
1516  PyObject* target_qbit = Py_BuildValue("i", gate->get_target_qbit() );
1517  PyObject* control_qbit = Py_BuildValue("i", gate->get_control_qbit() );
1518 
1519  // The python instance of the gate
1520  PyObject* py_gate = NULL;
1521 
1522  // import gate operation modules
1523  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.gates_Wrapper");
1524 
1525  if ( qgd_gate == NULL ) {
1526  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.gates_Wrapper" );
1527  return NULL;
1528  }
1529 
1530  if (gate->get_type() == CNOT_OPERATION) {
1531 
1532 
1533  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1534  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1535  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CNOT");
1536 
1537  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1538  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1539 
1540  // replace dummy data with real gate data
1541  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1542  delete( py_gate_C->gate );
1543  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1544 
1545  Py_DECREF( qgd_gate );
1546  Py_DECREF( gate_input );
1547 
1548 
1549  }
1550  else if (gate->get_type() == CZ_OPERATION) {
1551 
1552 
1553  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1554  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1555  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CZ");
1556 
1557  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1558  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1559 
1560  // replace dummy data with real gate data
1561  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1562  delete( py_gate_C->gate );
1563  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1564 
1565 
1566  Py_DECREF( qgd_gate );
1567  Py_DECREF( gate_input );
1568 
1569 
1570  }
1571  else if (gate->get_type() == CH_OPERATION) {
1572 
1573 
1574  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1575  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1576  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CH");
1577 
1578  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1579  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1580 
1581  // replace dummy data with real gate data
1582  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1583  delete( py_gate_C->gate );
1584  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1585 
1586  Py_DECREF( qgd_gate );
1587  Py_DECREF( gate_input );
1588 
1589  }
1590  else if (gate->get_type() == SYC_OPERATION) {
1591 
1592 
1593  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1594  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1595  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "SYC");
1596 
1597  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1598  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1599 
1600  // replace dummy data with real gate data
1601  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1602  delete( py_gate_C->gate );
1603  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1604 
1605  Py_DECREF( qgd_gate );
1606  Py_DECREF( gate_input );
1607 
1608 
1609  }
1610  else if (gate->get_type() == U1_OPERATION) {
1611 
1612  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1613  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1614  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "U1");
1615 
1616  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1617  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1618 
1619  // replace dummy data with real gate data
1620  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1621  delete( py_gate_C->gate );
1622  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1623 
1624  Py_DECREF( qgd_gate );
1625  Py_DECREF( gate_input );
1626 
1627  }
1628  else if (gate->get_type() == U2_OPERATION) {
1629 
1630  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1631  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1632  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "U2");
1633 
1634  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1635  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1636 
1637  // replace dummy data with real gate data
1638  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1639  delete( py_gate_C->gate );
1640  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1641 
1642  Py_DECREF( qgd_gate );
1643  Py_DECREF( gate_input );
1644 
1645  }
1646  else if (gate->get_type() == U3_OPERATION) {
1647 
1648  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1649  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1650  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "U3");
1651 
1652  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1653  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1654 
1655  // replace dummy data with real gate data
1656  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1657  delete( py_gate_C->gate );
1658  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1659 
1660  Py_DECREF( qgd_gate );
1661  Py_DECREF( gate_input );
1662 
1663  }
1664  else if (gate->get_type() == RX_OPERATION) {
1665 
1666 
1667  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1668  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1669  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "RX");
1670 
1671  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1672  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1673 
1674  // replace dummy data with real gate data
1675  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1676  delete( py_gate_C->gate );
1677  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1678 
1679  Py_DECREF( qgd_gate );
1680  Py_DECREF( gate_input );
1681 
1682  }
1683  else if (gate->get_type() == R_OPERATION) {
1684 
1685 
1686  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1687  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1688  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "R");
1689 
1690  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1691  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1692 
1693  // replace dummy data with real gate data
1694  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1695  delete( py_gate_C->gate );
1696  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1697 
1698  Py_DECREF( qgd_gate );
1699  Py_DECREF( gate_input );
1700 
1701  }
1702  else if (gate->get_type() == RY_OPERATION) {
1703 
1704 
1705  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1706  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1707  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "RY");
1708 
1709  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1710  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1711 
1712  // replace dummy data with real gate data
1713  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1714  delete( py_gate_C->gate );
1715  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1716 
1717  Py_DECREF( qgd_gate );
1718  Py_DECREF( gate_input );
1719 
1720  }
1721  else if (gate->get_type() == CRY_OPERATION) {
1722 
1723 
1724  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1725  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1726  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CRY");
1727 
1728  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1729  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1730 
1731  // replace dummy data with real gate data
1732  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1733  delete( py_gate_C->gate );
1734  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1735 
1736  Py_DECREF( qgd_gate );
1737  Py_DECREF( gate_input );
1738 
1739 /*
1740 
1741  // import gate operation modules
1742  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.qgd_CRY");
1743 
1744  if ( qgd_gate == NULL ) {
1745  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_CRY" );
1746  return NULL;
1747  }
1748 
1749  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1750  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1751  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "qgd_CRY");
1752 
1753  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1754  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1755 
1756  // replace dummy data with real gate data
1757  qgd_CRY_Wrapper* py_gate_C = reinterpret_cast<qgd_CRY_Wrapper*>( py_gate );
1758  delete( py_gate_C->gate );
1759  py_gate_C->gate = static_cast<CRY*>( gate->clone() );
1760 
1761  Py_DECREF( qgd_gate );
1762  Py_DECREF( gate_input );
1763 */
1764  }
1765  else if (gate->get_type() == CROT_OPERATION) {
1766 
1767  // import gate operation modules
1768  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.qgd_CROT");
1769  CROT* crot_gate = static_cast<CROT*>( gate->clone() );
1770  crot_type qgd_subtype = crot_gate->get_subtype();
1771  PyObject* subtype_pybytes;
1772  if(qgd_subtype==CONTROL_R){subtype_pybytes = PyBytes_FromString("CONTROL_R");}
1773  else if(qgd_subtype==CONTROL_OPPOSITE){subtype_pybytes = PyBytes_FromString("CONTROL_OPPOSITE");}
1774  else if(qgd_subtype==CONTROL_INDEPENDENT){subtype_pybytes = PyBytes_FromString("CONTROL_INDEPENDENT");}
1775  PyObject* subtype_string = PyObject_Str(subtype_pybytes);
1776 
1777  if ( qgd_gate == NULL ) {
1778  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_CROT" );
1779  return NULL;
1780  }
1781 
1782  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1783  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1784  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "qgd_CROT");
1785 
1786  PyObject* gate_input = Py_BuildValue("(OOOO)", qbit_num, target_qbit, control_qbit,subtype_string);
1787  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1788 
1789  // replace dummy data with real gate data
1790  qgd_CROT_Wrapper* py_gate_C = reinterpret_cast<qgd_CROT_Wrapper*>( py_gate );
1791  delete( py_gate_C->gate );
1792  py_gate_C->gate = static_cast<CROT*>( gate->clone() );
1793 
1794  Py_DECREF( qgd_gate );
1795  Py_DECREF( gate_input );
1796 
1797  }
1798  else if (gate->get_type() == RZ_OPERATION) {
1799 
1800 
1801  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1802  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1803  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "RZ");
1804 
1805  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1806  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1807 
1808  // replace dummy data with real gate data
1809  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1810  delete( py_gate_C->gate );
1811  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1812 
1813  Py_DECREF( qgd_gate );
1814  Py_DECREF( gate_input );
1815 
1816  }
1817  else if (gate->get_type() == H_OPERATION) {
1818 
1819 
1820  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1821  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1822  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "H");
1823 
1824  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1825  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1826 
1827  // replace dummy data with real gate data
1828  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1829  delete( py_gate_C->gate );
1830  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1831 
1832  Py_DECREF( qgd_gate );
1833  Py_DECREF( gate_input );
1834 
1835 
1836  }
1837  else if (gate->get_type() == X_OPERATION) {
1838 
1839 
1840  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1841  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1842  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "X");
1843 
1844  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1845  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1846 
1847  // replace dummy data with real gate data
1848  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1849  delete( py_gate_C->gate );
1850  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1851 
1852  Py_DECREF( qgd_gate );
1853  Py_DECREF( gate_input );
1854 
1855 
1856  }
1857  else if (gate->get_type() == Y_OPERATION) {
1858 
1859 
1860  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1861  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1862  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Y");
1863 
1864  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1865  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1866 
1867  // replace dummy data with real gate data
1868  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1869  delete( py_gate_C->gate );
1870  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1871 
1872  Py_DECREF( qgd_gate );
1873  Py_DECREF( gate_input );
1874 
1875 
1876  }
1877  else if (gate->get_type() == Z_OPERATION) {
1878 
1879 
1880  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1881  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1882  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Z");
1883 
1884  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1885  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1886 
1887  // replace dummy data with real gate data
1888  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1889  delete( py_gate_C->gate );
1890  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1891 
1892  Py_DECREF( qgd_gate );
1893  Py_DECREF( gate_input );
1894 
1895 
1896  }
1897  else if (gate->get_type() == SX_OPERATION) {
1898 
1899 
1900  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1901  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1902  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "SX");
1903 
1904  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1905  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1906 
1907  // replace dummy data with real gate data
1908  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1909  delete( py_gate_C->gate );
1910  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1911 
1912  Py_DECREF( qgd_gate );
1913  Py_DECREF( gate_input );
1914 
1915 
1916  }
1917  else if (gate->get_type() == T_OPERATION) {
1918 
1919 
1920  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1921  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1922  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "T");
1923 
1924  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1925  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1926 
1927  // replace dummy data with real gate data
1928  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1929  delete( py_gate_C->gate );
1930  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1931 
1932  Py_DECREF( qgd_gate );
1933  Py_DECREF( gate_input );
1934 
1935 
1936  }
1937  else if (gate->get_type() == TDG_OPERATION){
1938 
1939 
1940  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1941  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1942  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Tdg");
1943 
1944  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1945  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1946 
1947  // replace dummy data with real gate data
1948  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1949  delete( py_gate_C->gate );
1950  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1951 
1952  Py_DECREF( qgd_gate );
1953  Py_DECREF( gate_input );
1954 
1955 
1956  }
1957  else if (gate->get_type() == BLOCK_OPERATION) {
1958 
1959  // import gate operation modules
1960  PyObject* qgd_circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
1961 
1962  if ( qgd_circuit == NULL ) {
1963  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
1964  return NULL;
1965  }
1966 
1967  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_circuit );
1968 
1969  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
1970  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
1971 
1972  PyObject* circuit_input = Py_BuildValue("(O)", qbit_num );
1973  py_gate = PyObject_CallObject(py_circuit_class, circuit_input);
1974 
1975  // replace dummy data with real gate data
1976  qgd_Circuit_Wrapper* py_gate_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_gate );
1977 
1978  Gates_block* circuit = reinterpret_cast<Gates_block*>( gate );
1979  delete( py_gate_C->circuit );
1980  py_gate_C->circuit = circuit->clone();
1981 
1982  Py_DECREF( qgd_circuit );
1983  Py_DECREF( circuit_input );
1984 
1985  }
1986  else {
1987 
1988  Py_DECREF( qgd_gate );
1989  Py_XDECREF(qbit_num);
1990  Py_XDECREF(target_qbit);
1991  Py_XDECREF(control_qbit);
1992  PyErr_SetString(PyExc_Exception, "qgd_Circuit_Wrapper::get_gate: unimplemented gate type" );
1993  return NULL;
1994  }
1995 
1996  Py_XDECREF(qbit_num);
1997  Py_XDECREF(target_qbit);
1998  Py_XDECREF(control_qbit);
1999 
2000  return py_gate;
2001 
2002 }
2003 
2004 
2005 
2012 static PyObject *
2014 
2015  // initiate variables for input arguments
2016  int idx;
2017 
2018  // parsing input arguments
2019  if (!PyArg_ParseTuple(args, "|i", &idx )) return Py_BuildValue("i", -1);
2020 
2021 
2022  return get_gate( self->circuit, idx );
2023 
2024 
2025 }
2026 
2027 
2031 static PyObject *
2033 
2034  std::map< std::string, int > gate_nums;
2035 
2036  try {
2037  gate_nums = self->circuit->get_gate_nums();
2038  }
2039  catch (std::string err) {
2040  PyErr_SetString(PyExc_Exception, err.c_str());
2041  return NULL;
2042  }
2043  catch(...) {
2044  std::string err( "Invalid pointer to circuit class");
2045  PyErr_SetString(PyExc_Exception, err.c_str());
2046  return NULL;
2047  }
2048 
2049 
2050  PyObject* gate_nums_py = PyDict_New();
2051  if( gate_nums_py == NULL ) {
2052  std::string err( "Failed to create dictionary");
2053  PyErr_SetString(PyExc_Exception, err.c_str());
2054  return NULL;
2055  }
2056 
2057  for( auto it = gate_nums.begin(); it != gate_nums.end(); it++ ) {
2058 
2059  PyObject* key = Py_BuildValue( "s", it->first.c_str() );
2060  PyObject* val = Py_BuildValue("i", it->second );
2061 
2062  PyDict_SetItem(gate_nums_py, key, val);
2063  }
2064 
2065  return gate_nums_py;
2066 
2067 }
2068 
2069 
2070 
2071 
2075 static PyObject *
2077 
2078 
2079 
2080 
2081  // get the number of gates
2082  int op_num = self->circuit->get_gate_num();
2083 
2084  // preallocate Python tuple for the output
2085  PyObject* ret = PyTuple_New( (Py_ssize_t) op_num );
2086 
2087 
2088 
2089  // iterate over the gates to get the gate list
2090  for (int idx = 0; idx < op_num; idx++ ) {
2091 
2092  // get metadata about the idx-th gate
2093  PyObject* gate = get_gate( self->circuit, idx );
2094 
2095  // adding gate information to the tuple
2096  PyTuple_SetItem( ret, (Py_ssize_t) idx, gate );
2097 
2098  }
2099 
2100 
2101  return ret;
2102 
2103 }
2104 
2105 
2106 
2113 static PyObject *
2115 
2116  // the gate for which we look for the parents
2117  PyObject* py_gate = NULL;
2118 
2119  // parsing input arguments
2120  if (!PyArg_ParseTuple(args, "|O", &py_gate )) return Py_BuildValue("i", -1);
2121 
2122 
2123  if( py_gate == NULL ) {
2124  return PyTuple_New( 0 );
2125  }
2126 
2127  qgd_Gate* gate_struct = reinterpret_cast<qgd_Gate*>( py_gate );
2128  std::vector<Gate*> parents = gate_struct->gate->get_parents();
2129 
2130  // preallocate tuple for the output
2131  PyObject* parent_tuple = PyTuple_New( (Py_ssize_t) parents.size() );
2132 
2133  std::vector<Gate*>&& gates = self->circuit->get_gates();
2134 
2135 
2136  // find the indices of the parents
2137  for(int idx=0; idx<parents.size(); idx++) {
2138 
2139  Gate* parent_gate = parents[idx];
2140 
2141  // find the index of the parent_gate
2142  int parent_idx = -1;
2143  for( int jdx=0; jdx<gates.size(); jdx++ ) {
2144 
2145  Gate* gate = gates[jdx];
2146 
2147  if( parent_gate == gate ) {
2148  parent_idx = jdx;
2149  break;
2150  }
2151 
2152  if( jdx == gates.size()-1 ) {
2153  std::string err( "Parent gate did not found in the circuit. May be the gate is not in the circuit");
2154  PyErr_SetString(PyExc_Exception, err.c_str());
2155  return NULL;
2156  }
2157 
2158  }
2159 
2160  // adding parent_idx the tuple
2161  PyTuple_SetItem( parent_tuple, (Py_ssize_t) idx, Py_BuildValue("i", parent_idx) );
2162 
2163 
2164  }
2165 
2166 
2167  return parent_tuple;
2168 
2169 
2170 }
2171 
2172 
2173 
2174 
2181 static PyObject *
2183 
2184  // the gate for which we look for the children
2185  PyObject* py_gate = NULL;
2186 
2187  // parsing input arguments
2188  if (!PyArg_ParseTuple(args, "|O", &py_gate )) return Py_BuildValue("i", -1);
2189 
2190 
2191  if( py_gate == NULL ) {
2192  return PyTuple_New( 0 );
2193  }
2194 
2195  qgd_Gate* gate_struct = reinterpret_cast<qgd_Gate*>( py_gate );
2196  std::vector<Gate*> children = gate_struct->gate->get_children();
2197 
2198  // preallocate tuple for the output
2199  PyObject* children_tuple = PyTuple_New( (Py_ssize_t) children.size() );
2200 
2201  std::vector<Gate*>&& gates = self->circuit->get_gates();
2202 
2203 
2204  // find the indices of the children
2205  for(int idx=0; idx<children.size(); idx++) {
2206 
2207  Gate* child_gate = children[idx];
2208 
2209  // find the index of the child_gate
2210  int child_idx = -1;
2211  for( int jdx=0; jdx<gates.size(); jdx++ ) {
2212 
2213  Gate* gate = gates[jdx];
2214 
2215  if( child_gate == gate ) {
2216  child_idx = jdx;
2217  break;
2218  }
2219 
2220  if( jdx == gates.size()-1 ) {
2221  std::string err( "Child gate did not found in the circuit. May be the gate is not in the circuit");
2222  PyErr_SetString(PyExc_Exception, err.c_str());
2223  return NULL;
2224  }
2225 
2226  }
2227 
2228  // adding child_idx the tuple
2229  PyTuple_SetItem( children_tuple, (Py_ssize_t) idx, Py_BuildValue("i", child_idx) );
2230 
2231 
2232  }
2233 
2234 
2235  return children_tuple;
2236 
2237 
2238 }
2239 
2240 
2241 
2245 static PyObject *
2247 
2248  PyArrayObject * parameters_arr = NULL;
2249 
2250 
2251  // parsing input arguments
2252  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
2253  return Py_BuildValue("i", -1);
2254 
2255 
2256  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
2257  Py_INCREF(parameters_arr);
2258  }
2259  else {
2260  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
2261  }
2262 
2263  // get the C++ wrapper around the data
2264  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
2265 
2266 
2267 
2268  Matrix_real extracted_parameters;
2269 
2270  try {
2271  extracted_parameters = self->circuit->extract_parameters( parameters_mtx );
2272  }
2273  catch (std::string err) {
2274  PyErr_SetString(PyExc_Exception, err.c_str());
2275  return NULL;
2276  }
2277  catch(...) {
2278  std::string err( "Invalid pointer to circuit class");
2279  PyErr_SetString(PyExc_Exception, err.c_str());
2280  return NULL;
2281  }
2282 
2283 
2284  // convert to numpy array
2285  extracted_parameters.set_owner(false);
2286  PyObject *extracted_parameters_py = matrix_real_to_numpy( extracted_parameters );
2287 
2288 
2289  return extracted_parameters_py;
2290 }
2291 
2292 
2293 
2297 static PyObject *
2299 
2300  Gates_block* flat_circuit = self->circuit->get_flat_circuit();
2301  int qbit_num = flat_circuit->get_qbit_num();
2302 
2303  // import gate operation modules
2304  PyObject* qgd_circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
2305 
2306  if ( qgd_circuit == NULL ) {
2307  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
2308  return NULL;
2309  }
2310 
2311  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_circuit );
2312 
2313  // PyDict_GetItemString creates a borrowed reference to the item in the dict. Reference counting is not increased on this element, dont need to decrease the reference counting at the end
2314  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
2315 
2316  PyObject* circuit_input = Py_BuildValue("(O)", Py_BuildValue("i", qbit_num) );
2317  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
2318 
2319  // replace dummy data with real gate data
2320  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
2321  delete( py_circuit_C->circuit );
2322  py_circuit_C->circuit = flat_circuit;
2323 
2324 
2325  Py_DECREF( qgd_circuit );
2326  Py_DECREF( circuit_input );
2327 
2328  return py_circuit;
2329 }
2330 
2331 
2332 
2333 
2337 static PyObject *
2339 
2340 
2341  // get the number of gates
2342  int op_num = self->circuit->get_gate_num();
2343 
2344  // preallocate Python tuple for the output
2345  PyObject* ret = PyTuple_New( (Py_ssize_t) op_num+1 );
2346 
2347 
2348 
2349 
2350  // add qbit num value to the return tuple
2351  PyObject* qbit_num_dict = PyDict_New();
2352 
2353  if( qbit_num_dict == NULL ) {
2354  std::string err( "Failed to create dictionary");
2355  PyErr_SetString(PyExc_Exception, err.c_str());
2356  return NULL;
2357  }
2358 
2359  int qbit_num = self->circuit->get_qbit_num();
2360  PyObject* qbit_num_key = Py_BuildValue( "s", "qbit_num" );
2361  PyObject* qbit_num_val = Py_BuildValue("i", qbit_num );
2362 
2363  PyDict_SetItem(qbit_num_dict, qbit_num_key, qbit_num_val);
2364 
2365  PyTuple_SetItem( ret, 0, qbit_num_dict );
2366 
2367  Py_DECREF( qbit_num_key );
2368  Py_DECREF( qbit_num_val );
2369  //Py_DECREF( qbit_num_dict );
2370 
2371 
2372  PyObject* method_name = Py_BuildValue("s", "__getstate__");
2373 
2374  // iterate over the gates to get the gate list
2375  for (int idx = 0; idx < op_num; idx++ ) {
2376 
2377  // get metadata about the idx-th gate
2378  PyObject* gate = get_gate( self->circuit, idx );
2379 
2380  PyObject* gate_state = PyObject_CallMethodObjArgs( gate, method_name, NULL );
2381 
2382 
2383  // remove the field qbit_num from gate dict sice this will be redundant information
2384  if ( PyDict_Contains(gate_state, qbit_num_key) == 1 ) {
2385 
2386  if ( PyDict_DelItem(gate_state, qbit_num_key) != 0 ) {
2387  std::string err( "Failed to delete item qbit_num from gate state");
2388  PyErr_SetString(PyExc_Exception, err.c_str());
2389  return NULL;
2390  }
2391 
2392  }
2393 
2394 
2395  // adding gate information to the tuple
2396  PyTuple_SetItem( ret, (Py_ssize_t) idx+1, gate_state );
2397 
2398 
2399 
2400  Py_DECREF( gate );
2401  //Py_DECREF( gate_state );
2402 
2403  }
2404 
2405  Py_DECREF( method_name );
2406 
2407  return ret;
2408 }
2409 
2410 
2411 
2415 static PyObject *
2417 
2418  PyObject* state = NULL;
2419 
2420  // parsing input arguments
2421  if (!PyArg_ParseTuple(args, "|O", &state )) {
2422  std::string err( "Unable to parse state argument");
2423  PyErr_SetString(PyExc_Exception, err.c_str());
2424  return NULL;
2425  }
2426 
2427  if ( PyTuple_Size(state) == 0 ) {
2428  std::string err( "State should contain at least one element");
2429  PyErr_SetString(PyExc_Exception, err.c_str());
2430 
2431  Py_DECREF( state );
2432  return NULL;
2433  }
2434 
2435  PyObject* qbit_num_dict = PyTuple_GetItem( state, 0); // borrowed reference
2436 
2437 
2438  PyObject* qbit_num_key = Py_BuildValue( "s", "qbit_num" );
2439 
2440  if ( PyDict_Contains(qbit_num_dict, qbit_num_key) == 0 ) {
2441  std::string err( "The first entry of the circuit state should be the number of qubits");
2442  PyErr_SetString(PyExc_Exception, err.c_str());
2443 
2444  Py_DECREF( qbit_num_key );
2445  Py_DECREF( state );
2446  return NULL;
2447  }
2448 
2449  PyObject* qbit_num_py = PyDict_GetItem(qbit_num_dict, qbit_num_key); // borrowed reference
2450 
2451  if( !PyLong_Check(qbit_num_py) ) {
2452  std::string err( "The number of qubits should be an integer value");
2453  PyErr_SetString(PyExc_Exception, err.c_str());
2454 
2455  Py_DECREF( qbit_num_key );
2456  Py_DECREF( state );
2457  return NULL;
2458  }
2459 
2460 
2461  int qbit_num = (int)PyLong_AsLong( qbit_num_py );
2462 
2463 
2464  // import gate operation modules
2465  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.gates_Wrapper");
2466 
2467  if ( qgd_gate == NULL ) {
2468  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.gates_Wrapper" );
2469  Py_DECREF( qbit_num_key );
2470  Py_DECREF( state );
2471  return NULL;
2472  }
2473 
2474  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate ); // borrowed reference ???
2475  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Gate"); // borrowed reference
2476  PyObject* setstate_name = Py_BuildValue( "s", "__setstate__" );
2477  PyObject* dummy_target_qbit = Py_BuildValue( "i", 0 );
2478 
2479  // now build up the quantum circuit
2480  try {
2481 
2482  self->circuit->release_gates();
2483  self->circuit->set_qbit_num( qbit_num );
2484 
2485  int gates_idx_max = (int) PyTuple_Size(state);
2486 
2487  for( int gate_idx=1; gate_idx < gates_idx_max; gate_idx++ ) {
2488 
2489 
2490  // get gate state as python dictionary
2491  PyObject* gate_state_dict = PyTuple_GetItem( state, gate_idx); // borrowed reference
2492 
2493  if( !PyDict_Check( gate_state_dict ) ) {
2494  std::string err( "Gate state should be given by a dictionary");
2495  PyErr_SetString(PyExc_Exception, err.c_str());
2496 
2497  Py_DECREF( qgd_gate );
2498  Py_DECREF( qgd_gate_Dict );
2499  Py_DECREF( qbit_num_key );
2500  Py_DECREF( state );
2501  Py_DECREF( setstate_name );
2502  Py_DECREF( dummy_target_qbit );
2503  return NULL;
2504  }
2505 
2506  PyDict_SetItem(gate_state_dict, qbit_num_key, qbit_num_py);
2507 
2508  PyObject* gate_input = Py_BuildValue( "(O)", qbit_num_py );
2509  PyObject* py_gate = PyObject_CallObject(py_gate_class, gate_input);
2510 
2511  // turn the generic gate into a specific gate
2512  PyObject_CallMethodObjArgs( py_gate, setstate_name, gate_state_dict, NULL );
2513 
2514  Gate* gate_loc = static_cast<Gate*>( ((qgd_Gate*)py_gate)->gate->clone() );
2515  self->circuit->add_gate( gate_loc );
2516 
2517 
2518  Py_DECREF( gate_input );
2519  Py_DECREF( py_gate );
2520 
2521 
2522 
2523  }
2524 
2525 
2526  }
2527  catch (std::string err) {
2528  PyErr_SetString(PyExc_Exception, err.c_str());
2529  return NULL;
2530  }
2531  catch(...) {
2532  std::string err( "Invalid pointer to circuit class");
2533  PyErr_SetString(PyExc_Exception, err.c_str());
2534  return NULL;
2535  }
2536 
2537 
2538 
2539 
2540  Py_DECREF( qgd_gate );
2541  //Py_DECREF( qgd_gate_Dict );
2542  Py_DECREF( qbit_num_key );
2543  Py_DECREF( setstate_name );
2544  Py_DECREF( dummy_target_qbit );
2545 
2546 
2547  return Py_None;
2548 }
2549 
2550 
2551 
2556 static PyObject *
2558 
2559  int start_index = self->circuit->get_parameter_start_idx();
2560 
2561  return Py_BuildValue("i", start_index);
2562 
2563 }
2564 
2565 
2566 
2567 
2568 static PyMethodDef qgd_Circuit_Wrapper_Methods[] = {
2569  {"add_U1", (PyCFunction) qgd_Circuit_Wrapper_add_U1, METH_VARARGS | METH_KEYWORDS,
2570  "Call to add a U1 gate to the front of the gate structure"
2571  },
2572  {"add_U2", (PyCFunction) qgd_Circuit_Wrapper_add_U2, METH_VARARGS | METH_KEYWORDS,
2573  "Call to add a U2 gate to the front of the gate structure"
2574  },
2575  {"add_U3", (PyCFunction) qgd_Circuit_Wrapper_add_U3, METH_VARARGS | METH_KEYWORDS,
2576  "Call to add a U3 gate to the front of the gate structure"
2577  },
2578  {"add_RX", (PyCFunction) qgd_Circuit_Wrapper_add_RX, METH_VARARGS | METH_KEYWORDS,
2579  "Call to add a RX gate to the front of the gate structure"
2580  },
2581  {"add_R", (PyCFunction) qgd_Circuit_Wrapper_add_R, METH_VARARGS | METH_KEYWORDS,
2582  "Call to add a R gate to the front of the gate structure"
2583  },
2584  {"add_RY", (PyCFunction) qgd_Circuit_Wrapper_add_RY, METH_VARARGS | METH_KEYWORDS,
2585  "Call to add a RY gate to the front of the gate structure"
2586  },
2587  {"add_RZ", (PyCFunction) qgd_Circuit_Wrapper_add_RZ, METH_VARARGS | METH_KEYWORDS,
2588  "Call to add a RZ gate to the front of the gate structure"
2589  },
2590  {"add_CNOT", (PyCFunction) qgd_Circuit_Wrapper_add_CNOT, METH_VARARGS | METH_KEYWORDS,
2591  "Call to add a CNOT gate to the front of the gate structure"
2592  },
2593  {"add_CZ", (PyCFunction) qgd_Circuit_Wrapper_add_CZ, METH_VARARGS | METH_KEYWORDS,
2594  "Call to add a CZ gate to the front of the gate structure"
2595  },
2596  {"add_CH", (PyCFunction) qgd_Circuit_Wrapper_add_CH, METH_VARARGS | METH_KEYWORDS,
2597  "Call to add a CH gate to the front of the gate structure"
2598  },
2599  {"add_SYC", (PyCFunction) qgd_Circuit_Wrapper_add_SYC, METH_VARARGS | METH_KEYWORDS,
2600  "Call to add a Sycamore gate to the front of the gate structure"
2601  },
2602  {"add_H", (PyCFunction) qgd_Circuit_Wrapper_add_H, METH_VARARGS | METH_KEYWORDS,
2603  "Call to add a Hadamard gate to the front of the gate structure"
2604  },
2605  {"add_X", (PyCFunction) qgd_Circuit_Wrapper_add_X, METH_VARARGS | METH_KEYWORDS,
2606  "Call to add a X gate to the front of the gate structure"
2607  },
2608  {"add_Y", (PyCFunction) qgd_Circuit_Wrapper_add_Y, METH_VARARGS | METH_KEYWORDS,
2609  "Call to add a Y gate to the front of the gate structure"
2610  },
2611  {"add_Z", (PyCFunction) qgd_Circuit_Wrapper_add_Z, METH_VARARGS | METH_KEYWORDS,
2612  "Call to add a Z gate to the front of the gate structure"
2613  },
2614  {"add_SX", (PyCFunction) qgd_Circuit_Wrapper_add_SX, METH_VARARGS | METH_KEYWORDS,
2615  "Call to add a SX gate to the front of the gate structure"
2616  },
2617  {"add_T", (PyCFunction) qgd_Circuit_Wrapper_add_T, METH_VARARGS | METH_KEYWORDS,
2618  "Call to add a T gate to the front of the gate structure"
2619  },
2620  {"add_Tdg", (PyCFunction) qgd_Circuit_Wrapper_add_Tdg, METH_VARARGS | METH_KEYWORDS,
2621  "Call to add a Tdg gate to the front of the gate structure"
2622  },
2623  {"add_CRY", (PyCFunction) qgd_Circuit_Wrapper_add_CRY, METH_VARARGS | METH_KEYWORDS,
2624  "Call to add a CRY gate to the front of the gate structure"
2625  },
2626  {"add_CROT", (PyCFunction) qgd_Circuit_Wrapper_add_CROT, METH_VARARGS | METH_KEYWORDS,
2627  "Call to add a CROT gate to the front of the gate structure"
2628  },
2629  {"add_adaptive", (PyCFunction) qgd_Circuit_Wrapper_add_adaptive, METH_VARARGS | METH_KEYWORDS,
2630  "Call to add an adaptive gate to the front of the gate structure"
2631  },
2632  {"add_Circuit", (PyCFunction) qgd_Circuit_Wrapper_add_Circuit, METH_VARARGS,
2633  "Call to add a block of operations to the front of the gate structure."
2634  },
2635 #ifdef __DFE__
2636  {"convert_to_DFE_gates_with_derivates", (PyCFunction) qgd_Circuit_Wrapper_convert_to_DFE_gates_with_derivates, METH_VARARGS,
2637  "Call to convert to DFE gates with derivates."
2638  },
2639  {"adjust_parameters_for_derivation", (PyCFunction) qgd_Circuit_Wrapper_adjust_parameters_for_derivation, METH_VARARGS,
2640  "Call to adjust parameters for derivation."
2641  },
2642  {"convert_to_DFE_gates", (PyCFunction) qgd_Circuit_Wrapper_convert_to_DFE_gates, METH_VARARGS,
2643  "Call to convert to DFE gates."
2644  },
2645  {"convert_to_DFE_gates", (PyCFunction) qgd_Circuit_Wrapper_convert_to_DFE_gates, METH_VARARGS,
2646  "Call to convert to DFE gates."
2647  },
2648 #endif
2649  {"get_Matrix", (PyCFunction) qgd_Circuit_Wrapper_get_Matrix, METH_VARARGS,
2650  "Method to get the matrix of the operation."
2651  },
2652  {"get_Parameter_Num", (PyCFunction) qgd_Circuit_Wrapper_get_Parameter_Num, METH_NOARGS,
2653  "Call to get the number of free parameters in the circuit"
2654  },
2655  {"apply_to", (PyCFunction) qgd_Circuit_Wrapper_apply_to, METH_VARARGS | METH_KEYWORDS,
2656  "Call to apply the gate on the input matrix (or state)."
2657  },
2658  {"get_Second_Renyi_Entropy", (PyCFunction) qgd_Circuit_Wrapper_get_Second_Renyi_Entropy, METH_VARARGS,
2659  "Wrapper function to evaluate the second Rényi entropy of a quantum circuit at a specific parameter set."
2660  },
2661  {"get_Qbit_Num", (PyCFunction) qgd_Circuit_Wrapper_get_Qbit_Num, METH_NOARGS,
2662  "Call to get the number of qubits in the circuit"
2663  },
2664  {"set_Qbit_Num", (PyCFunction) qgd_Circuit_Wrapper_set_Qbit_Num, METH_VARARGS,
2665  "Call to set the number of qubits in the circuit"
2666  },
2667  {"get_Qbits", (PyCFunction) qgd_Circuit_Wrapper_get_Qbits, METH_NOARGS,
2668  "Call to get the list of qubits involved in the circuit"
2669  },
2670  {"Remap_Qbits", (PyCFunction) qgd_Circuit_Wrapper_Remap_Qbits, METH_VARARGS,
2671  "Call to remap the qubits in the circuit."
2672  },
2673  {"get_Gate", (PyCFunction) qgd_Circuit_Wrapper_get_gate, METH_VARARGS,
2674  "Method to get the i-th decomposing gates."
2675  },
2676  {"get_Gates", (PyCFunction) qgd_Circuit_Wrapper_get_gates, METH_NOARGS,
2677  "Method to get the tuple of decomposing gates."
2678  },
2679  {"get_Gate_Nums", (PyCFunction) qgd_Circuit_Wrapper_get_Gate_Nums, METH_NOARGS,
2680  "Method to get statisctics on the gate counts in the circuit."
2681  },
2682  {"get_Parameter_Start_Index", (PyCFunction) qgd_Circuit_Wrapper_get_Parameter_Start_Index, METH_NOARGS,
2683  "Call to get the starting index of the parameters in the parameter array corresponding to the circuit in which the current gate is incorporated."
2684  },
2685  {"Extract_Parameters", (PyCFunction) qgd_Circuit_Wrapper_Extract_Parameters, METH_VARARGS,
2686  "Call to extract the paramaters corresponding to the gate, from a parameter array associated to the circuit in which the gate is embedded."
2687  },
2688  {"get_Flat_Circuit", (PyCFunction) qgd_Circuit_Wrapper_get_Flat_Circuit, METH_NOARGS,
2689  "Method to generate a flat circuit. A flat circuit is a circuit does not containing subcircuits: there are no Gates_block instances (containing subcircuits) in the resulting circuit. If the original circuit contains subcircuits, the gates in the subcircuits are directly incorporated in the resulting flat circuit."
2690  },
2691  {"get_Parents", (PyCFunction) qgd_Circuit_Wrapper_get_parents, METH_VARARGS,
2692  "Method to get the list of parent gate indices. Then the parent gates can be obtained from the list of gates involved in the circuit."
2693  },
2694  {"get_Children", (PyCFunction) qgd_Circuit_Wrapper_get_children, METH_VARARGS,
2695  "Method to get the list of child gate indices. Then the children gates can be obtained from the list of gates involved in the circuit."
2696  },
2697  {"__getstate__", (PyCFunction) qgd_Circuit_Wrapper_getstate, METH_NOARGS,
2698  "Method to extract the stored quantum circuit in a human-readable data serialized and pickle-able format."
2699  },
2700  {"__setstate__", (PyCFunction) qgd_Circuit_Wrapper_setstate, METH_VARARGS,
2701  "Call to set the state of a quantum circuit from a human-readable data serialized and pickle-able format."
2702  },
2703 
2704 
2705  {NULL} /* Sentinel */
2706 };
2707 
2708 
2713  PyVarObject_HEAD_INIT(NULL, 0)
2714  "qgd_Circuit_Wrapper.qgd_Circuit_Wrapper", /*tp_name*/
2715  sizeof(qgd_Circuit_Wrapper), /*tp_basicsize*/
2716  0, /*tp_itemsize*/
2717  (destructor) qgd_Circuit_Wrapper_dealloc, /*tp_dealloc*/
2718  #if PY_VERSION_HEX < 0x030800b4
2719  0, /*tp_print*/
2720  #endif
2721  #if PY_VERSION_HEX >= 0x030800b4
2722  0, /*tp_vectorcall_offset*/
2723  #endif
2724  0, /*tp_getattr*/
2725  0, /*tp_setattr*/
2726  #if PY_MAJOR_VERSION < 3
2727  0, /*tp_compare*/
2728  #endif
2729  #if PY_MAJOR_VERSION >= 3
2730  0, /*tp_as_async*/
2731  #endif
2732  0, /*tp_repr*/
2733  0, /*tp_as_number*/
2734  0, /*tp_as_sequence*/
2735  0, /*tp_as_mapping*/
2736  0, /*tp_hash*/
2737  0, /*tp_call*/
2738  0, /*tp_str*/
2739  0, /*tp_getattro*/
2740  0, /*tp_setattro*/
2741  0, /*tp_as_buffer*/
2742  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
2743  "Object to represent a qgd_Circuit_Wrapper class of the QGD package.", /*tp_doc*/
2744  0, /*tp_traverse*/
2745  0, /*tp_clear*/
2746  0, /*tp_richcompare*/
2747  0, /*tp_weaklistoffset*/
2748  0, /*tp_iter*/
2749  0, /*tp_iternext*/
2750  qgd_Circuit_Wrapper_Methods, /*tp_methods*/
2751  qgd_Circuit_Wrapper_Members, /*tp_members*/
2752  0, /*tp_getset*/
2753  0, /*tp_base*/
2754  0, /*tp_dict*/
2755  0, /*tp_descr_get*/
2756  0, /*tp_descr_set*/
2757  0, /*tp_dictoffset*/
2758  (initproc) qgd_Circuit_Wrapper_init, /*tp_init*/
2759  0, /*tp_alloc*/
2760  qgd_Circuit_Wrapper_new, /*tp_new*/
2761  0, /*tp_free*/
2762  0, /*tp_is_gc*/
2763  0, /*tp_bases*/
2764  0, /*tp_mro*/
2765  0, /*tp_cache*/
2766  0, /*tp_subclasses*/
2767  0, /*tp_weaklist*/
2768  0, /*tp_del*/
2769  0, /*tp_version_tag*/
2770  #if PY_VERSION_HEX >= 0x030400a1
2771  0, /*tp_finalize*/
2772  #endif
2773  #if PY_VERSION_HEX >= 0x030800b1
2774  0, /*tp_vectorcall*/
2775  #endif
2776  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
2777  0, /*tp_print*/
2778  #endif
2779 };
2780 
2784 static PyModuleDef qgd_Circuit_Wrapper_Module = {
2785  PyModuleDef_HEAD_INIT,
2786  "qgd_Circuit_Wrapper",
2787  "Python binding for QGD Circuit class",
2788  -1,
2789 };
2790 
2794 PyMODINIT_FUNC
2796 {
2797 
2798  // initialize Numpy API
2799  import_array();
2800 
2801  PyObject *m;
2802  if (PyType_Ready(&qgd_Circuit_Wrapper_Type) < 0)
2803  return NULL;
2804 
2805  m = PyModule_Create(&qgd_Circuit_Wrapper_Module);
2806  if (m == NULL)
2807  return NULL;
2808 
2809  Py_INCREF(&qgd_Circuit_Wrapper_Type);
2810  if (PyModule_AddObject(m, "qgd_Circuit_Wrapper", (PyObject *) &qgd_Circuit_Wrapper_Type) < 0) {
2811  Py_DECREF(&qgd_Circuit_Wrapper_Type);
2812  Py_DECREF(m);
2813  return NULL;
2814  }
2815 
2816  return m;
2817 }
2818 
2819 
2820 
2821 }
static PyObject * qgd_Circuit_Wrapper_get_Parameter_Num(qgd_Circuit_Wrapper *self)
Get the number of free parameters in the gate structure used for the decomposition.
Gates_block * get_flat_circuit()
Method to generate a flat circuit.
PyMODINIT_FUNC PyInit_qgd_Circuit_Wrapper(void)
Method called when the Python module is initialized.
crot_type get_subtype()
Definition: CROT.cpp:527
static PyObject * qgd_Circuit_Wrapper_get_Parameter_Start_Index(qgd_Circuit_Wrapper *self)
Call to get the starting index of the parameters in the parameter array corresponding to the circuit ...
static PyObject * qgd_Circuit_Wrapper_add_Z(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a X gate to the front of the gate structure.
parameter_num
[set adaptive gate structure]
Header file for a class representing a rotation gate around the X axis.
PyObject_HEAD Gate * gate
Pointer to the C++ class of the base Gate gate.
Header file for a class for a composite gate operation.
static PyObject * qgd_Circuit_Wrapper_get_parents(qgd_Circuit_Wrapper *self, PyObject *args)
Wrapper function to get the indices of parent gates.
Header file for a class representing the X gate.
static PyObject * qgd_Circuit_Wrapper_get_Qbits(qgd_Circuit_Wrapper *self)
Call to retrieve the list of qubits involved in the circuit.
static PyObject * qgd_Circuit_Wrapper_get_gates(qgd_Circuit_Wrapper *self)
Call to get the incorporated gates in a python list.
Header file for a class representing the Y gate.
virtual Gate * clone()
Call to create a clone of the present class.
Definition: Gate.cpp:513
void add_gate(Gate *gate)
Append a general gate to the list of gates.
Header file for a class representing a controlled rotation gate around the Y axis.
static PyObject * qgd_Circuit_Wrapper_add_T(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a T gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_add_CRY(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add an adaptive gate to the front of the gate structure.
static PyObject * get_gate(Gates_block *circuit, int &idx)
Call to get the metadata organised into Python dictionary of the idx-th gate.
Matrix_real numpy2matrix_real(PyArrayObject *arr)
Call to create a PIC matrix_real representation of a numpy array.
static int qgd_Circuit_Wrapper_init(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_Circuit_Wrapper is initialized.
Header file for a class representing the SX axis.
static PyObject * qgd_Circuit_Wrapper_get_Gate_Nums(qgd_Circuit_Wrapper *self)
Call to get the counts on the individual gates in the circuit.
static PyObject * qgd_Circuit_Wrapper_get_Qbit_Num(qgd_Circuit_Wrapper *self)
Call to retrieve the number of qubits in the circuit.
static PyObject * qgd_Circuit_Wrapper_get_children(qgd_Circuit_Wrapper *self, PyObject *args)
Wrapper function to get the indices of children gates.
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
Gates_block * create_remapped_circuit(const std::map< int, int > &qbit_map)
Call to create a new circuit with remapped qubits.
Header file for a class representing a CH operation.
Type definition of the qgd_Gate Python class of the qgd_Gate module.
Header file for a class responsible for grouping gates into subcircuits. (Subcircuits can be nested) ...
PyObject * matrix_real_to_numpy(Matrix_real &mtx)
Call to make a numpy array from an instance of matrix class.
static PyObject * qgd_Circuit_Wrapper_Remap_Qbits(qgd_Circuit_Wrapper *self, PyObject *args)
Call to remap the qubits in the circuit.
void release_Circuit(Gates_block *instance)
Call to deallocate an instance of N_Qubit_Decomposition class.
static PyTypeObject qgd_Circuit_Wrapper_Type
A structure describing the type of the class Circuit.
static PyMemberDef qgd_Circuit_Wrapper_Members[]
Structure containing metadata about the members of class qgd_Circuit_Wrapper.
A class representing a CROT gate.
Definition: CROT.h:39
static PyObject * qgd_Circuit_Wrapper_apply_to(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Call to apply the gate operation on the inut matrix.
Header file for a class representing a CNOT operation.
static PyObject * qgd_Circuit_Wrapper_add_adaptive(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add an adaptive gate to the front of the gate structure.
Header file for a class representing a rotation gate around the Z axis.
static PyObject * qgd_Circuit_Wrapper_setstate(qgd_Circuit_Wrapper *self, PyObject *args)
Call to set the state of a quantum circuit from a human-readable data serialized and pickle-able form...
static PyObject * qgd_Circuit_Wrapper_add_Circuit(qgd_Circuit_Wrapper *self, PyObject *args)
Wrapper function to add a block of operations to the front of the gate structure. ...
Header file for a class representing the Hadamard gate.
static PyObject * qgd_Circuit_Wrapper_add_CNOT(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a CNOT gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_add_RX(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a RX gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_add_SYC(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a Sycamore gate to the front of the gate structure.
gate_type get_type()
Call to get the type of the operation.
Definition: Gate.cpp:495
Header file for a class for the representation of general gate operations on the first qbit_num-1 qub...
static PyObject * qgd_Circuit_Wrapper_add_SX(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a SX gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_set_Qbit_Num(qgd_Circuit_Wrapper *self, PyObject *args)
Call to set the number of qubits in the circuit.
static PyObject * qgd_Circuit_Wrapper_add_Y(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a X gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_Circuit_Wrapper is allocated.
static PyObject * qgd_Circuit_Wrapper_get_Second_Renyi_Entropy(qgd_Circuit_Wrapper *self, PyObject *args)
Wrapper function to evaluate the second Rényi entropy of a quantum circuit at a specific parameter s...
std::vector< Gate * > get_parents()
Call to get the parents of the current gate.
Definition: Gate.cpp:463
static PyObject * qgd_Circuit_Wrapper_get_Flat_Circuit(qgd_Circuit_Wrapper *self)
Method to generate a flat circuit.
static PyObject * qgd_Circuit_Wrapper_get_gate(qgd_Circuit_Wrapper *self, PyObject *args)
Wrapper function to get a gate from the circuit.
Header file for a class representing a CZ operation.
static PyObject * qgd_Circuit_Wrapper_add_RZ(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a RZ gate to the front of the gate structure.
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...
static PyObject * qgd_Circuit_Wrapper_add_U3(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a U3 gate to the front of the gate structure.
Structure type representing complex numbers in the SQUANDER package.
Definition: QGDTypes.h:38
static void qgd_Circuit_Wrapper_dealloc(qgd_Circuit_Wrapper *self)
Method called when a python instance of the class qgd_Circuit_Wrapper is destroyed.
static PyMethodDef qgd_Circuit_Wrapper_Methods[]
std::vector< Gate * > get_children()
Call to get the children of the current gate.
Definition: Gate.cpp:474
virtual Gates_block * clone()
Create a clone of the present class.
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
Header file for a class representing a U2 gate.
Header file for a class representing a gate used in adaptive decomposition.
int size() const
Call to get the number of the allocated elements.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
Definition: Gates_block.h:41
static PyObject * qgd_Circuit_Wrapper_add_CZ(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a CZ gate to the front of the gate structure.
Header file for a class representing a U3 gate.
static PyObject * qgd_Circuit_Wrapper_Extract_Parameters(qgd_Circuit_Wrapper *self, PyObject *args)
Call to extract the paramaters corresponding to the gate, from a parameter array associated to the ci...
Fixed point data related to a gate operation.
Definition: common_DFE.h:61
Type definition of the qgd_CROT Python class of the qgd_CROT module.
int get_target_qbit()
Call to get the index of the target qubit.
Definition: Gate.cpp:370
Header file for a class representing a rotation gate around the X axis.
static PyObject * qgd_Circuit_Wrapper_add_RY(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a RY gate to the front of the gate structure.
Base class for the representation of general gate operations.
Definition: Gate.h:73
static PyModuleDef qgd_Circuit_Wrapper_Module
Structure containing metadata about the module.
Header file for a class representing a rotation gate around the Y axis.
static PyObject * qgd_Circuit_Wrapper_add_CH(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a CH gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_get_Matrix(qgd_Circuit_Wrapper *self, PyObject *args)
Extract the optimized parameters.
static PyObject * qgd_Circuit_Wrapper_add_U1(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a U1 gate to the front of the gate structure.
PyObject_HEAD CROT * gate
Pointer to the C++ class of the CROT gate.
Definition: CROT.h:34
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a PIC matrix representation of a numpy array.
static PyObject * qgd_Circuit_Wrapper_getstate(qgd_Circuit_Wrapper *self)
Method to extract the stored quantum circuit in a human-readable data serialized and pickle-able form...
PyObject_HEAD Gates_block * circuit
Pointer to the C++ class of the base Gate_block module.
static PyObject * qgd_Circuit_Wrapper_add_H(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a Hadamard gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_add_R(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a R gate to the front of the gate structure.
static PyObject * qgd_Circuit_Wrapper_add_X(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a X gate to the front of the gate structure.
Header file for a class representing the Z gate.
Header file for a class for the representation of general gate operations on the first qbit_num-1 qub...
static PyObject * qgd_Circuit_Wrapper_add_Tdg(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a Tdg gate to the front of the gate structure.
int get_qbit_num()
Call to get the number of qubits composing the unitary.
Definition: Gate.cpp:504
gate_type
Type definition of operation types (also generalized for decomposition classes derived from the class...
Definition: Gate.h:34
Type definition of the qgd_Circuit_Wrapper Python class of the qgd_Circuit_Wrapper module...
Gate * get_gate(int idx)
Call to get the gates stored in the class.
Gates_block * create_Circuit(int qbit_num)
Creates an instance of class N_Qubit_Decomposition and return with a pointer pointing to the class in...
static PyObject * qgd_Circuit_Wrapper_add_U2(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add a U2 gate to the front of the gate structure.
PyObject * matrix_to_numpy(Matrix &mtx)
Call to make a numpy array from an instance of matrix class.
Header file for a class representing a U1 gate.
static PyObject * qgd_Circuit_Wrapper_add_CROT(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add an adaptive gate to the front of the gate structure.
int get_control_qbit()
Call to get the index of the control qubit.
Definition: Gate.cpp:378
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
crot_type
Definition: CROT.h:34
Header file for a class representing a Sycamore gate.