27 #define PY_SSIZE_T_CLEAN 31 #include <numpy/arrayobject.h> 32 #include "structmember.h" 92 if (instance != NULL ) {
115 if ( self->decomp != NULL ) {
122 if ( self->Umtx != NULL ) {
124 Py_DECREF(self->Umtx);
128 Py_TYPE(
self)->tp_free((PyObject *)
self);
148 return (PyObject *)
self;
162 static char *kwlist[] = {(
char*)
"Umtx", (
char*)
"qbit_num", (
char*)
"method", (
char*)
"topology", (
char*)
"config", (
char*)
"accelerator_num", NULL};
165 PyArrayObject *Umtx_arg = NULL;
166 PyObject *config_arg = NULL;
170 int accelerator_num = 0;
173 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|OiiOOi", kwlist,
174 &Umtx_arg, &qbit_num, &level_limit, &topology, &config_arg, &accelerator_num))
178 if ( Umtx_arg == NULL )
return -1;
179 self->Umtx = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*) Umtx_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
182 if ( !PyArray_IS_C_CONTIGUOUS(self->Umtx) ) {
183 std::cout <<
"Umtx is not memory contiguous" << std::endl;
191 bool is_None = topology == Py_None;
192 bool is_list = PyList_Check(topology);
195 if (!is_list && !is_None) {
196 printf(
"Input topology must be a list!\n");
201 std::vector<matrix_base<int>> topology_Cpp;
206 Py_ssize_t element_num = PyList_GET_SIZE(topology);
208 for ( Py_ssize_t idx=0; idx<element_num; idx++ ) {
209 PyObject *item = PyList_GetItem(topology, idx );
212 if (!PyTuple_Check(item)) {
213 printf(
"Elements of topology must be a tuple!\n");
218 item_Cpp[0] = (
int) PyLong_AsLong( PyTuple_GetItem(item, 0 ) );
219 item_Cpp[1] = (
int) PyLong_AsLong( PyTuple_GetItem(item, 1 ) );
221 topology_Cpp.push_back( item_Cpp );
228 bool is_dict = PyDict_Check( config_arg );
230 printf(
"Config object must be a python dictionary!\n");
235 std::map<std::string, Config_Element>
config;
239 PyObject *key, *value;
242 while (PyDict_Next(config_arg, &pos, &key, &value)) {
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);
249 std::string key_Cpp( key_C );
252 if ( PyLong_Check( value ) ) {
253 element.
set_property( key_Cpp, PyLong_AsLongLong( value ) );
254 config[ key_Cpp ] = element;
256 else if ( PyFloat_Check( value ) ) {
257 element.
set_property( key_Cpp, PyFloat_AsDouble( value ) );
258 config[ key_Cpp ] = element;
272 catch (std::string err ) {
273 PyErr_SetString(PyExc_Exception, err.c_str());
278 std::cout <<
"The number of qubits should be given as a positive integer, " << qbit_num <<
" was given" << std::endl;
298 static char *kwlist[] = {NULL};
302 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|", kwlist))
303 return Py_BuildValue(
"i", -1);
307 self->decomp->start_decomposition();
309 catch (std::string err) {
310 PyErr_SetString(PyExc_Exception, err.c_str());
311 std::cout << err << std::endl;
315 std::string err(
"Invalid pointer to decomposition class");
316 PyErr_SetString(PyExc_Exception, err.c_str());
322 return Py_BuildValue(
"i", 0);
336 int ret =
self->decomp->get_gate_num();
339 return Py_BuildValue(
"i", ret);
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));
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);
373 return Py_BuildValue(
"i", 0);
384 self->decomp->apply_global_phase_factor();
386 return Py_BuildValue(
"i", 0);
399 PyObject* qgd_Circuit = PyImport_ImportModule(
"squander.gates.qgd_Circuit");
401 if ( qgd_Circuit == NULL ) {
402 PyErr_SetString(PyExc_Exception,
"Module import error: squander.gates.qgd_Circuit" );
412 PyObject* qgd_circuit_Dict = PyModule_GetDict( qgd_Circuit );
415 PyObject* py_circuit_class = PyDict_GetItemString( qgd_circuit_Dict,
"qgd_Circuit");
419 PyObject* circuit_input = Py_BuildValue(
"(O)", qbit_num);
421 PyObject* py_circuit = PyObject_CallObject(py_circuit_class, circuit_input);
427 delete( py_circuit_C->
gate );
443 self->decomp->list_gates( 0 );
461 self->decomp->get_optimized_parameters(parameters);
467 return parameter_arr;
482 return Py_BuildValue(
"i", parameter_num);
491 int number_of_iters =
self->decomp->get_num_iters();
493 return Py_BuildValue(
"i", number_of_iters);
504 PyArrayObject* parameters_arr = NULL;
508 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arr ))
509 return Py_BuildValue(
"i", -1);
512 if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
513 Py_INCREF(parameters_arr);
516 parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
523 self->decomp->set_optimized_parameters(parameters_mtx.
get_data(), parameters_mtx.
size());
525 catch (std::string err ) {
526 PyErr_SetString(PyExc_Exception, err.c_str());
530 std::string err(
"Invalid pointer to decomposition class");
531 PyErr_SetString(PyExc_Exception, err.c_str());
537 Py_DECREF(parameters_arr);
539 return Py_BuildValue(
"i", 0);
554 PyObject* max_layer_num;
557 if (!PyArg_ParseTuple(args,
"|O", &max_layer_num ))
return Py_BuildValue(
"i", -1);
560 if (!PyDict_Check(max_layer_num)) {
561 printf(
"Input must be dictionary!\n");
562 return Py_BuildValue(
"i", -1);
566 PyObject* key = NULL;
567 PyObject* value = NULL;
571 while (PyDict_Next(max_layer_num, &pos, &key, &value)) {
574 assert(PyLong_Check(value) == 1);
575 int value_int = (
int) PyLong_AsLong(value);
578 assert(PyLong_Check(key) == 1);
579 int key_int = (
int) PyLong_AsLong(key);
582 self->decomp->set_max_layer_num( key_int, value_int );
586 return Py_BuildValue(
"i", 0);
604 PyObject* iteration_loops;
607 if (!PyArg_ParseTuple(args,
"|O", &iteration_loops ))
return Py_BuildValue(
"i", -1);
610 if (!PyDict_Check(iteration_loops)) {
611 printf(
"Input must be dictionary!\n");
612 return Py_BuildValue(
"i", -1);
616 PyObject* key = NULL;
617 PyObject* value = NULL;
621 while (PyDict_Next(iteration_loops, &pos, &key, &value)) {
624 assert(PyLong_Check(value) == 1);
625 int value_int = (
int) PyLong_AsLong(value);
628 assert(PyLong_Check(key) == 1);
629 int key_int = (
int) PyLong_AsLong(key);
632 self->decomp->set_iteration_loops( key_int, value_int );
636 return Py_BuildValue(
"i", 0);
651 if (!PyArg_ParseTuple(args,
"|i", &max_iters_input ))
return Py_BuildValue(
"i", -1);
655 self->decomp->set_max_inner_iterations(max_iters_input);
658 return Py_BuildValue(
"i", 0);
674 if (!PyArg_ParseTuple(args,
"|i", &verbose ))
return Py_BuildValue(
"i", -1);
678 self->decomp->set_verbose( verbose );
681 return Py_BuildValue(
"i", 0);
695 PyObject *debugfile = NULL;
698 if (!PyArg_ParseTuple(args,
"|O", &debugfile ))
return Py_BuildValue(
"s", -1);
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);
706 Py_XDECREF(debugfile_string);
707 Py_XDECREF(debugfile_string_unicode);
710 Py_ssize_t string_length = PyBytes_Size(debugfile_string_unicode);
711 std::string debugfile_Cpp(debugfile_C, string_length);
714 self->decomp->set_debugfile( debugfile_Cpp );
717 return Py_BuildValue(
"s", NULL);
735 if (!PyArg_ParseTuple(args,
"|d", &tolerance ))
return Py_BuildValue(
"i", -1);
739 self->decomp->set_optimization_tolerance( tolerance );
742 return Py_BuildValue(
"i", 0);
760 if (!PyArg_ParseTuple(args,
"|d", &threshold ))
return Py_BuildValue(
"i", -1);
764 self->decomp->set_convergence_threshold( threshold );
766 return Py_BuildValue(
"i", 0);
780 double optimization_block;
783 if (!PyArg_ParseTuple(args,
"|d", &optimization_block ))
return Py_BuildValue(
"i", -1);
787 self->decomp->set_optimization_blocks( optimization_block );
790 return Py_BuildValue(
"i", 0);
805 std::string
project_name =
self->decomp->get_project_name();
808 PyObject* project_name_pyhton = PyUnicode_FromString(project_name.c_str());
810 return project_name_pyhton;
823 PyObject* project_name_new=NULL;
826 if (!PyArg_ParseTuple(args,
"|O", &project_name_new))
return Py_BuildValue(
"i", -1);
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 );
835 self->decomp->set_project_name(project_name_new_str);
837 return Py_BuildValue(
"i", 0);
852 return Py_BuildValue(
"d", decomposition_error);
865 if (!PyArg_ParseTuple(args,
"|O", &filename))
return Py_BuildValue(
"i", -1);
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 );
874 self->decomp->export_unitary(filename_str);
876 return Py_BuildValue(
"i", 0);
890 Unitary_mtx =
self->decomp->get_Umtx().
copy();
892 catch (std::string err ) {
893 PyErr_SetString(PyExc_Exception, err.c_str());
897 std::string err(
"Invalid pointer to decomposition class");
898 PyErr_SetString(PyExc_Exception, err.c_str());
920 PyArrayObject* parameters_arg = NULL;
924 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arg )) {
926 std::string err(
"Unsuccessful argument parsing not ");
927 PyErr_SetString(PyExc_Exception, err.c_str());
933 if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
934 Py_INCREF(parameters_arg);
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);
940 std::string err(
"Parameters should be should be real (given in float64 format)");
941 PyErr_SetString(PyExc_Exception, err.c_str());
950 f0 =
self->decomp->optimization_problem(parameters_mtx );
952 catch (std::string err ) {
953 PyErr_SetString(PyExc_Exception, err.c_str());
957 std::string err(
"Invalid pointer to decomposition class");
958 PyErr_SetString(PyExc_Exception, err.c_str());
962 Py_DECREF(parameters_arg);
965 return Py_BuildValue(
"d", f0);
978 PyArrayObject* parameters_arg = NULL;
982 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arg )) {
984 std::string err(
"Unsuccessful argument parsing not ");
985 PyErr_SetString(PyExc_Exception, err.c_str());
991 if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
992 Py_INCREF(parameters_arg);
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);
998 std::string err(
"Parameters should be should be real (given in float64 format)");
999 PyErr_SetString(PyExc_Exception, err.c_str());
1008 self->decomp->optimization_problem_grad(parameters_mtx, self->decomp, grad_mtx );
1010 catch (std::string err ) {
1011 PyErr_SetString(PyExc_Exception, err.c_str());
1015 std::string err(
"Invalid pointer to decomposition class");
1016 PyErr_SetString(PyExc_Exception, err.c_str());
1021 grad_mtx.set_owner(
false);
1024 Py_DECREF(parameters_arg);
1039 PyArrayObject* parameters_arg = NULL;
1043 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arg )) {
1045 std::string err(
"Unsuccessful argument parsing not ");
1046 PyErr_SetString(PyExc_Exception, err.c_str());
1052 if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1053 Py_INCREF(parameters_arg);
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);
1059 std::string err(
"Parameters should be should be real (given in float64 format)");
1060 PyErr_SetString(PyExc_Exception, err.c_str());
1070 self->decomp->optimization_problem_combined(parameters_mtx, &f0, grad_mtx );
1072 catch (std::string err ) {
1073 PyErr_SetString(PyExc_Exception, err.c_str());
1077 std::string err(
"Invalid pointer to decomposition class");
1078 PyErr_SetString(PyExc_Exception, err.c_str());
1083 grad_mtx.set_owner(
false);
1086 Py_DECREF(parameters_arg);
1089 PyObject* p = Py_BuildValue(
"(dO)", f0, grad_py);
1103 PyArrayObject* parameters_arg = NULL;
1107 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arg )) {
1109 std::string err(
"Unsuccessful argument parsing not ");
1110 PyErr_SetString(PyExc_Exception, err.c_str());
1116 if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1117 Py_INCREF(parameters_arg);
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);
1123 std::string err(
"Parameters should be should be real (given in float64 format)");
1124 PyErr_SetString(PyExc_Exception, err.c_str());
1131 std::vector<Matrix> Umtx_deriv;
1134 self->decomp->optimization_problem_combined_unitary(parameters_mtx, Umtx, Umtx_deriv );
1136 catch (std::string err ) {
1137 PyErr_SetString(PyExc_Exception, err.c_str());
1141 std::string err(
"Invalid pointer to decomposition class");
1142 PyErr_SetString(PyExc_Exception, err.c_str());
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);
1155 Py_DECREF(parameters_arg);
1158 PyObject* p = Py_BuildValue(
"(OO)", unitary_py, graduni_py);
1159 Py_DECREF(unitary_py); Py_DECREF(graduni_py);
1172 PyArrayObject* parameters_arg = NULL;
1176 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arg )) {
1178 std::string err(
"Unsuccessful argument parsing not ");
1179 PyErr_SetString(PyExc_Exception, err.c_str());
1185 if ( PyArray_IS_C_CONTIGUOUS(parameters_arg) && PyArray_TYPE(parameters_arg) == NPY_FLOAT64 ){
1186 Py_INCREF(parameters_arg);
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);
1192 std::string err(
"Parameters should be should be real (given in float64 format)");
1193 PyErr_SetString(PyExc_Exception, err.c_str());
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++ ) {
1207 result_mtx =
self->decomp->optimization_problem_batched( parameters_vec );
1209 catch (std::string err ) {
1210 PyErr_SetString(PyExc_Exception, err.c_str());
1214 std::string err(
"Invalid pointer to decomposition class");
1215 PyErr_SetString(PyExc_Exception, err.c_str());
1223 Py_DECREF(parameters_arg);
1232 if ( self->Umtx != NULL ) {
1234 Py_DECREF(self->Umtx);
1238 PyArrayObject *Umtx_arg = NULL;
1240 if (!PyArg_ParseTuple(args,
"|O", &Umtx_arg ))
return Py_BuildValue(
"i", -1);
1243 if ( Umtx_arg == NULL ) {
1244 PyErr_SetString(PyExc_Exception,
"Umtx argument in empty");
1248 self->Umtx = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)Umtx_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1251 if ( !PyArray_IS_C_CONTIGUOUS(self->Umtx) ) {
1252 std::cout <<
"Umtx is not memory contiguous" << std::endl;
1258 self->decomp->set_unitary(Umtx_mtx);
1260 return Py_BuildValue(
"i", 0);
1271 PyObject* qbit_list;
1274 if (!PyArg_ParseTuple(args,
"|O", &qbit_list ))
return Py_BuildValue(
"i", -1);
1276 bool is_tuple = PyTuple_Check(qbit_list);
1277 bool is_list = PyList_Check(qbit_list);
1280 if (!is_list && !is_tuple) {
1281 printf(
"Input must be tuple or list!\n");
1282 return Py_BuildValue(
"i", -1);
1286 Py_ssize_t element_num;
1289 element_num = PyTuple_GET_SIZE(qbit_list);
1292 element_num = PyList_GET_SIZE(qbit_list);
1297 std::vector<int> qbit_list_C( (
int) element_num);
1298 for ( Py_ssize_t idx=0; idx<element_num; idx++ ) {
1300 qbit_list_C[(
int) idx] = (
int) PyLong_AsLong( PyTuple_GetItem(qbit_list, idx ) );
1303 qbit_list_C[(
int) idx] = (
int) PyLong_AsLong( PyList_GetItem(qbit_list, idx ) );
1310 self->decomp->reorder_qubits( qbit_list_C );
1315 return Py_BuildValue(
"i", 0);
1330 PyArrayObject* parameters_arr = NULL;
1334 if (!PyArg_ParseTuple(args,
"|O", ¶meters_arr ))
1335 return Py_BuildValue(
"i", -1);
1338 if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1339 Py_INCREF(parameters_arr);
1342 parameters_arr = (PyArrayObject*)PyArray_FROM_OTF( (PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1352 unitary_mtx =
self->decomp->get_matrix( parameters_mtx );
1360 Py_DECREF(parameters_arr);
1377 static char *kwlist[] = {(
char*)
"optimizer", NULL};
1379 PyObject* optimizer_arg = NULL;
1383 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|O", kwlist, &optimizer_arg)) {
1385 std::string err(
"Unsuccessful argument parsing not ");
1386 PyErr_SetString(PyExc_Exception, err.c_str());
1392 if ( optimizer_arg == NULL ) {
1393 std::string err(
"optimizer argument not set");
1394 PyErr_SetString(PyExc_Exception, err.c_str());
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);
1405 if ( strcmp(
"bfgs", optimizer_C) == 0 || strcmp(
"BFGS", optimizer_C) == 0) {
1406 qgd_optimizer =
BFGS;
1408 else if ( strcmp(
"adam", optimizer_C)==0 || strcmp(
"ADAM", optimizer_C)==0) {
1409 qgd_optimizer =
ADAM;
1411 else if ( strcmp(
"grad_descend", optimizer_C)==0 || strcmp(
"GRAD_DESCEND", optimizer_C)==0) {
1414 else if ( strcmp(
"adam_batched", optimizer_C)==0 || strcmp(
"ADAM_BATCHED", optimizer_C)==0) {
1417 else if ( strcmp(
"bfgs2", optimizer_C)==0 || strcmp(
"BFGS2", optimizer_C)==0) {
1418 qgd_optimizer =
BFGS2;
1420 else if ( strcmp(
"agents", optimizer_C)==0 || strcmp(
"AGENTS", optimizer_C)==0) {
1423 else if ( strcmp(
"cosine", optimizer_C)==0 || strcmp(
"COSINE", optimizer_C)==0) {
1426 else if ( strcmp(
"grad_descend_phase_shift_rule", optimizer_C)==0 || strcmp(
"GRAD_DESCEND_PARAMETER_SHIFT_RULE", optimizer_C)==0) {
1429 else if ( strcmp(
"agents_combined", optimizer_C)==0 || strcmp(
"AGENTS_COMBINED", optimizer_C)==0) {
1432 else if ( strcmp(
"bayes_opt", optimizer_C)==0 || strcmp(
"BAYES_OPT", optimizer_C)==0) {
1436 std::cout <<
"Wrong optimizer: " << optimizer_C <<
". Using default: BFGS" << std::endl;
1437 qgd_optimizer =
BFGS;
1442 self->decomp->set_optimizer(qgd_optimizer);
1444 catch (std::string err) {
1445 PyErr_SetString(PyExc_Exception, err.c_str());
1446 std::cout << err << std::endl;
1450 std::string err(
"Invalid pointer to decomposition class");
1451 PyErr_SetString(PyExc_Exception, err.c_str());
1456 return Py_BuildValue(
"i", 0);
1472 static char *kwlist[] = {(
char*)
"costfnc", NULL};
1474 int costfnc_arg = 0;
1478 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|i", kwlist, &costfnc_arg)) {
1480 std::string err(
"Unsuccessful argument parsing");
1481 PyErr_SetString(PyExc_Exception, err.c_str());
1490 self->decomp->set_cost_function_variant(qgd_costfnc);
1492 catch (std::string err) {
1493 PyErr_SetString(PyExc_Exception, err.c_str());
1494 std::cout << err << std::endl;
1498 std::string err(
"Invalid pointer to decomposition class");
1499 PyErr_SetString(PyExc_Exception, err.c_str());
1504 return Py_BuildValue(
"i", 0);
1522 static char *kwlist[] = {(
char*)
"trace_offset", NULL};
1524 int trace_offset_arg = 0;
1528 if (!PyArg_ParseTupleAndKeywords(args, kwds,
"|i", kwlist, &trace_offset_arg)) {
1530 std::string err(
"Unsuccessful argument parsing");
1531 PyErr_SetString(PyExc_Exception, err.c_str());
1538 self->decomp->set_trace_offset(trace_offset_arg);
1540 catch (std::string err) {
1541 PyErr_SetString(PyExc_Exception, err.c_str());
1542 std::cout << err << std::endl;
1546 std::string err(
"Invalid pointer to decomposition class");
1547 PyErr_SetString(PyExc_Exception, err.c_str());
1552 return Py_BuildValue(
"i", 0);
1566 int trace_offset = 0;
1569 trace_offset =
self->decomp->get_trace_offset();
1571 catch (std::string err) {
1572 PyErr_SetString(PyExc_Exception, err.c_str());
1573 std::cout << err << std::endl;
1577 std::string err(
"Invalid pointer to decomposition class");
1578 PyErr_SetString(PyExc_Exception, err.c_str());
1583 return Py_BuildValue(
"i", trace_offset);
1599 self->decomp->upload_Umtx_to_DFE();
1601 catch (std::string err) {
1602 PyErr_SetString(PyExc_Exception, err.c_str());
1603 std::cout << err << std::endl;
1607 std::string err(
"Invalid pointer to decomposition class");
1608 PyErr_SetString(PyExc_Exception, err.c_str());
1614 return Py_BuildValue(
"i", 0);
1631 PyArrayObject * parameters_arr = NULL;
1632 PyArrayObject * input_state_arg = NULL;
1633 PyObject * qubit_list_arg = NULL;
1637 if (!PyArg_ParseTuple(args,
"|OOO", ¶meters_arr, &input_state_arg, &qubit_list_arg ))
1638 return Py_BuildValue(
"i", -1);
1641 if ( PyArray_IS_C_CONTIGUOUS(parameters_arr) ) {
1642 Py_INCREF(parameters_arr);
1645 parameters_arr = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)parameters_arr, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY);
1653 if ( input_state_arg == NULL ) {
1654 PyErr_SetString(PyExc_Exception,
"Input matrix was not given");
1658 PyArrayObject* input_state = (PyArrayObject*)PyArray_FROM_OTF((PyObject*)input_state_arg, NPY_COMPLEX128, NPY_ARRAY_IN_ARRAY);
1661 if ( !PyArray_IS_C_CONTIGUOUS(input_state) ) {
1662 PyErr_SetString(PyExc_Exception,
"input mtrix is not memory contiguous");
1672 if ( qubit_list_arg == NULL || (!PyList_Check( qubit_list_arg )) ) {
1673 PyErr_SetString(PyExc_Exception,
"qubit_list should be a list");
1677 Py_ssize_t reduced_qbit_num = PyList_Size( qubit_list_arg );
1680 for (
int idx=0; idx<reduced_qbit_num; idx++ ) {
1682 PyObject* item = PyList_GET_ITEM( qubit_list_arg, idx );
1683 qbit_list_mtx[idx] = (
int) PyLong_AsLong( item );
1692 entropy =
self->decomp->get_second_Renyi_entropy( parameters_mtx, input_state_mtx, qbit_list_mtx );
1694 catch (std::string err) {
1695 PyErr_SetString(PyExc_Exception, err.c_str());
1696 std::cout << err << std::endl;
1700 std::string err(
"Invalid pointer to decomposition class");
1701 PyErr_SetString(PyExc_Exception, err.c_str());
1706 Py_DECREF(parameters_arr);
1707 Py_DECREF(input_state);
1711 PyObject* p = Py_BuildValue(
"d", entropy);
1726 qbit_num =
self->decomp->get_qbit_num();
1728 catch (std::string err) {
1729 PyErr_SetString(PyExc_Exception, err.c_str());
1730 std::cout << err << std::endl;
1734 std::string err(
"Invalid pointer to decomposition class");
1735 PyErr_SetString(PyExc_Exception, err.c_str());
1740 return Py_BuildValue(
"i", qbit_num );
1758 "Method to start the decomposition." 1761 "Method to get the number of decomposing gates." 1764 "Call to get the number of free parameters in the gate structure used for the decomposition" 1767 "Method to get the array of optimized parameters." 1770 "Method to set the initial array of optimized parameters." 1773 "Method to get the incorporated circuit." 1776 "Call to print the decomposing nitaries on standard output" 1779 "Method to get the number of iterations." 1782 "Call to set the maximal number of layers used in the subdecomposition of the qbit-th qubit." 1785 "Call to set the number of iteration loops during the subdecomposition of the qbit-th qubit." 1788 "Call to set the verbosity of the qgd_N_Qubit_Decomposition class." 1791 "Set the debugfile name of the N_Qubit_Decomposition class." 1794 "Wrapper method to reorder the qubits in the decomposition class." 1797 "Wrapper method to set the optimization tolerance of the optimization process during the decomposition." 1800 "Wrapper method to set the threshold of convergence in the optimization processes." 1803 "Wrapper method to to set the number of gate blocks to be optimized in one shot." 1806 "Call to set unitary matrix to a numpy matrix" 1809 "Call to export unitary matrix to a binary file" 1812 "Call to get the name of SQUANDER project" 1815 "Call to set the name of SQUANDER project" 1818 "Call to get global phase" 1821 "Call to set global phase" 1824 "Call to apply global phase on Unitary matrix" 1827 "Call to get Unitary Matrix" 1830 "Wrapper method to to set the optimizer method for the gate synthesis." 1833 "Wrapper method to to set the maximum number of iterations for the gate synthesis." 1836 "Method to retrieve the unitary of the circuit." 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." 1842 "Wrapper function to evaluate the cost function." 1845 "Wrapper function to evaluate the unitary function and the gradient components." 1848 "Wrapper function to evaluate the gradient components." 1851 "Wrapper function to evaluate the cost function and the gradient components." 1854 "Wrapper function to evaluate the cost function of batch." 1857 "Call to upload the unitary to the DFE. (Has no effect for non-DFE builds)" 1860 "Call to get the trace offset used in the cost function. In this case Tr(A) = sum_(i-offset=j) A_{ij}" 1863 "Call to set the trace offset used in the cost function. In this case Tr(A) = sum_(i-offset=j) A_{ij}" 1866 "Call to get the error of the decomposition. (i.e. the final value of the cost function)" 1869 "Wrapper function to evaluate the second Rényi entropy of a quantum circuit at a specific parameter set." 1872 "Call to get the number of qubits in the circuit" 1881 PyVarObject_HEAD_INIT(NULL, 0)
1882 "qgd_N_Qubit_Decomposition_Tree_Search_Wrapper.qgd_N_Qubit_Decomposition_Tree_Search_Wrapper",
1886 #if PY_VERSION_HEX < 0x030800b4 1889 #if PY_VERSION_HEX >= 0x030800b4 1894 #if PY_MAJOR_VERSION < 3 1897 #if PY_MAJOR_VERSION >= 3 1910 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1911 "Object to represent a Circuit class of the QGD package.",
1938 #
if PY_VERSION_HEX >= 0x030400a1
1941 #
if PY_VERSION_HEX >= 0x030800b1
1944 #
if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000
1953 PyModuleDef_HEAD_INIT,
1954 "qgd_N_Qubit_Decomposition_Tree_Search_Wrapper",
1955 "Python binding for QGD N_Qubit_Decomposition class",
1970 if (PyType_Ready(&qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Type) < 0)
1973 m = PyModule_Create(&qgd_N_Qubit_Decomposition_Tree_Search_Wrapper_Module);
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);
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.
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)
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.
int cols
The number of columns.
PyObject_HEAD Gates_block * gate
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.
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.
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.
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.
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.
double real
the real part of a complex number
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.
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
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.
double imag
the imaginary part of a complex number
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.