Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_N_Qubit_Decomposition_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_N_Qubit_Decomposition_Wrapper.cpp
24 \brief Python interface for the N_Qubit_Decomposition class
25 */
26 
27 #define PY_SSIZE_T_CLEAN
28 
29 
30 #include <Python.h>
31 #include <numpy/arrayobject.h>
32 #include "structmember.h"
33 #include <stdio.h>
34 #include "N_Qubit_Decomposition.h"
35 
36 #include "numpy_interface.h"
37 
38 
39 
40 
41 
45 typedef struct qgd_Circuit_Wrapper {
46  PyObject_HEAD
49 
50 
55  PyObject_HEAD
57  PyArrayObject *Umtx;
60 
62 
63 
64 
74 create_N_Qubit_Decomposition( Matrix& Umtx, int qbit_num, bool optimize_layer_num, std::map<std::string, Config_Element>& config, guess_type initial_guess ) {
75 
76  return new N_Qubit_Decomposition( Umtx, qbit_num, optimize_layer_num, config, initial_guess );
77 }
78 
79 
84 void
86 
87  if (instance != NULL ) {
88  delete instance;
89  }
90  return;
91 }
92 
93 
94 
95 extern "C"
96 {
97 
98 
103 static void
105 {
106 
107  if ( self->decomp != NULL ) {
108  // deallocate the instance of class N_Qubit_Decomposition
109  release_N_Qubit_Decomposition( self->decomp );
110  self->decomp = NULL;
111  }
112 
113  if ( self->Umtx != NULL ) {
114  // release the unitary to be decomposed
115  Py_DECREF(self->Umtx);
116  self->Umtx = NULL;
117  }
118 
119  Py_TYPE(self)->tp_free((PyObject *) self);
120 
121 }
122 
127 static PyObject *
128 qgd_N_Qubit_Decomposition_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
129 {
131  self = (qgd_N_Qubit_Decomposition_Wrapper *) type->tp_alloc(type, 0);
132  if (self != NULL) {}
133 
134  self->decomp = NULL;
135  self->Umtx = NULL;
136 
137  return (PyObject *) self;
138 }
139 
140 
147 static int
149 {
150  // The tuple of expected keywords
151  static char *kwlist[] = {(char*)"Umtx", (char*)"qbit_num", (char*)"optimize_layer_num", (char*)"initial_guess", NULL};
152 
153  // initiate variables for input arguments
154  PyArrayObject *Umtx_arg = NULL;
155  int qbit_num = -1;
156  bool optimize_layer_num = false;
157  PyObject *initial_guess = NULL;
158 
159  // parsing input arguments
160  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OibO", kwlist,
161  &Umtx_arg, &qbit_num, &optimize_layer_num, &initial_guess))
162  return -1;
163 
164  // convert python object array to numpy C API array
165  if ( Umtx_arg == NULL ) return -1;
166  self->Umtx = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)Umtx_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
167 
168  // test C-style contiguous memory allocation of the array
169  if ( !PyArray_IS_C_CONTIGUOUS((PyArrayObject*)self->Umtx) ) {
170  std::cout << "Umtx is not memory contiguous" << std::endl;
171  }
172 
173 
174  // create QGD version of the Umtx
175  Matrix Umtx_mtx = numpy2matrix(self->Umtx);
176 
177 
178  // determine the initial guess type
179  PyObject* initial_guess_string = PyObject_Str(initial_guess);
180  PyObject* initial_guess_string_unicode = PyUnicode_AsEncodedString(initial_guess_string, "utf-8", "~E~");
181  const char* initial_guess_C = PyBytes_AS_STRING(initial_guess_string_unicode);
182 
183  guess_type qgd_initial_guess;
184  if ( strcmp("zeros", initial_guess_C) == 0 || strcmp("ZEROS", initial_guess_C) == 0) {
185  qgd_initial_guess = ZEROS;
186  }
187  else if ( strcmp("random", initial_guess_C)==0 || strcmp("RANDOM", initial_guess_C)==0) {
188  qgd_initial_guess = RANDOM;
189  }
190  else if ( strcmp("close_to_zero", initial_guess_C)==0 || strcmp("CLOSE_TO_ZERO", initial_guess_C)==0) {
191  qgd_initial_guess = CLOSE_TO_ZERO;
192  }
193  else {
194  std::cout << "Wrong initial guess format. Using default ZEROS." << std::endl;
195  qgd_initial_guess = ZEROS;
196  }
197 
198  // parse config and create C++ version of the hyperparameters
199 
200  // integer type config metadata utilized during the optimization
201  std::map<std::string, Config_Element> config;
202 
203 
204  // create an instance of the class N_Qubit_Decomposition
205  if (qbit_num > 0 ) {
206  self->decomp = create_N_Qubit_Decomposition( Umtx_mtx, qbit_num, optimize_layer_num, config, qgd_initial_guess);
207  }
208  else {
209  std::cout << "The number of qubits should be given as a positive integer, " << qbit_num << " was given" << std::endl;
210  return -1;
211  }
212 
213 
214 
215  Py_XDECREF(initial_guess_string);
216  Py_XDECREF(initial_guess_string_unicode);
217 
218  return 0;
219 }
220 
226 static PyObject *
228 {
229 
230  // The tuple of expected keywords
231  static char *kwlist[] = {NULL};
232 
233 
234  // parsing input arguments
235  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|", kwlist))
236  return Py_BuildValue("i", -1);
237 
238 
239  // starting the decomposition
240  self->decomp->start_decomposition(true);
241 
242 
243  return Py_BuildValue("i", 0);
244 
245 }
246 
247 
248 
249 
250 
256 static PyObject *
258 
259  // get the number of gates
260  int ret = self->decomp->get_gate_num();
261 
262 
263  return Py_BuildValue("i", ret);
264 
265 }
266 
267 
268 
269 
270 
275 static PyObject *
277 
278 
279  PyObject* qgd_Circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
280 
281  if ( qgd_Circuit == NULL ) {
282  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
283  return NULL;
284  }
285 
286  // retrieve the C++ variant of the flat circuit (flat circuit does not conatain any sub-circuits)
287  Gates_block* circuit = self->decomp->get_flat_circuit();
288 
289 
290 
291  // construct python interfarce for the circuit
292  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_Circuit );
293 
294  // 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
295  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
296 
297  // create gate parameters
298  PyObject* qbit_num = Py_BuildValue("i", circuit->get_qbit_num() );
299  PyObject* circuit_input = Py_BuildValue("(O)", qbit_num);
300 
301  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
302  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
303 
304 
305  // replace the empty circuit with the extracted one
306 
307  delete( py_circuit_C->gate );
308  py_circuit_C->gate = circuit;
309 
310 
311  return py_circuit;
312 
313 }
314 
315 
320 static PyObject *
322 
323  self->decomp->list_gates( 0 );
324 
325  return Py_None;
326 }
327 
328 
329 
330 
335 static PyObject *
337 
338  int parameter_num = self->decomp->get_parameter_num();
339 
340  Matrix_real parameters_mtx(1, parameter_num);
341  double* parameters = parameters_mtx.get_data();
342  self->decomp->get_optimized_parameters(parameters);
343 
344  // convert to numpy array
345  parameters_mtx.set_owner(false);
346  PyObject * parameter_arr = matrix_real_to_numpy( parameters_mtx );
347 
348  return parameter_arr;
349 }
350 
351 
352 
353 
354 
355 
360 static PyObject *
362 
363  // initiate variables for input arguments
364  PyObject* max_layer_num;
365 
366  // parsing input arguments
367  if (!PyArg_ParseTuple(args, "|O", &max_layer_num )) return Py_BuildValue("i", -1);
368 
369  // Check whether input is dictionary
370  if (!PyDict_Check(max_layer_num)) {
371  printf("Input must be dictionary!\n");
372  return Py_BuildValue("i", -1);
373  }
374 
375 
376  PyObject* key = NULL;
377  PyObject* value = NULL;
378  Py_ssize_t pos = 0;
379 
380 
381  while (PyDict_Next(max_layer_num, &pos, &key, &value)) {
382 
383  // convert value fron PyObject to int
384  assert(PyLong_Check(value) == 1);
385  int value_int = (int) PyLong_AsLong(value);
386 
387  // convert keylue fron PyObject to int
388  assert(PyLong_Check(key) == 1);
389  int key_int = (int) PyLong_AsLong(key);
390 
391  // set maximal layer nums on the C++ side
392  self->decomp->set_max_layer_num( key_int, value_int );
393  }
394 
395  return Py_BuildValue("i", 0);
396 }
397 
398 
399 
400 
405 static PyObject *
407 
408  // initiate variables for input arguments
409  PyObject* identical_blocks;
410 
411  // parsing input arguments
412  if (!PyArg_ParseTuple(args, "|O", &identical_blocks )) return Py_BuildValue("i", -1);
413 
414  // Check whether input is dictionary
415  if (!PyDict_Check(identical_blocks)) {
416  printf("Input must be dictionary!\n");
417  return Py_BuildValue("i", -1);
418  }
419 
420 
421  PyObject* key = NULL;
422  PyObject* value = NULL;
423  Py_ssize_t pos = 0;
424 
425 
426  while (PyDict_Next(identical_blocks, &pos, &key, &value)) {
427 
428  // convert value fron PyObject to int
429  assert(PyLong_Check(value) == 1);
430  int value_int = (int) PyLong_AsLong(value);
431 
432  // convert keylue fron PyObject to int
433  assert(PyLong_Check(key) == 1);
434  int key_int = (int) PyLong_AsLong(key);
435 
436  // set maximal layer nums on the C++ side
437  self->decomp->set_identical_blocks( key_int, value_int );
438  }
439 
440  return Py_BuildValue("i", 0);
441 }
442 
443 
444 
445 
446 
453 static PyObject *
455 
456  // initiate variables for input arguments
457  PyObject* iteration_loops;
458 
459  // parsing input arguments
460  if (!PyArg_ParseTuple(args, "|O", &iteration_loops )) return Py_BuildValue("i", -1);
461 
462  // Check whether input is dictionary
463  if (!PyDict_Check(iteration_loops)) {
464  printf("Input must be dictionary!\n");
465  return Py_BuildValue("i", -1);
466  }
467 
468 
469  PyObject* key = NULL;
470  PyObject* value = NULL;
471  Py_ssize_t pos = 0;
472 
473 
474  while (PyDict_Next(iteration_loops, &pos, &key, &value)) {
475 
476  // convert value fron PyObject to int
477  assert(PyLong_Check(value) == 1);
478  int value_int = (int) PyLong_AsLong(value);
479 
480  // convert keylue fron PyObject to int
481  assert(PyLong_Check(key) == 1);
482  int key_int = (int) PyLong_AsLong(key);
483 
484  // set maximal layer nums on the C++ side
485  self->decomp->set_iteration_loops( key_int, value_int );
486  }
487 
488  return Py_BuildValue("i", 0);
489 }
490 
491 
492 
499 static PyObject *
501 
502  // initiate variables for input arguments
503  int verbose;
504 
505  // parsing input arguments
506  if (!PyArg_ParseTuple(args, "|i", &verbose )) return Py_BuildValue("i", -1);
507 
508 
509  // set maximal layer nums on the C++ side
510  self->decomp->set_verbose( verbose );
511 
512  return Py_BuildValue("i", 0);
513 }
514 
521 static PyObject *
523 
524 
525  PyObject *debugfile = NULL;
526 
527  // parsing input arguments
528  if (!PyArg_ParseTuple(args, "|O", &debugfile )) return Py_BuildValue("s", -1);
529 
530  // determine the debugfile name type
531  PyObject* debugfile_string = PyObject_Str(debugfile);
532  PyObject* debugfile_string_unicode = PyUnicode_AsEncodedString(debugfile_string, "utf-8", "~E~");
533  const char* debugfile_C = PyBytes_AS_STRING(debugfile_string_unicode);
534 
535 
536  Py_XDECREF(debugfile_string);
537  Py_XDECREF(debugfile_string_unicode);
538 
539  // determine the length of the filename and initialize C++ variant of the string
540  Py_ssize_t string_length = PyBytes_Size(debugfile_string_unicode);
541  std::string debugfile_Cpp(debugfile_C, string_length);
542 
543  // set the name of the debugfile on the C++ side
544  self->decomp->set_debugfile( debugfile_Cpp );
545 
546 
547  return Py_BuildValue("s", NULL);
548 }
549 
556 static PyObject *
558 
559  // initiate variables for input arguments
560  double tolerance;
561 
562  // parsing input arguments
563  if (!PyArg_ParseTuple(args, "|d", &tolerance )) return Py_BuildValue("i", -1);
564 
565 
566  // set maximal layer nums on the C++ side
567  self->decomp->set_optimization_tolerance( tolerance );
568 
569  return Py_BuildValue("i", 0);
570 }
571 
572 
579 static PyObject *
581 
582  // initiate variables for input arguments
583  double threshold;
584 
585  // parsing input arguments
586  if (!PyArg_ParseTuple(args, "|d", &threshold )) return Py_BuildValue("i", -1);
587 
588 
589  // set maximal layer nums on the C++ side
590  self->decomp->set_convergence_threshold( threshold );
591 
592  return Py_BuildValue("i", 0);
593 }
594 
595 
596 
603 static PyObject *
605 
606  // initiate variables for input arguments
607  double optimization_block;
608 
609  // parsing input arguments
610  if (!PyArg_ParseTuple(args, "|d", &optimization_block )) return Py_BuildValue("i", -1);
611 
612 
613  // set maximal layer nums on the C++ side
614  self->decomp->set_optimization_blocks( optimization_block );
615 
616  return Py_BuildValue("i", 0);
617 }
618 
619 
620 
628 static PyObject *
630 
631 
632  // initiate variables for input arguments
633  PyObject* gate_structure_dict;
634 
635  // parsing input arguments
636  if (!PyArg_ParseTuple(args, "|O", &gate_structure_dict )) return Py_BuildValue("i", -1);
637 
638  // Check whether input is dictionary
639  if (!PyDict_Check(gate_structure_dict)) {
640  printf("Input must be dictionary!\n");
641  return Py_BuildValue("i", -1);
642  }
643 
644 
645  PyObject* key = NULL;
646  PyObject* value = NULL;
647  Py_ssize_t pos = 0;
648 
649  std::map< int, Gates_block* > gate_structure;
650 
651 
652  while (PyDict_Next(gate_structure_dict, &pos, &key, &value)) {
653 
654  // convert keylue from PyObject to int
655  assert(PyLong_Check(key) == 1);
656  int key_int = (int) PyLong_AsLong(key);
657 
658  // convert keylue from PyObject to qgd_Circuit_Wrapper
659  qgd_Circuit_Wrapper* qgd_op_block = (qgd_Circuit_Wrapper*) value;
660 
661  gate_structure.insert( std::pair<int, Gates_block*>( key_int, qgd_op_block->gate ));
662 
663  }
664 
665  self->decomp->set_custom_gate_structure( gate_structure );
666 
667  return Py_BuildValue("i", 0);
668 
669 
670 }
671 
676 static PyObject *
678 
679  // initiate variables for input arguments
680  PyObject* qbit_list;
681 
682  // parsing input arguments
683  if (!PyArg_ParseTuple(args, "|O", &qbit_list )) return Py_BuildValue("i", -1);
684 
685  bool is_tuple = PyTuple_Check(qbit_list);
686  bool is_list = PyList_Check(qbit_list);
687 
688  // Check whether input is dictionary
689  if (!is_list && !is_tuple) {
690  printf("Input must be tuple or list!\n");
691  return Py_BuildValue("i", -1);
692  }
693 
694  // get the number of qbubits
695  Py_ssize_t element_num;
696 
697  if (is_tuple) {
698  element_num = PyTuple_GET_SIZE(qbit_list);
699  }
700  else {
701  element_num = PyList_GET_SIZE(qbit_list);
702  }
703 
704 
705  // create C++ variant of the tuple/list
706  std::vector<int> qbit_list_C( (int) element_num);
707  for ( Py_ssize_t idx=0; idx<element_num; idx++ ) {
708  if (is_tuple) {
709  qbit_list_C[(int) idx] = (int) PyLong_AsLong( PyTuple_GetItem(qbit_list, idx ) );
710  }
711  else {
712  qbit_list_C[(int) idx] = (int) PyLong_AsLong( PyList_GetItem(qbit_list, idx ) );
713  }
714 
715  }
716 
717 
718  // reorder the qubits in the decomposition class
719  self->decomp->reorder_qubits( qbit_list_C );
720 
721 
722 
723  return Py_BuildValue("i", 0);
724 }
725 
726 
727 
732  {NULL} /* Sentinel */
733 };
734 
739  {"Start_Decomposition", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_Start_Decomposition, METH_VARARGS | METH_KEYWORDS,
740  "Method to start the decomposition."
741  },
742  {"get_Gate_Num", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_get_gate_num, METH_NOARGS,
743  "Method to get the number of decomposing gates."
744  },
745  {"get_Optimized_Parameters", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_get_Optimized_Parameters, METH_NOARGS,
746  "Method to get the array of optimized parameters."
747  },
748  {"get_Circuit", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_get_circuit, METH_NOARGS,
749  "Method to get the incorporated circuit."
750  },
751  {"List_Gates", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_List_Gates, METH_NOARGS,
752  "Call to print the decomposing nitaries on standard output"
753  },
754  {"set_Max_Layer_Num", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Max_Layer_Num, METH_VARARGS,
755  "Call to set the maximal number of layers used in the subdecomposition of the qbit-th qubit."
756  },
757  {"set_Identical_Blocks", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Identical_Blocks, METH_VARARGS,
758  "Call to set the number of identical successive blocks during the subdecomposition of the qbit-th qubit."
759  },
760  {"set_Iteration_Loops", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Iteration_Loops, METH_VARARGS,
761  "Call to set the number of iteration loops during the subdecomposition of the qbit-th qubit."
762  },
763  {"set_Verbose", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Verbose, METH_VARARGS,
764  "Call to set the verbosity of the qgd_N_Qubit_Decomposition class."
765  },
766  {"set_Debugfile", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Debugfile, METH_VARARGS,
767  "Set the debugfile name of the N_Qubit_Decomposition class."
768  },
769  {"set_Gate_Structure", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Gate_Structure, METH_VARARGS,
770  "Call to set custom gate structure in the decomposition."
771  },
772  {"Reorder_Qubits", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_Reorder_Qubits, METH_VARARGS,
773  "Wrapper method to reorder the qubits in the decomposition class."
774  },
775  {"set_Optimization_Tolerance", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Optimization_Tolerance, METH_VARARGS,
776  "Wrapper method to set the optimization tolerance of the optimization process during the decomposition."
777  },
778  {"set_Convergence_Threshold", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Convergence_Threshold, METH_VARARGS,
779  "Wrapper method to set the threshold of convergence in the optimization processes."
780  },
781  {"set_Optimization_Blocks", (PyCFunction) qgd_N_Qubit_Decomposition_Wrapper_set_Optimization_Blocks, METH_VARARGS,
782  "Wrapper method to to set the number of gate blocks to be optimized in one shot."
783  },
784  {NULL} /* Sentinel */
785 };
786 
791  PyVarObject_HEAD_INIT(NULL, 0)
792  "qgd_N_Qubit_Decomposition_Wrapper.qgd_N_Qubit_Decomposition_Wrapper", /*tp_name*/
793  sizeof(qgd_N_Qubit_Decomposition_Wrapper), /*tp_basicsize*/
794  0, /*tp_itemsize*/
795  (destructor) qgd_N_Qubit_Decomposition_Wrapper_dealloc, /*tp_dealloc*/
796  #if PY_VERSION_HEX < 0x030800b4
797  0, /*tp_print*/
798  #endif
799  #if PY_VERSION_HEX >= 0x030800b4
800  0, /*tp_vectorcall_offset*/
801  #endif
802  0, /*tp_getattr*/
803  0, /*tp_setattr*/
804  #if PY_MAJOR_VERSION < 3
805  0, /*tp_compare*/
806  #endif
807  #if PY_MAJOR_VERSION >= 3
808  0, /*tp_as_async*/
809  #endif
810  0, /*tp_repr*/
811  0, /*tp_as_number*/
812  0, /*tp_as_sequence*/
813  0, /*tp_as_mapping*/
814  0, /*tp_hash*/
815  0, /*tp_call*/
816  0, /*tp_str*/
817  0, /*tp_getattro*/
818  0, /*tp_setattro*/
819  0, /*tp_as_buffer*/
820  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
821  "Object to represent a Circuit class of the QGD package.", /*tp_doc*/
822  0, /*tp_traverse*/
823  0, /*tp_clear*/
824  0, /*tp_richcompare*/
825  0, /*tp_weaklistoffset*/
826  0, /*tp_iter*/
827  0, /*tp_iternext*/
830  0, /*tp_getset*/
831  0, /*tp_base*/
832  0, /*tp_dict*/
833  0, /*tp_descr_get*/
834  0, /*tp_descr_set*/
835  0, /*tp_dictoffset*/
836  (initproc) qgd_N_Qubit_Decomposition_Wrapper_init, /*tp_init*/
837  0, /*tp_alloc*/
839  0, /*tp_free*/
840  0, /*tp_is_gc*/
841  0, /*tp_bases*/
842  0, /*tp_mro*/
843  0, /*tp_cache*/
844  0, /*tp_subclasses*/
845  0, /*tp_weaklist*/
846  0, /*tp_del*/
847  0, /*tp_version_tag*/
848  #if PY_VERSION_HEX >= 0x030400a1
849  0, /*tp_finalize*/
850  #endif
851  #if PY_VERSION_HEX >= 0x030800b1
852  0, /*tp_vectorcall*/
853  #endif
854  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
855  0, /*tp_print*/
856  #endif
857 };
858 
863  PyModuleDef_HEAD_INIT,
864  "qgd_N_Qubit_Decomposition_Wrapper",
865  "Python binding for QGD N_Qubit_Decomposition class",
866  -1,
867 };
868 
869 
873 PyMODINIT_FUNC
875 {
876  // initialize Numpy API
877  import_array();
878 
879  PyObject *m;
880  if (PyType_Ready(&qgd_N_Qubit_Decomposition_Wrapper_Type) < 0)
881  return NULL;
882 
883  m = PyModule_Create(&qgd_N_Qubit_Decomposition_Wrapper_Module);
884  if (m == NULL)
885  return NULL;
886 
887  Py_INCREF(&qgd_N_Qubit_Decomposition_Wrapper_Type);
888  if (PyModule_AddObject(m, "qgd_N_Qubit_Decomposition_Wrapper", (PyObject *) &qgd_N_Qubit_Decomposition_Wrapper_Type) < 0) {
889  Py_DECREF(&qgd_N_Qubit_Decomposition_Wrapper_Type);
890  Py_DECREF(m);
891  return NULL;
892  }
893 
894  return m;
895 }
896 
897 
898 } //extern C
899 
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Optimization_Blocks(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Wrapper method to to set the number of gate blocks to be optimized in one shot.
Gates_block * get_flat_circuit()
Method to generate a flat circuit.
parameter_num
[set adaptive gate structure]
N_Qubit_Decomposition * decomp
An object to decompose the unitary.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Gate_Structure(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Wrapper function to set custom gate structure for the decomposition.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Debugfile(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Set the debugfile name of the N_Qubit_Decomposition class.
static PyMethodDef qgd_N_Qubit_Decomposition_Wrapper_methods[]
Structure containing metadata about the methods of class qgd_N_Qubit_Decomposition_Wrapper.
PyObject * matrix_real_to_numpy(Matrix_real &mtx)
Call to make a numpy array from an instance of matrix class.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_Start_Decomposition(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to call the start_decomposition method of C++ class N_Qubit_Decomposition.
N_Qubit_Decomposition * create_N_Qubit_Decomposition(Matrix &Umtx, int qbit_num, bool optimize_layer_num, std::map< std::string, Config_Element > &config, guess_type initial_guess)
Creates an instance of class N_Qubit_Decomposition and return with a pointer pointing to the class in...
static void qgd_N_Qubit_Decomposition_Wrapper_dealloc(qgd_N_Qubit_Decomposition_Wrapper *self)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_Wrapper is destroyed...
static PyModuleDef qgd_N_Qubit_Decomposition_Wrapper_Module
Structure containing metadata about the module.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_Wrapper is allocated...
scalar * get_data() const
Call to get the pointer to the stored data.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Max_Layer_Num(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Set the maximal number of layers used in the subdecomposition of the qbit-th qubit.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Iteration_Loops(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Set the number of iteration loops during the subdecomposition of the qbit-th qubit.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_get_gate_num(qgd_N_Qubit_Decomposition_Wrapper *self)
Wrapper function to get the number of decomposing gates.
Umtx
The unitary to be decomposed.
Definition: example.py:53
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_get_circuit(qgd_N_Qubit_Decomposition_Wrapper *self)
Wrapper function to retrieve the circuit (Squander format) incorporated in the instance.
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_N_Qubit_Decomposition_Wrapper_set_Optimization_Tolerance(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Wrapper method to set the optimization tolerance of the optimization process during the decomposition...
PyObject_HEAD PyArrayObject * Umtx
pointer to the unitary to be decomposed to keep it alive
dictionary config
gate systhesis #####################################
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
Definition: Gates_block.h:41
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_List_Gates(qgd_N_Qubit_Decomposition_Wrapper *self)
Lists the gates decomposing the initial unitary.
PyMODINIT_FUNC PyInit_qgd_N_Qubit_Decomposition_Wrapper(void)
Method called when the Python module is initialized.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Verbose(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Set the verbosity of the N_Qubit_Decomposition class.
static int qgd_N_Qubit_Decomposition_Wrapper_init(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_Wrapper is initialized...
guess_type
Type definition of the types of the initial guess.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Identical_Blocks(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Set the number of identical successive blocks during the subdecomposition of the qbit-th qubit...
static PyMemberDef qgd_N_Qubit_Decomposition_Wrapper_members[]
Structure containing metadata about the members of class qgd_N_Qubit_Decomposition_Wrapper.
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a PIC matrix representation of a numpy array.
PyObject_HEAD Gates_block * circuit
Pointer to the C++ class of the base Gate_block module.
void release_N_Qubit_Decomposition(N_Qubit_Decomposition *instance)
Call to deallocate an instance of N_Qubit_Decomposition class.
int get_qbit_num()
Call to get the number of qubits composing the unitary.
Definition: Gate.cpp:504
Type definition of the qgd_Circuit_Wrapper Python class of the qgd_Circuit_Wrapper module...
static PyTypeObject qgd_N_Qubit_Decomposition_Wrapper_Type
A structure describing the type of the class qgd_N_Qubit_Decomposition_Wrapper.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_set_Convergence_Threshold(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Wrapper method to set the threshold of convergence in the optimization processes. ...
Header file for a class to determine the decomposition of an N-qubit unitary into a sequence of CNOT ...
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_Reorder_Qubits(qgd_N_Qubit_Decomposition_Wrapper *self, PyObject *args)
Wrapper method to reorder the qubits in the decomposition class.
static PyObject * qgd_N_Qubit_Decomposition_Wrapper_get_Optimized_Parameters(qgd_N_Qubit_Decomposition_Wrapper *self)
Extract the optimized parameters.
Type definition of the qgd_N_Qubit_Decomposition_Wrapper Python class of the qgd_N_Qubit_Decompositio...
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...