# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: conda_braket
#     language: python
#     name: python3
# ---

# # Step 3: Optimize Configuration

# In this part, we use SA and QA to find the optimized configuration of molecular unfolding.
# At first, we load the model file using **QMUQUBO** object

# +
from utility.MoleculeParser import MoleculeData
from utility.QMUQUBO import QMUQUBO
from utility.AnnealerOptimizer import Annealer
from utility.ResultProcess import ResultParser
import time

timestamp = time.strftime("%Y%m%d-%H")
# -

qmu_qubo_optimize = QMUQUBO.load(model_path)

model_info = qmu_qubo_optimize.describe_model()

# We can see the parameters of this model, with M equaling 2, D equaling 8, 
# A equaling 300 and hubo_qubo_val equaling 200. 
# Actually, we can contain multiple models in this file just 
# by giving multiple values for one parameter when creating models.
# Then, we need use **model_name** to get the model for experiments.

# +
# get the model you want to optimize
M = 2
D = 8
A = 300
hubo_qubo_val = 200
model_name = "{}_{}_{}_{}".format(M, D, A, hubo_qubo_val)
method = "pre-calc"

qubo_model = qmu_qubo_optimize.get_model(method, model_name)
# -

# We can see that we want to carry out experiment with the QUBO model with M equaling 2.
#  After that, we set the parameters for optimization.
#
# | Parameter | Description | Value |
# |--- |--- |--- |
# |method | annealing method for QUBO problem |'dwave-sa': use the simulated annealer in ocean toolkit<br> 'dwave-qa': use the quantum annealer|
# |shots| number of reads, refer to [dwave-sa](https://docs.ocean.dwavesys.com/projects/neal/en/latest/reference/generated/neal.sampler.SimulatedAnnealingSampler.sample.html#neal.sampler.SimulatedAnnealingSampler.sample) and [dwave-qa](https://amazon-braket-ocean-plugin-python.readthedocs.io/en/latest/_apidoc/braket.ocean_plugin.braket_sampler.html) for details |1 to 10,000|
# |bucket | the s3 bucket to store your results | - |
# |prefix | the name of the folder in your s3 bucket | - |
# |device | the arn name to run your quantum annealing| 'arn:aws:braket:::device/qpu/d-wave/Advantage_system4' <br> 'arn:aws:braket:::device/qpu/d-wave/DW_2000Q_6'|
#
# Then, we can run the SA for this problem:

# +
method = 'dwave-sa'

optimizer_param = {}
optimizer_param['shots'] = 1000

sa_optimizer = Annealer(qubo_model, method, **optimizer_param)
# -

sa_optimize_result = sa_optimizer.fit()

# We can tell that we set the number of shots for SA to 1000. 
# The result is saved as the local file **./sa_result.pickle.**
# Alternatively, we can use QA to solve this problem:

# +
method = 'dwave-qa'

optimizer_param = {}
optimizer_param['shots'] = 1000
optimizer_param['bucket'] = s3_bucket # the name of the bucket
optimizer_param['prefix'] = prefix # the name of the folder in the bucket
optimizer_param['device'] = "arn:aws:braket:::device/qpu/d-wave/Advantage_system4"
optimizer_param["embed_method"] = "default"

qa_optimizer = Annealer(qubo_model, method, **optimizer_param)
# -

# In this QA, we set the number of shots to 1000 and 
# choose the 
# [Advantage_System4.1](https://docs.dwavesys.com/docs/latest/doc_physical_properties.html)
# as the QPU. In addition, the results are saved to your bucket automatically and you 
# can get the task id for future process. 

# not create annealing task, only embedding logic
qa_optimizer.embed()
# create annealing task
qa_optimize_result = qa_optimizer.fit()

qa_task_id = qa_optimizer.get_task_id()
print(f"task id is {qa_task_id}")

# Finally, we can compare the execution time between SA and QA :

print(f"dwave-sa run time {sa_optimize_result['time']}")
print(f"dwave-qa run time {qa_optimize_result['time']}")

# We can tell from the image that SA needs 174.2 seconds 
# and QA needs 7.7 seconds to find 
# solution.
#
# We sometimes get the best result that occurs only once.
#
# ![OneTimeQA](../../../images/one-time-qa.png)
#
# This does not always indicate an error. It is actually the characteristic of the problem or how the problem 
# is formulated. Because we have different linear and quadratic terms that vary by many orders of magnitude. If we 
# set change value of A to some smaller number, like 10 or 100, more occurrences of the best answer will be observed. 
# However, these answers usually break the constraints. For more information about this phenomenon, please refer to this 
# [Link](https://support.dwavesys.com/hc/en-us/community/posts/1500000698522-Number-of-occurrences-?input_string=number%20occurance).

StarcoderdataJupyterScriptsDedupFiltered