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 "CR.h"
44 #include "RZ.h"
45 #include "H.h"
46 #include "X.h"
47 #include "Y.h"
48 #include "Z.h"
49 #include "SX.h"
50 #include "SYC.h"
51 #include "UN.h"
52 #include "ON.h"
53 #include "Adaptive.h"
54 #include "Composite.h"
55 
56 #include "numpy_interface.h"
57 
58 #ifdef __DFE__
59 #include <numpy/arrayobject.h>
60 #include "numpy_interface.h"
61 #endif
62 
66 typedef struct {
67  PyObject_HEAD
70 } qgd_Gate;
71 
75 typedef struct qgd_Circuit_Wrapper {
76  PyObject_HEAD
80 
88  return new Gates_block(qbit_num);
89 }
90 
95 void
97  delete instance;
98  return;
99 }
100 
101 
102 
103 
104 
105 extern "C"
106 {
107 
112 static void
114 {
115 
116  // deallocate the instance of class N_Qubit_Decomposition
117  release_Circuit( self->circuit );
118 
119  Py_TYPE(self)->tp_free((PyObject *) self);
120 }
121 
126 static PyObject *
127 qgd_Circuit_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
128 {
129 
130  // The tuple of expected keywords
131  static char *kwlist[] = {(char*)"qbit_num", NULL};
132 
133  // initiate variables for input arguments
134  int qbit_num = 0;
135 
136  // parsing input arguments
137  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &qbit_num)) {
138  std::string err( "Unable to parse arguments");
139  PyErr_SetString(PyExc_Exception, err.c_str());
140  return NULL;
141  }
142 
143  qgd_Circuit_Wrapper *self;
144  self = (qgd_Circuit_Wrapper *) type->tp_alloc(type, 0);
145 
146  if (self != NULL) {
147  self->circuit = create_Circuit( qbit_num );
148  }
149 
150  return (PyObject *) self;
151 }
152 
153 
161 static int
162 qgd_Circuit_Wrapper_init(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
163 {
164  return 0;
165 }
166 
167 
171 static PyMemberDef qgd_Circuit_Wrapper_Members[] = {
172  {NULL} /* Sentinel */
173 };
174 
175 
176 
183 static PyObject *
184 qgd_Circuit_Wrapper_add_U1(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
185 {
186  // The tuple of expected keywords
187  static char *kwlist[] = {(char*)"target_qbit", NULL};
188 
189  // initiate variables for input arguments
190  int target_qbit = -1;
191 
192  // parsing input arguments
193  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
194  &target_qbit))
195  return Py_BuildValue("i", -1);
196 
197  // adding U1 gate to the end of the gate structure
198  if (target_qbit != -1 ) {
199  self->circuit->add_u1(target_qbit);
200  }
201 
202  return Py_BuildValue("i", 0);
203 }
204 
205 
206 
213 static PyObject *
214 qgd_Circuit_Wrapper_add_U2(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
215 {
216  // The tuple of expected keywords
217  static char *kwlist[] = {(char*)"target_qbit", NULL};
218 
219  // initiate variables for input arguments
220  int target_qbit = -1;
221 
222  // parsing input arguments
223  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
224  &target_qbit))
225  return Py_BuildValue("i", -1);
226 
227  // adding U2 gate to the end of the gate structure
228  if (target_qbit != -1 ) {
229  self->circuit->add_u2(target_qbit);
230  }
231 
232  return Py_BuildValue("i", 0);
233 }
234 
235 
236 
243 static PyObject *
244 qgd_Circuit_Wrapper_add_U3(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
245 {
246 
247  // The tuple of expected keywords
248  static char *kwlist[] = {(char*)"target_qbit", NULL};
249 
250  // initiate variables for input arguments
251  int target_qbit = -1;
252 
253  // parsing input arguments
254  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
255  &target_qbit))
256  return Py_BuildValue("i", -1);
257 
258  // adding U3 gate to the end of the gate structure
259  if (target_qbit != -1 ) {
260  self->circuit->add_u3(target_qbit);
261  }
262 
263  return Py_BuildValue("i", 0);
264 }
265 
266 
267 
274 static PyObject *
275 qgd_Circuit_Wrapper_add_RX(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
276 {
277 
278  // The tuple of expected keywords
279  static char *kwlist[] = {(char*)"target_qbit", NULL};
280 
281  // initiate variables for input arguments
282  int target_qbit = -1;
283 
284  // parsing input arguments
285  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
286  &target_qbit))
287  return Py_BuildValue("i", -1);
288 
289  // adding U3 gate to the end of the gate structure
290  if (target_qbit != -1 ) {
291  self->circuit->add_rx(target_qbit);
292  }
293 
294  return Py_BuildValue("i", 0);
295 
296 }
297 
298 
299 
306 static PyObject *
307 qgd_Circuit_Wrapper_add_R(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
308 {
309 
310  // The tuple of expected keywords
311  static char *kwlist[] = {(char*)"target_qbit", NULL};
312 
313  // initiate variables for input arguments
314  int target_qbit = -1;
315 
316  // parsing input arguments
317  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
318  &target_qbit))
319  return Py_BuildValue("i", -1);
320 
321  // adding U3 gate to the end of the gate structure
322  if (target_qbit != -1 ) {
323  self->circuit->add_r(target_qbit);
324  }
325 
326  return Py_BuildValue("i", 0);
327 
328 }
329 
330 
331 
338 static PyObject *
339 qgd_Circuit_Wrapper_add_RY(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
340 {
341 
342  // The tuple of expected keywords
343  static char *kwlist[] = {(char*)"target_qbit", NULL};
344 
345  // initiate variables for input arguments
346  int target_qbit = -1;
347 
348  // parsing input arguments
349  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
350  &target_qbit))
351  return Py_BuildValue("i", -1);
352 
353  // adding U3 gate to the end of the gate structure
354  if (target_qbit != -1 ) {
355  self->circuit->add_ry(target_qbit);
356  }
357 
358  return Py_BuildValue("i", 0);
359 
360 }
361 
362 
363 
370 static PyObject *
371 qgd_Circuit_Wrapper_add_RZ(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
372 {
373 
374  // The tuple of expected keywords
375  static char *kwlist[] = {(char*)"target_qbit", NULL};
376 
377  // initiate variables for input arguments
378  int target_qbit = -1;
379 
380  // parsing input arguments
381  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
382  &target_qbit))
383  return Py_BuildValue("i", -1);
384 
385  // adding U3 gate to the end of the gate structure
386  if (target_qbit != -1 ) {
387  self->circuit->add_rz(target_qbit);
388  }
389 
390  return Py_BuildValue("i", 0);
391 
392 }
393 
394 
395 
402 static PyObject *
403 qgd_Circuit_Wrapper_add_CNOT(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
404 {
405 
406  // The tuple of expected keywords
407  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
408 
409  // initiate variables for input arguments
410  int target_qbit = -1;
411  int control_qbit = -1;
412 
413  // parsing input arguments
414  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
415  &target_qbit, &control_qbit))
416  return Py_BuildValue("i", -1);
417 
418 
419  // adding CNOT gate to the end of the gate structure
420  if (target_qbit != -1 ) {
421  self->circuit->add_cnot(target_qbit, control_qbit);
422  }
423 
424  return Py_BuildValue("i", 0);
425 
426 }
427 
428 
429 
436 static PyObject *
437 qgd_Circuit_Wrapper_add_CZ(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
438 {
439 
440  // The tuple of expected keywords
441  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
442 
443  // initiate variables for input arguments
444  int target_qbit = -1;
445  int control_qbit = -1;
446 
447  // parsing input arguments
448  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
449  &target_qbit, &control_qbit))
450  return Py_BuildValue("i", -1);
451 
452 
453  // adding CZ gate to the end of the gate structure
454  if (target_qbit != -1 ) {
455  self->circuit->add_cz(target_qbit, control_qbit);
456  }
457 
458  return Py_BuildValue("i", 0);
459 
460 }
461 
462 
463 
470 static PyObject *
471 qgd_Circuit_Wrapper_add_CH(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
472 {
473 
474  // The tuple of expected keywords
475  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
476 
477  // initiate variables for input arguments
478  int target_qbit = -1;
479  int control_qbit = -1;
480 
481  // parsing input arguments
482  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
483  &target_qbit, &control_qbit))
484  return Py_BuildValue("i", -1);
485 
486 
487  // adding CZ gate to the end of the gate structure
488  if (target_qbit != -1 ) {
489  self->circuit->add_ch(target_qbit, control_qbit);
490  }
491 
492  return Py_BuildValue("i", 0);
493 
494 }
495 
496 
497 
504 static PyObject *
505 qgd_Circuit_Wrapper_add_SYC(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
506 {
507 
508  // The tuple of expected keywords
509  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
510 
511  // initiate variables for input arguments
512  int target_qbit = -1;
513  int control_qbit = -1;
514 
515  // parsing input arguments
516  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
517  &target_qbit, &control_qbit))
518  return Py_BuildValue("i", -1);
519 
520 
521  // adding Sycamore gate to the end of the gate structure
522  if (target_qbit != -1 ) {
523  self->circuit->add_syc(target_qbit, control_qbit);
524  }
525 
526  return Py_BuildValue("i", 0);
527 
528 }
529 
530 
531 
538 static PyObject *
539 qgd_Circuit_Wrapper_add_H(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
540 {
541 
542  // The tuple of expected keywords
543  static char *kwlist[] = {(char*)"target_qbit", NULL};
544 
545  // initiate variables for input arguments
546  int target_qbit = -1;
547 
548  // parsing input arguments
549  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
550  &target_qbit))
551  return Py_BuildValue("i", -1);
552 
553 
554  // adding X gate to the end of the gate structure
555  if (target_qbit != -1 ) {
556  self->circuit->add_h(target_qbit);
557  }
558 
559  return Py_BuildValue("i", 0);
560 
561 }
562 
563 
564 
571 static PyObject *
572 qgd_Circuit_Wrapper_add_X(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
573 {
574 
575  // The tuple of expected keywords
576  static char *kwlist[] = {(char*)"target_qbit", NULL};
577 
578  // initiate variables for input arguments
579  int target_qbit = -1;
580 
581  // parsing input arguments
582  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
583  &target_qbit))
584  return Py_BuildValue("i", -1);
585 
586 
587  // adding X gate to the end of the gate structure
588  if (target_qbit != -1 ) {
589  self->circuit->add_x(target_qbit);
590  }
591 
592  return Py_BuildValue("i", 0);
593 
594 }
595 
596 
597 
604 static PyObject *
605 qgd_Circuit_Wrapper_add_Y(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
606 {
607 
608  // The tuple of expected keywords
609  static char *kwlist[] = {(char*)"target_qbit", NULL};
610 
611  // initiate variables for input arguments
612  int target_qbit = -1;
613 
614  // parsing input arguments
615  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
616  &target_qbit))
617  return Py_BuildValue("i", -1);
618 
619 
620  // adding X gate to the end of the gate structure
621  if (target_qbit != -1 ) {
622  self->circuit->add_y(target_qbit);
623  }
624 
625  return Py_BuildValue("i", 0);
626 
627 }
628 
629 
630 
637 static PyObject *
638 qgd_Circuit_Wrapper_add_Z(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
639 {
640 
641  // The tuple of expected keywords
642  static char *kwlist[] = {(char*)"target_qbit", NULL};
643 
644  // initiate variables for input arguments
645  int target_qbit = -1;
646 
647  // parsing input arguments
648  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
649  &target_qbit))
650  return Py_BuildValue("i", -1);
651 
652 
653  // adding X gate to the end of the gate structure
654  if (target_qbit != -1 ) {
655  self->circuit->add_z(target_qbit);
656  }
657 
658  return Py_BuildValue("i", 0);
659 
660 }
661 
662 
663 
670 static PyObject *
671 qgd_Circuit_Wrapper_add_SX(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
672 {
673 
674  // The tuple of expected keywords
675  static char *kwlist[] = {(char*)"target_qbit", NULL};
676 
677  // initiate variables for input arguments
678  int target_qbit = -1;
679 
680  // parsing input arguments
681  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
682  &target_qbit))
683  return Py_BuildValue("i", -1);
684 
685 
686  // adding SX gate to the end of the gate structure
687  if (target_qbit != -1 ) {
688  self->circuit->add_sx(target_qbit);
689  }
690 
691  return Py_BuildValue("i", 0);
692 
693 }
694 
695 
696 
703 static PyObject *
704 qgd_Circuit_Wrapper_add_T(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
705 {
706 
707  // The tuple of expected keywords
708  static char *kwlist[] = {(char*)"target_qbit", NULL};
709 
710  // initiate variables for input arguments
711  int target_qbit = -1;
712 
713  // parsing input arguments
714  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
715  &target_qbit))
716  return Py_BuildValue("i", -1);
717 
718 
719  // adding T gate to the end of the gate structure
720  if (target_qbit != -1 ) {
721  self->circuit->add_t(target_qbit);
722  }
723 
724  return Py_BuildValue("i", 0);
725 
726 }
727 
728 
729 
736 static PyObject *
737 qgd_Circuit_Wrapper_add_Tdg(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
738 {
739 
740  // The tuple of expected keywords
741  static char *kwlist[] = {(char*)"target_qbit", NULL};
742 
743  // initiate variables for input arguments
744  int target_qbit = -1;
745 
746  // parsing input arguments
747  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist,
748  &target_qbit))
749  return Py_BuildValue("i", -1);
750 
751 
752  // adding Tdg gate to the end of the gate structure
753  if (target_qbit != -1 ) {
754  self->circuit->add_tdg(target_qbit);
755  }
756 
757  return Py_BuildValue("i", 0);
758 
759 }
760 
761 
762 
769 static PyObject *
770 qgd_Circuit_Wrapper_add_CRY(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
771 {
772 
773  // The tuple of expected keywords
774  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
775 
776  // initiate variables for input arguments
777  int target_qbit = -1;
778  int control_qbit = -1;
779 
780  // parsing input arguments
781  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
782  &target_qbit, &control_qbit))
783  return Py_BuildValue("i", -1);
784 
785  // adding U3 gate to the end of the gate structure
786  if (target_qbit != -1 ) {
787  self->circuit->add_cry(target_qbit, control_qbit);
788  }
789 
790  return Py_BuildValue("i", 0);
791 
792 }
793 
794 
801 static PyObject *
802 qgd_Circuit_Wrapper_add_CR(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
803 {
804 
805  // The tuple of expected keywords
806  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
807 
808  // initiate variables for input arguments
809  int target_qbit = -1;
810  int control_qbit = -1;
811 
812  // parsing input arguments
813  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
814  &target_qbit, &control_qbit))
815  return Py_BuildValue("i", -1);
816 
817  // adding U3 gate to the end of the gate structure
818  if (target_qbit != -1 ) {
819  self->circuit->add_cr(target_qbit, control_qbit);
820  }
821 
822  return Py_BuildValue("i", 0);
823 
824 }
825 
832 static PyObject *
833 qgd_Circuit_Wrapper_add_CROT(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
834 {
835 
836  // The tuple of expected keywords
837  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
838 
839  // initiate variables for input arguments
840  int target_qbit = -1;
841  int control_qbit = -1;
842 
843  // parsing input arguments
844  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
845  &target_qbit, &control_qbit))
846  return Py_BuildValue("i", -1);
847  // adding U3 gate to the end of the gate structure
848  if (target_qbit != -1 ) {
849  self->circuit->add_crot(target_qbit, control_qbit);
850  }
851 
852  return Py_BuildValue("i", 0);
853 
854 }
855 
856 
857 
864 static PyObject *
865 qgd_Circuit_Wrapper_add_adaptive(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
866 {
867 
868  // The tuple of expected keywords
869  static char *kwlist[] = {(char*)"target_qbit", (char*)"control_qbit", NULL};
870 
871  // initiate variables for input arguments
872  int target_qbit = -1;
873  int control_qbit = -1;
874 
875  // parsing input arguments
876  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwlist,
877  &target_qbit, &control_qbit))
878  return Py_BuildValue("i", -1);
879 
880  // adding U3 gate to the end of the gate structure
881  if (target_qbit != -1 ) {
882  self->circuit->add_adaptive(target_qbit, control_qbit);
883  }
884 
885  return Py_BuildValue("i", 0);
886 
887 }
888 
889 
890 
897 static PyObject *
899 {
900 
901  // initiate variables for input arguments
902  PyObject *Py_Circuit;
903 
904  // parsing input arguments
905  if (!PyArg_ParseTuple(args, "|O",
906  &Py_Circuit))
907  return Py_BuildValue("i", -1);
908 
909 
910  qgd_Circuit_Wrapper* qgd_op_block = (qgd_Circuit_Wrapper*) Py_Circuit;
911 
912 
913  // adding general gate to the end of the gate structure
914  self->circuit->add_gate( static_cast<Gate*>( qgd_op_block->circuit->clone() ) );
915 
916  return Py_BuildValue("i", 0);
917 
918 }
919 
920 #ifdef __DFE__
921 
922 static PyObject*
923 DFEgateQGD_to_Python(DFEgate_kernel_type* DFEgates, int gatesNum)
924 {
925  PyObject* o = PyList_New(0);
926  for (int i = 0; i < gatesNum; i++) {
927  PyList_Append(o, Py_BuildValue("iiibbbb", DFEgates[i].ThetaOver2, DFEgates[i].Phi,
928  DFEgates[i].Lambda, DFEgates[i].target_qbit, DFEgates[i].control_qbit,
929  DFEgates[i].gate_type, DFEgates[i].metadata));
930  }
931  delete [] DFEgates;
932  return o;
933 }
934 
935 static DFEgate_kernel_type*
936 DFEgatePython_to_QGD(PyObject* obj)
937 {
938  Py_ssize_t gatesNum = PyList_Size(obj); //assert type is list
939  DFEgate_kernel_type* DFEgates = new DFEgate_kernel_type[gatesNum];
940  for (Py_ssize_t i = 0; i < gatesNum; i++) {
941  PyObject* t = PyList_GetItem(obj, i);
942  //assert type is tuple and PyTuple_Size(t) == 7
943  DFEgates[i].ThetaOver2 = PyLong_AsLong(PyTuple_GetItem(t, 0));
944  DFEgates[i].Phi = PyLong_AsLong(PyTuple_GetItem(t, 1));
945  DFEgates[i].Lambda = PyLong_AsLong(PyTuple_GetItem(t, 2));
946  DFEgates[i].target_qbit = PyLong_AsLong(PyTuple_GetItem(t, 3));
947  DFEgates[i].control_qbit = PyLong_AsLong(PyTuple_GetItem(t, 4));
948  DFEgates[i].gate_type = PyLong_AsLong(PyTuple_GetItem(t, 5));
949  DFEgates[i].metadata = PyLong_AsLong(PyTuple_GetItem(t, 6));
950  }
951  return DFEgates;
952 }
953 
954 static PyObject *
955 qgd_Circuit_Wrapper_convert_to_DFE_gates_with_derivates(qgd_Circuit_Wrapper *self, PyObject *args)
956 {
957  bool only_derivates = false;
958  PyArrayObject* parameters_mtx_np = NULL;
959 
960  if (!PyArg_ParseTuple(args, "|Ob",
961  &parameters_mtx_np, &only_derivates))
962  return Py_BuildValue("");
963 
964  if ( parameters_mtx_np == NULL ) {
965  return Py_BuildValue("");
966  }
967 
968  PyArrayObject* parameters_mtx = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)parameters_mtx_np, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
969 
970  // test C-style contiguous memory allocation of the array
971  if ( !PyArray_IS_C_CONTIGUOUS(parameters_mtx) ) {
972  std::cout << "parameters_mtx is not memory contiguous" << std::endl;
973  }
974 
975  // create QGD version of the parameters_mtx
976  Matrix_real parameters_mtx_mtx = numpy2matrix_real(parameters_mtx);
977 
978  int gatesNum = -1, gateSetNum = -1, redundantGateSets = -1;
979  DFEgate_kernel_type* ret = self->circuit->convert_to_DFE_gates_with_derivates(parameters_mtx_mtx, gatesNum, gateSetNum, redundantGateSets, only_derivates);
980  return Py_BuildValue("Oii", DFEgateQGD_to_Python(ret, gatesNum), gateSetNum, redundantGateSets);
981 }
982 
983 static PyObject *
984 qgd_Circuit_Wrapper_adjust_parameters_for_derivation(qgd_Circuit_Wrapper *self, PyObject *args)
985 {
986  int gatesNum = -1;
987  PyObject* dfegates = NULL;
988  if (!PyArg_ParseTuple(args, "|Oi",
989  &dfegates, &gatesNum))
990  return Py_BuildValue("");
991  int gate_idx = -1, gate_set_index = -1;
992  DFEgate_kernel_type* dfegates_qgd = DFEgatePython_to_QGD(dfegates);
993  self->circuit->adjust_parameters_for_derivation(dfegates_qgd, gatesNum, gate_idx, gate_set_index);
994  return Py_BuildValue("Oii", DFEgateQGD_to_Python(dfegates_qgd, gatesNum), gate_idx, gate_set_index);
995 }
996 
997 /*static PyObject *
998 qgd_Circuit_Wrapper_convert_to_DFE_gates(qgd_Circuit_Wrapper *self, PyObject *args)
999 {
1000  PyObject* parameters_mtx_np = NULL;
1001  if (!PyArg_ParseTuple(args, "|O",
1002  &parameters_mtx_np))
1003  return Py_BuildValue("");
1004 
1005  if ( parameters_mtx_np == NULL ) return Py_BuildValue("");
1006  PyObject* parameters_mtx = PyArray_FROM_OTF(parameters_mtx_np, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1007 
1008  // test C-style contiguous memory allocation of the array
1009  if ( !PyArray_IS_C_CONTIGUOUS(parameters_mtx) ) {
1010  std::cout << "parameters_mtx is not memory contiguous" << std::endl;
1011  }
1012 
1013  // create QGD version of the parameters_mtx
1014  Matrix_real parameters_mtx_mtx = numpy2matrix_real(parameters_mtx);
1015 
1016  int gatesNum = -1;
1017  DFEgate_kernel_type* ret = self->circuit->convert_to_DFE_gates(parameters_mtx_mtx, gatesNum);
1018  return DFEgateQGD_to_Python(ret, gatesNum);
1019 }*/
1020 
1021 static PyObject *
1022 qgd_Circuit_Wrapper_convert_to_DFE_gates(qgd_Circuit_Wrapper *self, PyObject *args)
1023 {
1024  int start_index = -1;
1025  PyArrayObject* parameters_mtx_np = NULL;
1026  PyObject* dfegates = NULL;
1027 
1028  if (!PyArg_ParseTuple(args, "|OOi",
1029  &parameters_mtx_np, &dfegates, &start_index))
1030  return Py_BuildValue("");
1031 
1032 
1033  if ( parameters_mtx_np == NULL ) {
1034  return Py_BuildValue("");
1035  }
1036 
1037  PyArrayObject* parameters_mtx = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)parameters_mtx_np, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1038 
1039  // test C-style contiguous memory allocation of the array
1040  if ( !PyArray_IS_C_CONTIGUOUS(parameters_mtx) ) {
1041  std::cout << "parameters_mtx is not memory contiguous" << std::endl;
1042  }
1043 
1044  // create QGD version of the parameters_mtx
1045  Matrix_real parameters_mtx_mtx = numpy2matrix_real(parameters_mtx);
1046  DFEgate_kernel_type* dfegates_qgd = DFEgatePython_to_QGD(dfegates);
1047 
1048  Py_ssize_t gatesNum = PyList_Size(dfegates);
1049 
1050  self->circuit->convert_to_DFE_gates(parameters_mtx_mtx, dfegates_qgd, start_index);
1051 
1052  return DFEgateQGD_to_Python(dfegates_qgd, gatesNum);
1053 }
1054 
1055 #endif
1056 
1061 static PyObject *
1063 
1064  PyArrayObject * parameters_arr = NULL;
1065 
1066 
1067  // parsing input arguments
1068  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
1069  return Py_BuildValue("i", -1);
1070 
1071 
1072  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1073  Py_INCREF(parameters_arr);
1074  }
1075  else {
1076  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1077  }
1078 
1079 
1080  // get the C++ wrapper around the data
1081  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1082 
1083 
1084  Matrix mtx = self->circuit->get_matrix( parameters_mtx );
1085 
1086  // convert to numpy array
1087  mtx.set_owner(false);
1088  PyObject *mtx_py = matrix_to_numpy( mtx );
1089 
1090 
1091  Py_DECREF(parameters_arr);
1092 
1093  return mtx_py;
1094 }
1095 
1096 
1097 
1101 static PyObject *
1103 
1104  int parameter_num = self->circuit->get_parameter_num();
1105 
1106  return Py_BuildValue("i", parameter_num);
1107 }
1108 
1109 
1110 
1114 static PyObject *
1115 qgd_Circuit_Wrapper_apply_to( qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds ) {
1116 
1117  PyArrayObject * parameters_arr = NULL;
1118  PyArrayObject * unitary_arg = NULL;
1119 
1120  int parallel = 1;
1121 
1122  static char *kwlist[] = {(char*)"", (char*)"", (char*)"parallel", NULL};
1123 
1124 
1125  // parsing input arguments
1126  if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i", kwlist, &parameters_arr, &unitary_arg, &parallel )) {
1127  PyErr_SetString(PyExc_Exception, "Unable to parse input");
1128  return NULL;
1129  }
1130 
1131 
1132 
1133  if ( unitary_arg == NULL ) {
1134  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1135  return NULL;
1136  }
1137 
1138 
1139  if ( parameters_arr == NULL ) {
1140  PyErr_SetString(PyExc_Exception, "Parameters were not given");
1141  return NULL;
1142  }
1143 
1144 
1145 
1146  if ( PyArray_TYPE(parameters_arr) != NPY_DOUBLE ) {
1147  PyErr_SetString(PyExc_Exception, "Parameter vector should be real typed");
1148  return NULL;
1149  }
1150 
1151 
1152  if ( PyArray_TYPE(unitary_arg) != NPY_COMPLEX128 ) {
1153  PyErr_SetString(PyExc_Exception, "input matrix or state should be complex typed");
1154  return NULL;
1155  }
1156 
1157 
1158  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1159  Py_INCREF(parameters_arr);
1160  }
1161  else {
1162  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1163  }
1164 
1165  // get the C++ wrapper around the data
1166  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1167 
1168 
1169 
1170  PyArrayObject* unitary = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)unitary_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1171 
1172  // test C-style contiguous memory allocation of the array
1173  if ( !PyArray_IS_C_CONTIGUOUS(unitary) ) {
1174  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
1175  return NULL;
1176  }
1177 
1178 
1179  // create QGD version of the input matrix
1180  Matrix unitary_mtx = numpy2matrix(unitary);
1181 
1182  try {
1183  self->circuit->apply_to( parameters_mtx, unitary_mtx, parallel );
1184  }
1185  catch (std::string err) {
1186 
1187  Py_DECREF(parameters_arr);
1188  Py_DECREF(unitary);
1189 
1190  PyErr_SetString(PyExc_Exception, err.c_str());
1191  return NULL;
1192  }
1193  catch(...) {
1194 
1195  Py_DECREF(parameters_arr);
1196  Py_DECREF(unitary);
1197 
1198  std::string err( "Invalid pointer to circuit class");
1199  PyErr_SetString(PyExc_Exception, err.c_str());
1200  return NULL;
1201  }
1202 
1203  if (unitary_mtx.data != PyArray_DATA(unitary)) {
1204  memcpy(PyArray_DATA(unitary), unitary_mtx.data, unitary_mtx.size() * sizeof(QGD_Complex16));
1205  }
1206 
1207  Py_DECREF(parameters_arr);
1208  Py_DECREF(unitary);
1209 
1210  return Py_BuildValue("i", 0);
1211 }
1212 
1213 
1214 
1218 static PyObject *
1220 {
1221 
1222 
1223  PyArrayObject * parameters_arr = NULL;
1224  PyArrayObject * input_state_arg = NULL;
1225  PyObject * qubit_list_arg = NULL;
1226 
1227 
1228  // parsing input arguments
1229  if (!PyArg_ParseTuple(args, "|OOO", &parameters_arr, &input_state_arg, &qubit_list_arg ))
1230  return Py_BuildValue("i", -1);
1231 
1232 
1233  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1234  Py_INCREF(parameters_arr);
1235  }
1236  else {
1237  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1238  }
1239 
1240  // get the C++ wrapper around the data
1241  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1242 
1243 
1244  // convert python object array to numpy C API array
1245  if ( input_state_arg == NULL ) {
1246  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1247  return NULL;
1248  }
1249 
1250  PyArrayObject* input_state = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)input_state_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1251 
1252  // test C-style contiguous memory allocation of the array
1253  if ( !PyArray_IS_C_CONTIGUOUS(input_state) ) {
1254  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
1255  return NULL;
1256  }
1257 
1258 
1259 
1260 
1261  // create QGD version of the input matrix
1262  Matrix input_state_mtx = numpy2matrix(input_state);
1263 
1264 
1265  // check input argument qbit_list
1266  if ( qubit_list_arg == NULL || (!PyList_Check( qubit_list_arg )) ) {
1267  PyErr_SetString(PyExc_Exception, "qubit_list should be a list");
1268  return NULL;
1269  }
1270 
1271  Py_ssize_t reduced_qbit_num = PyList_Size( qubit_list_arg );
1272 
1273  matrix_base<int> qbit_list_mtx( (int)reduced_qbit_num, 1);
1274  for ( int idx=0; idx<reduced_qbit_num; idx++ ) {
1275 
1276  PyObject* item = PyList_GET_ITEM( qubit_list_arg, idx );
1277  qbit_list_mtx[idx] = (int) PyLong_AsLong( item );
1278 
1279  }
1280 
1281 
1282  double entropy = -1;
1283 
1284 
1285  try {
1286  entropy = self->circuit->get_second_Renyi_entropy( parameters_mtx, input_state_mtx, qbit_list_mtx );
1287  }
1288  catch (std::string err) {
1289  PyErr_SetString(PyExc_Exception, err.c_str());
1290  return NULL;
1291  }
1292  catch(...) {
1293  std::string err( "Invalid pointer to circuit class");
1294  PyErr_SetString(PyExc_Exception, err.c_str());
1295  return NULL;
1296  }
1297 
1298 
1299  Py_DECREF(parameters_arr);
1300  Py_DECREF(input_state);
1301 
1302 
1303 
1304  PyObject* p = Py_BuildValue("d", entropy);
1305 
1306  return p;
1307 }
1308 
1309 
1310 
1314 static PyObject *
1316 
1317  int qbit_num = 0;
1318 
1319  try {
1320  qbit_num = self->circuit->get_qbit_num();
1321  }
1322  catch (std::string err) {
1323  PyErr_SetString(PyExc_Exception, err.c_str());
1324  std::cout << err << std::endl;
1325  return NULL;
1326  }
1327  catch(...) {
1328  std::string err( "Invalid pointer to circuit class");
1329  PyErr_SetString(PyExc_Exception, err.c_str());
1330  return NULL;
1331  }
1332 
1333 
1334  return Py_BuildValue("i", qbit_num );
1335 
1336 }
1337 
1338 
1339 
1340 
1344 static PyObject *
1346 
1347  int qbit_num = 0;
1348 
1349  // parsing input arguments
1350  if (!PyArg_ParseTuple(args, "|i", &qbit_num )) {
1351  std::string err( "Unable to parse arguments");
1352  PyErr_SetString(PyExc_Exception, err.c_str());
1353  return NULL;
1354  }
1355 
1356 
1357  try {
1358  self->circuit->set_qbit_num( qbit_num );
1359  }
1360  catch (std::string err) {
1361  PyErr_SetString(PyExc_Exception, err.c_str());
1362  std::cout << err << std::endl;
1363  return NULL;
1364  }
1365  catch(...) {
1366  std::string err( "Invalid pointer to circuit class");
1367  PyErr_SetString(PyExc_Exception, err.c_str());
1368  return NULL;
1369  }
1370 
1371 
1372  return Py_None;
1373 
1374 }
1375 
1376 
1377 
1381 static PyObject *
1383 
1384  PyObject* ret = PyList_New(0);
1385 
1386  try {
1387  std::vector<int>&& qbits = self->circuit->get_involved_qubits();
1388  for (int idx = 0; idx < qbits.size(); idx++) {
1389  PyList_Append(ret, Py_BuildValue("i", qbits[idx] ) );
1390  }
1391 
1392  }
1393  catch (std::string err) {
1394  PyErr_SetString(PyExc_Exception, err.c_str());
1395  std::cout << err << std::endl;
1396  return NULL;
1397  }
1398  catch(...) {
1399  std::string err( "Invalid pointer to circuit class");
1400  PyErr_SetString(PyExc_Exception, err.c_str());
1401  return NULL;
1402  }
1403 
1404 
1405  return Py_BuildValue("O", ret );
1406 
1407 }
1408 
1409 
1410 
1414 static PyObject *
1416 
1417 
1418  PyObject* qbit_map_arg = NULL;
1419  int qbit_num = 0;
1420 
1421 
1422  // parsing input arguments
1423  if (!PyArg_ParseTuple(args, "|Oi", &qbit_map_arg, &qbit_num ))
1424  return Py_BuildValue("i", -1);
1425 
1426 
1427  // parse qbit map and create C++ version of the map
1428 
1429  bool is_dict = PyDict_Check( qbit_map_arg );
1430  if (!is_dict) {
1431  printf("Qubit map object must be a python dictionary!\n");
1432  return Py_BuildValue("i", -1);
1433  }
1434 
1435  // integer type config metadata utilized during the optimization
1436  std::map<int, int> qbit_map;
1437 
1438 
1439  // keys and values of the config dict (borrowed references)
1440  PyObject *key, *value;
1441  Py_ssize_t pos = 0;
1442 
1443  while (PyDict_Next(qbit_map_arg, &pos, &key, &value)) {
1444 
1445 
1446  if ( PyLong_Check( value ) && PyLong_Check( key ) ) {
1447  int key_Cpp = (int)PyLong_AsLongLong( key );
1448  qbit_map[ key_Cpp ] = (int)PyLong_AsLongLong( value );
1449  }
1450  else {
1451  std::string err( "Key and value in the qbit_map should be integers");
1452  PyErr_SetString(PyExc_Exception, err.c_str());
1453  return NULL;
1454  }
1455 
1456  }
1457 
1458 
1459  Gates_block* remapped_circuit = NULL;
1460 
1461  try {
1462  remapped_circuit = self->circuit->create_remapped_circuit( qbit_map, qbit_num);
1463 
1464  }
1465  catch (std::string err) {
1466  PyErr_SetString(PyExc_Exception, err.c_str());
1467  std::cout << err << std::endl;
1468  return NULL;
1469  }
1470  catch(...) {
1471  std::string err( "Invalid pointer to circuit class");
1472  PyErr_SetString(PyExc_Exception, err.c_str());
1473  return NULL;
1474  }
1475 
1476 
1477 
1478  // import gate operation modules
1479  PyObject* qgd_circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
1480 
1481  if ( qgd_circuit == NULL ) {
1482  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
1483  return NULL;
1484  }
1485 
1486  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_circuit );
1487 
1488  // 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
1489  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
1490 
1491  PyObject* circuit_input = Py_BuildValue("(O)", Py_BuildValue("i", qbit_num) );
1492  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
1493 
1494 
1495  // replace dummy data with real gate data
1496  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
1497 
1498  delete( py_circuit_C->circuit );
1499  py_circuit_C->circuit = remapped_circuit;
1500 
1501  Py_DECREF( qgd_circuit );
1502  Py_DECREF( circuit_input );
1503 
1504 
1505  return py_circuit;
1506 
1507 }
1508 
1509 
1510 
1511 
1518 static PyObject *
1520 
1521 
1522  Gate* gate = circuit->get_gate( idx );
1523 
1524  // create dummy gate parameters to instantiate dummy object, which are then filled up with valid data
1525  PyObject* qbit_num = Py_BuildValue("i", gate->get_qbit_num() );
1526  PyObject* target_qbit = Py_BuildValue("i", gate->get_target_qbit() );
1527  PyObject* control_qbit = Py_BuildValue("i", gate->get_control_qbit() );
1528 
1529  // The python instance of the gate
1530  PyObject* py_gate = NULL;
1531 
1532  // import gate operation modules
1533  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.gates_Wrapper");
1534 
1535  if ( qgd_gate == NULL ) {
1536  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.gates_Wrapper" );
1537  return NULL;
1538  }
1539 
1540  if (gate->get_type() == CNOT_OPERATION) {
1541 
1542 
1543  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1544  // 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
1545  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CNOT");
1546 
1547  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1548  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1549 
1550  // replace dummy data with real gate data
1551  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1552  delete( py_gate_C->gate );
1553  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1554 
1555  Py_DECREF( qgd_gate );
1556  Py_DECREF( gate_input );
1557 
1558 
1559  }
1560  else if (gate->get_type() == CZ_OPERATION) {
1561 
1562 
1563  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1564  // 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
1565  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CZ");
1566 
1567  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1568  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1569 
1570  // replace dummy data with real gate data
1571  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1572  delete( py_gate_C->gate );
1573  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1574 
1575 
1576  Py_DECREF( qgd_gate );
1577  Py_DECREF( gate_input );
1578 
1579 
1580  }
1581  else if (gate->get_type() == CH_OPERATION) {
1582 
1583 
1584  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1585  // 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
1586  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CH");
1587 
1588  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1589  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1590 
1591  // replace dummy data with real gate data
1592  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1593  delete( py_gate_C->gate );
1594  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1595 
1596  Py_DECREF( qgd_gate );
1597  Py_DECREF( gate_input );
1598 
1599  }
1600  else if (gate->get_type() == SYC_OPERATION) {
1601 
1602 
1603  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1604  // 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
1605  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "SYC");
1606 
1607  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1608  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1609 
1610  // replace dummy data with real gate data
1611  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1612  delete( py_gate_C->gate );
1613  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1614 
1615  Py_DECREF( qgd_gate );
1616  Py_DECREF( gate_input );
1617 
1618 
1619  }
1620  else if (gate->get_type() == U1_OPERATION) {
1621 
1622  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1623  // 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
1624  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "U1");
1625 
1626  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1627  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1628 
1629  // replace dummy data with real gate data
1630  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1631  delete( py_gate_C->gate );
1632  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1633 
1634  Py_DECREF( qgd_gate );
1635  Py_DECREF( gate_input );
1636 
1637  }
1638  else if (gate->get_type() == U2_OPERATION) {
1639 
1640  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1641  // 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
1642  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "U2");
1643 
1644  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1645  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1646 
1647  // replace dummy data with real gate data
1648  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1649  delete( py_gate_C->gate );
1650  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1651 
1652  Py_DECREF( qgd_gate );
1653  Py_DECREF( gate_input );
1654 
1655  }
1656  else if (gate->get_type() == U3_OPERATION) {
1657 
1658  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1659  // 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
1660  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "U3");
1661 
1662  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1663  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1664 
1665  // replace dummy data with real gate data
1666  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1667  delete( py_gate_C->gate );
1668  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1669 
1670  Py_DECREF( qgd_gate );
1671  Py_DECREF( gate_input );
1672 
1673  }
1674  else if (gate->get_type() == RX_OPERATION) {
1675 
1676 
1677  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1678  // 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
1679  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "RX");
1680 
1681  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1682  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1683 
1684  // replace dummy data with real gate data
1685  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1686  delete( py_gate_C->gate );
1687  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1688 
1689  Py_DECREF( qgd_gate );
1690  Py_DECREF( gate_input );
1691 
1692  }
1693  else if (gate->get_type() == R_OPERATION) {
1694 
1695 
1696  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1697  // 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
1698  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "R");
1699 
1700  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1701  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1702 
1703  // replace dummy data with real gate data
1704  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1705  delete( py_gate_C->gate );
1706  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1707 
1708  Py_DECREF( qgd_gate );
1709  Py_DECREF( gate_input );
1710 
1711  }
1712  else if (gate->get_type() == RY_OPERATION) {
1713 
1714 
1715  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1716  // 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
1717  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "RY");
1718 
1719  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1720  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1721 
1722  // replace dummy data with real gate data
1723  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1724  delete( py_gate_C->gate );
1725  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1726 
1727  Py_DECREF( qgd_gate );
1728  Py_DECREF( gate_input );
1729 
1730  }
1731  else if (gate->get_type() == CRY_OPERATION) {
1732 
1733 
1734  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1735  // 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
1736  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CRY");
1737 
1738  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1739  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1740 
1741  // replace dummy data with real gate data
1742  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1743  delete( py_gate_C->gate );
1744  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1745 
1746  Py_DECREF( qgd_gate );
1747  Py_DECREF( gate_input );
1748 
1749 /*
1750 
1751  // import gate operation modules
1752  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.qgd_CRY");
1753 
1754  if ( qgd_gate == NULL ) {
1755  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_CRY" );
1756  return NULL;
1757  }
1758 
1759  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1760  // 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
1761  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "qgd_CRY");
1762 
1763  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1764  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1765 
1766  // replace dummy data with real gate data
1767  qgd_CRY_Wrapper* py_gate_C = reinterpret_cast<qgd_CRY_Wrapper*>( py_gate );
1768  delete( py_gate_C->gate );
1769  py_gate_C->gate = static_cast<CRY*>( gate->clone() );
1770 
1771  Py_DECREF( qgd_gate );
1772  Py_DECREF( gate_input );
1773 */
1774  }
1775  else if (gate->get_type() == CROT_OPERATION) {
1776 
1777  // import gate operation modules
1778 
1779  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1780  // 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
1781  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CROT");
1782 
1783  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1784  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1785 
1786  // replace dummy data with real gate data
1787  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1788  delete( py_gate_C->gate );
1789  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1790 
1791  Py_DECREF( qgd_gate );
1792  Py_DECREF( gate_input );
1793 
1794  }
1795  else if (gate->get_type() == CR_OPERATION) {
1796 
1797  // import gate operation modules
1798 
1799  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1800  // 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
1801  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "CR");
1802 
1803  PyObject* gate_input = Py_BuildValue("(OOO)", qbit_num, target_qbit, control_qbit);
1804  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1805 
1806  // replace dummy data with real gate data
1807  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1808  delete( py_gate_C->gate );
1809  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1810 
1811  Py_DECREF( qgd_gate );
1812  Py_DECREF( gate_input );
1813 
1814  }
1815  else if (gate->get_type() == RZ_OPERATION) {
1816 
1817 
1818  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1819  // 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
1820  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "RZ");
1821 
1822  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1823  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1824 
1825  // replace dummy data with real gate data
1826  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1827  delete( py_gate_C->gate );
1828  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1829 
1830  Py_DECREF( qgd_gate );
1831  Py_DECREF( gate_input );
1832 
1833  }
1834  else if (gate->get_type() == H_OPERATION) {
1835 
1836 
1837  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1838  // 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
1839  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "H");
1840 
1841  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1842  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1843 
1844  // replace dummy data with real gate data
1845  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1846  delete( py_gate_C->gate );
1847  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1848 
1849  Py_DECREF( qgd_gate );
1850  Py_DECREF( gate_input );
1851 
1852 
1853  }
1854  else if (gate->get_type() == X_OPERATION) {
1855 
1856 
1857  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1858  // 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
1859  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "X");
1860 
1861  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1862  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1863 
1864  // replace dummy data with real gate data
1865  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1866  delete( py_gate_C->gate );
1867  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1868 
1869  Py_DECREF( qgd_gate );
1870  Py_DECREF( gate_input );
1871 
1872 
1873  }
1874  else if (gate->get_type() == Y_OPERATION) {
1875 
1876 
1877  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1878  // 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
1879  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Y");
1880 
1881  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1882  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1883 
1884  // replace dummy data with real gate data
1885  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1886  delete( py_gate_C->gate );
1887  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1888 
1889  Py_DECREF( qgd_gate );
1890  Py_DECREF( gate_input );
1891 
1892 
1893  }
1894  else if (gate->get_type() == Z_OPERATION) {
1895 
1896 
1897  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1898  // 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
1899  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Z");
1900 
1901  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1902  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1903 
1904  // replace dummy data with real gate data
1905  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1906  delete( py_gate_C->gate );
1907  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1908 
1909  Py_DECREF( qgd_gate );
1910  Py_DECREF( gate_input );
1911 
1912 
1913  }
1914  else if (gate->get_type() == SX_OPERATION) {
1915 
1916 
1917  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1918  // 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
1919  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "SX");
1920 
1921  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1922  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1923 
1924  // replace dummy data with real gate data
1925  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1926  delete( py_gate_C->gate );
1927  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1928 
1929  Py_DECREF( qgd_gate );
1930  Py_DECREF( gate_input );
1931 
1932 
1933  }
1934  else if (gate->get_type() == T_OPERATION) {
1935 
1936 
1937  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1938  // 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
1939  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "T");
1940 
1941  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1942  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1943 
1944  // replace dummy data with real gate data
1945  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1946  delete( py_gate_C->gate );
1947  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1948 
1949  Py_DECREF( qgd_gate );
1950  Py_DECREF( gate_input );
1951 
1952 
1953  }
1954  else if (gate->get_type() == TDG_OPERATION){
1955 
1956 
1957  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate );
1958  // 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
1959  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Tdg");
1960 
1961  PyObject* gate_input = Py_BuildValue("(OO)", qbit_num, target_qbit);
1962  py_gate = PyObject_CallObject(py_gate_class, gate_input);
1963 
1964  // replace dummy data with real gate data
1965  qgd_Gate* py_gate_C = reinterpret_cast<qgd_Gate*>( py_gate );
1966  delete( py_gate_C->gate );
1967  py_gate_C->gate = static_cast<Gate*>( gate->clone() );
1968 
1969  Py_DECREF( qgd_gate );
1970  Py_DECREF( gate_input );
1971 
1972 
1973  }
1974  else if (gate->get_type() == BLOCK_OPERATION) {
1975 
1976  // import gate operation modules
1977  PyObject* qgd_circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
1978 
1979  if ( qgd_circuit == NULL ) {
1980  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
1981  return NULL;
1982  }
1983 
1984  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_circuit );
1985 
1986  // 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
1987  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
1988 
1989  PyObject* circuit_input = Py_BuildValue("(O)", qbit_num );
1990  py_gate = PyObject_CallObject(py_circuit_class, circuit_input);
1991 
1992  // replace dummy data with real gate data
1993  qgd_Circuit_Wrapper* py_gate_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_gate );
1994 
1995  Gates_block* circuit = reinterpret_cast<Gates_block*>( gate );
1996  delete( py_gate_C->circuit );
1997  py_gate_C->circuit = circuit->clone();
1998 
1999  Py_DECREF( qgd_circuit );
2000  Py_DECREF( circuit_input );
2001 
2002  }
2003  else {
2004 
2005  Py_DECREF( qgd_gate );
2006  Py_XDECREF(qbit_num);
2007  Py_XDECREF(target_qbit);
2008  Py_XDECREF(control_qbit);
2009  PyErr_SetString(PyExc_Exception, "qgd_Circuit_Wrapper::get_gate: unimplemented gate type" );
2010  return NULL;
2011  }
2012 
2013  Py_XDECREF(qbit_num);
2014  Py_XDECREF(target_qbit);
2015  Py_XDECREF(control_qbit);
2016 
2017  return py_gate;
2018 
2019 }
2020 
2021 
2022 
2029 static PyObject *
2031 
2032  // initiate variables for input arguments
2033  int idx;
2034 
2035  // parsing input arguments
2036  if (!PyArg_ParseTuple(args, "|i", &idx )) return Py_BuildValue("i", -1);
2037 
2038 
2039  return get_gate( self->circuit, idx );
2040 
2041 
2042 }
2043 
2044 
2048 static PyObject *
2050 
2051  std::map< std::string, int > gate_nums;
2052 
2053  try {
2054  gate_nums = self->circuit->get_gate_nums();
2055  }
2056  catch (std::string err) {
2057  PyErr_SetString(PyExc_Exception, err.c_str());
2058  return NULL;
2059  }
2060  catch(...) {
2061  std::string err( "Invalid pointer to circuit class");
2062  PyErr_SetString(PyExc_Exception, err.c_str());
2063  return NULL;
2064  }
2065 
2066 
2067  PyObject* gate_nums_py = PyDict_New();
2068  if( gate_nums_py == NULL ) {
2069  std::string err( "Failed to create dictionary");
2070  PyErr_SetString(PyExc_Exception, err.c_str());
2071  return NULL;
2072  }
2073 
2074  for( auto it = gate_nums.begin(); it != gate_nums.end(); it++ ) {
2075 
2076  PyObject* key = Py_BuildValue( "s", it->first.c_str() );
2077  PyObject* val = Py_BuildValue("i", it->second );
2078 
2079  PyDict_SetItem(gate_nums_py, key, val);
2080  }
2081 
2082  return gate_nums_py;
2083 
2084 }
2085 
2086 
2087 
2088 
2092 static PyObject *
2094 
2095 
2096 
2097 
2098  // get the number of gates
2099  int op_num = self->circuit->get_gate_num();
2100 
2101  // preallocate Python tuple for the output
2102  PyObject* ret = PyTuple_New( (Py_ssize_t) op_num );
2103 
2104 
2105 
2106  // iterate over the gates to get the gate list
2107  for (int idx = 0; idx < op_num; idx++ ) {
2108 
2109  // get metadata about the idx-th gate
2110  PyObject* gate = get_gate( self->circuit, idx );
2111 
2112  // adding gate information to the tuple
2113  PyTuple_SetItem( ret, (Py_ssize_t) idx, gate );
2114 
2115  }
2116 
2117 
2118  return ret;
2119 
2120 }
2121 
2122 
2123 
2130 static PyObject *
2132 
2133  // the gate for which we look for the parents
2134  PyObject* py_gate = NULL;
2135 
2136  // parsing input arguments
2137  if (!PyArg_ParseTuple(args, "|O", &py_gate )) return Py_BuildValue("i", -1);
2138 
2139 
2140  if( py_gate == NULL ) {
2141  return PyTuple_New( 0 );
2142  }
2143 
2144  qgd_Gate* gate_struct = reinterpret_cast<qgd_Gate*>( py_gate );
2145  std::vector<Gate*> parents = gate_struct->gate->get_parents();
2146 
2147  // preallocate tuple for the output
2148  PyObject* parent_tuple = PyTuple_New( (Py_ssize_t) parents.size() );
2149 
2150  std::vector<Gate*>&& gates = self->circuit->get_gates();
2151 
2152 
2153  // find the indices of the parents
2154  for(int idx=0; idx<parents.size(); idx++) {
2155 
2156  Gate* parent_gate = parents[idx];
2157 
2158  // find the index of the parent_gate
2159  int parent_idx = -1;
2160  for( int jdx=0; jdx<gates.size(); jdx++ ) {
2161 
2162  Gate* gate = gates[jdx];
2163 
2164  if( parent_gate == gate ) {
2165  parent_idx = jdx;
2166  break;
2167  }
2168 
2169  if( jdx == gates.size()-1 ) {
2170  std::string err( "Parent gate did not found in the circuit. May be the gate is not in the circuit");
2171  PyErr_SetString(PyExc_Exception, err.c_str());
2172  return NULL;
2173  }
2174 
2175  }
2176 
2177  // adding parent_idx the tuple
2178  PyTuple_SetItem( parent_tuple, (Py_ssize_t) idx, Py_BuildValue("i", parent_idx) );
2179 
2180 
2181  }
2182 
2183 
2184  return parent_tuple;
2185 
2186 
2187 }
2188 
2189 
2190 
2191 
2198 static PyObject *
2200 
2201  // the gate for which we look for the children
2202  PyObject* py_gate = NULL;
2203 
2204  // parsing input arguments
2205  if (!PyArg_ParseTuple(args, "|O", &py_gate )) return Py_BuildValue("i", -1);
2206 
2207 
2208  if( py_gate == NULL ) {
2209  return PyTuple_New( 0 );
2210  }
2211 
2212  qgd_Gate* gate_struct = reinterpret_cast<qgd_Gate*>( py_gate );
2213  std::vector<Gate*> children = gate_struct->gate->get_children();
2214 
2215  // preallocate tuple for the output
2216  PyObject* children_tuple = PyTuple_New( (Py_ssize_t) children.size() );
2217 
2218  std::vector<Gate*>&& gates = self->circuit->get_gates();
2219 
2220 
2221  // find the indices of the children
2222  for(int idx=0; idx<children.size(); idx++) {
2223 
2224  Gate* child_gate = children[idx];
2225 
2226  // find the index of the child_gate
2227  int child_idx = -1;
2228  for( int jdx=0; jdx<gates.size(); jdx++ ) {
2229 
2230  Gate* gate = gates[jdx];
2231 
2232  if( child_gate == gate ) {
2233  child_idx = jdx;
2234  break;
2235  }
2236 
2237  if( jdx == gates.size()-1 ) {
2238  std::string err( "Child gate did not found in the circuit. May be the gate is not in the circuit");
2239  PyErr_SetString(PyExc_Exception, err.c_str());
2240  return NULL;
2241  }
2242 
2243  }
2244 
2245  // adding child_idx the tuple
2246  PyTuple_SetItem( children_tuple, (Py_ssize_t) idx, Py_BuildValue("i", child_idx) );
2247 
2248 
2249  }
2250 
2251 
2252  return children_tuple;
2253 
2254 
2255 }
2256 
2257 
2258 
2262 static PyObject *
2264 
2265  PyArrayObject * parameters_arr = NULL;
2266 
2267 
2268  // parsing input arguments
2269  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
2270  return Py_BuildValue("i", -1);
2271 
2272 
2273  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
2274  Py_INCREF(parameters_arr);
2275  }
2276  else {
2277  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
2278  }
2279 
2280  // get the C++ wrapper around the data
2281  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
2282 
2283 
2284 
2285  Matrix_real extracted_parameters;
2286 
2287  try {
2288  extracted_parameters = self->circuit->extract_parameters( parameters_mtx );
2289  }
2290  catch (std::string err) {
2291  PyErr_SetString(PyExc_Exception, err.c_str());
2292  return NULL;
2293  }
2294  catch(...) {
2295  std::string err( "Invalid pointer to circuit class");
2296  PyErr_SetString(PyExc_Exception, err.c_str());
2297  return NULL;
2298  }
2299 
2300 
2301  // convert to numpy array
2302  extracted_parameters.set_owner(false);
2303  PyObject *extracted_parameters_py = matrix_real_to_numpy( extracted_parameters );
2304 
2305 
2306  return extracted_parameters_py;
2307 }
2308 
2309 
2310 
2314 static PyObject *
2316 
2317  Gates_block* flat_circuit = self->circuit->get_flat_circuit();
2318  int qbit_num = flat_circuit->get_qbit_num();
2319 
2320  // import gate operation modules
2321  PyObject* qgd_circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
2322 
2323  if ( qgd_circuit == NULL ) {
2324  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
2325  return NULL;
2326  }
2327 
2328  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_circuit );
2329 
2330  // 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
2331  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
2332 
2333  PyObject* circuit_input = Py_BuildValue("(O)", Py_BuildValue("i", qbit_num) );
2334  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
2335 
2336  // replace dummy data with real gate data
2337  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
2338  delete( py_circuit_C->circuit );
2339  py_circuit_C->circuit = flat_circuit;
2340 
2341 
2342  Py_DECREF( qgd_circuit );
2343  Py_DECREF( circuit_input );
2344 
2345  return py_circuit;
2346 }
2347 
2348 
2349 
2350 
2354 static PyObject *
2356 
2357 
2358  // get the number of gates
2359  int op_num = self->circuit->get_gate_num();
2360 
2361  // preallocate Python tuple for the output
2362  PyObject* ret = PyTuple_New( (Py_ssize_t) op_num+1 );
2363 
2364 
2365 
2366 
2367  // add qbit num value to the return tuple
2368  PyObject* qbit_num_dict = PyDict_New();
2369 
2370  if( qbit_num_dict == NULL ) {
2371  std::string err( "Failed to create dictionary");
2372  PyErr_SetString(PyExc_Exception, err.c_str());
2373  return NULL;
2374  }
2375 
2376  int qbit_num = self->circuit->get_qbit_num();
2377  PyObject* qbit_num_key = Py_BuildValue( "s", "qbit_num" );
2378  PyObject* qbit_num_val = Py_BuildValue("i", qbit_num );
2379 
2380  PyDict_SetItem(qbit_num_dict, qbit_num_key, qbit_num_val);
2381 
2382  PyTuple_SetItem( ret, 0, qbit_num_dict );
2383 
2384  Py_DECREF( qbit_num_key );
2385  Py_DECREF( qbit_num_val );
2386  //Py_DECREF( qbit_num_dict );
2387 
2388 
2389  PyObject* method_name = Py_BuildValue("s", "__getstate__");
2390 
2391  // iterate over the gates to get the gate list
2392  for (int idx = 0; idx < op_num; idx++ ) {
2393 
2394  // get metadata about the idx-th gate
2395  PyObject* gate = get_gate( self->circuit, idx );
2396 
2397  PyObject* gate_state = PyObject_CallMethodObjArgs( gate, method_name, NULL );
2398 
2399 
2400  // remove the field qbit_num from gate dict sice this will be redundant information
2401  if ( PyDict_Contains(gate_state, qbit_num_key) == 1 ) {
2402 
2403  if ( PyDict_DelItem(gate_state, qbit_num_key) != 0 ) {
2404  std::string err( "Failed to delete item qbit_num from gate state");
2405  PyErr_SetString(PyExc_Exception, err.c_str());
2406  return NULL;
2407  }
2408 
2409  }
2410 
2411 
2412  // adding gate information to the tuple
2413  PyTuple_SetItem( ret, (Py_ssize_t) idx+1, gate_state );
2414 
2415 
2416 
2417  Py_DECREF( gate );
2418  //Py_DECREF( gate_state );
2419 
2420  }
2421 
2422  Py_DECREF( method_name );
2423 
2424  return ret;
2425 }
2426 
2427 
2428 
2432 static PyObject *
2434 
2435  PyObject* state = NULL;
2436 
2437  // parsing input arguments
2438  if (!PyArg_ParseTuple(args, "|O", &state )) {
2439  std::string err( "Unable to parse state argument");
2440  PyErr_SetString(PyExc_Exception, err.c_str());
2441  return NULL;
2442  }
2443 
2444  if ( PyTuple_Size(state) == 0 ) {
2445  std::string err( "State should contain at least one element");
2446  PyErr_SetString(PyExc_Exception, err.c_str());
2447 
2448  Py_DECREF( state );
2449  return NULL;
2450  }
2451 
2452  PyObject* qbit_num_dict = PyTuple_GetItem( state, 0); // borrowed reference
2453 
2454 
2455  PyObject* qbit_num_key = Py_BuildValue( "s", "qbit_num" );
2456 
2457  if ( PyDict_Contains(qbit_num_dict, qbit_num_key) == 0 ) {
2458  std::string err( "The first entry of the circuit state should be the number of qubits");
2459  PyErr_SetString(PyExc_Exception, err.c_str());
2460 
2461  Py_DECREF( qbit_num_key );
2462  Py_DECREF( state );
2463  return NULL;
2464  }
2465 
2466  PyObject* qbit_num_py = PyDict_GetItem(qbit_num_dict, qbit_num_key); // borrowed reference
2467 
2468  if( !PyLong_Check(qbit_num_py) ) {
2469  std::string err( "The number of qubits should be an integer value");
2470  PyErr_SetString(PyExc_Exception, err.c_str());
2471 
2472  Py_DECREF( qbit_num_key );
2473  Py_DECREF( state );
2474  return NULL;
2475  }
2476 
2477 
2478  int qbit_num = (int)PyLong_AsLong( qbit_num_py );
2479 
2480 
2481  // import gate operation modules
2482  PyObject* qgd_gate = PyImport_ImportModule("squander.gates.gates_Wrapper");
2483 
2484  if ( qgd_gate == NULL ) {
2485  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.gates_Wrapper" );
2486  Py_DECREF( qbit_num_key );
2487  Py_DECREF( state );
2488  return NULL;
2489  }
2490 
2491  PyObject* qgd_gate_Dict = PyModule_GetDict( qgd_gate ); // borrowed reference ???
2492  PyObject* py_gate_class = PyDict_GetItemString( qgd_gate_Dict, "Gate"); // borrowed reference
2493  PyObject* setstate_name = Py_BuildValue( "s", "__setstate__" );
2494  PyObject* dummy_target_qbit = Py_BuildValue( "i", 0 );
2495 
2496  // now build up the quantum circuit
2497  try {
2498 
2499  self->circuit->release_gates();
2500  self->circuit->set_qbit_num( qbit_num );
2501 
2502  int gates_idx_max = (int) PyTuple_Size(state);
2503 
2504  for( int gate_idx=1; gate_idx < gates_idx_max; gate_idx++ ) {
2505 
2506 
2507  // get gate state as python dictionary
2508  PyObject* gate_state_dict = PyTuple_GetItem( state, gate_idx); // borrowed reference
2509 
2510  if( !PyDict_Check( gate_state_dict ) ) {
2511  std::string err( "Gate state should be given by a dictionary");
2512  PyErr_SetString(PyExc_Exception, err.c_str());
2513 
2514  Py_DECREF( qgd_gate );
2515  Py_DECREF( qgd_gate_Dict );
2516  Py_DECREF( qbit_num_key );
2517  Py_DECREF( state );
2518  Py_DECREF( setstate_name );
2519  Py_DECREF( dummy_target_qbit );
2520  return NULL;
2521  }
2522 
2523  PyDict_SetItem(gate_state_dict, qbit_num_key, qbit_num_py);
2524 
2525  PyObject* gate_input = Py_BuildValue( "(O)", qbit_num_py );
2526  PyObject* py_gate = PyObject_CallObject(py_gate_class, gate_input);
2527 
2528  // turn the generic gate into a specific gate
2529  PyObject_CallMethodObjArgs( py_gate, setstate_name, gate_state_dict, NULL );
2530 
2531  Gate* gate_loc = static_cast<Gate*>( ((qgd_Gate*)py_gate)->gate->clone() );
2532  self->circuit->add_gate( gate_loc );
2533 
2534 
2535  Py_DECREF( gate_input );
2536  Py_DECREF( py_gate );
2537 
2538 
2539 
2540  }
2541 
2542 
2543  }
2544  catch (std::string err) {
2545  PyErr_SetString(PyExc_Exception, err.c_str());
2546  return NULL;
2547  }
2548  catch(...) {
2549  std::string err( "Invalid pointer to circuit class");
2550  PyErr_SetString(PyExc_Exception, err.c_str());
2551  return NULL;
2552  }
2553 
2554 
2555 
2556 
2557  Py_DECREF( qgd_gate );
2558  //Py_DECREF( qgd_gate_Dict );
2559  Py_DECREF( qbit_num_key );
2560  Py_DECREF( setstate_name );
2561  Py_DECREF( dummy_target_qbit );
2562 
2563 
2564  return Py_None;
2565 }
2566 
2567 
2568 
2573 static PyObject *
2575 
2576  int start_index = self->circuit->get_parameter_start_idx();
2577 
2578  return Py_BuildValue("i", start_index);
2579 
2580 }
2581 
2582 
2583 
2584 
2585 static PyMethodDef qgd_Circuit_Wrapper_Methods[] = {
2586  {"add_U1", (PyCFunction) qgd_Circuit_Wrapper_add_U1, METH_VARARGS | METH_KEYWORDS,
2587  "Call to add a U1 gate to the front of the gate structure"
2588  },
2589  {"add_U2", (PyCFunction) qgd_Circuit_Wrapper_add_U2, METH_VARARGS | METH_KEYWORDS,
2590  "Call to add a U2 gate to the front of the gate structure"
2591  },
2592  {"add_U3", (PyCFunction) qgd_Circuit_Wrapper_add_U3, METH_VARARGS | METH_KEYWORDS,
2593  "Call to add a U3 gate to the front of the gate structure"
2594  },
2595  {"add_RX", (PyCFunction) qgd_Circuit_Wrapper_add_RX, METH_VARARGS | METH_KEYWORDS,
2596  "Call to add a RX gate to the front of the gate structure"
2597  },
2598  {"add_R", (PyCFunction) qgd_Circuit_Wrapper_add_R, METH_VARARGS | METH_KEYWORDS,
2599  "Call to add a R gate to the front of the gate structure"
2600  },
2601  {"add_RY", (PyCFunction) qgd_Circuit_Wrapper_add_RY, METH_VARARGS | METH_KEYWORDS,
2602  "Call to add a RY gate to the front of the gate structure"
2603  },
2604  {"add_RZ", (PyCFunction) qgd_Circuit_Wrapper_add_RZ, METH_VARARGS | METH_KEYWORDS,
2605  "Call to add a RZ gate to the front of the gate structure"
2606  },
2607  {"add_CNOT", (PyCFunction) qgd_Circuit_Wrapper_add_CNOT, METH_VARARGS | METH_KEYWORDS,
2608  "Call to add a CNOT gate to the front of the gate structure"
2609  },
2610  {"add_CZ", (PyCFunction) qgd_Circuit_Wrapper_add_CZ, METH_VARARGS | METH_KEYWORDS,
2611  "Call to add a CZ gate to the front of the gate structure"
2612  },
2613  {"add_CH", (PyCFunction) qgd_Circuit_Wrapper_add_CH, METH_VARARGS | METH_KEYWORDS,
2614  "Call to add a CH gate to the front of the gate structure"
2615  },
2616  {"add_SYC", (PyCFunction) qgd_Circuit_Wrapper_add_SYC, METH_VARARGS | METH_KEYWORDS,
2617  "Call to add a Sycamore gate to the front of the gate structure"
2618  },
2619  {"add_H", (PyCFunction) qgd_Circuit_Wrapper_add_H, METH_VARARGS | METH_KEYWORDS,
2620  "Call to add a Hadamard gate to the front of the gate structure"
2621  },
2622  {"add_X", (PyCFunction) qgd_Circuit_Wrapper_add_X, METH_VARARGS | METH_KEYWORDS,
2623  "Call to add a X gate to the front of the gate structure"
2624  },
2625  {"add_Y", (PyCFunction) qgd_Circuit_Wrapper_add_Y, METH_VARARGS | METH_KEYWORDS,
2626  "Call to add a Y gate to the front of the gate structure"
2627  },
2628  {"add_Z", (PyCFunction) qgd_Circuit_Wrapper_add_Z, METH_VARARGS | METH_KEYWORDS,
2629  "Call to add a Z gate to the front of the gate structure"
2630  },
2631  {"add_SX", (PyCFunction) qgd_Circuit_Wrapper_add_SX, METH_VARARGS | METH_KEYWORDS,
2632  "Call to add a SX gate to the front of the gate structure"
2633  },
2634  {"add_T", (PyCFunction) qgd_Circuit_Wrapper_add_T, METH_VARARGS | METH_KEYWORDS,
2635  "Call to add a T gate to the front of the gate structure"
2636  },
2637  {"add_Tdg", (PyCFunction) qgd_Circuit_Wrapper_add_Tdg, METH_VARARGS | METH_KEYWORDS,
2638  "Call to add a Tdg gate to the front of the gate structure"
2639  },
2640  {"add_CRY", (PyCFunction) qgd_Circuit_Wrapper_add_CRY, METH_VARARGS | METH_KEYWORDS,
2641  "Call to add a CRY gate to the front of the gate structure"
2642  },
2643  {"add_CROT", (PyCFunction) qgd_Circuit_Wrapper_add_CROT, METH_VARARGS | METH_KEYWORDS,
2644  "Call to add a CROT gate to the front of the gate structure"
2645  },
2646  {"add_CR", (PyCFunction) qgd_Circuit_Wrapper_add_CR, METH_VARARGS | METH_KEYWORDS,
2647  "Call to add a CR gate to the front of the gate structure"
2648  },
2649  {"add_adaptive", (PyCFunction) qgd_Circuit_Wrapper_add_adaptive, METH_VARARGS | METH_KEYWORDS,
2650  "Call to add an adaptive gate to the front of the gate structure"
2651  },
2652  {"add_Circuit", (PyCFunction) qgd_Circuit_Wrapper_add_Circuit, METH_VARARGS,
2653  "Call to add a block of operations to the front of the gate structure."
2654  },
2655 #ifdef __DFE__
2656  {"convert_to_DFE_gates_with_derivates", (PyCFunction) qgd_Circuit_Wrapper_convert_to_DFE_gates_with_derivates, METH_VARARGS,
2657  "Call to convert to DFE gates with derivates."
2658  },
2659  {"adjust_parameters_for_derivation", (PyCFunction) qgd_Circuit_Wrapper_adjust_parameters_for_derivation, METH_VARARGS,
2660  "Call to adjust parameters for derivation."
2661  },
2662  {"convert_to_DFE_gates", (PyCFunction) qgd_Circuit_Wrapper_convert_to_DFE_gates, METH_VARARGS,
2663  "Call to convert to DFE gates."
2664  },
2665  {"convert_to_DFE_gates", (PyCFunction) qgd_Circuit_Wrapper_convert_to_DFE_gates, METH_VARARGS,
2666  "Call to convert to DFE gates."
2667  },
2668 #endif
2669  {"get_Matrix", (PyCFunction) qgd_Circuit_Wrapper_get_Matrix, METH_VARARGS,
2670  "Method to get the matrix of the operation."
2671  },
2672  {"get_Parameter_Num", (PyCFunction) qgd_Circuit_Wrapper_get_Parameter_Num, METH_NOARGS,
2673  "Call to get the number of free parameters in the circuit"
2674  },
2675  {"apply_to", (PyCFunction) qgd_Circuit_Wrapper_apply_to, METH_VARARGS | METH_KEYWORDS,
2676  "Call to apply the gate on the input matrix (or state)."
2677  },
2678  {"get_Second_Renyi_Entropy", (PyCFunction) qgd_Circuit_Wrapper_get_Second_Renyi_Entropy, METH_VARARGS,
2679  "Wrapper function to evaluate the second Rényi entropy of a quantum circuit at a specific parameter set."
2680  },
2681  {"get_Qbit_Num", (PyCFunction) qgd_Circuit_Wrapper_get_Qbit_Num, METH_NOARGS,
2682  "Call to get the number of qubits in the circuit"
2683  },
2684  {"set_Qbit_Num", (PyCFunction) qgd_Circuit_Wrapper_set_Qbit_Num, METH_VARARGS,
2685  "Call to set the number of qubits in the circuit"
2686  },
2687  {"get_Qbits", (PyCFunction) qgd_Circuit_Wrapper_get_Qbits, METH_NOARGS,
2688  "Call to get the list of qubits involved in the circuit"
2689  },
2690  {"Remap_Qbits", (PyCFunction) qgd_Circuit_Wrapper_Remap_Qbits, METH_VARARGS,
2691  "Call to remap the qubits in the circuit."
2692  },
2693  {"get_Gate", (PyCFunction) qgd_Circuit_Wrapper_get_gate, METH_VARARGS,
2694  "Method to get the i-th decomposing gates."
2695  },
2696  {"get_Gates", (PyCFunction) qgd_Circuit_Wrapper_get_gates, METH_NOARGS,
2697  "Method to get the tuple of decomposing gates."
2698  },
2699  {"get_Gate_Nums", (PyCFunction) qgd_Circuit_Wrapper_get_Gate_Nums, METH_NOARGS,
2700  "Method to get statisctics on the gate counts in the circuit."
2701  },
2702  {"get_Parameter_Start_Index", (PyCFunction) qgd_Circuit_Wrapper_get_Parameter_Start_Index, METH_NOARGS,
2703  "Call to get the starting index of the parameters in the parameter array corresponding to the circuit in which the current gate is incorporated."
2704  },
2705  {"Extract_Parameters", (PyCFunction) qgd_Circuit_Wrapper_Extract_Parameters, METH_VARARGS,
2706  "Call to extract the paramaters corresponding to the gate, from a parameter array associated to the circuit in which the gate is embedded."
2707  },
2708  {"get_Flat_Circuit", (PyCFunction) qgd_Circuit_Wrapper_get_Flat_Circuit, METH_NOARGS,
2709  "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."
2710  },
2711  {"get_Parents", (PyCFunction) qgd_Circuit_Wrapper_get_parents, METH_VARARGS,
2712  "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."
2713  },
2714  {"get_Children", (PyCFunction) qgd_Circuit_Wrapper_get_children, METH_VARARGS,
2715  "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."
2716  },
2717  {"__getstate__", (PyCFunction) qgd_Circuit_Wrapper_getstate, METH_NOARGS,
2718  "Method to extract the stored quantum circuit in a human-readable data serialized and pickle-able format."
2719  },
2720  {"__setstate__", (PyCFunction) qgd_Circuit_Wrapper_setstate, METH_VARARGS,
2721  "Call to set the state of a quantum circuit from a human-readable data serialized and pickle-able format."
2722  },
2723 
2724 
2725  {NULL} /* Sentinel */
2726 };
2727 
2728 
2733  PyVarObject_HEAD_INIT(NULL, 0)
2734  "qgd_Circuit_Wrapper.qgd_Circuit_Wrapper", /*tp_name*/
2735  sizeof(qgd_Circuit_Wrapper), /*tp_basicsize*/
2736  0, /*tp_itemsize*/
2737  (destructor) qgd_Circuit_Wrapper_dealloc, /*tp_dealloc*/
2738  #if PY_VERSION_HEX < 0x030800b4
2739  0, /*tp_print*/
2740  #endif
2741  #if PY_VERSION_HEX >= 0x030800b4
2742  0, /*tp_vectorcall_offset*/
2743  #endif
2744  0, /*tp_getattr*/
2745  0, /*tp_setattr*/
2746  #if PY_MAJOR_VERSION < 3
2747  0, /*tp_compare*/
2748  #endif
2749  #if PY_MAJOR_VERSION >= 3
2750  0, /*tp_as_async*/
2751  #endif
2752  0, /*tp_repr*/
2753  0, /*tp_as_number*/
2754  0, /*tp_as_sequence*/
2755  0, /*tp_as_mapping*/
2756  0, /*tp_hash*/
2757  0, /*tp_call*/
2758  0, /*tp_str*/
2759  0, /*tp_getattro*/
2760  0, /*tp_setattro*/
2761  0, /*tp_as_buffer*/
2762  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
2763  "Object to represent a qgd_Circuit_Wrapper class of the QGD package.", /*tp_doc*/
2764  0, /*tp_traverse*/
2765  0, /*tp_clear*/
2766  0, /*tp_richcompare*/
2767  0, /*tp_weaklistoffset*/
2768  0, /*tp_iter*/
2769  0, /*tp_iternext*/
2770  qgd_Circuit_Wrapper_Methods, /*tp_methods*/
2771  qgd_Circuit_Wrapper_Members, /*tp_members*/
2772  0, /*tp_getset*/
2773  0, /*tp_base*/
2774  0, /*tp_dict*/
2775  0, /*tp_descr_get*/
2776  0, /*tp_descr_set*/
2777  0, /*tp_dictoffset*/
2778  (initproc) qgd_Circuit_Wrapper_init, /*tp_init*/
2779  0, /*tp_alloc*/
2780  qgd_Circuit_Wrapper_new, /*tp_new*/
2781  0, /*tp_free*/
2782  0, /*tp_is_gc*/
2783  0, /*tp_bases*/
2784  0, /*tp_mro*/
2785  0, /*tp_cache*/
2786  0, /*tp_subclasses*/
2787  0, /*tp_weaklist*/
2788  0, /*tp_del*/
2789  0, /*tp_version_tag*/
2790  #if PY_VERSION_HEX >= 0x030400a1
2791  0, /*tp_finalize*/
2792  #endif
2793  #if PY_VERSION_HEX >= 0x030800b1
2794  0, /*tp_vectorcall*/
2795  #endif
2796  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
2797  0, /*tp_print*/
2798  #endif
2799 };
2800 
2804 static PyModuleDef qgd_Circuit_Wrapper_Module = {
2805  PyModuleDef_HEAD_INIT,
2806  "qgd_Circuit_Wrapper",
2807  "Python binding for QGD Circuit class",
2808  -1,
2809 };
2810 
2814 PyMODINIT_FUNC
2816 {
2817 
2818  // initialize Numpy API
2819  import_array();
2820 
2821  PyObject *m;
2822  if (PyType_Ready(&qgd_Circuit_Wrapper_Type) < 0)
2823  return NULL;
2824 
2825  m = PyModule_Create(&qgd_Circuit_Wrapper_Module);
2826  if (m == NULL)
2827  return NULL;
2828 
2829  Py_INCREF(&qgd_Circuit_Wrapper_Type);
2830  if (PyModule_AddObject(m, "qgd_Circuit_Wrapper", (PyObject *) &qgd_Circuit_Wrapper_Type) < 0) {
2831  Py_DECREF(&qgd_Circuit_Wrapper_Type);
2832  Py_DECREF(m);
2833  return NULL;
2834  }
2835 
2836  return m;
2837 }
2838 
2839 
2840 
2841 }
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.
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.
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_add_CR(qgd_Circuit_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to add an adaptive 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
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:74
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.
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
Header file for a class representing a Sycamore gate.