32 std::mt19937 make_decomposition_generator(
33 std::map<std::string, Config_Element>*
config =
nullptr) {
35 if (
config !=
nullptr &&
config->count(
"random_seed") > 0) {
37 (*config)[
"random_seed"].get_property(seed);
38 return std::mt19937(static_cast<std::mt19937::result_type>(seed));
41 return std::mt19937(std::random_device{}());
54 name =
"Decomposition_Interface";
108 std::string projectname =
"";
111 gen = make_decomposition_generator();
134 name =
"Decomposition_Interface";
189 std::string projectname =
"";
196 if (
config.count(
"use_float") > 0 ) {
199 if (
config.count(
"convergence_threshold") > 0 ) {
207 gen = make_decomposition_generator(&
config);
220 MPI_Comm_rank(MPI_COMM_WORLD, ¤t_rank);
232 name =
"Decomposition_Interface";
284 std::string projectname =
"";
289 if (
config.count(
"convergence_threshold") > 0 ) {
293 gen = make_decomposition_generator(&
config);
306 MPI_Comm_rank(MPI_COMM_WORLD, ¤t_rank);
378 if (
gates.size() == 0 ) {
383 const int min_vec_num = 20;
384 double minimum_vec[min_vec_num];
385 for (
int idx=0; idx<min_vec_num; idx++) {
386 minimum_vec[idx] = 0;
393 std::vector<Gate*> gates_loc =
gates;
415 std::uniform_real_distribution<> distrib_real(0.0, 2*
M_PI);
418 Matrix_real optimized_parameters(1, parameter_num_loc);
422 for(
int idx = 0; idx <
parameter_num-solution_guess_num; idx++) {
423 optimized_parameters[idx] = 0;
427 for(
int idx = 0; idx <
parameter_num-solution_guess_num; idx++) {
428 optimized_parameters[idx] = distrib_real(
gen);
438 for(
int idx = 0; idx <
parameter_num-solution_guess_num; idx++) {
439 optimized_parameters[idx] = distrib_real(
gen)/100;
448 std::string err(
"bad value for initial guess");
451 if ( solution_guess_num > 0) {
452 memcpy(optimized_parameters.
get_data() +
parameter_num-solution_guess_num, solution_guess, solution_guess_num*
sizeof(double));
457 int pre_gate_parameter_num = 0;
460 size_t block_idx_end;
461 size_t block_idx_start = 0;
463 int block_parameter_num;
465 std::vector<Matrix, tbb::cache_aligned_allocator<Matrix>> gates_mtxs_post;
475 long long max_outer_iterations_loc;
476 if (
config.count(
"max_outer_iterations") > 0 ) {
477 config[
"max_outer_iterations"].get_property( max_outer_iterations_loc );
486 tbb::tick_count
start_time = tbb::tick_count::now();
492 for ( iter_idx=0; iter_idx<max_outer_iterations_loc; iter_idx++) {
496 if (block_idx_end > gates_loc.size()) {
497 block_idx_end = gates_loc.size();
501 block_parameter_num = 0;
502 for (
size_t block_idx=block_idx_start; block_idx < block_idx_end; block_idx++) {
503 block_parameter_num = block_parameter_num + gates_loc[block_idx]->get_parameter_num();
507 if (block_idx_start > 0 ) {
510 std::vector<Gate*> gates_save =
gates;
512 gates.reserve( gates_save.size()-1 );
513 for( std::vector<Gate*>::iterator gate_it = gates_save.begin(); gate_it != gates_save.end()-1; gate_it++ ) {
514 gates.push_back( *gate_it );
549 for (
size_t idx=block_idx_start; idx<block_idx_end; idx++ ) {
550 gates.push_back( gates_loc[idx] );
554 if (block_idx_end < gates_loc.size()) {
557 for (
size_t gate_idx=0; gate_idx<block_idx_end; gate_idx++) {
558 Gate* gate = gates_loc[gate_idx];
564 std::vector<Gate*> gates_save =
gates;
566 gates.reserve( gates_loc.size()-block_idx_end );
567 for( std::vector<Gate*>::iterator gate_it = gates_loc.begin() + block_idx_end; gate_it != gates_loc.end(); gate_it++ ) {
568 gates.push_back( *gate_it );
574 for (
int pidx=0; pidx<optimized_parameters_partial.
size(); pidx++) {
575 optimized_parameters_partial_float[pidx] =
static_cast<float>(optimized_parameters_partial[pidx]);
586 apply_to( optimized_parameters_partial, post_mtx );
593 gates.push_back( fixed_gate_post );
616 double minvec_mean = 0;
617 for (
int idx=min_vec_num-1; idx>0; idx--) {
618 minimum_vec[idx] = minimum_vec[idx-1];
619 minvec_mean = minvec_mean + minimum_vec[idx-1];
623 minvec_mean = minvec_mean/min_vec_num;
631 if (block_idx_end == gates_loc.size()) {
634 pre_gate_parameter_num = 0;
639 pre_gate_parameter_num = pre_gate_parameter_num + block_parameter_num;
644 if (iter_idx % 500 == 0) {
645 tbb::tick_count current_time = tbb::tick_count::now();
646 std::stringstream sstream;
647 sstream <<
"The minimum with " <<
layer_num <<
" layers after " << iter_idx <<
" outer iterations is " << current_minimum <<
" calculated in " << (current_time -
start_time).seconds() <<
" seconds" << std::endl;
649 start_time = tbb::tick_count::now();
654 double minvec_std = 0.0;
655 for (
int kdx=0; kdx<min_vec_num; kdx++ ) {
656 double tmp = minimum_vec[kdx] - minvec_mean;
657 minvec_std += tmp*tmp;
659 minvec_std = sqrt(minvec_std/(min_vec_num-1));
663 std::stringstream sstream;
664 sstream <<
"The iterations converged to minimum " << current_minimum <<
" after " << iter_idx <<
" outer iterations with " <<
layer_num <<
" layers" << std::endl;
669 std::stringstream sstream;
670 sstream <<
"The minimum with " <<
layer_num <<
" layers after " << iter_idx <<
" outer iterations is " << current_minimum << std::endl;
678 if (iter_idx == max_outer_iterations_loc && max_outer_iterations_loc>1) {
679 std::stringstream sstream;
680 sstream <<
"Reached maximal number of outer iterations" << std::endl << std::endl;
700 delete(fixed_gate_post);
744 double optimization_tolerance_loc;
745 if (
config.count(
"optimization_tolerance") > 0 ) {
746 config[
"optimization_tolerance"].get_property( optimization_tolerance_loc );
815 if ( num_of_parameters == 0 ) {
822 std::string err(
"Decomposition_Base::set_optimized_parameters: The number of parameters does not match with the free parameters of the circuit.");
864 return dot( gate_mtx, input_matrix );
876 std::map<int,int>::iterator key_it =
max_layer_num.find( n );
882 max_layer_num.insert( std::pair<int, int>(n, max_layer_num_in) );
897 for ( std::map<int,int>::iterator it = max_layer_num_in.begin(); it!=max_layer_num_in.end(); it++) {
918 std::vector<int> perm_indices;
926 for(
int qbit_idx=0; qbit_idx<
qbit_num; qbit_idx++ ) {
929 int qbit_state = ( idx >> qbit_list[qbit_idx] ) & 1;
931 row_idx = row_idx + qbit_state*
Power_of_2(qbit_idx);
934 perm_indices.push_back(row_idx);
939 Matrix reordered_mtx =
Matrix(matrix_size, matrix_size);
940 for (
int row_idx = 0; row_idx<
matrix_size; row_idx++) {
941 for (
int col_idx = 0; col_idx<
matrix_size; col_idx++) {
942 int index_reordered = perm_indices[row_idx]*
Umtx.
rows + perm_indices[col_idx];
943 int index_umtx = row_idx*
Umtx.
rows + col_idx;
944 reordered_mtx[index_reordered] =
Umtx[index_umtx];
948 Umtx = reordered_mtx;
982 for ( std::map<int,int>::iterator it=iteration_loops_in.begin(); it!= iteration_loops_in.end(); it++ ) {
1109 mult(global_phase_factor, u3_gate);
1132 const char* c_filename = filename.c_str();
1133 pFile = fopen(c_filename,
"wb");
1135 fputs (
"File error",stderr);
1136 std::string error(
"Cannot open file.");
1141 fwrite(&
Umtx.
rows,
sizeof(
int), 1, pFile);
1142 fwrite(&
Umtx.
cols,
sizeof(
int), 1, pFile);
1159 const char* c_filename = filename.c_str();
1162 pFile = fopen(c_filename,
"rb");
1164 fputs (
"File error",stderr);
1187 if (
config.count(
"parallel") > 0 ) {
1189 config[
"parallel"].get_property( value );
1190 parallel = (
int) value;
1209 int matrix_size_loc = 1 << qbit_num_in;
1211 std::string err(
"Decomposition_Base::set_qbit_num: The new number of qubits is not in line with the input unitary to be decomposed");
void list_gates(int start_index)
Call to print the gates decomposing the initial unitary.
Matrix dot(Matrix &A, Matrix &B)
Call to calculate the product of two complex matrices by calling method zgemm3m from the CBLAS librar...
Gate()
Default constructor of the class.
virtual void reorder_qubits(std::vector< int > qbit_list) override
Call to reorder the qubits in the matrix of the gates (Obsolete function)
std::string get_project_name()
Call to get the current name of the project.
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
Class to store single-precision real arrays and properties.
Matrix_float to_float32() const
Convert to single precision.
Matrix get_decomposed_matrix()
Calculate the decomposed matrix resulted by the effect of the optimized gates on the unitary Umtx...
void set_project_name(std::string &project_name_new)
Call to set the name of the project.
bool decomposition_finalized
The optimized parameters for the gates.
Matrix get_Umtx()
Call to retrive a pointer to the unitary to be transformed.
Matrix_real copy() const
Call to create a copy of the matrix.
bool optimization_problem_solved
logical value describing whether the optimization problem was solved or not
Matrix to_float64() const
Convert to double precision.
int finalizing_gates_num
number of finalizing (deterministic) opertaions rotating the disentangled qubits into state |0>...
bool use_float
Selects float32 circuit application for parameter/unitary/state data.
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.
Matrix_real_float optimized_parameters_mtx_float
Float32 optimized parameters used by the hot gate-application path.
double get_current_minimum()
Call to get the obtained minimum of the cost function.
Matrix_real_float get_optimized_parameters_float()
Return optimized parameters in float32.
int layer_num
number of gate layers
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...
QGD_Complex16 mult(QGD_Complex16 &a, QGD_Complex16 &b)
Call to calculate the product of two complex scalars.
virtual void set_qbit_num(int qbit_num_in) override
Set the number of qubits spanning the matrix of the gates stored in the block of gates.
int matrix_size
The size N of the NxN matrix associated with the operations.
Matrix apply_gate(Matrix &gate_mtx, Matrix &input_matrix)
Apply an gates on the input matrix.
scalar * get_data() const
Call to get the pointer to the stored data.
guess_type initial_guess
type to guess the initial values for the optimization. Possible values: ZEROS=0, RANDOM=1, CLOSE_TO_ZERO=2
static void Init_max_layer_num()
Initializes default layer numbers.
void sync_optimized_parameters_float()
Synchronize the float32 parameter mirror from the double optimizer storage.
void apply_global_phase_factor()
Call to apply the current global phase to the unitary matrix.
std::vector< Gate * > gates
The list of stored gates.
void set_qbit_num(int qbit_num_in)
Set the number of qubits spanning the matrix of the gates stored in the block of gates.
Matrix_real_float copy() const
int max_outer_iterations
Maximal number of iterations allowed in the optimization process.
std::string project_name
the name of the project
double optimization_tolerance
The maximal allowed error of the optimization problem (The error of the decomposition would scale wit...
gate_type type
The type of the operation (see enumeration gate_type)
void set_global_phase(double new_global_phase)
Call to set global phase.
QGD_Complex16 get_global_phase_factor()
Get the global phase of the Unitary matrix.
int rows
The number of rows.
int cols
The number of columns.
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.
double convergence_threshold
The convergence threshold in the optimization process.
Matrix_float Umtx_float
Float32 copy of the unitary used when config["use_float"] is true.
Matrix_real get_optimized_parameters()
Call to get the optimized parameters.
std::map< int, int > iteration_loops
A map of <int n: int num> indicating the number of iteration in each step of the decomposition.
void set_optimized_parameters(double *parameters, int num_of_parameters)
Call to set the optimized parameters for initial optimization.
virtual void apply_to(Matrix_real ¶meters_mtx, Matrix &input, int parallel=0) override
Call to apply the gate on the input array/matrix Gates_block*input.
int num_threads
Store the number of OpenMP threads. (During the calculations OpenMP multithreading is turned off...
Structure type representing complex numbers in the SQUANDER package.
Matrix copy() const
Call to create a copy of the matrix.
void set_optimization_tolerance(double tolerance_in)
Call to set the tolerance of the optimization processes.
void set_matrix(Matrix input)
Call to set the stored matrix in the operation.
int Power_of_2(int n)
Calculates the n-th power of 2.
Double-precision complex matrix (float64).
Header file for a class containing basic methods for the decomposition process.
virtual ~Decomposition_Base()
Destructor of the class.
QGD_Complex16 global_phase_factor
The global phase.
int size() const
Call to get the number of the allocated elements.
virtual int get_parameter_num()
Call to get the number of free parameters.
void set_convergence_threshold(double convergence_threshold_in)
Call to set the threshold of convergence in the optimization processes.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
void calculate_new_global_phase_factor(QGD_Complex16 global_phase_factor_new)
Calculate the new global phase of the Unitary matrix after removing a trivial U3 matrix.
void reorder_qubits(std::vector< int > qbit_list)
Call to reorder the qubits in the matrix of the gate.
std::string name
A string labeling the gate operation.
Single-precision complex matrix (float32).
guess_type
Type definition of the types of the initial guess.
std::map< std::string, Config_Element > config
config metadata utilized during the optimization
Base class for the representation of general gate operations.
Matrix create_identity(int matrix_size)
Call to create an identity matrix.
virtual void solve_layer_optimization_problem(int num_of_parameters, Matrix_real solution_guess_gsl)
Abstarct function to be used to solve a single sub-layer optimization problem.
int parameter_num
the number of free parameters of the operation
volatile double current_minimum
The current minimum of the optimization problem.
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.
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
void reset_parameter_start_indices()
Method to reset the parameter start indices of gate operations incorporated in the circuit...
Matrix_float get_Umtx_float()
Return the float32 unitary copy used by float execution.
void export_unitary(std::string &filename)
exports unitary matrix to binary file
int qbit_num
number of qubits spanning the matrix of the operation
int finalizing_parameter_num
the number of the finalizing (deterministic) parameters of gates rotating the disentangled qubits int...
void set_max_iteration(int max_outer_iterations_in)
Call to set the maximal number of the iterations in the optimization process.
bool check_optimization_solution()
check_optimization_solution
int optimization_block
number of gate blocks used in one shot of the optimization process
double decomposition_error
error 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.
void fread_wrapper(void *buffer, size_t size, size_t count, FILE *stream)
Wrapper function aound fread with error handling.
void list_gates(const Matrix_real ¶meters, int start_index)
Call to print the list of gates stored in the block of gates for a specific set of parameters...
Matrix import_unitary_from_binary(std::string &filename)
Import a Unitary matrix from a file.
Matrix_real optimized_parameters_mtx
The optimized parameters for the gates.
int get_parallel_configuration()
Get the parallel configuration from the config.
Matrix_float copy() const
Call to create a copy of the matrix.
bool get_use_float() const
True when config["use_float"] requests float32 circuit execution.
double global_target_minimum
The global target minimum of the optimization problem.
Header file for the paralleized calculation of the cost function of the subdecomposition (supporting ...
void set_optimization_blocks(int optimization_block_in)
Call to set the number of gate blocks to be optimized in one shot.
Class to store data of complex arrays and its properties.
Decomposition_Base()
Nullary constructor of the class.
std::mt19937 gen
Standard mersenne_twister_engine seeded with rd()
double imag
the imaginary part of a complex number
Matrix_float create_identity_float(int matrix_size)
Call to create a single-precision complex identity matrix.
virtual double optimization_problem(const double *parameters)
This is an abstact definition of function giving the cost functions measuring the entaglement of the ...