87 Generative_Quantum_Machine_Learning_Base::Generative_Quantum_Machine_Learning_Base(std::vector<int> sample_indices_in, std::vector<std::vector<int>> sample_bitstrings_in,
Matrix_real P_star_in,
Matrix_real sigma_in,
int qbit_num_in,
bool use_lookup_table_in, std::vector<std::vector<int>> cliques_in,
bool use_exact_in, std::map<std::string, Config_Element>& config_in) :
Optimization_Interface(
Matrix(
Power_of_2(qbit_num_in),1), qbit_num_in, false, config_in,
RANDOM, 0) {
140 for (
int idx=0; idx<1<<
qbit_num; idx++) {
141 std::vector<int> bitstring;
142 for (
int j = qbit_num - 1; j >= 0; --j) {
143 bitstring.push_back(((idx) >> j) & 1);
189 if (
gates.size() == 0 ) {
190 std::string error(
"Variational_Quantum_Eigensolver_Base::Get_ground_state: for GQML process the circuit needs to be initialized");
195 if ( num_of_parameters == 0 ) {
196 std::string error(
"Variational_Quantum_Eigensolver_Base::Get_ground_state: No intial parameters were given");
202 std::string error(
"Variational_Quantum_Eigensolver_Base::Get_ground_state: The number of initial parameters does not match with the number of parameters in the circuit");
230 double norm = (x - y)*(x - y);
231 double result = (exp(-norm*0.5/sigma[0])+ exp(-norm*0.5/sigma[1])+ exp(-norm*0.5/sigma[2]))/3;
240 for (
int idx1=0; idx1 < 1<<
qbit_num; idx1++) {
241 for (
int idx2=0; idx2 < 1<<
qbit_num; idx2++) {
253 tbb::combinable<double> priv_partial_ev{[](){
return 0.0;}};
254 tbb::parallel_for( tbb::blocked_range<int>(0,
sample_size, 1024), [&](tbb::blocked_range<int> r) {
255 double& ev_local = priv_partial_ev.local();
256 for (
int idx1=r.begin(); idx1<r.end(); idx1++) {
264 priv_partial_ev.combine_each([&ev](
double a) {
277 tbb::combinable<double> priv_partial_ev{[](){
return 0.0;}};
278 tbb::parallel_for( tbb::blocked_range<int>(0, 1<<
qbit_num, 1024), [&](tbb::blocked_range<int> r) {
279 double& ev_local = priv_partial_ev.local();
280 for (
int idx1=r.begin(); idx1<r.end(); idx1++) {
281 for (
int idx2=0; idx2<1<<
qbit_num; idx2++) {
286 priv_partial_ev.combine_each([&ev](
double a) {
300 for (
int x_idx=0; x_idx < static_cast<int>(State_right.
size()); x_idx++){
301 P_theta.push_back(State_right[x_idx].
real*State_right[x_idx].
real +State_right[x_idx].imag*State_right[x_idx].imag);
305 for (
int i=0; i < static_cast<int>(P_theta.size()); i++) {
306 TV += abs(P_theta[i]-
P_star[i]);
325 tbb::parallel_for( tbb::blocked_range<int>(0, 1<<
qbit_num, 1024), [&](tbb::blocked_range<int> r) {
326 for (
int idx=r.begin(); idx<r.end(); idx++) {
327 P_theta[idx] = State_right[idx].real*State_right[idx].real + State_right[idx].imag*State_right[idx].imag;
332 double ev_P_theta_P_theta = 0.0;
333 double ev_P_theta_P_star = 0.0;
334 tbb::combinable<double> priv_partial_ev_P_theta_P_theta{[](){
return 0.0;}};
335 tbb::combinable<double> priv_partial_ev_P_theta_P_star{[](){
return 0.0;}};
336 tbb::parallel_for( tbb::blocked_range2d<int>(0, 1<<
qbit_num, 0, 1<<
qbit_num), [&](tbb::blocked_range2d<int> r) {
337 double& ev_P_theta_P_theta_local = priv_partial_ev_P_theta_P_theta.local();
338 double& ev_P_theta_P_star_local = priv_partial_ev_P_theta_P_star.local();
339 for (
int idx1=r.rows().begin(); idx1<r.rows().end(); idx1++) {
340 for (
int idx2=r.cols().begin(); idx2<r.cols().end(); idx2++) {
343 ev_P_theta_P_star_local += P_theta[idx1]*
P_star[idx2]*gaussian_lookup_table[idx1][idx2];
352 priv_partial_ev_P_theta_P_theta.combine_each([&ev_P_theta_P_theta](
double a) {
353 ev_P_theta_P_theta += a;
355 priv_partial_ev_P_theta_P_star.combine_each([&ev_P_theta_P_star](
double a) {
356 ev_P_theta_P_star += a;
361 tbb::spin_mutex::scoped_lock my_lock{
my_mutex};
386 tbb::parallel_for( tbb::blocked_range<int>(0, 1<<
qbit_num, 1024), [&](tbb::blocked_range<int> r) {
387 for (
int idx=r.begin(); idx<r.end(); idx++) {
388 P_theta[idx] = State_right[idx].real*State_right[idx].real + State_right[idx].imag*State_right[idx].imag;
392 std::random_device rd;
393 std::mt19937
gen(rd());
394 std::discrete_distribution<> dist(P_theta.begin(), P_theta.end());
396 std::vector<int> theta_sample_indices(
sample_size);
397 tbb::parallel_for( tbb::blocked_range<int>(0,
sample_size, 1024), [&](tbb::blocked_range<int> r) {
398 for (
int sample_idx=r.begin(); sample_idx < r.end(); sample_idx++) {
399 theta_sample_indices[sample_idx] = dist(gen);
405 double ev_P_theta_P_theta = 0.0;
406 double ev_P_theta_P_star = 0.0;
407 tbb::combinable<double> priv_partial_ev_P_theta_P_theta{[](){
return 0.0;}};
408 tbb::combinable<double> priv_partial_ev_P_theta_P_star{[](){
return 0.0;}};
409 tbb::parallel_for( tbb::blocked_range2d<int>(0,
sample_size, 0,
sample_size), [&](tbb::blocked_range2d<int> r) {
410 double& ev_P_theta_P_theta_local = priv_partial_ev_P_theta_P_theta.local();
411 double& ev_P_theta_P_star_local = priv_partial_ev_P_theta_P_star.local();
412 for (
int idx1=r.rows().begin(); idx1<r.rows().end(); idx1++) {
413 for (
int idx2=r.cols().begin(); idx2<r.cols().end(); idx2++) {
416 ev_P_theta_P_theta_local +=
gaussian_lookup_table[theta_sample_indices[idx1]][theta_sample_indices[idx2]];
422 ev_P_theta_P_theta_local +=
Gaussian_kernel(theta_sample_indices[idx1],theta_sample_indices[idx2],
sigma);
429 priv_partial_ev_P_theta_P_theta.combine_each([&ev_P_theta_P_theta](
double a) {
430 ev_P_theta_P_theta += a;
432 priv_partial_ev_P_theta_P_star.combine_each([&ev_P_theta_P_star](
double a) {
433 ev_P_theta_P_star += a;
440 tbb::spin_mutex::scoped_lock my_lock{
my_mutex};
464 instance->
apply_to(parameters, State);
512 int parameter_num_loc = parameters.
size();
517 std::vector<Matrix> State_deriv;
522 tbb::parallel_invoke(
525 instance->
apply_to(parameters, State);
536 tbb::parallel_for( tbb::blocked_range<int>(0,parameter_num_loc,2), [&](tbb::blocked_range<int> r) {
537 for (
int idx=r.begin(); idx<r.end(); ++idx) {
624 std::string
filename(
"costfuncs_entropy_and_tv.txt");
628 const char* c_filename = filename.c_str();
630 #pragma warning(suppress: 4996) 632 pFile = fopen(c_filename,
"a");
635 fputs (
"File error",stderr);
636 std::string error(
"Cannot open file.");
642 std::uniform_int_distribution<> distrib(0,
qbit_num-2);
644 memset(input_state.
get_data(), 0, (input_state.
size()*2)*
sizeof(
double) );
645 input_state[0].real = 1.0;
663 fprintf(pFile,
"%i\t%f\t%f\t%f\n", (
int)
number_of_iters, current_minimum, renyi_entropy, tv_distance);
721 std::string error(
"Variational_Quantum_Eigensolver_Base::generate_initial_circuit: number of qubits should be at least 2");
725 for (
int layer_idx=0; layer_idx<
layers ;layer_idx++){
766 std::string error(
"Variational_Quantum_Eigensolver_Base::generate_initial_circuit: number of qubits should be at least 2");
770 for (
int layer_idx=0; layer_idx<
layers ;layer_idx++){
841 int num_cliques =
static_cast<int>(
cliques.size());
843 std::string error(
"Variational_Quantum_Eigensolver_Base::generate_initial_circuit: input the cliques for using QCMRF ansatz");
847 for (
int qbit_idx=0; qbit_idx <
qbit_num; qbit_idx++) {
851 std::vector<std::vector<int>> all_subsets;
852 for (
int clique_idx = 0; clique_idx < num_cliques; clique_idx++) {
853 std::vector<int> subset;
856 for (
int qbit_idx=0; qbit_idx <
qbit_num; qbit_idx++) {
862 std::string error(
"Generative_Quantum_Machine_Learning_Base::generate_initial_circuit: ansatz not implemented");
873 for (
size_t idx=0; idx<qbits.size()-1; idx++) {
876 add_rz(qbits[qbits.size()-1]);
877 for (
int idx=static_cast<int>(qbits.size())-1; idx>0; idx--) {
889 if (static_cast<size_t>(i) == arr.size()) {
890 if (subset.size() != 0) {
891 if (std::find(res.begin(), res.end(), subset) == res.end()) {
892 res.push_back(subset);
899 subset.push_back(arr[i]);
913 if (
gates.size() > 0 ) {
914 gate_structure_tmp->
combine( static_cast<Gates_block*>(
this) );
921 memcpy( optimized_parameters_mtx_tmp2.get_data(), optimized_parameters_mtx_tmp.
get_data(), optimized_parameters_mtx_tmp.
size()*
sizeof(double) );
929 std::stringstream sstream;
933 for(
auto it=gate_nums.begin(); it != gate_nums.end(); it++ ) {
934 sstream << it->second <<
" " << it->first <<
" gates" << std::endl;
954 std::string error(
"Variational_Quantum_Eigensolver_Base::set_initial_state: teh number of elements in the input state does not match with the number of qubits.");
virtual double optimization_problem(Matrix_real ¶meters) override
The optimization problem of the final optimization.
optimization_aglorithms alg
The optimization algorithm to be used in the optimization.
bool adaptive_eta
logical variable indicating whether adaptive learning reate is used in the ADAM algorithm ...
virtual ~Generative_Quantum_Machine_Learning_Base()
Destructor of the class.
void print(const std::stringstream &sstream, int verbose_level=1) const
Call to print output messages in the function of the verbosity level.
ansatz_type
Type definition of the fifferent types of ansatz.
void add_h(int target_qbit)
Append a Hadamard gate to the list of gates.
static tbb::spin_mutex my_mutex
bool decomposition_finalized
The optimized parameters for the gates.
std::vector< std::vector< int > > cliques
std::map< std::string, int > get_gate_nums()
Call to get the number of the individual gate types in the list of gates.
static void optimization_problem_grad_vqe(Matrix_real parameters, void *void_instance, Matrix_real &grad)
Calculate the derivative of the cost function with respect to the free parameters.
void set_gate_structure(std::string filename)
Call to set custom layers to the gate structure that are intended to be used in the GQML process...
double expectation_value_P_star_P_star_exact()
Call to evaluate the expectation value of the square of the distribution.
Matrix_real copy() const
Call to create a copy of the matrix.
int control_qbit
The index of the qubit which acts as a control qubit (control_qbit >= 0) in controlled operations...
bool optimization_problem_solved
logical value describing whether the optimization problem was solved or not
void add_gate(Gate *gate)
Append a general gate to the list of gates.
cost_function_type cost_fnc
The chosen variant of the cost function.
void generate_circuit(int layers, int inner_blocks)
Call to generate the circuit ansatz.
double Gaussian_kernel(int x, int y, Matrix_real &sigma)
Call to evaluate the value of one gaussian kernel function.
void release_gates()
Call to release the stored gates.
double MMD_of_the_distributions_approx(Matrix &State_right)
Call to evaluate the approximated maximum mean discrepancy of the given distribution and the one crea...
void set_ansatz(ansatz_type ansatz_in)
Call to set the ansatz type.
void release_data()
Call to release the data stored by the matrix.
Generative_Quantum_Machine_Learning_Base()
Nullary constructor of the class.
std::atomic< int > number_of_iters
number of iterations
void add_cnot(int target_qbit, int control_qbit)
Append a CNOT gate gate to the list of gates.
scalar * get_data() const
Call to get the pointer to the stored data.
virtual void optimization_problem_combined_non_static(Matrix_real parameters, void *void_instance, double *f0, Matrix_real &grad) override
Call to calculate both the cost function and the its gradient components.
Gates_block * import_gate_list_from_binary(Matrix_real ¶meters, const std::string &filename, int verbosity)
Use to import a quantum circuit from a binary format.
double MMD_of_the_distributions_exact(Matrix &State_right)
Call to evaluate the maximum mean discrepancy of the given distribution and the one created by our ci...
double ev_P_star_P_star
The expectation value of the the square of the given ditribution (only needed to calculate once) ...
std::vector< Gate * > gates
The list of stored gates.
double expectation_value_P_star_P_star_approx()
Call to evaluate the approximated expectation value of the square of the distribution.
std::vector< std::vector< int > > sample_bitstrings
Same as the x_vectors but in binary.
std::string project_name
the name of the project
double TV_of_the_distributions(Matrix &State_right)
Call to evaluate the total variational distance of the given distribution and the one created by our ...
double optimization_tolerance
The maximal allowed error of the optimization problem (The error of the decomposition would scale wit...
double get_second_Renyi_entropy(Matrix_real ¶meters_mtx, Matrix &input_state, matrix_base< int > &qbit_list)
Call to evaluate the seconf Rényi entropy.
void export_current_cost_fnc(double current_minimum, Matrix_real ¶meters) override
Call to print out into a file the current cost function and the second Rényi entropy on the subsyste...
double convergence_threshold
The convergence threshold in the optimization process.
Matrix initial_state
Quantum state used as an initial state in the VQE iterations.
void add_u3(int target_qbit)
Append a U3 gate to the list of gates.
A base class to determine the decomposition of an N-qubit unitary into a sequence of CNOT and U3 gate...
void add_rz(int target_qbit)
Append a RZ gate to the list of gates.
void combine(Gates_block *op_block)
Call to append the gates of an gate block to the current block.
void add_ry(int target_qbit)
Append a RY gate to the list of gates.
A base class to solve GQML problems This class can be used to approximate a given distribution via a ...
virtual void optimization_problem_combined(Matrix_real parameters, double *f0, Matrix_real grad) override
Call to calculate both the cost function and the its gradient components.
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.
std::vector< std::vector< int > > all_bitstrings
Structure type representing complex numbers in the SQUANDER package.
Matrix copy() const
Call to create a copy of the matrix.
void start_optimization()
Call to start solving the GQML problem.
int Power_of_2(int n)
Calculates the n-th power of 2.
Double-precision complex matrix (float64).
Matrix_real sigma
Parameter of the Gaussian kernel.
int size() const
Call to get the number of the allocated elements.
Gates_block()
Default constructor of the class.
A class responsible for grouping two-qubit (CNOT,CZ,CH) and one-qubit gates into layers.
void fill_lookup_table()
Call to calculate and save the values of the gaussian kernel needed for traing.
ansatz_type ansatz
Ansatz type (HEA stands for hardware efficient ansatz)
Class to solve GQML problems.
virtual double optimization_problem_non_static(Matrix_real parameters, void *void_instance) override
The optimization problem of the final optimization.
std::map< std::string, Config_Element > config
config metadata utilized during the optimization
void set_initial_state(Matrix initial_state_in)
Call to set the initial quantum state in the VQE iterations.
std::vector< std::vector< double > > gaussian_lookup_table
double(Generative_Quantum_Machine_Learning_Base::* MMD_of_the_distributions)(Matrix &)
void generate_clique_circuit(int i, std::vector< int > &qbits, std::vector< std::vector< int >> &res, std::vector< int > &subset)
Call to generate the circuit ansatz for the given clique.
Matrix_real P_star
The distribution we are trying to approximate.
int parameter_num
the number of free parameters of the operation
void solve_layer_optimization_problem(int num_of_parameters, Matrix_real solution_guess)
Call to solve layer by layer the optimization problem via calling one of the implemented algorithms...
void initialize_zero_state()
Initialize the state used in the quantun circuit.
volatile double current_minimum
The current minimum of the optimization problem.
int qbit_num
number of qubits spanning the matrix of the operation
void MultyRZ(std::vector< int > &qbits)
Call to generate a MultiRZ gate.
double decomposition_error
error of the final decomposition
int random_shift_count_max
the maximal number of parameter randomization tries to escape a local minimum.
Matrix_real optimized_parameters_mtx
The optimized parameters for the gates.
int get_parallel_configuration()
Get the parallel configuration from the config.
int get_parameter_num() override
Call to get the number of free parameters.
std::vector< int > sample_indices
The state vector's corresponding indices of the training data.
double global_target_minimum
The global target minimum of the optimization problem.
Class to store data of complex arrays and its properties.
std::mt19937 gen
Standard mersenne_twister_engine seeded with rd()
virtual std::vector< Matrix > apply_derivate_to(Matrix_real ¶meters_mtx, Matrix &input, int parallel) override
Call to evaluate the derivate of the circuit on an inout with respect to all of the free parameters...