Sequential Quantum Gate Decomposer  v1.9.3
Powerful decomposition of general unitarias into one- and two-qubit gates gates
qgd_N_Qubit_Decomposition_Tree_Search_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_Tree_Search_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;
61 
63 
64 
65 
77 create_N_Qubit_Decomposition_Tree_Search( Matrix& Umtx, int qbit_num, int level_limit, std::vector<matrix_base<int>> topology_in, std::map<std::string, Config_Element>& config, int accelerator_num ) {
78 
79  return new N_Qubit_Decomposition_Tree_Search( Umtx, qbit_num, level_limit, topology_in, config, accelerator_num );
80 }
81 
82 
83 
84 
89 void
91 
92  if (instance != NULL ) {
93  delete instance;
94  }
95  return;
96 }
97 
98 
99 
100 
101 
102 
103 extern "C"
104 {
105 
106 
111 static void
113 {
114 
115  if ( self->decomp != NULL ) {
116  // deallocate the instance of class N_Qubit_Decomposition
118  self->decomp = NULL;
119  }
120 
121 
122  if ( self->Umtx != NULL ) {
123  // release the unitary to be decomposed
124  Py_DECREF(self->Umtx);
125  self->Umtx = NULL;
126  }
127 
128  Py_TYPE(self)->tp_free((PyObject *) self);
129 
130 }
131 
136 static PyObject *
138 {
140  self = (qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *) type->tp_alloc(type, 0);
141  if (self != NULL) {
142 
143  self->decomp = NULL;
144  self->Umtx = NULL;
145 
146  }
147 
148  return (PyObject *) self;
149 }
150 
151 
158 static int
160 {
161  // The tuple of expected keywords
162  static char *kwlist[] = {(char*)"Umtx", (char*)"qbit_num", (char*)"method", (char*)"topology", (char*)"config", (char*)"accelerator_num", NULL};
163 
164  // initiate variables for input arguments
165  PyArrayObject *Umtx_arg = NULL;
166  PyObject *config_arg = NULL;
167  int qbit_num = -1;
168  int level_limit = 0;
169  PyObject *topology = NULL;
170  int accelerator_num = 0;
171 
172  // parsing input arguments
173  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OiiOOi", kwlist,
174  &Umtx_arg, &qbit_num, &level_limit, &topology, &config_arg, &accelerator_num))
175  return -1;
176 
177  // convert python object array to numpy C API array
178  if ( Umtx_arg == NULL ) return -1;
179  self->Umtx = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*) Umtx_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
180 
181  // test C-style contiguous memory allocation of the array
182  if ( !PyArray_IS_C_CONTIGUOUS(self->Umtx) ) {
183  std::cout << "Umtx is not memory contiguous" << std::endl;
184  }
185 
186 
187  // create QGD version of the Umtx
188  Matrix Umtx_mtx = numpy2matrix(self->Umtx);
189 
190  // elaborate connectivity topology
191  bool is_None = topology == Py_None;
192  bool is_list = PyList_Check(topology);
193 
194  // Check whether input is a list
195  if (!is_list && !is_None) {
196  printf("Input topology must be a list!\n");
197  return -1;
198  }
199 
200  // create C++ variant of the list
201  std::vector<matrix_base<int>> topology_Cpp;
202 
203  if ( !is_None ) {
204 
205  // get the number of qbubits
206  Py_ssize_t element_num = PyList_GET_SIZE(topology);
207 
208  for ( Py_ssize_t idx=0; idx<element_num; idx++ ) {
209  PyObject *item = PyList_GetItem(topology, idx );
210 
211  // Check whether input is a list
212  if (!PyTuple_Check(item)) {
213  printf("Elements of topology must be a tuple!\n");
214  return -1;
215  }
216 
217  matrix_base<int> item_Cpp(1,2);
218  item_Cpp[0] = (int) PyLong_AsLong( PyTuple_GetItem(item, 0 ) );
219  item_Cpp[1] = (int) PyLong_AsLong( PyTuple_GetItem(item, 1 ) );
220 
221  topology_Cpp.push_back( item_Cpp );
222  }
223  }
224 
225 
226  // parse config and create C++ version of the hyperparameters
227 
228  bool is_dict = PyDict_Check( config_arg );
229  if (!is_dict) {
230  printf("Config object must be a python dictionary!\n");
231  return -1;
232  }
233 
234  // integer type config metadata utilized during the optimization
235  std::map<std::string, Config_Element> config;
236 
237 
238  // keys and values of the config dict (borrowed references)
239  PyObject *key, *value;
240  Py_ssize_t pos = 0;
241 
242  while (PyDict_Next(config_arg, &pos, &key, &value)) {
243 
244  // determine the initial guess type
245  PyObject* key_string = PyObject_Str(key);
246  PyObject* key_string_unicode = PyUnicode_AsEncodedString(key_string, "utf-8", "~E~");
247  const char* key_C = PyBytes_AS_STRING(key_string_unicode);
248 
249  std::string key_Cpp( key_C );
250  Config_Element element;
251 
252  if ( PyLong_Check( value ) ) {
253  element.set_property( key_Cpp, PyLong_AsLongLong( value ) );
254  config[ key_Cpp ] = element;
255  }
256  else if ( PyFloat_Check( value ) ) {
257  element.set_property( key_Cpp, PyFloat_AsDouble( value ) );
258  config[ key_Cpp ] = element;
259  }
260  else {
261 
262  }
263 
264  }
265 
266 
267  // create an instance of the class N_Qubit_Decomposition
268  if (qbit_num > 0 ) {
269  try {
270  self->decomp = create_N_Qubit_Decomposition_Tree_Search( Umtx_mtx, qbit_num, level_limit, topology_Cpp, config, accelerator_num);
271  }
272  catch (std::string err ) {
273  PyErr_SetString(PyExc_Exception, err.c_str());
274  return -1;
275  }
276  }
277  else {
278  std::cout << "The number of qubits should be given as a positive integer, " << qbit_num << " was given" << std::endl;
279  return -1;
280  }
281 
282 
283 
284  return 0;
285 }
286 
293 static PyObject *
295 {
296 
297  // The tuple of expected keywords
298  static char *kwlist[] = {NULL};
299 
300 
301  // parsing input arguments
302  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|", kwlist))
303  return Py_BuildValue("i", -1);
304 
305  // starting the decomposition
306  try {
307  self->decomp->start_decomposition();
308  }
309  catch (std::string err) {
310  PyErr_SetString(PyExc_Exception, err.c_str());
311  std::cout << err << std::endl;
312  return NULL;
313  }
314  catch(...) {
315  std::string err( "Invalid pointer to decomposition class");
316  PyErr_SetString(PyExc_Exception, err.c_str());
317  return NULL;
318  }
319 
320 
321 
322  return Py_BuildValue("i", 0);
323 }
324 
325 
326 
332 static PyObject *
334 
335  // get the number of gates
336  int ret = self->decomp->get_gate_num();
337 
338 
339  return Py_BuildValue("i", ret);
340 
341 }
342 
343 
344 
345 
346 
347 
352 static PyObject *
354 
355  QGD_Complex16 global_phase_factor_C = self->decomp->get_global_phase_factor();
356  PyObject* global_phase = PyFloat_FromDouble( std::atan2(global_phase_factor_C.imag,global_phase_factor_C.real));
357 
358  return global_phase;
359 
360 }
361 
368 
369  double new_global_phase;
370  if (!PyArg_ParseTuple(args, "|d", &new_global_phase )) return Py_BuildValue("i", -1);
371  self->decomp->set_global_phase(new_global_phase);
372 
373  return Py_BuildValue("i", 0);
374 
375 }
376 
382 
383  // get the number of gates
384  self->decomp->apply_global_phase_factor();
385 
386  return Py_BuildValue("i", 0);
387 
388 }
389 
390 
395 static PyObject *
397 
398 
399  PyObject* qgd_Circuit = PyImport_ImportModule("squander.gates.qgd_Circuit");
400 
401  if ( qgd_Circuit == NULL ) {
402  PyErr_SetString(PyExc_Exception, "Module import error: squander.gates.qgd_Circuit" );
403  return NULL;
404  }
405 
406  // retrieve the C++ variant of the flat circuit (flat circuit does not conatain any sub-circuits)
407  Gates_block* circuit = self->decomp->get_flat_circuit();
408 
409 
410 
411  // construct python interfarce for the circuit
412  PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_Circuit );
413 
414  // 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
415  PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict, "qgd_Circuit");
416 
417  // create gate parameters
418  PyObject* qbit_num = Py_BuildValue("i", circuit->get_qbit_num() );
419  PyObject* circuit_input = Py_BuildValue("(O)", qbit_num);
420 
421  PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
422  qgd_Circuit_Wrapper* py_circuit_C = reinterpret_cast<qgd_Circuit_Wrapper*>( py_circuit );
423 
424 
425  // replace the empty circuit with the extracted one
426 
427  delete( py_circuit_C->gate );
428  py_circuit_C->gate = circuit;
429 
430 
431  return py_circuit;
432 
433 }
434 
435 
440 static PyObject *
442 
443  self->decomp->list_gates( 0 );
444 
445  return Py_None;
446 }
447 
448 
449 
450 
455 static PyObject *
457 
458  int parameter_num = self->decomp->get_parameter_num();
459  Matrix_real parameters_mtx(1, parameter_num);
460  double* parameters = parameters_mtx.get_data();
461  self->decomp->get_optimized_parameters(parameters);
462 
463  // convert to numpy array
464  parameters_mtx.set_owner(false);
465  PyObject * parameter_arr = matrix_real_to_numpy( parameters_mtx );
466 
467  return parameter_arr;
468 
469 }
470 
471 
472 
473 
477 static PyObject *
479 
480  int parameter_num = self->decomp->get_parameter_num();
481 
482  return Py_BuildValue("i", parameter_num);
483 }
484 
488 static PyObject *
490 
491  int number_of_iters = self->decomp->get_num_iters();
492 
493  return Py_BuildValue("i", number_of_iters);
494 }
495 
496 
501 static PyObject *
503 
504  PyArrayObject* parameters_arr = NULL;
505 
506 
507  // parsing input arguments
508  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
509  return Py_BuildValue("i", -1);
510 
511 
512  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
513  Py_INCREF(parameters_arr);
514  }
515  else {
516  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
517  }
518 
519 
520  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arr );
521 
522  try {
523  self->decomp->set_optimized_parameters(parameters_mtx.get_data(), parameters_mtx.size());
524  }
525  catch (std::string err ) {
526  PyErr_SetString(PyExc_Exception, err.c_str());
527  return NULL;
528  }
529  catch(...) {
530  std::string err( "Invalid pointer to decomposition class");
531  PyErr_SetString(PyExc_Exception, err.c_str());
532  return NULL;
533  }
534 
535 
536 
537  Py_DECREF(parameters_arr);
538 
539  return Py_BuildValue("i", 0);
540 }
541 
542 
543 
544 
545 
550 static PyObject *
552 
553  // initiate variables for input arguments
554  PyObject* max_layer_num;
555 
556  // parsing input arguments
557  if (!PyArg_ParseTuple(args, "|O", &max_layer_num )) return Py_BuildValue("i", -1);
558 
559  // Check whether input is dictionary
560  if (!PyDict_Check(max_layer_num)) {
561  printf("Input must be dictionary!\n");
562  return Py_BuildValue("i", -1);
563  }
564 
565 
566  PyObject* key = NULL;
567  PyObject* value = NULL;
568  Py_ssize_t pos = 0;
569 
570 
571  while (PyDict_Next(max_layer_num, &pos, &key, &value)) {
572 
573  // convert value fron PyObject to int
574  assert(PyLong_Check(value) == 1);
575  int value_int = (int) PyLong_AsLong(value);
576 
577  // convert keylue fron PyObject to int
578  assert(PyLong_Check(key) == 1);
579  int key_int = (int) PyLong_AsLong(key);
580 
581  // set maximal layer nums on the C++ side
582  self->decomp->set_max_layer_num( key_int, value_int );
583 
584  }
585 
586  return Py_BuildValue("i", 0);
587 }
588 
589 
590 
591 
592 
593 
600 static PyObject *
602 
603  // initiate variables for input arguments
604  PyObject* iteration_loops;
605 
606  // parsing input arguments
607  if (!PyArg_ParseTuple(args, "|O", &iteration_loops )) return Py_BuildValue("i", -1);
608 
609  // Check whether input is dictionary
610  if (!PyDict_Check(iteration_loops)) {
611  printf("Input must be dictionary!\n");
612  return Py_BuildValue("i", -1);
613  }
614 
615 
616  PyObject* key = NULL;
617  PyObject* value = NULL;
618  Py_ssize_t pos = 0;
619 
620 
621  while (PyDict_Next(iteration_loops, &pos, &key, &value)) {
622 
623  // convert value fron PyObject to int
624  assert(PyLong_Check(value) == 1);
625  int value_int = (int) PyLong_AsLong(value);
626 
627  // convert keylue fron PyObject to int
628  assert(PyLong_Check(key) == 1);
629  int key_int = (int) PyLong_AsLong(key);
630 
631  // set maximal layer nums on the C++ side
632  self->decomp->set_iteration_loops( key_int, value_int );
633 
634  }
635 
636  return Py_BuildValue("i", 0);
637 }
638 
644 static PyObject *
646 
647  // initiate variables for input arguments
648  int max_iters_input;
649 
650  // parsing input arguments
651  if (!PyArg_ParseTuple(args, "|i", &max_iters_input )) return Py_BuildValue("i", -1);
652 
653 
654  //set the maximum number of iterations
655  self->decomp->set_max_inner_iterations(max_iters_input);
656 
657 
658  return Py_BuildValue("i", 0);
659 }
660 
667 static PyObject *
669 
670  // initiate variables for input arguments
671  int verbose;
672 
673  // parsing input arguments
674  if (!PyArg_ParseTuple(args, "|i", &verbose )) return Py_BuildValue("i", -1);
675 
676 
677  // set maximal layer nums on the C++ side
678  self->decomp->set_verbose( verbose );
679 
680 
681  return Py_BuildValue("i", 0);
682 }
683 
684 
691 static PyObject *
693 
694 
695  PyObject *debugfile = NULL;
696 
697  // parsing input arguments
698  if (!PyArg_ParseTuple(args, "|O", &debugfile )) return Py_BuildValue("s", -1);
699 
700  // determine the debugfile name type
701  PyObject* debugfile_string = PyObject_Str(debugfile);
702  PyObject* debugfile_string_unicode = PyUnicode_AsEncodedString(debugfile_string, "utf-8", "~E~");
703  const char* debugfile_C = PyBytes_AS_STRING(debugfile_string_unicode);
704 
705 
706  Py_XDECREF(debugfile_string);
707  Py_XDECREF(debugfile_string_unicode);
708 
709  // determine the length of the filename and initialize C++ variant of the string
710  Py_ssize_t string_length = PyBytes_Size(debugfile_string_unicode);
711  std::string debugfile_Cpp(debugfile_C, string_length);
712 
713  // set the name of the debugfile on the C++ side
714  self->decomp->set_debugfile( debugfile_Cpp );
715 
716 
717  return Py_BuildValue("s", NULL);
718 }
719 
720 
721 
728 static PyObject *
730 
731  // initiate variables for input arguments
732  double tolerance;
733 
734  // parsing input arguments
735  if (!PyArg_ParseTuple(args, "|d", &tolerance )) return Py_BuildValue("i", -1);
736 
737 
738  // set maximal layer nums on the C++ side
739  self->decomp->set_optimization_tolerance( tolerance );
740 
741 
742  return Py_BuildValue("i", 0);
743 }
744 
745 
746 
753 static PyObject *
755 
756  // initiate variables for input arguments
757  double threshold;
758 
759  // parsing input arguments
760  if (!PyArg_ParseTuple(args, "|d", &threshold )) return Py_BuildValue("i", -1);
761 
762 
763  // set maximal layer nums on the C++ side
764  self->decomp->set_convergence_threshold( threshold );
765 
766  return Py_BuildValue("i", 0);
767 }
768 
769 
776 static PyObject *
778 
779  // initiate variables for input arguments
780  double optimization_block;
781 
782  // parsing input arguments
783  if (!PyArg_ParseTuple(args, "|d", &optimization_block )) return Py_BuildValue("i", -1);
784 
785 
786  // set maximal layer nums on the C++ side
787  self->decomp->set_optimization_blocks( optimization_block );
788 
789 
790  return Py_BuildValue("i", 0);
791 }
792 
793 
794 
795 
796 
801 static PyObject *
803 
804 
805  std::string project_name = self->decomp->get_project_name();
806 
807  // convert to python string
808  PyObject* project_name_pyhton = PyUnicode_FromString(project_name.c_str());
809 
810  return project_name_pyhton;
811 }
812 
813 
814 
815 
820 static PyObject *
822  // initiate variables for input arguments
823  PyObject* project_name_new=NULL;
824 
825  // parsing input arguments
826  if (!PyArg_ParseTuple(args, "|O", &project_name_new)) return Py_BuildValue("i", -1);
827 
828 
829  PyObject* project_name_new_string = PyObject_Str(project_name_new);
830  PyObject* project_name_new_unicode = PyUnicode_AsEncodedString(project_name_new_string, "utf-8", "~E~");
831  const char* project_name_new_C = PyBytes_AS_STRING(project_name_new_unicode);
832  std::string project_name_new_str = ( project_name_new_C );
833 
834  // convert to python string
835  self->decomp->set_project_name(project_name_new_str);
836 
837  return Py_BuildValue("i", 0);
838 }
839 
840 
845 static PyObject *
847 
848 
849  double decomposition_error = self->decomp->get_decomposition_error();
850 
851 
852  return Py_BuildValue("d", decomposition_error);
853 }
854 
859 static PyObject *
861  // initiate variables for input arguments
862  PyObject* filename=NULL;
863 
864  // parsing input arguments
865  if (!PyArg_ParseTuple(args, "|O", &filename)) return Py_BuildValue("i", -1);
866 
867 
868  PyObject* filename_string = PyObject_Str(filename);
869  PyObject* filename_unicode = PyUnicode_AsEncodedString(filename_string, "utf-8", "~E~");
870  const char* filename_C = PyBytes_AS_STRING(filename_unicode);
871  std::string filename_str = ( filename_C );
872 
873  // convert to python string
874  self->decomp->export_unitary(filename_str);
875 
876  return Py_BuildValue("i", 0);
877 }
878 
883 static PyObject *
885 
886 
887  Matrix Unitary_mtx;
888 
889  try {
890  Unitary_mtx = self->decomp->get_Umtx().copy();
891  }
892  catch (std::string err ) {
893  PyErr_SetString(PyExc_Exception, err.c_str());
894  return NULL;
895  }
896  catch (...) {
897  std::string err( "Invalid pointer to decomposition class");
898  PyErr_SetString(PyExc_Exception, err.c_str());
899  return NULL;
900  }
901 
902 
903  // convert to numpy array
904  Unitary_mtx.set_owner(false);
905  PyObject *Unitary_py = matrix_to_numpy( Unitary_mtx );
906 
907  return Unitary_py;
908 }
909 
910 
915 static PyObject *
917 {
918 
919 
920  PyArrayObject* parameters_arg = NULL;
921 
922 
923  // parsing input arguments
924  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
925 
926  std::string err( "Unsuccessful argument parsing not ");
927  PyErr_SetString(PyExc_Exception, err.c_str());
928  return NULL;
929 
930  }
931 
932  // establish memory contiguous arrays for C calculations
933  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
934  Py_INCREF(parameters_arg);
935  }
936  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
937  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
938  }
939  else {
940  std::string err( "Parameters should be should be real (given in float64 format)");
941  PyErr_SetString(PyExc_Exception, err.c_str());
942  return NULL;
943  }
944 
945 
946  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
947  double f0;
948 
949  try {
950  f0 = self->decomp->optimization_problem(parameters_mtx );
951  }
952  catch (std::string err ) {
953  PyErr_SetString(PyExc_Exception, err.c_str());
954  return NULL;
955  }
956  catch (...) {
957  std::string err( "Invalid pointer to decomposition class");
958  PyErr_SetString(PyExc_Exception, err.c_str());
959  return NULL;
960  }
961 
962  Py_DECREF(parameters_arg);
963 
964 
965  return Py_BuildValue("d", f0);
966 }
967 
968 
973 static PyObject *
975 {
976 
977 
978  PyArrayObject* parameters_arg = NULL;
979 
980 
981  // parsing input arguments
982  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
983 
984  std::string err( "Unsuccessful argument parsing not ");
985  PyErr_SetString(PyExc_Exception, err.c_str());
986  return NULL;
987 
988  }
989 
990  // establish memory contiguous arrays for C calculations
991  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
992  Py_INCREF(parameters_arg);
993  }
994  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
995  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
996  }
997  else {
998  std::string err( "Parameters should be should be real (given in float64 format)");
999  PyErr_SetString(PyExc_Exception, err.c_str());
1000  return NULL;
1001  }
1002 
1003 
1004  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
1005  Matrix_real grad_mtx(parameters_mtx.size(), 1);
1006 
1007  try {
1008  self->decomp->optimization_problem_grad(parameters_mtx, self->decomp, grad_mtx );
1009  }
1010  catch (std::string err ) {
1011  PyErr_SetString(PyExc_Exception, err.c_str());
1012  return NULL;
1013  }
1014  catch (...) {
1015  std::string err( "Invalid pointer to decomposition class");
1016  PyErr_SetString(PyExc_Exception, err.c_str());
1017  return NULL;
1018  }
1019 
1020  // convert to numpy array
1021  grad_mtx.set_owner(false);
1022  PyObject *grad_py = matrix_real_to_numpy( grad_mtx );
1023 
1024  Py_DECREF(parameters_arg);
1025 
1026 
1027  return grad_py;
1028 }
1029 
1034 static PyObject *
1036 {
1037 
1038 
1039  PyArrayObject* parameters_arg = NULL;
1040 
1041 
1042  // parsing input arguments
1043  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
1044 
1045  std::string err( "Unsuccessful argument parsing not ");
1046  PyErr_SetString(PyExc_Exception, err.c_str());
1047  return NULL;
1048 
1049  }
1050 
1051  // establish memory contiguous arrays for C calculations
1052  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1053  Py_INCREF(parameters_arg);
1054  }
1055  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
1056  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1057  }
1058  else {
1059  std::string err( "Parameters should be should be real (given in float64 format)");
1060  PyErr_SetString(PyExc_Exception, err.c_str());
1061  return NULL;
1062  }
1063 
1064 
1065  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
1066  Matrix_real grad_mtx(parameters_mtx.size(), 1);
1067  double f0;
1068 
1069  try {
1070  self->decomp->optimization_problem_combined(parameters_mtx, &f0, grad_mtx );
1071  }
1072  catch (std::string err ) {
1073  PyErr_SetString(PyExc_Exception, err.c_str());
1074  return NULL;
1075  }
1076  catch (...) {
1077  std::string err( "Invalid pointer to decomposition class");
1078  PyErr_SetString(PyExc_Exception, err.c_str());
1079  return NULL;
1080  }
1081 
1082  // convert to numpy array
1083  grad_mtx.set_owner(false);
1084  PyObject *grad_py = matrix_real_to_numpy( grad_mtx );
1085 
1086  Py_DECREF(parameters_arg);
1087 
1088 
1089  PyObject* p = Py_BuildValue("(dO)", f0, grad_py);
1090  Py_DECREF(grad_py);
1091  return p;
1092 }
1093 
1098 static PyObject *
1100 {
1101 
1102 
1103  PyArrayObject* parameters_arg = NULL;
1104 
1105 
1106  // parsing input arguments
1107  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
1108 
1109  std::string err( "Unsuccessful argument parsing not ");
1110  PyErr_SetString(PyExc_Exception, err.c_str());
1111  return NULL;
1112 
1113  }
1114 
1115  // establish memory contiguous arrays for C calculations
1116  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1117  Py_INCREF(parameters_arg);
1118  }
1119  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
1120  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1121  }
1122  else {
1123  std::string err( "Parameters should be should be real (given in float64 format)");
1124  PyErr_SetString(PyExc_Exception, err.c_str());
1125  return NULL;
1126  }
1127 
1128 
1129  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
1130  Matrix Umtx;
1131  std::vector<Matrix> Umtx_deriv;
1132 
1133  try {
1134  self->decomp->optimization_problem_combined_unitary(parameters_mtx, Umtx, Umtx_deriv );
1135  }
1136  catch (std::string err ) {
1137  PyErr_SetString(PyExc_Exception, err.c_str());
1138  return NULL;
1139  }
1140  catch (...) {
1141  std::string err( "Invalid pointer to decomposition class");
1142  PyErr_SetString(PyExc_Exception, err.c_str());
1143  return NULL;
1144  }
1145 
1146  // convert to numpy array
1147  Umtx.set_owner(false);
1148  PyObject *unitary_py = matrix_to_numpy( Umtx );
1149  PyObject* graduni_py = PyList_New(Umtx_deriv.size());
1150  for (size_t i = 0; i < Umtx_deriv.size(); i++) {
1151  Umtx_deriv[i].set_owner(false);
1152  PyList_SetItem(graduni_py, i, matrix_to_numpy(Umtx_deriv[i]));
1153  }
1154 
1155  Py_DECREF(parameters_arg);
1156 
1157 
1158  PyObject* p = Py_BuildValue("(OO)", unitary_py, graduni_py);
1159  Py_DECREF(unitary_py); Py_DECREF(graduni_py);
1160  return p;
1161 }
1162 
1167 static PyObject *
1169 {
1170 
1171 
1172  PyArrayObject* parameters_arg = NULL;
1173 
1174 
1175  // parsing input arguments
1176  if (!PyArg_ParseTuple(args, "|O", &parameters_arg )) {
1177 
1178  std::string err( "Unsuccessful argument parsing not ");
1179  PyErr_SetString(PyExc_Exception, err.c_str());
1180  return NULL;
1181 
1182  }
1183 
1184  // establish memory contiguous arrays for C calculations
1185  if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1186  Py_INCREF(parameters_arg);
1187  }
1188  else if (PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ) {
1189  parameters_arg = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arg, NPY_FLOAT64, NPY_ARRAY_IN_ARRAY);
1190  }
1191  else {
1192  std::string err( "Parameters should be should be real (given in float64 format)");
1193  PyErr_SetString(PyExc_Exception, err.c_str());
1194  return NULL;
1195  }
1196 
1197 
1198  Matrix_real parameters_mtx = numpy2matrix_real( parameters_arg );
1199  Matrix_real result_mtx;
1200 
1201  try {
1202  std::vector<Matrix_real> parameters_vec;
1203  parameters_vec.resize(parameters_mtx.rows);
1204  for( int row_idx=0; row_idx<parameters_mtx.rows; row_idx++ ) {
1205  parameters_vec[row_idx] = Matrix_real( parameters_mtx.get_data() + row_idx*parameters_mtx.stride, 1, parameters_mtx.cols, parameters_mtx.stride );
1206  }
1207  result_mtx = self->decomp->optimization_problem_batched( parameters_vec );
1208  }
1209  catch (std::string err ) {
1210  PyErr_SetString(PyExc_Exception, err.c_str());
1211  return NULL;
1212  }
1213  catch (...) {
1214  std::string err( "Invalid pointer to decomposition class");
1215  PyErr_SetString(PyExc_Exception, err.c_str());
1216  return NULL;
1217  }
1218 
1219  // convert to numpy array
1220  result_mtx.set_owner(false);
1221  PyObject *result_py = matrix_real_to_numpy( result_mtx );
1222 
1223  Py_DECREF(parameters_arg);
1224 
1225  return result_py;
1226 
1227 }
1228 
1229 static PyObject *
1231 
1232  if ( self->Umtx != NULL ) {
1233  // release the unitary to be decomposed
1234  Py_DECREF(self->Umtx);
1235  self->Umtx = NULL;
1236  }
1237 
1238  PyArrayObject *Umtx_arg = NULL;
1239  //Parse arguments
1240  if (!PyArg_ParseTuple(args, "|O", &Umtx_arg )) return Py_BuildValue("i", -1);
1241 
1242  // convert python object array to numpy C API array
1243  if ( Umtx_arg == NULL ) {
1244  PyErr_SetString(PyExc_Exception, "Umtx argument in empty");
1245  return NULL;
1246  }
1247 
1248  self->Umtx = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)Umtx_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1249 
1250  // test C-style contiguous memory allocation of the array
1251  if ( !PyArray_IS_C_CONTIGUOUS(self->Umtx) ) {
1252  std::cout << "Umtx is not memory contiguous" << std::endl;
1253  }
1254 
1255 
1256  // create QGD version of the Umtx
1257  Matrix Umtx_mtx = numpy2matrix(self->Umtx);
1258  self->decomp->set_unitary(Umtx_mtx);
1259 
1260  return Py_BuildValue("i", 0);
1261 }
1262 
1267 static PyObject *
1269 
1270  // initiate variables for input arguments
1271  PyObject* qbit_list;
1272 
1273  // parsing input arguments
1274  if (!PyArg_ParseTuple(args, "|O", &qbit_list )) return Py_BuildValue("i", -1);
1275 
1276  bool is_tuple = PyTuple_Check(qbit_list);
1277  bool is_list = PyList_Check(qbit_list);
1278 
1279  // Check whether input is dictionary
1280  if (!is_list && !is_tuple) {
1281  printf("Input must be tuple or list!\n");
1282  return Py_BuildValue("i", -1);
1283  }
1284 
1285  // get the number of qbubits
1286  Py_ssize_t element_num;
1287 
1288  if (is_tuple) {
1289  element_num = PyTuple_GET_SIZE(qbit_list);
1290  }
1291  else {
1292  element_num = PyList_GET_SIZE(qbit_list);
1293  }
1294 
1295 
1296  // create C++ variant of the tuple/list
1297  std::vector<int> qbit_list_C( (int) element_num);
1298  for ( Py_ssize_t idx=0; idx<element_num; idx++ ) {
1299  if (is_tuple) {
1300  qbit_list_C[(int) idx] = (int) PyLong_AsLong( PyTuple_GetItem(qbit_list, idx ) );
1301  }
1302  else {
1303  qbit_list_C[(int) idx] = (int) PyLong_AsLong( PyList_GetItem(qbit_list, idx ) );
1304  }
1305 
1306  }
1307 
1308 
1309  // reorder the qubits in the decomposition class
1310  self->decomp->reorder_qubits( qbit_list_C );
1311 
1312 
1313 
1314 
1315  return Py_BuildValue("i", 0);
1316 }
1317 
1318 
1319 
1320 
1321 
1322 
1327 static PyObject *
1329 
1330  PyArrayObject* parameters_arr = NULL;
1331 
1332 
1333  // parsing input arguments
1334  if (!PyArg_ParseTuple(args, "|O", &parameters_arr ))
1335  return Py_BuildValue("i", -1);
1336 
1337 
1338  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1339  Py_INCREF(parameters_arr);
1340  }
1341  else {
1342  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1343  }
1344 
1345 
1346  // get the C++ wrapper around the data
1347  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1348 
1349 
1350  Matrix unitary_mtx;
1351 
1352  unitary_mtx = self->decomp->get_matrix( parameters_mtx );
1353 
1354 
1355  // convert to numpy array
1356  unitary_mtx.set_owner(false);
1357  PyObject *unitary_py = matrix_to_numpy( unitary_mtx );
1358 
1359 
1360  Py_DECREF(parameters_arr);
1361 
1362  return unitary_py;
1363 }
1364 
1365 
1366 
1372 static PyObject *
1374 {
1375 
1376  // The tuple of expected keywords
1377  static char *kwlist[] = {(char*)"optimizer", NULL};
1378 
1379  PyObject* optimizer_arg = NULL;
1380 
1381 
1382  // parsing input arguments
1383  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &optimizer_arg)) {
1384 
1385  std::string err( "Unsuccessful argument parsing not ");
1386  PyErr_SetString(PyExc_Exception, err.c_str());
1387  return NULL;
1388 
1389  }
1390 
1391 
1392  if ( optimizer_arg == NULL ) {
1393  std::string err( "optimizer argument not set");
1394  PyErr_SetString(PyExc_Exception, err.c_str());
1395  return NULL;
1396  }
1397 
1398 
1399 
1400  PyObject* optimizer_string = PyObject_Str(optimizer_arg);
1401  PyObject* optimizer_string_unicode = PyUnicode_AsEncodedString(optimizer_string, "utf-8", "~E~");
1402  const char* optimizer_C = PyBytes_AS_STRING(optimizer_string_unicode);
1403 
1404  optimization_aglorithms qgd_optimizer;
1405  if ( strcmp("bfgs", optimizer_C) == 0 || strcmp("BFGS", optimizer_C) == 0) {
1406  qgd_optimizer = BFGS;
1407  }
1408  else if ( strcmp("adam", optimizer_C)==0 || strcmp("ADAM", optimizer_C)==0) {
1409  qgd_optimizer = ADAM;
1410  }
1411  else if ( strcmp("grad_descend", optimizer_C)==0 || strcmp("GRAD_DESCEND", optimizer_C)==0) {
1412  qgd_optimizer = GRAD_DESCEND;
1413  }
1414  else if ( strcmp("adam_batched", optimizer_C)==0 || strcmp("ADAM_BATCHED", optimizer_C)==0) {
1415  qgd_optimizer = ADAM_BATCHED;
1416  }
1417  else if ( strcmp("bfgs2", optimizer_C)==0 || strcmp("BFGS2", optimizer_C)==0) {
1418  qgd_optimizer = BFGS2;
1419  }
1420  else if ( strcmp("agents", optimizer_C)==0 || strcmp("AGENTS", optimizer_C)==0) {
1421  qgd_optimizer = AGENTS;
1422  }
1423  else if ( strcmp("cosine", optimizer_C)==0 || strcmp("COSINE", optimizer_C)==0) {
1424  qgd_optimizer = COSINE;
1425  }
1426  else if ( strcmp("grad_descend_phase_shift_rule", optimizer_C)==0 || strcmp("GRAD_DESCEND_PARAMETER_SHIFT_RULE", optimizer_C)==0) {
1427  qgd_optimizer = GRAD_DESCEND_PARAMETER_SHIFT_RULE;
1428  }
1429  else if ( strcmp("agents_combined", optimizer_C)==0 || strcmp("AGENTS_COMBINED", optimizer_C)==0) {
1430  qgd_optimizer = AGENTS_COMBINED;
1431  }
1432  else if ( strcmp("bayes_opt", optimizer_C)==0 || strcmp("BAYES_OPT", optimizer_C)==0) {
1433  qgd_optimizer = BAYES_OPT;
1434  }
1435  else {
1436  std::cout << "Wrong optimizer: " << optimizer_C << ". Using default: BFGS" << std::endl;
1437  qgd_optimizer = BFGS;
1438  }
1439 
1440 
1441  try {
1442  self->decomp->set_optimizer(qgd_optimizer);
1443  }
1444  catch (std::string err) {
1445  PyErr_SetString(PyExc_Exception, err.c_str());
1446  std::cout << err << std::endl;
1447  return NULL;
1448  }
1449  catch(...) {
1450  std::string err( "Invalid pointer to decomposition class");
1451  PyErr_SetString(PyExc_Exception, err.c_str());
1452  return NULL;
1453  }
1454 
1455 
1456  return Py_BuildValue("i", 0);
1457 
1458 }
1459 
1460 
1461 
1467 static PyObject *
1469 {
1470 
1471  // The tuple of expected keywords
1472  static char *kwlist[] = {(char*)"costfnc", NULL};
1473 
1474  int costfnc_arg = 0;
1475 
1476 
1477  // parsing input arguments
1478  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &costfnc_arg)) {
1479 
1480  std::string err( "Unsuccessful argument parsing");
1481  PyErr_SetString(PyExc_Exception, err.c_str());
1482  return NULL;
1483 
1484  }
1485 
1486  cost_function_type qgd_costfnc = (cost_function_type)costfnc_arg;
1487 
1488 
1489  try {
1490  self->decomp->set_cost_function_variant(qgd_costfnc);
1491  }
1492  catch (std::string err) {
1493  PyErr_SetString(PyExc_Exception, err.c_str());
1494  std::cout << err << std::endl;
1495  return NULL;
1496  }
1497  catch(...) {
1498  std::string err( "Invalid pointer to decomposition class");
1499  PyErr_SetString(PyExc_Exception, err.c_str());
1500  return NULL;
1501  }
1502 
1503 
1504  return Py_BuildValue("i", 0);
1505 
1506 }
1507 
1508 
1509 
1510 
1511 
1512 
1517 static PyObject *
1519 {
1520 
1521  // The tuple of expected keywords
1522  static char *kwlist[] = {(char*)"trace_offset", NULL};
1523 
1524  int trace_offset_arg = 0;
1525 
1526 
1527  // parsing input arguments
1528  if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &trace_offset_arg)) {
1529 
1530  std::string err( "Unsuccessful argument parsing");
1531  PyErr_SetString(PyExc_Exception, err.c_str());
1532  return NULL;
1533 
1534  }
1535 
1536 
1537  try {
1538  self->decomp->set_trace_offset(trace_offset_arg);
1539  }
1540  catch (std::string err) {
1541  PyErr_SetString(PyExc_Exception, err.c_str());
1542  std::cout << err << std::endl;
1543  return NULL;
1544  }
1545  catch(...) {
1546  std::string err( "Invalid pointer to decomposition class");
1547  PyErr_SetString(PyExc_Exception, err.c_str());
1548  return NULL;
1549  }
1550 
1551 
1552  return Py_BuildValue("i", 0);
1553 
1554 }
1555 
1556 
1557 
1562 static PyObject *
1564 {
1565 
1566  int trace_offset = 0;
1567 
1568  try {
1569  trace_offset = self->decomp->get_trace_offset();
1570  }
1571  catch (std::string err) {
1572  PyErr_SetString(PyExc_Exception, err.c_str());
1573  std::cout << err << std::endl;
1574  return NULL;
1575  }
1576  catch(...) {
1577  std::string err( "Invalid pointer to decomposition class");
1578  PyErr_SetString(PyExc_Exception, err.c_str());
1579  return NULL;
1580  }
1581 
1582 
1583  return Py_BuildValue("i", trace_offset);
1584 
1585 }
1586 
1587 
1588 
1589 
1593 static PyObject *
1595 
1596 #ifdef __DFE__
1597 
1598  try {
1599  self->decomp->upload_Umtx_to_DFE();
1600  }
1601  catch (std::string err) {
1602  PyErr_SetString(PyExc_Exception, err.c_str());
1603  std::cout << err << std::endl;
1604  return NULL;
1605  }
1606  catch(...) {
1607  std::string err( "Invalid pointer to decomposition class");
1608  PyErr_SetString(PyExc_Exception, err.c_str());
1609  return NULL;
1610  }
1611 
1612 #endif
1613 
1614  return Py_BuildValue("i", 0);
1615 
1616 }
1617 
1618 
1619 
1620 
1621 
1622 
1626 static PyObject *
1628 {
1629 
1630 
1631  PyArrayObject * parameters_arr = NULL;
1632  PyArrayObject * input_state_arg = NULL;
1633  PyObject * qubit_list_arg = NULL;
1634 
1635 
1636  // parsing input arguments
1637  if (!PyArg_ParseTuple(args, "|OOO", &parameters_arr, &input_state_arg, &qubit_list_arg ))
1638  return Py_BuildValue("i", -1);
1639 
1640 
1641  if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1642  Py_INCREF(parameters_arr);
1643  }
1644  else {
1645  parameters_arr = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1646  }
1647 
1648  // get the C++ wrapper around the data
1649  Matrix_real&& parameters_mtx = numpy2matrix_real( parameters_arr );
1650 
1651 
1652  // convert python object array to numpy C API array
1653  if ( input_state_arg == NULL ) {
1654  PyErr_SetString(PyExc_Exception, "Input matrix was not given");
1655  return NULL;
1656  }
1657 
1658  PyArrayObject* input_state = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)input_state_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1659 
1660  // test C-style contiguous memory allocation of the array
1661  if ( !PyArray_IS_C_CONTIGUOUS(input_state) ) {
1662  PyErr_SetString(PyExc_Exception, "input mtrix is not memory contiguous");
1663  return NULL;
1664  }
1665 
1666 
1667  // create QGD version of the input matrix
1668  Matrix input_state_mtx = numpy2matrix(input_state);
1669 
1670 
1671  // check input argument qbit_list
1672  if ( qubit_list_arg == NULL || (!PyList_Check( qubit_list_arg )) ) {
1673  PyErr_SetString(PyExc_Exception, "qubit_list should be a list");
1674  return NULL;
1675  }
1676 
1677  Py_ssize_t reduced_qbit_num = PyList_Size( qubit_list_arg );
1678 
1679  matrix_base<int> qbit_list_mtx( (int)reduced_qbit_num, 1);
1680  for ( int idx=0; idx<reduced_qbit_num; idx++ ) {
1681 
1682  PyObject* item = PyList_GET_ITEM( qubit_list_arg, idx );
1683  qbit_list_mtx[idx] = (int) PyLong_AsLong( item );
1684 
1685  }
1686 
1687 
1688  double entropy = -1;
1689 
1690 
1691  try {
1692  entropy = self->decomp->get_second_Renyi_entropy( parameters_mtx, input_state_mtx, qbit_list_mtx );
1693  }
1694  catch (std::string err) {
1695  PyErr_SetString(PyExc_Exception, err.c_str());
1696  std::cout << err << std::endl;
1697  return NULL;
1698  }
1699  catch(...) {
1700  std::string err( "Invalid pointer to decomposition class");
1701  PyErr_SetString(PyExc_Exception, err.c_str());
1702  return NULL;
1703  }
1704 
1705 
1706  Py_DECREF(parameters_arr);
1707  Py_DECREF(input_state);
1708 
1709 
1710 
1711  PyObject* p = Py_BuildValue("d", entropy);
1712 
1713  return p;
1714 }
1715 
1716 
1720 static PyObject *
1722 
1723  int qbit_num = 0;
1724 
1725  try {
1726  qbit_num = self->decomp->get_qbit_num();
1727  }
1728  catch (std::string err) {
1729  PyErr_SetString(PyExc_Exception, err.c_str());
1730  std::cout << err << std::endl;
1731  return NULL;
1732  }
1733  catch(...) {
1734  std::string err( "Invalid pointer to decomposition class");
1735  PyErr_SetString(PyExc_Exception, err.c_str());
1736  return NULL;
1737  }
1738 
1739 
1740  return Py_BuildValue("i", qbit_num );
1741 
1742 }
1743 
1744 
1745 
1750  {NULL} /* Sentinel */
1751 };
1752 
1757  {"Start_Decomposition", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Start_Decomposition, METH_VARARGS | METH_KEYWORDS,
1758  "Method to start the decomposition."
1759  },
1760  {"get_Gate_Num", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_gate_num, METH_NOARGS,
1761  "Method to get the number of decomposing gates."
1762  },
1763  {"get_Parameter_Num", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Parameter_Num, METH_NOARGS,
1764  "Call to get the number of free parameters in the gate structure used for the decomposition"
1765  },
1766  {"get_Optimized_Parameters", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Optimized_Parameters, METH_NOARGS,
1767  "Method to get the array of optimized parameters."
1768  },
1769  {"set_Optimized_Parameters", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimized_Parameters, METH_VARARGS,
1770  "Method to set the initial array of optimized parameters."
1771  },
1772  {"get_Circuit", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_circuit, METH_NOARGS,
1773  "Method to get the incorporated circuit."
1774  },
1775  {"List_Gates", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_List_Gates, METH_NOARGS,
1776  "Call to print the decomposing nitaries on standard output"
1777  },
1778  {"get_Num_of_Iters", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Num_of_Iters, METH_NOARGS,
1779  "Method to get the number of iterations."
1780  },
1781  {"set_Max_Layer_Num", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Max_Layer_Num, METH_VARARGS,
1782  "Call to set the maximal number of layers used in the subdecomposition of the qbit-th qubit."
1783  },
1784  {"set_Iteration_Loops", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Iteration_Loops, METH_VARARGS,
1785  "Call to set the number of iteration loops during the subdecomposition of the qbit-th qubit."
1786  },
1787  {"set_Verbose", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Verbose, METH_VARARGS,
1788  "Call to set the verbosity of the qgd_N_Qubit_Decomposition class."
1789  },
1790  {"set_Debugfile", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Debugfile, METH_VARARGS,
1791  "Set the debugfile name of the N_Qubit_Decomposition class."
1792  },
1793  {"Reorder_Qubits", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Reorder_Qubits, METH_VARARGS,
1794  "Wrapper method to reorder the qubits in the decomposition class."
1795  },
1796  {"set_Optimization_Tolerance", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimization_Tolerance, METH_VARARGS,
1797  "Wrapper method to set the optimization tolerance of the optimization process during the decomposition."
1798  },
1799  {"set_Convergence_Threshold", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Convergence_Threshold, METH_VARARGS,
1800  "Wrapper method to set the threshold of convergence in the optimization processes."
1801  },
1802  {"set_Optimization_Blocks", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimization_Blocks, METH_VARARGS,
1803  "Wrapper method to to set the number of gate blocks to be optimized in one shot."
1804  },
1805  {"set_Unitary", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Unitary, METH_VARARGS,
1806  "Call to set unitary matrix to a numpy matrix"
1807  },
1808  {"export_Unitary", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_export_Unitary, METH_VARARGS,
1809  "Call to export unitary matrix to a binary file"
1810  },
1811  {"get_Project_Name", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Project_Name, METH_NOARGS,
1812  "Call to get the name of SQUANDER project"
1813  },
1814  {"set_Project_Name", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Project_Name, METH_VARARGS,
1815  "Call to set the name of SQUANDER project"
1816  },
1817  {"get_Global_Phase", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Global_Phase, METH_NOARGS,
1818  "Call to get global phase"
1819  },
1820  {"set_Global_Phase", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Global_Phase, METH_VARARGS,
1821  "Call to set global phase"
1822  },
1823  {"apply_Global_Phase_Factor", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_apply_Global_Phase_Factor, METH_NOARGS,
1824  "Call to apply global phase on Unitary matrix"
1825  },
1826  {"get_Unitary", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Unitary, METH_NOARGS,
1827  "Call to get Unitary Matrix"
1828  },
1829  {"set_Optimizer", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimizer, METH_VARARGS | METH_KEYWORDS,
1830  "Wrapper method to to set the optimizer method for the gate synthesis."
1831  },
1832  {"set_Max_Iterations", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Max_Iterations, METH_VARARGS | METH_VARARGS,
1833  "Wrapper method to to set the maximum number of iterations for the gate synthesis."
1834  },
1835  {"get_Matrix", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Matrix, METH_VARARGS,
1836  "Method to retrieve the unitary of the circuit."
1837  },
1838  {"set_Cost_Function_Variant", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Cost_Function_Variant, METH_VARARGS | METH_KEYWORDS,
1839  "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."
1840  },
1841  {"Optimization_Problem", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem, METH_VARARGS,
1842  "Wrapper function to evaluate the cost function."
1843  },
1844  {"Optimization_Problem_Combined_Unitary", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Combined_Unitary, METH_VARARGS,
1845  "Wrapper function to evaluate the unitary function and the gradient components."
1846  },
1847  {"Optimization_Problem_Grad", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Grad, METH_VARARGS,
1848  "Wrapper function to evaluate the gradient components."
1849  },
1850  {"Optimization_Problem_Combined", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Combined, METH_VARARGS,
1851  "Wrapper function to evaluate the cost function and the gradient components."
1852  },
1853  {"Optimization_Problem_Batch", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Batch, METH_VARARGS,
1854  "Wrapper function to evaluate the cost function of batch."
1855  },
1856  {"Upload_Umtx_to_DFE", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Upload_Umtx_to_DFE, METH_NOARGS,
1857  "Call to upload the unitary to the DFE. (Has no effect for non-DFE builds)"
1858  },
1859  {"get_Trace_Offset", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Trace_Offset, METH_NOARGS,
1860  "Call to get the trace offset used in the cost function. In this case Tr(A) = sum_(i-offset=j) A_{ij}"
1861  },
1862  {"set_Trace_Offset", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Trace_Offset, METH_VARARGS | METH_KEYWORDS,
1863  "Call to set the trace offset used in the cost function. In this case Tr(A) = sum_(i-offset=j) A_{ij}"
1864  },
1865  {"get_Decomposition_Error", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Decomposition_Error, METH_NOARGS,
1866  "Call to get the error of the decomposition. (i.e. the final value of the cost function)"
1867  },
1868  {"get_Second_Renyi_Entropy", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Second_Renyi_Entropy, METH_VARARGS,
1869  "Wrapper function to evaluate the second Rényi entropy of a quantum circuit at a specific parameter set."
1870  },
1871  {"get_Qbit_Num", (PyCFunction) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Qbit_Num, METH_NOARGS,
1872  "Call to get the number of qubits in the circuit"
1873  },
1874  {NULL} /* Sentinel */
1875 };
1876 
1881  PyVarObject_HEAD_INIT(NULL, 0)
1882  "qgd_N_Qubit_Decomposition_Tree_Search_Wrapper.qgd_N_Qubit_Decomposition_Tree_Search_Wrapper", /*tp_name*/
1883  sizeof(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper), /*tp_basicsize*/
1884  0, /*tp_itemsize*/
1885  (destructor) qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_dealloc, /*tp_dealloc*/
1886  #if PY_VERSION_HEX < 0x030800b4
1887  0, /*tp_print*/
1888  #endif
1889  #if PY_VERSION_HEX >= 0x030800b4
1890  0, /*tp_vectorcall_offset*/
1891  #endif
1892  0, /*tp_getattr*/
1893  0, /*tp_setattr*/
1894  #if PY_MAJOR_VERSION < 3
1895  0, /*tp_compare*/
1896  #endif
1897  #if PY_MAJOR_VERSION >= 3
1898  0, /*tp_as_async*/
1899  #endif
1900  0, /*tp_repr*/
1901  0, /*tp_as_number*/
1902  0, /*tp_as_sequence*/
1903  0, /*tp_as_mapping*/
1904  0, /*tp_hash*/
1905  0, /*tp_call*/
1906  0, /*tp_str*/
1907  0, /*tp_getattro*/
1908  0, /*tp_setattro*/
1909  0, /*tp_as_buffer*/
1910  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1911  "Object to represent a Circuit class of the QGD package.", /*tp_doc*/
1912  0, /*tp_traverse*/
1913  0, /*tp_clear*/
1914  0, /*tp_richcompare*/
1915  0, /*tp_weaklistoffset*/
1916  0, /*tp_iter*/
1917  0, /*tp_iternext*/
1920  0, /*tp_getset*/
1921  0, /*tp_base*/
1922  0, /*tp_dict*/
1923  0, /*tp_descr_get*/
1924  0, /*tp_descr_set*/
1925  0, /*tp_dictoffset*/
1927  0, /*tp_alloc*/
1929  0, /*tp_free*/
1930  0, /*tp_is_gc*/
1931  0, /*tp_bases*/
1932  0, /*tp_mro*/
1933  0, /*tp_cache*/
1934  0, /*tp_subclasses*/
1935  0, /*tp_weaklist*/
1936  0, /*tp_del*/
1937  0, /*tp_version_tag*/
1938  #if PY_VERSION_HEX >= 0x030400a1
1939  0, /*tp_finalize*/
1940  #endif
1941  #if PY_VERSION_HEX >= 0x030800b1
1942  0, /*tp_vectorcall*/
1943  #endif
1944  #if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
1945  0, /*tp_print*/
1946  #endif
1947 };
1948 
1953  PyModuleDef_HEAD_INIT,
1954  "qgd_N_Qubit_Decomposition_Tree_Search_Wrapper",
1955  "Python binding for QGD N_Qubit_Decomposition class",
1956  -1,
1957 };
1958 
1959 
1963 PyMODINIT_FUNC
1965 {
1966  // initialize Numpy API
1967  import_array();
1968 
1969  PyObject *m;
1970  if (PyType_Ready(&qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Type) < 0)
1971  return NULL;
1972 
1973  m = PyModule_Create(&qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Module);
1974  if (m == NULL)
1975  return NULL;
1976 
1977  Py_INCREF(&qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Type);
1978  if (PyModule_AddObject(m, "qgd_N_Qubit_Decomposition_Tree_Search_Wrapper", (PyObject *) &qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Type) < 0) {
1979  Py_DECREF(&qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Type);
1980  Py_DECREF(m);
1981  return NULL;
1982  }
1983 
1984  return m;
1985 }
1986 
1987 
1988 } //extern C
1989 
Gates_block * get_flat_circuit()
Method to generate a flat circuit.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Convergence_Threshold(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper method to set the threshold of convergence in the optimization processes. ...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Num_of_Iters(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Get the number of free parameters in the gate structure used for the decomposition.
string project_name
Definition: test_Groq.py:98
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Grad(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function an dthe gradient components.
parameter_num
[set adaptive gate structure]
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Global_Phase(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
returns the angle of the global phase (the radius us always sqrt(2))
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_apply_Global_Phase_Factor(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
applies the global phase to the Unitary matrix
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Project_Name(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
get project name
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Trace_Offset(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Wrapper function to get the trace offset used in the cost function.
static void qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_dealloc(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_Tree_Search_Wrapper is de...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Second_Renyi_Entropy(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper function to evaluate the second Rényi entropy of a quantum circuit at a specific parameter s...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimized_Parameters(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Extract the optimized parameters.
Type definition of the qgd_N_Qubit_Decomposition_Tree_Search_Wrapper Python class of the qgd_N_Qubit_...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_gate_num(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Wrapper function to get the number of decomposing gates.
static int qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_init(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_Tree_Search_Wrapper is in...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Batch(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function an dthe gradient components.
int stride
The column stride of the array. (The array elements in one row are a_0, a_1, ... a_{cols-1}, 0, 0, 0, 0. The number of zeros is stride-cols)
Definition: matrix_base.hpp:46
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_export_Unitary(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
export unitary to binary file
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...
Matrix_real numpy2matrix_real(PyArrayObject *arr)
Call to create a PIC matrix_real representation of a numpy array.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimizer(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to set custom gate structure for the decomposition.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Combined_Unitary(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper function to evaluate the unitary function and the unitary derivates.
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.
A class describing a universal configuration element.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimization_Blocks(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper method to to set the number of gate blocks to be optimized in one shot.
scalar * get_data() const
Call to get the pointer to the stored data.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Max_Iterations(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Set the number of maximum iterations.
static PyMemberDef qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_members[]
Structure containing metadata about the members of class qgd_N_Qubit_Decomposition_Tree_Search_Wrappe...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Unitary(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
get Unitary
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_List_Gates(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Lists the gates decomposing the initial unitary.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Parameter_Num(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Get the number of free parameters in the gate structure used for the decomposition.
PyMODINIT_FUNC PyInit_qgd_N_Qubit_Decomposition_Tree_Search_Wrapper(void)
Method called when the Python module is initialized.
optimization_aglorithms
implemented optimization strategies
PyObject_HEAD PyArrayObject * Umtx
pointer to the unitary to be decomposed to keep it alive
int rows
The number of rows.
Definition: matrix_base.hpp:42
int cols
The number of columns.
Definition: matrix_base.hpp:44
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_circuit(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Wrapper function to retrieve the circuit (Squander format) incorporated in the instance.
Umtx
The unitary to be decomposed.
Definition: example.py:53
Header file for a class implementing the adaptive gate decomposition algorithm of arXiv:2203...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Reorder_Qubits(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper method to reorder the qubits in the decomposition class.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Trace_Offset(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to set the trace offset used in the cost function.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Max_Layer_Num(qgd_N_Qubit_Decomposition_Tree_Search_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_Tree_Search_Wrapper_set_Verbose(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Set the verbosity of the N_Qubit_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 PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Optimization_Tolerance(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper method to set the optimization tolerance of the optimization process during the decomposition...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Method called when a python instance of the class qgd_N_Qubit_Decomposition_Tree_Search_Wrapper is al...
Structure type representing complex numbers in the SQUANDER package.
Definition: QGDTypes.h:38
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Unitary(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Start_Decomposition(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to call the start_decomposition method of C++ class N_Qubit_Decomposition.
dictionary config
gate systhesis #####################################
Class to store data of complex arrays and its properties.
Definition: matrix.h:38
N_Qubit_Decomposition_Tree_Search * create_N_Qubit_Decomposition_Tree_Search(Matrix &Umtx, int qbit_num, int level_limit, std::vector< matrix_base< int >> topology_in, std::map< std::string, Config_Element > &config, int accelerator_num)
Constructor of the class.
N_Qubit_Decomposition_Tree_Search * decomp
An object to decompose the unitary.
int size() const
Call to get the number of the allocated elements.
cost_function_type
Type definition of the fifferent types of the cost function.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Qbit_Num(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Call to retrieve the number of qubits in the circuit.
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_Tree_Search_Wrapper_get_Optimized_Parameters(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Extract the optimized parameters.
void set_property(std::string name_, double val_)
Call to set a double value.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Global_Phase(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
sets the global phase to the new angle given
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Debugfile(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Set the debugfile name of the N_Qubit_Decomposition class.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Decomposition_Error(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Cll to get the error of the decomposition (i.e.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Cost_Function_Variant(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args, PyObject *kwds)
Wrapper function to set a variant for the cost function.
Matrix numpy2matrix(PyArrayObject *arr)
Call to create a PIC matrix representation of a numpy array.
static PyModuleDef qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Module
Structure containing metadata about the module.
PyObject_HEAD Gates_block * circuit
Pointer to the C++ class of the base Gate_block module.
Matrix copy()
Call to create a copy of the matrix.
Definition: matrix.cpp:105
double real
the real part of a complex number
Definition: QGDTypes.h:40
static PyTypeObject qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Type
A structure describing the type of the class qgd_N_Qubit_Decomposition_Tree_Search_Wrapper.
void release_N_Qubit_Decomposition_Tree_Search(N_Qubit_Decomposition_Tree_Search *instance)
Call to deallocate an instance of N_Qubit_Decomposition_Tree_Search class.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_get_Matrix(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Retrieve the unified unitary operation of the circuit.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Project_Name(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
set project name
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...
PyObject * matrix_to_numpy(Matrix &mtx)
Call to make a numpy array from an instance of matrix class.
tuple decomposition_error
Definition: example.py:97
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Upload_Umtx_to_DFE(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self)
Call to upload the unitary to the DFE.
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_set_Iteration_Loops(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Set the number of iteration loops during the subdecomposition of the qbit-th qubit.
static PyMethodDef qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_methods[]
Structure containing metadata about the methods of class qgd_N_Qubit_Decomposition_Tree_Search_Wrappe...
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function.
Class to store data of complex arrays and its properties.
Definition: matrix_real.h:39
double imag
the imaginary part of a complex number
Definition: QGDTypes.h:42
static PyObject * qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Optimization_Problem_Combined(qgd_N_Qubit_Decomposition_Tree_Search_Wrapper *self, PyObject *args)
Wrapper function to evaluate the cost function an dthe gradient components.