Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_N_Qubit_Decomposition_custom_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_custom_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>
35 #include "Gates_block.h"
36 
37 #include "numpy_interface.h"
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_custom( Matrix& Umtx, int qbit_num, bool optimize_layer_num, guess_type initial_guess, std::map<std::string, Config_Element>& config, int accelerator_num ) {
75 
76  return new N_Qubit_Decomposition_custom( Umtx, qbit_num, optimize_layer_num, config, initial_guess, accelerator_num );
77 }
78 
79 
84 void
86  if (instance != NULL ) {
87  delete instance;
88  }
89  return;
90 }
91 
92 
93 
94 extern "C"
95 {
96 
97 
102 static void
104 {
105 
106  if ( self->decomp != NULL ) {
107  // deallocate the instance of class N_Qubit_Decomposition_custom
108  release_N_Qubit_Decomposition_custom( self->decomp );
109  self->decomp = NULL;
110  }
111 
112  if ( self->Umtx != NULL ) {
113  // release the unitary to be decomposed
114  Py_DECREF(self->Umtx);
115  self->Umtx = NULL;
116  }
117 
118  Py_TYPE(self)->tp_free((PyObject *) self);
119 
120 }
121 
126 static PyObject *
128 {
130  self = (qgd_N_Qubit_Decomposition_custom_Wrapper *) type->tp_alloc(type, 0);
131  if (self != NULL) {}
132 
133  self->decomp = NULL;
134  self->Umtx = NULL;
135 
136  return (PyObject *) self;
137 }
138 
139 
146 static int
148 {
149  // The tuple of expected keywords
150  static char *kwlist[] = {(char*)"Umtx", (char*)"qbit_num", (char*)"initial_guess", (char*)"config", (char*)"accelerator_num", NULL};
151 
152  // initiate variables for input arguments
153  PyObject *Umtx_arg = NULL;
154  PyObject *config_arg = NULL;
155  int qbit_num = -1;
156  PyObject *initial_guess = NULL;
157  int accelerator_num = 0;
158 
159  // parsing input arguments
160  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OiOOi", kwlist,
161  &Umtx_arg, &qbit_num, &initial_guess, &config_arg, &accelerator_num))
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(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 
199  // parse config and create C++ version of the hyperparameters
200 
201  // integer type config metadata utilized during the optimization
202  std::map<std::string, Config_Element> config;
203 
204  // keys and values of the config dict
205  PyObject *key, *value;
206  Py_ssize_t pos = 0;
207 
208  while (PyDict_Next(config_arg, &pos, &key, &value)) {
209 
210  // determine the initial guess type
211  PyObject* key_string = PyObject_Str(key);
212  PyObject* key_string_unicode = PyUnicode_AsEncodedString(key_string, "utf-8", "~E~");
213  const char* key_C = PyBytes_AS_STRING(key_string_unicode);
214 
215  std::string key_Cpp( key_C );
216  Config_Element element;
217 
218  if ( PyLong_Check( value ) ) {
219  element.set_property( key_Cpp, PyLong_AsLongLong( value ) );
220  config[ key_Cpp ] = element;
221  }
222  else if ( PyFloat_Check( value ) ) {
223  element.set_property( key_Cpp, PyFloat_AsDouble( value ) );
224  config[ key_Cpp ] = element;
225  }
226  else {
227 
228  }
229 
230  }
231 
232  // create an instance of the class N_Qubit_Decomposition_custom
233  if (qbit_num > 0 ) {
234  try {
235  self->decomp = create_N_Qubit_Decomposition_custom( Umtx_mtx, qbit_num, false, qgd_initial_guess, config, accelerator_num);
236  }
237  catch (std::string err ) {
238  PyErr_SetString(PyExc_Exception, err.c_str());
239  return -1;
240  }
241  }
242  else {
243  std::cout << "The number of qubits should be given as a positive integer, " << qbit_num << " was given" << std::endl;
244  return -1;
245  }
246 
247 
248 
249  Py_XDECREF(initial_guess_string);
250  Py_XDECREF(initial_guess_string_unicode);
251 
252  return 0;
253 }
254 
260 static PyObject *
262 {
263 
264  // The tuple of expected keywords
265  static char *kwlist[] = {NULL};
266 
267 
268  // parsing input arguments
269  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|", kwlist))
270  return Py_BuildValue("i", -1);
271 
272 
273  // start the decomposition
274  try {
275  self->decomp->start_decomposition();
276  }
277  catch (std::string err) {
278  PyErr_SetString(PyExc_Exception, err.c_str());
279  std::cout << err << std::endl;
280  return NULL;
281  }
282  catch(...) {
283  std::string err( "Invalid pointer to decomposition class");
284  PyErr_SetString(PyExc_Exception, err.c_str());
285  return NULL;
286  }
287 
288 
289  return Py_BuildValue("i", 0);
290 
291 }
292 
293 
294 
295 
296 
302 static PyObject *
304 
305  // get the number of gates
306  int ret = self->decomp->get_gate_num();
307 
308 
309  return Py_BuildValue("i", ret);
310 
311 }
312 
313 
314 
315 
316 
317 
318 
323 static PyObject *
325 
326 
327  PyObject* qgd_Circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
328 
329  if ( qgd_Circuit == NULL ) {
330  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
331  return NULL;
332  }
333 
334  // retrieve the C++ variant of the flat circuit (flat circuit does not conatain any sub-circuits)
335  Gates_block* circuit = self->decomp->get_flat_circuit();
336 
337 
338 
339  // construct python interfarce for the circuit
340  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_Circuit );
341 
342  // 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
343  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
344 
345  // create gate parameters
346  PyObject* qbit_num = Py_BuildValue("i", circuit->get_qbit_num() );
347  PyObject* circuit_input = Py_BuildValue("(O)", qbit_num);
348 
349  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
350  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
351 
352 
353  // replace the empty circuit with the extracted one
354 
355  delete( py_circuit_C->gate );
356  py_circuit_C->gate = circuit;
357 
358 
359  return py_circuit;
360 
361 }
362 
363 
368 static PyObject *
370 
371  self->decomp->list_gates( 0 );
372 
373  return Py_None;
374 }
375 
376 
377 
378 
383 static PyObject *
385 
386  int parameter_num = self->decomp->get_parameter_num();
387  Matrix_real parameters_mtx(1, parameter_num);
388  double* parameters = parameters_mtx.get_data();
389  self->decomp->get_optimized_parameters(parameters);
390 
391  // convert to numpy array
392  parameters_mtx.set_owner(false);
393  PyObject * parameter_arr = matrix_real_to_numpy( parameters_mtx );
394 
395  return parameter_arr;
396 }
397 
398 
399 
400 
401 
406 static PyObject *
408 
409  PyArrayObject * parameters_arr = NULL;
410 
411 
412  // parsing input arguments
413  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
414  return Py_BuildValue("i", -1);
415 
416 
417  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
418  Py_INCREF(parameters_arr);
419  }
420  else {
421  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
422  }
423 
424 
425  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arr );
426 
427 
428  try {
429  self->decomp->set_optimized_parameters(parameters_mtx.get_data(), parameters_mtx.size());
430  }
431  catch (std::string err ) {
432  PyErr_SetString(PyExc_Exception, err.c_str());
433  return NULL;
434  }
435  catch(...) {
436  std::string err( "Invalid pointer to decomposition class");
437  PyErr_SetString(PyExc_Exception, err.c_str());
438  return NULL;
439  }
440 
441 
442  Py_DECREF(parameters_arr);
443 
444  return Py_BuildValue("i", 0);
445 }
446 
447 
448 
449 
450 
455 static PyObject *
457 
458  // initiate variables for input arguments
459  PyObject* max_layer_num;
460 
461  // parsing input arguments
462  if (!PyArg_ParseTuple(args, "|O", &max_layer_num )) return Py_BuildValue("i", -1);
463 
464  // Check whether input is dictionary
465  if (!PyDict_Check(max_layer_num)) {
466  printf("Input must be dictionary!\n");
467  return Py_BuildValue("i", -1);
468  }
469 
470 
471  PyObject* key = NULL;
472  PyObject* value = NULL;
473  Py_ssize_t pos = 0;
474 
475 
476  while (PyDict_Next(max_layer_num, &pos, &key, &value)) {
477 
478  // convert value fron PyObject to int
479  assert(PyLong_Check(value) == 1);
480  int value_int = (int) PyLong_AsLong(value);
481 
482  // convert keylue fron PyObject to int
483  assert(PyLong_Check(key) == 1);
484  int key_int = (int) PyLong_AsLong(key);
485 
486  // set maximal layer nums on the C++ side
487  self->decomp->set_max_layer_num( key_int, value_int );
488  }
489 
490  return Py_BuildValue("i", 0);
491 }
492 
493 
494 
495 
496 
497 
504 static PyObject *
506 
507  // initiate variables for input arguments
508  PyObject* iteration_loops;
509 
510  // parsing input arguments
511  if (!PyArg_ParseTuple(args, "|O", &iteration_loops )) return Py_BuildValue("i", -1);
512 
513  // Check whether input is dictionary
514  if (!PyDict_Check(iteration_loops)) {
515  printf("Input must be dictionary!\n");
516  return Py_BuildValue("i", -1);
517  }
518 
519 
520  PyObject* key = NULL;
521  PyObject* value = NULL;
522  Py_ssize_t pos = 0;
523 
524 
525  while (PyDict_Next(iteration_loops, &pos, &key, &value)) {
526 
527  // convert value fron PyObject to int
528  assert(PyLong_Check(value) == 1);
529  int value_int = (int) PyLong_AsLong(value);
530 
531  // convert keylue fron PyObject to int
532  assert(PyLong_Check(key) == 1);
533  int key_int = (int) PyLong_AsLong(key);
534 
535  // set maximal layer nums on the C++ side
536  self->decomp->set_iteration_loops( key_int, value_int );
537  }
538 
539  return Py_BuildValue("i", 0);
540 }
541 
542 
543 
550 static PyObject *
552 
553  // initiate variables for input arguments
554  int verbose;
555 
556  // parsing input arguments
557  if (!PyArg_ParseTuple(args, "|i", &verbose )) return Py_BuildValue("i", -1);
558 
559 
560  // set maximal layer nums on the C++ side
561  self->decomp->set_verbose( verbose );
562 
563  return Py_BuildValue("i", 0);
564 }
565 
572 static PyObject *
574 
575 
576  PyObject *debugfile = NULL;
577 
578  // parsing input arguments
579  if (!PyArg_ParseTuple(args, "|O", &debugfile )) return Py_BuildValue("s", -1);
580 
581  // determine the debugfile name type
582  PyObject* debugfile_string = PyObject_Str(debugfile);
583  PyObject* debugfile_string_unicode = PyUnicode_AsEncodedString(debugfile_string, "utf-8", "~E~");
584  const char* debugfile_C = PyBytes_AS_STRING(debugfile_string_unicode);
585 
586 
587  Py_XDECREF(debugfile_string);
588  Py_XDECREF(debugfile_string_unicode);
589 
590  // determine the length of the filename and initialize C++ variant of the string
591  Py_ssize_t string_length = PyBytes_Size(debugfile_string_unicode);
592  std::string debugfile_Cpp(debugfile_C, string_length);
593 
594  // set the name of the debugfile on the C++ side
595  self->decomp->set_debugfile( debugfile_Cpp );
596 
597 
598  return Py_BuildValue("s", NULL);
599 }
600 
601 
602 
609 static PyObject *
611 
612  // initiate variables for input arguments
613  double tolerance;
614 
615  // parsing input arguments
616  if (!PyArg_ParseTuple(args, "|d", &tolerance )) return Py_BuildValue("i", -1);
617 
618 
619  // set maximal layer nums on the C++ side
620  self->decomp->set_optimization_tolerance( tolerance );
621 
622  return Py_BuildValue("i", 0);
623 }
624 
625 
626 
627 
634 static PyObject *
636 
637  // initiate variables for input arguments
638  double threshold;
639 
640  // parsing input arguments
641  if (!PyArg_ParseTuple(args, "|d", &threshold )) return Py_BuildValue("i", -1);
642 
643 
644  // set maximal layer nums on the C++ side
645  self->decomp->set_convergence_threshold( threshold );
646 
647  return Py_BuildValue("i", 0);
648 }
649 
650 
657 static PyObject *
659 
660  // initiate variables for input arguments
661  double optimization_block;
662 
663  // parsing input arguments
664  if (!PyArg_ParseTuple(args, "|d", &optimization_block )) return Py_BuildValue("i", -1);
665 
666 
667  // set maximal layer nums on the C++ side
668  self->decomp->set_optimization_blocks( optimization_block );
669 
670  return Py_BuildValue("i", 0);
671 }
672 
673 
674 
682 static PyObject *
684 
685  // initiate variables for input arguments
686  PyObject* gate_structure_py;
687 
688  // parsing input arguments
689  if (!PyArg_ParseTuple(args, "|O", &gate_structure_py )) return Py_BuildValue("i", -1);
690 
691  // convert gate structure from PyObject to qgd_Circuit_Wrapper
692  qgd_Circuit_Wrapper* qgd_op_block = (qgd_Circuit_Wrapper*) gate_structure_py;
693 
694  self->decomp->set_custom_gate_structure( qgd_op_block->gate );
695 
696  return Py_BuildValue("i", 0);
697 
698 
699 }
700 
701 
706 static PyObject *
708 
709  // initiate variables for input arguments
710  PyObject* qbit_list;
711 
712  // parsing input arguments
713  if (!PyArg_ParseTuple(args, "|O", &qbit_list )) return Py_BuildValue("i", -1);
714 
715  bool is_tuple = PyTuple_Check(qbit_list);
716  bool is_list = PyList_Check(qbit_list);
717 
718  // Check whether input is dictionary
719  if (!is_list && !is_tuple) {
720  printf("Input must be tuple or list!\n");
721  return Py_BuildValue("i", -1);
722  }
723 
724  // get the number of qbubits
725  Py_ssize_t element_num;
726 
727  if (is_tuple) {
728  element_num = PyTuple_GET_SIZE(qbit_list);
729  }
730  else {
731  element_num = PyList_GET_SIZE(qbit_list);
732  }
733 
734 
735  // create C++ variant of the tuple/list
736  std::vector<int> qbit_list_C( (int) element_num);
737  for ( Py_ssize_t idx=0; idx<element_num; idx++ ) {
738  if (is_tuple) {
739  qbit_list_C[(int) idx] = (int) PyLong_AsLong( PyTuple_GetItem(qbit_list, idx ) );
740  }
741  else {
742  qbit_list_C[(int) idx] = (int) PyLong_AsLong( PyList_GetItem(qbit_list, idx ) );
743  }
744 
745  }
746 
747 
748  // reorder the qubits in the decomposition class
749  self->decomp->reorder_qubits( qbit_list_C );
750 
751 
752 
753  return Py_BuildValue("i", 0);
754 }
755 
756 
757 
763 static PyObject *
765 {
766 
767  // The tuple of expected keywords
768  static char *kwlist[] = {(char*)"optimizer", NULL};
769 
770  PyObject* optimizer_arg = NULL;
771 
772 
773  // parsing input arguments
774  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &optimizer_arg)) {
775 
776  std::string err( "Unsuccessful argument parsing not ");
777  PyErr_SetString(PyExc_Exception, err.c_str());
778  return NULL;
779 
780  }
781 
782 
783  if ( optimizer_arg == NULL ) {
784  std::string err( "optimizer argument not set");
785  PyErr_SetString(PyExc_Exception, err.c_str());
786  return NULL;
787  }
788 
789 
790 
791  PyObject* optimizer_string = PyObject_Str(optimizer_arg);
792  PyObject* optimizer_string_unicode = PyUnicode_AsEncodedString(optimizer_string, "utf-8", "~E~");
793  const char* optimizer_C = PyBytes_AS_STRING(optimizer_string_unicode);
794 
795 
796  optimization_aglorithms qgd_optimizer;
797  if ( strcmp("bfgs", optimizer_C) == 0 || strcmp("BFGS", optimizer_C) == 0) {
798  qgd_optimizer = BFGS;
799  }
800  else if ( strcmp("adam", optimizer_C)==0 || strcmp("ADAM", optimizer_C)==0) {
801  qgd_optimizer = ADAM;
802  }
803  else if ( strcmp("grad_descend", optimizer_C)==0 || strcmp("GRAD_DESCEND", optimizer_C)==0) {
804  qgd_optimizer = GRAD_DESCEND;
805  }
806  else if ( strcmp("adam_batched", optimizer_C)==0 || strcmp("ADAM_BATCHED", optimizer_C)==0) {
807  qgd_optimizer = ADAM_BATCHED;
808  }
809  else if ( strcmp("bfgs2", optimizer_C)==0 || strcmp("BFGS2", optimizer_C)==0) {
810  qgd_optimizer = BFGS2;
811  }
812  else if ( strcmp("agents", optimizer_C)==0 || strcmp("AGENTS", optimizer_C)==0) {
813  qgd_optimizer = AGENTS;
814  }
815  else if ( strcmp("cosine", optimizer_C)==0 || strcmp("COSINE", optimizer_C)==0) {
816  qgd_optimizer = COSINE;
817  }
818  else if ( strcmp("grad_descend_phase_shift_rule", optimizer_C)==0 || strcmp("GRAD_DESCEND_PARAMETER_SHIFT_RULE", optimizer_C)==0) {
819  qgd_optimizer = GRAD_DESCEND_PARAMETER_SHIFT_RULE;
820  }
821  else if ( strcmp("agents_combined", optimizer_C)==0 || strcmp("AGENTS_COMBINED", optimizer_C)==0) {
822  qgd_optimizer = AGENTS_COMBINED;
823  }
824  else {
825  std::cout << "Wrong optimizer: " << optimizer_C << ". Using default: BFGS" << std::endl;
826  qgd_optimizer = BFGS;
827  }
828 
829 
830  try {
831  self->decomp->set_optimizer(qgd_optimizer);
832  }
833  catch (std::string err) {
834  PyErr_SetString(PyExc_Exception, err.c_str());
835  std::cout << err << std::endl;
836  return NULL;
837  }
838  catch(...) {
839  std::string err( "Invalid pointer to decomposition class");
840  PyErr_SetString(PyExc_Exception, err.c_str());
841  return NULL;
842  }
843 
844 
845  return Py_BuildValue("i", 0);
846 
847 }
848 
849 
850 
856 static PyObject *
858 {
859 
860  // The tuple of expected keywords
861  static char *kwlist[] = {(char*)"costfnc", NULL};
862 
863  int costfnc_arg = 0;
864 
865 
866  // parsing input arguments
867  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &costfnc_arg)) {
868 
869  std::string err( "Unsuccessful argument parsing");
870  PyErr_SetString(PyExc_Exception, err.c_str());
871  return NULL;
872 
873  }
874 
875  cost_function_type qgd_costfnc = (cost_function_type)costfnc_arg;
876 
877 
878  try {
879  self->decomp->set_cost_function_variant(qgd_costfnc);
880  }
881  catch (std::string err) {
882  PyErr_SetString(PyExc_Exception, err.c_str());
883  std::cout << err << std::endl;
884  return NULL;
885  }
886  catch(...) {
887  std::string err( "Invalid pointer to decomposition class");
888  PyErr_SetString(PyExc_Exception, err.c_str());
889  return NULL;
890  }
891 
892 
893  return Py_BuildValue("i", 0);
894 
895 }
896 
898 
903 static PyObject *
905 {
906 
907 
908  PyArrayObject* parameters_arg = NULL;
909 
910 
911  // parsing input arguments
912  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
913 
914  std::string err( "Unsuccessful argument parsing not ");
915  PyErr_SetString(PyExc_Exception, err.c_str());
916  return NULL;
917 
918  }
919 
920  // establish memory contiguous arrays for C calculations
921  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
922  Py_INCREF(parameters_arg);
923  }
924  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
925  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
926  }
927  else {
928  std::string err( "Parameters should be should be real (given in float64 format)");
929  PyErr_SetString(PyExc_Exception, err.c_str());
930  return NULL;
931  }
932 
933 
934  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
935  double f0;
936 
937  try {
938  f0 = self->decomp->optimization_problem(parameters_mtx );
939  }
940  catch (std::string err ) {
941  PyErr_SetString(PyExc_Exception, err.c_str());
942  return NULL;
943  }
944  catch (...) {
945  std::string err( "Invalid pointer to decomposition class");
946  PyErr_SetString(PyExc_Exception, err.c_str());
947  return NULL;
948  }
949 
950  Py_DECREF(parameters_arg);
951 
952 
953  return Py_BuildValue("d", f0);
954 }
955 
956 
961 static PyObject *
963 {
964 
965 
966  PyArrayObject* parameters_arg = NULL;
967 
968 
969  // parsing input arguments
970  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
971 
972  std::string err( "Unsuccessful argument parsing not ");
973  PyErr_SetString(PyExc_Exception, err.c_str());
974  return NULL;
975 
976  }
977 
978  // establish memory contiguous arrays for C calculations
979  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
980  Py_INCREF(parameters_arg);
981  }
982  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
983  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
984  }
985  else {
986  std::string err( "Parameters should be should be real (given in float64 format)");
987  PyErr_SetString(PyExc_Exception, err.c_str());
988  return NULL;
989  }
990 
991 
992  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
993  Matrix_real grad_mtx(parameters_mtx.size(), 1);
994 
995  try {
996  self->decomp->optimization_problem_grad(parameters_mtx, self->decomp, grad_mtx );
997  }
998  catch (std::string err ) {
999  PyErr_SetString(PyExc_Exception, err.c_str());
1000  return NULL;
1001  }
1002  catch (...) {
1003  std::string err( "Invalid pointer to decomposition class");
1004  PyErr_SetString(PyExc_Exception, err.c_str());
1005  return NULL;
1006  }
1007 
1008  // convert to numpy array
1009  grad_mtx.set_owner(false);
1010  PyObject *grad_py = matrix_real_to_numpy( grad_mtx );
1011 
1012  Py_DECREF(parameters_arg);
1013 
1014 
1015  return grad_py;
1016 }
1017 
1022 static PyObject *
1024 {
1025 
1026 
1027  PyArrayObject* parameters_arg = NULL;
1028 
1029 
1030  // parsing input arguments
1031  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
1032 
1033  std::string err( "Unsuccessful argument parsing not ");
1034  PyErr_SetString(PyExc_Exception, err.c_str());
1035  return NULL;
1036 
1037  }
1038 
1039  // establish memory contiguous arrays for C calculations
1040  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1041  Py_INCREF(parameters_arg);
1042  }
1043  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
1044  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1045  }
1046  else {
1047  std::string err( "Parameters should be should be real (given in float64 format)");
1048  PyErr_SetString(PyExc_Exception, err.c_str());
1049  return NULL;
1050  }
1051 
1052 
1053  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
1054  Matrix_real grad_mtx(parameters_mtx.size(), 1);
1055  double f0;
1056 
1057  try {
1058  self->decomp->optimization_problem_combined(parameters_mtx, &f0, grad_mtx );
1059  }
1060  catch (std::string err ) {
1061  PyErr_SetString(PyExc_Exception, err.c_str());
1062  return NULL;
1063  }
1064  catch (...) {
1065  std::string err( "Invalid pointer to decomposition class");
1066  PyErr_SetString(PyExc_Exception, err.c_str());
1067  return NULL;
1068  }
1069 
1070  // convert to numpy array
1071  grad_mtx.set_owner(false);
1072  PyObject *grad_py = matrix_real_to_numpy( grad_mtx );
1073 
1074  Py_DECREF(parameters_arg);
1075 
1076 
1077  PyObject* p = Py_BuildValue("(dO)", f0, grad_py);
1078  Py_DECREF(grad_py);
1079  return p;
1080 }
1081 
1082 
1083 
1087 static PyObject *
1089 
1090 #ifdef __DFE__
1091 
1092  try {
1093  self->decomp->upload_Umtx_to_DFE();
1094  }
1095  catch (std::string err) {
1096  PyErr_SetString(PyExc_Exception, err.c_str());
1097  std::cout << err << std::endl;
1098  return NULL;
1099  }
1100  catch(...) {
1101  std::string err( "Invalid pointer to decomposition class");
1102  PyErr_SetString(PyExc_Exception, err.c_str());
1103  return NULL;
1104  }
1105 
1106 #endif
1107 
1108  return Py_BuildValue("i", 0);
1109 
1110 }
1111 
1112 
1113 
1118  {NULL} /* Sentinel */
1119 };
1120 
1125  {"Start_Decomposition", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_Start_Decomposition, METH_VARARGS | METH_KEYWORDS,
1126  "Method to start the decomposition."
1127  },
1128  {"get_Gate_Num", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_get_gate_num, METH_NOARGS,
1129  "Method to get the number of decomposing gates."
1130  },
1131  {"get_Optimized_Parameters", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_get_Optimized_Parameters, METH_NOARGS,
1132  "Method to get the array of optimized parameters."
1133  },
1134  {"set_Optimized_Parameters", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimized_Parameters, METH_VARARGS,
1135  "Method to set the initial array of optimized parameters."
1136  },
1137  {"get_Circuit", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_get_circuit, METH_NOARGS,
1138  "Method to get the incorporated circuit."
1139  },
1140  {"List_Gates", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_List_Gates, METH_NOARGS,
1141  "Call to print the decomposing nitaries on standard output"
1142  },
1143  {"set_Max_Layer_Num", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Max_Layer_Num, METH_VARARGS,
1144  "Call to set the maximal number of layers used in the subdecomposition of the qbit-th qubit."
1145  },
1146  {"set_Iteration_Loops", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Iteration_Loops, METH_VARARGS,
1147  "Call to set the number of iteration loops during the subdecomposition of the qbit-th qubit."
1148  },
1149  {"set_Verbose", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Verbose, METH_VARARGS,
1150  "Call to set the verbosity of the qgd_N_Qubit_Decomposition class."
1151  },
1152  {"set_Debugfile", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Debugfile, METH_VARARGS,
1153  "Set the debugfile name of the N_Qubit_Decomposition class."
1154  },
1155  {"set_Gate_Structure", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Gate_Structure, METH_VARARGS,
1156  "Call to set custom gate structure in the decomposition."
1157  },
1158  {"Reorder_Qubits", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_Reorder_Qubits, METH_VARARGS,
1159  "Wrapper method to reorder the qubits in the decomposition class."
1160  },
1161  {"set_Optimization_Tolerance", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimization_Tolerance, METH_VARARGS,
1162  "Wrapper method to set the optimization tolerance of the optimization process during the decomposition."
1163  },
1164  {"set_Convergence_Threshold", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Convergence_Threshold, METH_VARARGS,
1165  "Wrapper method to set the threshold of convergence in the optimization processes."
1166  },
1167  {"set_Optimization_Blocks", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimization_Blocks, METH_VARARGS,
1168  "Wrapper method to to set the number of gate blocks to be optimized in one shot."
1169  },
1170  {"set_Optimizer", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimizer, METH_VARARGS | METH_KEYWORDS,
1171  "Wrapper method to to set the optimizer method for the gate synthesis."
1172  },
1173  {"Upload_Umtx_to_DFE", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_Upload_Umtx_to_DFE, METH_NOARGS,
1174  "Call to upload the unitary to the DFE. (Has no effect for non-DFE builds)"
1175  },
1176  {"set_Cost_Function_Variant", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_set_Cost_Function_Variant, METH_VARARGS | METH_KEYWORDS,
1177  "Wrapper method to to set the variant of the cost function. Input argument 0 stands for FROBENIUS_NORM, 1 for FROBENIUS_NORM_CORRECTION1, 2 for FROBENIUS_NORM_CORRECTION2, 3 for HILBERT_SCHMIDT_TEST, 4 for HILBERT_SCHMIDT_TEST_CORRECTION1, 5 for HILBERT_SCHMIDT_TEST_CORRECTION2."
1178  },
1179  {"Optimization_Problem", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_Optimization_Problem, METH_VARARGS,
1180  "Wrapper function to evaluate the cost function."
1181  },
1182  {"Optimization_Problem_Grad", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_Optimization_Problem_Grad, METH_VARARGS,
1183  "Wrapper function to evaluate the gradient components."
1184  },
1185  {"Optimization_Problem_Combined", (PyCFunction) qgd_N_Qubit_Decomposition_custom_Wrapper_Optimization_Problem_Combined, METH_VARARGS,
1186  "Wrapper function to evaluate the cost function and the gradient components."
1187  },
1188  {NULL} /* Sentinel */
1189 };
1190 
1195  PyVarObject_HEAD_INIT(NULL, 0)
1196  "qgd_N_Qubit_Decomposition_custom_Wrapper.qgd_N_Qubit_Decomposition_custom_Wrapper", /*tp_name*/
1197  sizeof(qgd_N_Qubit_Decomposition_custom_Wrapper), /*tp_basicsize*/
1198  0, /*tp_itemsize*/
1199  (destructor) qgd_N_Qubit_Decomposition_custom_Wrapper_dealloc, /*tp_dealloc*/
1200  #if PY_VERSION_HEX < 0x030800b4
1201  0, /*tp_print*/
1202  #endif
1203  #if PY_VERSION_HEX >= 0x030800b4
1204  0, /*tp_vectorcall_offset*/
1205  #endif
1206  0, /*tp_getattr*/
1207  0, /*tp_setattr*/
1208  #if PY_MAJOR_VERSION < 3
1209  0, /*tp_compare*/
1210  #endif
1211  #if PY_MAJOR_VERSION >= 3
1212  0, /*tp_as_async*/
1213  #endif
1214  0, /*tp_repr*/
1215  0, /*tp_as_number*/
1216  0, /*tp_as_sequence*/
1217  0, /*tp_as_mapping*/
1218  0, /*tp_hash*/
1219  0, /*tp_call*/
1220  0, /*tp_str*/
1221  0, /*tp_getattro*/
1222  0, /*tp_setattro*/
1223  0, /*tp_as_buffer*/
1224  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1225  "Object to represent a Circuit class of the QGD package.", /*tp_doc*/
1226  0, /*tp_traverse*/
1227  0, /*tp_clear*/
1228  0, /*tp_richcompare*/
1229  0, /*tp_weaklistoffset*/
1230  0, /*tp_iter*/
1231  0, /*tp_iternext*/
1234  0, /*tp_getset*/
1235  0, /*tp_base*/
1236  0, /*tp_dict*/
1237  0, /*tp_descr_get*/
1238  0, /*tp_descr_set*/
1239  0, /*tp_dictoffset*/
1240  (initproc) qgd_N_Qubit_Decomposition_custom_Wrapper_init, /*tp_init*/
1241  0, /*tp_alloc*/
1243  0, /*tp_free*/
1244  0, /*tp_is_gc*/
1245  0, /*tp_bases*/
1246  0, /*tp_mro*/
1247  0, /*tp_cache*/
1248  0, /*tp_subclasses*/
1249  0, /*tp_weaklist*/
1250  0, /*tp_del*/
1251  0, /*tp_version_tag*/
1252  #if PY_VERSION_HEX >= 0x030400a1
1253  0, /*tp_finalize*/
1254  #endif
1255  #if PY_VERSION_HEX >= 0x030800b1
1256  0, /*tp_vectorcall*/
1257  #endif
1258  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
1259  0, /*tp_print*/
1260  #endif
1261 };
1262 
1267  PyModuleDef_HEAD_INIT,
1268  "qgd_N_Qubit_Decomposition_custom_Wrapper",
1269  "Python binding for QGD N_Qubit_Decomposition class",
1270  -1,
1271 };
1272 
1273 
1277 PyMODINIT_FUNC
1279 {
1280  // initialize Numpy API
1281  import_array();
1282 
1283  PyObject *m;
1284  if (PyType_Ready(&qgd_N_Qubit_Decomposition_custom_Wrapper_Type) < 0)
1285  return NULL;
1286 
1287  m = PyModule_Create(&qgd_N_Qubit_Decomposition_custom_Wrapper_Module);
1288  if (m == NULL)
1289  return NULL;
1290 
1291  Py_INCREF(&qgd_N_Qubit_Decomposition_custom_Wrapper_Type);
1292  if (PyModule_AddObject(m, "qgd_N_Qubit_Decomposition_custom_Wrapper", (PyObject *) &qgd_N_Qubit_Decomposition_custom_Wrapper_Type) < 0) {
1293  Py_DECREF(&qgd_N_Qubit_Decomposition_custom_Wrapper_Type);
1294  Py_DECREF(m);
1295  return NULL;
1296  }
1297 
1298  return m;
1299 }
1300 
1301 
1302 } //extern C
1303 
1304 
Gates_block * get_flat_circuit()
Method to generate a flat circuit.
parameter_num
[set adaptive gate structure]
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Verbose(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Set the verbosity of the N_Qubit_Decomposition class.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_get_Optimized_Parameters(qgd_N_Qubit_Decomposition_custom_Wrapper *self)
Extract the optimized parameters.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimization_Tolerance(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper method to set the optimization tolerance of the optimization process during the decomposition...
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Debugfile(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Set the debugfile name of the N_Qubit_Decomposition class.
static PyModuleDef qgd_N_Qubit_Decomposition_custom_Wrapper_Module
Structure containing metadata about the module.
Matrix_real numpy2matrix_real(PyArrayObject *arr)
Call to create a PIC matrix_real representation of a numpy array.
static int qgd_N_Qubit_Decomposition_custom_Wrapper_init(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_custom_Wrapper is initial...
static void qgd_N_Qubit_Decomposition_custom_Wrapper_dealloc(qgd_N_Qubit_Decomposition_custom_Wrapper *self)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_custom_Wrapper is destroy...
PyObject_HEAD PyArrayObject * Umtx
pointer to the unitary to be decomposed to keep it alive
void release_N_Qubit_Decomposition_custom(N_Qubit_Decomposition_custom *instance)
Call to deallocate an instance of N_Qubit_Decomposition_custom class.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimizer(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to set custom gate structure for the decomposition.
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 PyTypeObject qgd_N_Qubit_Decomposition_custom_Wrapper_Type
A structure describing the type of the class qgd_N_Qubit_Decomposition_custom_Wrapper.
A class describing a universal configuration element.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_Upload_Umtx_to_DFE(qgd_N_Qubit_Decomposition_custom_Wrapper *self)
Call to upload the unitary to the DFE.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_Optimization_Problem_Grad(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function an dthe gradient components.
scalar * get_data() const
Call to get the pointer to the stored data.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimized_Parameters(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Extract the optimized parameters.
PyMODINIT_FUNC PyInit_qgd_N_Qubit_Decomposition_custom_Wrapper(void)
Method called when the Python module is initialized.
optimization_aglorithms
implemented optimization strategies
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_get_circuit(qgd_N_Qubit_Decomposition_custom_Wrapper *self)
Wrapper function to retrieve the circuit (Squander format) incorporated in the instance.
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_Optimization_Problem_Combined(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function an dthe gradient components.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Max_Layer_Num(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Set the maximal number of layers used in the subdecomposition of the qbit-th qubit.
Umtx
The unitary to be decomposed.
Definition: example.py:53
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Convergence_Threshold(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper method to set the threshold of convergence in the optimization processes. ...
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_Optimization_Problem(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function.
N_Qubit_Decomposition_custom * decomp
An object to decompose the unitary.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Iteration_Loops(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Set the number of iteration loops during the subdecomposition of the qbit-th qubit.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_Reorder_Qubits(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper method to reorder the qubits in the decomposition class.
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 PyMemberDef qgd_N_Qubit_Decomposition_custom_Wrapper_members[]
Structure containing metadata about the members of class qgd_N_Qubit_Decomposition_custom_Wrapper.
dictionary config
gate systhesis #####################################
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_Start_Decomposition(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to call the start_decomposition method of C++ class N_Qubit_Decomposition.
static PyMethodDef qgd_N_Qubit_Decomposition_custom_Wrapper_methods[]
Structure containing metadata about the methods of class qgd_N_Qubit_Decomposition_custom_Wrapper.
int size() const
Call to get the number of the allocated elements.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Optimization_Blocks(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper method to to set the number of gate blocks to be optimized in one shot.
cost_function_type
Type definition of the fifferent types of the cost function.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
Definition: Gates_block.h:41
guess_type
Type definition of the types of the initial guess.
void set_property(std::string name_, double val_)
Call to set a double value.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_List_Gates(qgd_N_Qubit_Decomposition_custom_Wrapper *self)
Lists the gates decomposing the initial unitary.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_custom_Wrapper is allocat...
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.
N_Qubit_Decomposition_custom * create_N_Qubit_Decomposition_custom(Matrix &Umtx, int qbit_num, bool optimize_layer_num, guess_type initial_guess, std::map< std::string, Config_Element > &config, int accelerator_num)
Creates an instance of class N_Qubit_Decomposition and return with a pointer pointing to the class in...
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 PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_get_gate_num(qgd_N_Qubit_Decomposition_custom_Wrapper *self)
Wrapper function to get the number of decomposing gates.
Type definition of the qgd_N_Qubit_Decomposition_custom_Wrapper Python class of the qgd_N_Qubit_Decom...
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Cost_Function_Variant(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to set a variant for the cost function.
static PyObject * qgd_N_Qubit_Decomposition_custom_Wrapper_set_Gate_Structure(qgd_N_Qubit_Decomposition_custom_Wrapper *self, PyObject *args)
Wrapper function to set custom gate structure for the decomposition.