min_qubits=2
max_qubits=8
max_circuits=1
num_shots=1000

backend_id="qasm_simulator"
hub="ibm-q"; group="open"; project="main"
provider_backend = None
exec_options = {}

# # ==========================
# # *** If using IBMQ hardware, run this once to authenticate
# from qiskit import IBMQ
# IBMQ.save_account('YOUR_API_TOKEN_HERE')

# # *** If you are part of an IBMQ group, set hub, group, and project name here
# hub="YOUR_HUB_NAME"; group="YOUR_GROUP_NAME"; project="YOUR_PROJECT_NAME"

# # *** This example shows how to specify an IBMQ backend using a known "backend_id"
# exec_options = { "optimization_level":3, "use_sessions":True, "resilience_level":1}
# backend_id="ibmq_belem"

# # ==========================
# # *** If using Azure Quantum, use this hub identifier and specify the desired backend_id
# # Identify your resources with env variables AZURE_QUANTUM_RESOURCE_ID and AZURE_QUANTUM_LOCATION
# hub="azure-quantum"; group="open"; project="QED-C App-Oriented Benchmarks - Qiskit Version"
# backend_id="<YOUR_BACKEND_NAME_HERE>"

# # ==========================
# The remaining examples create a provider instance and get a backend from it

# # An example using IonQ provider
# from qiskit_ionq import IonQProvider
# provider = IonQProvider()   # Be sure to set the QISKIT_IONQ_API_TOKEN environment variable
# provider_backend = provider.get_backend("ionq_qpu")
# backend_id="ionq_qpu"

# # An example using BlueQubit provider
# import sys
# sys.path.insert(1, "../..")
# import os, bluequbit, _common.executors.bluequbit_executor as bluequbit_executor
# provider_backend = bluequbit.init()
# backend_id="BlueQubit-CPU"
# exec_options = { "executor": bluequbit_executor.run, "device":'cpu' }

# # *** Here's an example of using a typical custom provider backend (e.g. AQT simulator)
# import os
# from qiskit_aqt_provider import AQTProvider
# provider = AQTProvider(os.environ.get('AQT_ACCESS_KEY'))    # get your key from environment
# provider_backend = provider.backends.aqt_qasm_simulator_noise_1
# backend_id="aqt_qasm_simulator_noise_1"


import os, hydrogen_lattice_benchmark

#backend_id="qasm_simulator"

# Additional arguments specific to Hydrogen Lattice benchmark method 2 plotting
hl_app_args = dict(
    
    # display options for line plots (pairwise)
    line_y_metrics=['energy', 'accuracy_ratio_error'],             # + 'solution_quality', 'accuracy_ratio', 'solution_quality_error'
    line_x_metrics=['iteration_count', 'cumulative_exec_time'],    # + 'cumulative_elapsed_time'
    plot_layout_style='grid',                                      # plot layout, can be 'grid', 'stacked', or 'individual'
    
    # display options for bar plots (exec time, accuracy ratio)
    bar_y_metrics=["average_exec_times", "accuracy_ratio_error"],
    bar_x_metrics=["num_qubits"],
    use_logscale_for_times=False,                                  # use log scale for cumulative exec time bar chart
    show_elapsed_times=True,                                       # include elapsed time in average_exec_times plot
    
    # display options for area plots (multiplicative)
    score_metric=['accuracy_ratio'],                               # + 'solution_quality'
    x_metric=['cumulative_exec_time', 'cumulative_elapsed_time'],  # + 'cumulative_opt_exec_time', 
)

hydrogen_lattice_benchmark.load_data_and_plot(os.path.join('__data', backend_id, ''), backend_id=backend_id,                                             
    **hl_app_args)


import sys
sys.path.insert(1, "hydrogen-lattice/qiskit")
import hydrogen_lattice_benchmark

# define a custom Nelder-Mead minimizer function
from scipy.optimize import minimize

tol=0.01
max_iter=30

def my_minimizer(objective_function, initial_parameters, callback):

    ret = minimize(objective_function,
        x0=initial_parameters, 

        
        # a custom minimizer 
        method='nelder-mead',
        options={'xatol':tol, 'fatol':tol, 'maxiter': max_iter, 'maxfev': max_iter, 'disp': False},
                   
        callback=callback) 
    
    print(f"\n... my_minimizer completed, return = \n{ret}")
    return ret

# Additional arguments specific to Hydrogen Lattice benchmark method 2
hl_app_args = dict(   

    max_iter=30,                # maximum minimizer iterations to perform
    comfort=True,               # show 'comfort dots' during execution
   
    minimizer_function=my_minimizer,   # use custom minimizer function
)

# Run the benchmark in method 2
hydrogen_lattice_benchmark.run(
    min_qubits=min_qubits, max_qubits=max_qubits, max_circuits=max_circuits, num_shots=num_shots,
    method=2, 
    backend_id=backend_id, provider_backend=provider_backend,
    hub=hub, group=group, project=project, exec_options=exec_options,
    **hl_app_args
)

import sys
sys.path.insert(1, "hydrogen-lattice/qiskit")
import hydrogen_lattice_benchmark
 
# Arguments specific to execution of single instance of the Hydrogen Lattice objective function
hl_app_args = dict(

    num_qubits=4,               # problem size, dexscribed by number of qubits
    num_shots=1000,             # number of shots to perform
    
    radius=1.0,                # select single problem radius, None = use first radius   
    
    parameter_mode=1,           # 1 - use single theta parameter, 2 - map multiple thetas to pairs
    thetas_array=[ 0.0 ],       # use custom thetas_array
    
    backend_id=backend_id,
    provider_backend=provider_backend,
    hub=hub, group=group,
    project=project, exec_options=exec_options,
)

# Execute the objective function once with the given arguments
energy, key_metrics = hydrogen_lattice_benchmark.run_objective_function(**hl_app_args)

# Print the return value of energy
print(f"Final Energy value = {energy}")

# Print key metrics from execution
print(f"Key Metrics = {key_metrics}")


import sys
sys.path.insert(1, "hydrogen-lattice/qiskit")
import hydrogen_lattice_benchmark

# Arguments specific to Hydrogen Lattice benchmark method (2)
hl_app_args = dict(
    
    min_qubits=2,               # configure min, max widths, and shots here
    max_qubits=4,
    num_shots=1000,
    
    max_circuits=4,             # number of 'restarts' to perform at same radius
    
    radius=0.75,                # select single problem radius for multiple execution of same circuit
  
    thetas_array=None,          # specify a custom thetas_array
    parameter_mode=1,           # 1 - use single theta parameter, 2 - map multiple thetas to pairs
    parameterized=False,        # use Parameter objects in circuit, cache transpiled circuits for performance
    
    max_iter=30,                # maximum minimizer iterations to perform
    minimizer_tolerance=0.001,  # tolerance passed to the minimizer
    comfort=True,               # show 'comfort dots' during execution
    
    # disable print of results at every iteration
    show_results_summary=False,
    
    # display options for bar plots (exec time, accuracy ratio)
    bar_y_metrics=["average_exec_times", "accuracy_ratio_error"],
    bar_x_metrics=["num_qubits"],
    use_logscale_for_times=True,                                  # use log scale for cumulative exec time bar chart
    show_elapsed_times=True,                                      # include elapsed time in average_exec_times plot
    
    # disable options for line plots and area plots
    line_y_metrics=None,
    score_metric=None, 
)

# Run the benchmark in method 2
hydrogen_lattice_benchmark.run(method=2, 
    backend_id=backend_id, provider_backend=provider_backend,
    hub=hub, group=group, project=project, exec_options=exec_options,
    **hl_app_args)

