151 optimized_parameters_tmp[idx] = finalizing_parameters[idx];
159 finalizing_parameters = NULL;
161 optimized_parameters_tmp = NULL;
211 double Theta, Lambda, Phi;
228 Theta = 2*acos( cos_theta_2 );
230 if ( sqrt(element00.
real*element00.
real + element00.
imag*element00.
imag) < 1e-7 ) {
231 Phi = atan2(element10.
imag, element10.
real);
232 Lambda = atan2(-element01.
imag, -element01.
real);
234 else if ( sqrt(element10.
real*element10.
real + element10.
imag*element10.
imag) < 1e-7 ) {
243 double parameters_loc[3];
244 parameters_loc[0] = Theta;
245 parameters_loc[1] = M_PI-Lambda;
246 parameters_loc[2] = M_PI-Phi;
251 finalizing_parameters[parameter_idx] = M_PI-Phi;
253 finalizing_parameters[parameter_idx] = M_PI-Lambda;
255 finalizing_parameters[parameter_idx] = Theta;
291 int min_vec_num = 20;
292 double minimum_vec[min_vec_num];
293 for (
int idx=0; idx<min_vec_num; idx++) {
294 minimum_vec[idx] = 0;
301 std::vector<Operation*> operations_loc =
operations;
318 gsl_vector* optimized_parameters_gsl = gsl_vector_alloc (parameter_num_loc);
322 for(
unsigned int idx = 0; idx <
parameter_num-solution_guess_num; idx++) {
323 optimized_parameters_gsl->data[idx] = 0;
327 for(
unsigned int idx = 0; idx <
parameter_num-solution_guess_num; idx++) {
328 optimized_parameters_gsl->data[idx] = (2*double(rand())/double(RAND_MAX)-1)*2*M_PI;
332 for(
unsigned int idx = 0; idx <
parameter_num-solution_guess_num; idx++) {
333 optimized_parameters_gsl->data[idx] = (2*double(rand())/double(RAND_MAX)-1)*2*M_PI/100;
337 printf(
"bad value for initial guess\n");
341 if ( solution_guess_num > 0) {
342 memcpy(optimized_parameters_gsl->data +
parameter_num-solution_guess_num, solution_guess, solution_guess_num*
sizeof(
double));
346 int pre_operation_parameter_num = 0;
350 unsigned int block_idx_start =
operations.size();
352 int block_parameter_num;
353 Matrix operations_mtx_pre;
355 std::vector<Matrix, tbb::cache_aligned_allocator<Matrix>> operations_mtxs_post;
361 gsl_vector *solution_guess_gsl = NULL;
365 clock_t start_time = time(NULL);
374 if (block_idx_end < 0) {
379 block_parameter_num = 0;
380 for (
int block_idx=block_idx_start-1; block_idx>=block_idx_end; block_idx--) {
381 block_parameter_num = block_parameter_num + operations_loc[block_idx]->get_parameter_num();
385 if (block_idx_start < operations_loc.size() ) {
386 std::vector<Operation*>::iterator fixed_operations_pre_it =
operations.begin() + 1;
388 operations_mtx_pre = tmp;
391 operations_mtx_pre = Identity.
copy();
408 if (block_idx_start == operations_loc.size() ) {
410 double* fixed_parameters_post = optimized_parameters_gsl->data;
411 std::vector<Operation*>::iterator fixed_operations_post_it = operations_loc.begin();
413 operations_mtxs_post =
get_operation_products(fixed_parameters_post, fixed_operations_post_it, block_idx_end);
417 if (block_idx_end > 0) {
418 fixed_operation_post->
set_matrix( operations_mtxs_post[block_idx_end-1] );
422 operations_mtxs_post.clear();
428 for (
unsigned int idx=block_idx_end; idx<block_idx_start; idx++ ) {
435 if ( solution_guess_gsl == NULL ) {
439 gsl_vector_free(solution_guess_gsl);
442 memcpy( solution_guess_gsl->data, optimized_parameters_gsl->data+parameter_num_loc - pre_operation_parameter_num - block_parameter_num,
parameter_num*
sizeof(
double) );
448 double minvec_mean = 0;
449 for (
int idx=min_vec_num-1; idx>0; idx--) {
450 minimum_vec[idx] = minimum_vec[idx-1];
451 minvec_mean = minvec_mean + minimum_vec[idx-1];
455 minvec_mean = minvec_mean/min_vec_num;
458 memcpy( optimized_parameters_gsl->data+parameter_num_loc - pre_operation_parameter_num-block_parameter_num,
optimized_parameters,
parameter_num*
sizeof(
double) );
460 if (block_idx_end == 0) {
461 block_idx_start = operations_loc.size();
462 pre_operation_parameter_num = 0;
466 pre_operation_parameter_num = pre_operation_parameter_num + block_parameter_num;
471 if (iter_idx % 500 == 0) {
473 printf(
"The minimum with %d layers after %d iterations is %e calculated in %f seconds\n",
layer_num, iter_idx,
current_minimum,
float(time(NULL) - start_time));
476 start_time = time(NULL);
481 double minvec_std = sqrt(gsl_stats_variance_m( minimum_vec, 1, min_vec_num, minvec_mean));
486 printf(
"The iterations converged to minimum %e after %d iterations with %d layers\n",
current_minimum, iter_idx,
layer_num );
504 printf(
"Reached maximal number of iterations\n\n");
525 gsl_vector_free(optimized_parameters_gsl);
526 gsl_vector_free(solution_guess_gsl);
527 optimized_parameters_gsl = NULL;
528 solution_guess_gsl = NULL;
530 delete(fixed_operation_post);
637 if (num_of_operations==0) {
638 return initial_matrix.
copy();
647 for (
int idx=0; idx<num_of_operations; idx++) {
656 CNOT* cnot_operation = static_cast<CNOT*>( operation );
663 U3* u3_operation = static_cast<U3*>( operation );
665 operation_mtx = u3_operation->
get_matrix( parameters );
666 parameters = parameters + parameters_num;
669 Operation_block* block_operation = static_cast<Operation_block*>( operation );
671 operation_mtx = block_operation->
get_matrix( parameters );
672 parameters = parameters + parameters_num;
676 Operation_product = operation_mtx;
679 ret_matrix =
dot( Operation_product, operation_mtx );
680 Operation_product = ret_matrix;
714 return dot( operation_mtx, input_matrix );
726 std::map<int,int>::iterator key_it =
max_layer_num.find( n );
732 max_layer_num.insert( std::pair<int, int>(n, max_layer_num_in) );
747 for ( std::map<int,int>::iterator it = max_layer_num_in.begin(); it!=max_layer_num_in.end(); it++) {
767 std::vector<int> perm_indices;
774 std::vector<int> bin_rep;
776 for (
int i = 1 << (
qbit_num-1); i > 0; i = i / 2) {
777 (idx & i) ? bin_rep.push_back(1) : bin_rep.push_back(0);
781 for (
int jdx=0; jdx<
qbit_num; jdx++) {
784 perm_indices.push_back(row_idx);
799 for (
int row_idx = 0; row_idx<
matrix_size; row_idx++) {
800 for (
int col_idx = 0; col_idx<
matrix_size; col_idx++) {
801 int index_umtx = perm_indices[row_idx]*
Umtx.
rows + perm_indices[col_idx];
802 int index_reordered = row_idx*
Umtx.
rows + col_idx;
803 reordered_mtx[index_reordered] =
Umtx[index_umtx];
807 Umtx = reordered_mtx;
840 for ( std::map<int,int>::iterator it=iteration_loops_in.begin(); it!= iteration_loops_in.end(); it++ ) {
890 std::vector<Operation*> ops_ret;
891 int parameter_idx = 0;
894 for(std::vector<Operation*>::iterator it = ops.begin(); it != ops.end(); it++) {
899 ops_ret.push_back( operation );
910 U3* u3_operation = static_cast<U3*>(operation);
913 vartheta = std::fmod( parameters[parameter_idx], 4*M_PI);
916 parameter_idx = parameter_idx + 1;
921 varphi = std::fmod( parameters[ parameter_idx ], 2*M_PI);
923 parameter_idx = parameter_idx + 1;
928 varlambda = std::fmod( parameters[ parameter_idx ], 2*M_PI);
929 parameter_idx = parameter_idx + 1;
932 vartheta = std::fmod( parameters[ parameter_idx ], 4*M_PI);
933 varphi = std::fmod( parameters[ parameter_idx+1 ], 2*M_PI);
935 parameter_idx = parameter_idx + 2;
938 vartheta = std::fmod( parameters[ parameter_idx ], 4*M_PI);
940 varlambda = std::fmod( parameters[ parameter_idx+1 ], 2*M_PI);
941 parameter_idx = parameter_idx + 2;
945 varphi = std::fmod( parameters[ parameter_idx], 2*M_PI);
946 varlambda = std::fmod( parameters[ parameter_idx+1 ], 2*M_PI);
947 parameter_idx = parameter_idx + 2;
950 vartheta = std::fmod( parameters[ parameter_idx ], 4*M_PI);
951 varphi = std::fmod( parameters[ parameter_idx+1 ], 2*M_PI);
952 varlambda = std::fmod( parameters[ parameter_idx+2 ], 2*M_PI);
953 parameter_idx = parameter_idx + 3;
956 printf(
"wrong parameters in U3 class\n");
961 ops_ret.push_back( static_cast<Operation*>(u3_operation) );
966 Operation_block* block_operation = static_cast<Operation_block*>(operation);
967 const double* parameters_layer = parameters + parameter_idx;
972 ops_ret.insert( ops_ret.end(), ops_loc.begin(), ops_loc.end() );
1025 memset( parameters, 0, 3*
sizeof(
double) );
1029 U3* u3_operation = static_cast<U3*>(operation);
Matrix dot(Matrix &A, Matrix &B)
Call to calculate the product of two complex matrices by calling method zgemm3m from the CBLAS librar...
A class representing a U3 operation.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operations.
std::vector< Operation * > get_operations()
Call to get the operations stored in the class.
Matrix get_finalizing_operations(Matrix &mtx, Operation_block *finalizing_operations, double *finalizing_parameters)
This method determine the operations needed to rotate the indepent qubits into the state |0>
Matrix get_transformed_matrix(const double *parameters, std::vector< Operation * >::iterator operations_it, int num_of_operations)
Calculate the transformed matrix resulting by an array of operations on the matrix Umtx.
void finalize_decomposition()
After the main optimization problem is solved, the indepent qubits can be rotated into state |0> by t...
Base class for the representation of one- and two-qubit operations.
void prepare_operations_to_export()
Call to prepare the optimized operations to export.
Matrix get_decomposed_matrix()
Calculate the decomposed matrix resulted by the effect of the optimized operations on the unitary Umt...
size_t rows
The number of rows.
int target_qbit
The index of the qubit on which the operation acts (target_qbit >= 0)
int control_qbit
The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled operations.
bool decomposition_finalized
logical value describing whether the decomposition was finalized or not (i.e. whether the decomposed ...
void * qgd_calloc(size_t element_num, size_t size, size_t alignment)
custom defined memory allocation function.
Matrix get_Umtx()
Call to retrive a pointer to the unitary to be transformed.
int get_parameter_num()
Call to get the number of free parameters.
Operation()
Default constructor of the class.
double current_minimum
The current minimum of the optimization problem.
bool optimization_problem_solved
logical value describing whether the optimization problem was solved or not
void qgd_free(void *ptr)
custom defined memory release function.
int get_target_qbit()
Call to get the index of the target qubit.
Matrix apply_operation(Matrix &operation_mtx, Matrix &input_matrix)
Apply an operations on the input matrix.
int set_max_layer_num(int n, int max_layer_num_in)
Set the maximal number of layers used in the subdecomposition of the n-th qubit.
Structure type conatining numbers of gates.
scalar * get_data()
Call to get the pointer to the stored data.
void get_optimized_parameters(double *parameters_in)
Call to get the final optimized parameters of the operation.
std::map< int, int > max_layer_num
A map of <int n: int num> indicating that how many layers should be used in the subdecomposition proc...
void set_optimized_parameters(double Theta, double Phi, double Lambda)
Call to set the final optimized parameters of the operation.
int matrix_size
The size N of the NxN matrix associated with the operations.
guess_type initial_guess
type to guess the initial values for the optimization. Possible values: ZEROS=0, RANDOM=1,...
void list_operations(const double *parameters, int start_index)
Call to print the list of operations stored in the block of operations for a specific set of paramete...
static void Init_max_layer_num()
Initializes default layer numbers.
bool is_theta_parameter()
Call to check whether theta is a free parameter of the gate.
std::vector< Matrix, tbb::cache_aligned_allocator< Matrix > > get_operation_products(double *parameters, std::vector< Operation * >::iterator operations_it, int num_of_operations)
Calculate the list of gate operation matrices such that the i>0-th element in the result list is the ...
int finalizing_operations_num
number of finalizing (deterministic) opertaions rotating the disentangled qubits into state |0>.
double * get_optimized_parameters()
Call to get the optimized parameters.
Decomposition_Base(Matrix Umtx_in, int qbit_num_in, guess_type initial_guess_in)
Contructor of the class.
double optimization_tolerance
The maximal allowed error of the optimization problem.
operation_type type
The type of the operation (see enumeration operation_type)
int u3
The number of U3 gates.
double get_decomposition_error()
Call to get the error of the decomposition.
int get_Umtx_size()
Call to get the size of the unitary to be transformed.
virtual void solve_layer_optimization_problem(int num_of_parameters, gsl_vector *solution_guess_gsl)
Abstarct function to be used to solve a single sub-layer optimization problem.
int qbit_num
number of qubits spanning the matrix of the operation
A class responsible for grouping CNOT and U3 operations into layers.
Operation_block()
Deafult constructor of the class.
void set_max_iteration(int max_iterations_in)
Call to set the maximal number of the iterations in the optimization process.
std::map< int, int > iteration_loops
A map of <int n: int num> indicating the number of iteration in each step of the decomposition.
int num_threads
Number of outer OpenMP threads. (During the calculations OpenMP multithreading is turned off....
unsigned int parameter_num
the number of free parameters of the operation
gates_num get_gate_nums()
Call to get the number of the individual gate types in the list of operations.
Structure type representing complex numbers in the QGD package.
A class representing a CNOT operation.
int layer_num
number of operation layers
int Power_of_2(int n)
Calculates the n-th power of 2.
Matrix get_matrix()
Call to retrieve the operation matrix.
Class to store data of complex arrays and its properties.
Header file for a class containing basic methods for the decomposition process.
virtual ~Decomposition_Base()
Destructor of the class.
void subtract_diag(Matrix &mtx, QGD_Complex16 scalar)
Call to subtract a scalar from the diagonal of a complex matrix.
std::vector< Operation * > operations
The list of stored operations.
unsigned int get_parameter_num()
Call to get the number of free parameters.
void set_matrix(Matrix input)
Call to set the stored matrix in the operation.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the operation.
bool verbose
Logical variable. Set true for verbose mode, or to false to suppress output messages.
guess_type
Type definition of the types of the initial guess.
Matrix get_matrix(const double *parameters)
Call to retrieve the operation matrix (Which is the product of all the operation matrices stored in t...
double * optimized_parameters
The optimized parameters for the operations.
int get_operation(unsigned int n, operation_type &type, int &target_qbit, int &control_qbit, double *parameters)
Call to prepare the optimized operations to export.
void add_operation_to_front(Operation *operation)
Add an operation to the front of the list of operations.
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
operation_type get_type()
Call to get the type of the operation.
bool is_lambda_parameter()
Call to check whether Lambda is a free parameter of the gate.
bool is_phi_parameter()
Call to check whether Phi is a free parameter of the gate.
Matrix get_matrix(const double *parameters)
Call to retrieve the operation matrix.
void solve_optimization_problem(double *solution_guess, int solution_guess_num)
This method can be used to solve the main optimization problem which is devidid into sub-layer optimi...
Matrix Umtx
The unitary to be decomposed.
Matrix copy()
Call to create a copy of the matrix.
static std::map< int, int > max_layer_num_def
A map of <int n: int num> indicating that how many layers should be used in the subdecomposition proc...
double real
the real part of a complex number
int get_operation_num()
Call to get the number of operations grouped in the class.
void set_verbose(bool verbose_in)
Call to set the verbose attribute to true or false.
Matrix get_matrix()
Call to retrieve the operation matrix.
int finalizing_parameter_num
the number of the finalizing (deterministic) parameters of operations rotating the disentangled qubit...
int get_control_qbit()
Call to get the index of the control qubit.
bool check_optimization_solution()
check_optimization_solution
int optimization_block
number of operation blocks used in one shot of the optimization process
double decomposition_error
error of the unitarity of the final decomposition
int set_iteration_loops(int n, int iteration_loops_in)
Set the number of iteration loops during the subdecomposition of the n-th qubit.
operation_type
Type definition of operation types (also generalized for decomposition classes derived from the class...
int cnot
The number of CNOT gates.
void list_operations(int start_index)
Call to print the operations decomposing the initial unitary.
double global_target_minimum
The global target minimum of the optimization problem.
void set_optimization_blocks(int optimization_block_in)
Call to set the number of operation blocks to be optimized in one shot.
double imag
the imaginary part of a complex number
int max_iterations
Maximal number of iterations allowed in the optimization process.
virtual double optimization_problem(const double *parameters)
This is an abstact definition of function giving the cost functions measuring the entaglement of the ...