Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sanjgupt/onlineproblem #55

Merged
merged 25 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
9a63c66
add online problem plus testing for it. Download method in problme
sanjgupt May 3, 2021
d83a6d5
nit
sanjgupt May 3, 2021
35620ab
add another assertion for online problems
sanjgupt May 3, 2021
926ad2a
update solver to handle online problmes
sanjgupt May 3, 2021
f473660
Raise error for setting fixed variables for online problem and test
sanjgupt May 3, 2021
b7a6b28
merge from upstream main
sanjgupt May 4, 2021
a15062f
codestyle errors
sanjgupt May 4, 2021
95d808d
nit
sanjgupt May 4, 2021
6ba91ab
Make online problem wrapper for name and url
sanjgupt May 4, 2021
40c1f0b
codestyle errors
sanjgupt May 4, 2021
cabf16e
add a small function to enable getting terms from index
sanjgupt May 4, 2021
89226d9
remove evalutate and fixed variables from online problem
sanjgupt May 5, 2021
cd4272f
update the download function to correctly authenticate the storage ac…
sanjgupt May 5, 2021
197754d
styling errors
sanjgupt May 5, 2021
ace7965
styling errors
sanjgupt May 5, 2021
1e108b6
Merge branch 'main' into sanjgupt/onlineproblem
sanjgupt May 6, 2021
0d3b9b2
nit
sanjgupt May 6, 2021
6d63cec
Merge branch 'main' of https://github.com/microsoft/qdk-python into s…
sanjgupt May 6, 2021
417939e
Merge branch 'sanjgupt/onlineproblem' of https://github.com/sanjgupt/…
sanjgupt May 6, 2021
9986d47
disablinb test for Online Problem for now till it becomes available i…
sanjgupt May 7, 2021
ee2a67c
Update azure-quantum/tests/unit/test_online_problem.py
sanjgupt May 10, 2021
e05559b
revert styles changes to _client. This folder should not be changed b…
sanjgupt May 10, 2021
e68e221
nit
sanjgupt May 10, 2021
342f430
commneting out onliune problem code till OnlineProblem can be made av…
sanjgupt May 10, 2021
bad7699
nit
sanjgupt May 10, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions azure-quantum/azure/quantum/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,11 @@ def refresh(self):
self.details = self.workspace.get_job(self.id).details

def has_completed(self):
return (self.details.status == "Succeeded"
or self.details.status == "Failed"
or self.details.status == "Cancelled")
return (
self.details.status == "Succeeded"
or self.details.status == "Failed"
or self.details.status == "Cancelled"
)

def wait_until_completed(self, max_poll_wait_secs=30):
"""Keeps refreshing the Job's details
Expand All @@ -54,14 +56,17 @@ def wait_until_completed(self, max_poll_wait_secs=30):
poll_wait = 0.2
while not self.has_completed():
logger.debug(
f"Waiting for job {self.id}," +
f"it is in status '{self.details.status}'"
f"Waiting for job {self.id},"
+ f"it is in status '{self.details.status}'"
)
print(".", end="", flush=True)
time.sleep(poll_wait)
self.refresh()
poll_wait = (max_poll_wait_secs if poll_wait >= max_poll_wait_secs
else poll_wait * 1.5)
poll_wait = (
max_poll_wait_secs
if poll_wait >= max_poll_wait_secs
else poll_wait * 1.5
)

def get_results(self):
if self.results is not None:
Expand All @@ -72,19 +77,21 @@ def get_results(self):

if not self.details.status == "Succeeded":
raise RuntimeError(
f'{"Cannot retrieve results as job execution failed"}' +
f"(status: {self.details.status}." +
f"error: {self.details.error_data})"
f'{"Cannot retrieve results as job execution failed"}'
+ f"(status: {self.details.status}."
+ f"error: {self.details.error_data})"
)

url = urlparse(self.details.output_data_uri)
if url.query.find("se=") == -1:
# output_data_uri does not contains SAS token,
# get sas url from service
blob_client = BlobClient.from_blob_url(
self.details.output_data_uri)
self.details.output_data_uri
)
blob_uri = self.workspace._get_linked_storage_sas_uri(
blob_client.container_name, blob_client.blob_name)
blob_client.container_name, blob_client.blob_name
)
payload = download_blob(blob_uri)
else:
# output_data_uri contains SAS token, use it
Expand Down
1 change: 1 addition & 0 deletions azure-quantum/azure/quantum/optimization/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@
from .problem import *
from .solvers import *
from .streaming_problem import *
from .online_problem import *
25 changes: 25 additions & 0 deletions azure-quantum/azure/quantum/optimization/online_problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import logging
from typing import TYPE_CHECKING, Union, Dict
from azure.quantum.optimization import Problem

logger = logging.getLogger(__name__)

__all__ = ["OnlineProblem"]

if TYPE_CHECKING:
from azure.quantum.workspace import Workspace


class OnlineProblem(object):
def __init__(
self, name: str,
blob_uri: str,
**kw
):
super(OnlineProblem, self).__init__(**kw)
self.name = name
self.uploaded_blob_uri = blob_uri

def download(self, workspace:"Workspace") -> Problem:
logger.warning("The problem will be downloaded to the client")
return Problem.download(self, workspace)
75 changes: 59 additions & 16 deletions azure-quantum/azure/quantum/optimization/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@
from typing import List, Union, Dict, Optional, TYPE_CHECKING
from enum import Enum
from azure.quantum.optimization import Term
from azure.quantum.storage import upload_blob, ContainerClient
from azure.quantum.storage import (
upload_blob,
ContainerClient,
download_blob,
BlobClient
)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -43,6 +48,7 @@ class Problem:
ProblemType.ising), defaults to ProblemType.ising
:type problem_type: ProblemType, optional
"""

def __init__(
self,
name: str,
Expand Down Expand Up @@ -100,7 +106,8 @@ def deserialize(cls, problem_as_json: str, name: str):

if "initial_configuration" in result["cost_function"]:
problem.init_config = result["cost_function"][
"initial_configuration"]
"initial_configuration"
]

return problem

Expand Down Expand Up @@ -167,9 +174,11 @@ def upload(
if not workspace.storage:
# No storage account is passed, use the linked one
container_uri = workspace._get_linked_storage_sas_uri(
container_name)
container_name
)
container_client = ContainerClient.from_container_url(
container_uri)
container_uri
)
self.uploaded_blob_uri = upload_blob(
container_client,
blob_name,
Expand All @@ -181,7 +190,8 @@ def upload(
else:
# Use the specified storage account
container_client = ContainerClient.from_connection_string(
workspace.storage, container_name)
workspace.storage, container_name
)
self.uploaded_blob_uri = upload_blob(
container_client,
blob_name,
Expand All @@ -195,8 +205,8 @@ def upload(
return self.uploaded_blob_uri

def set_fixed_variables(
self, fixed_variables: Union[Dict[int, int],
Dict[str, int]]) -> Problem:
self, fixed_variables: Union[Dict[int, int], Dict[str, int]]
) -> Problem:
"""Transforms the current problem with a set of fixed
variables and returns the new modified problem.
The original Problem instance is untouched.
Expand All @@ -211,8 +221,7 @@ def set_fixed_variables(
)

fixed_transformed = {
int(k): fixed_variables[k]
for k in fixed_variables
int(k): fixed_variables[k] for k in fixed_variables
} # if ids are given in string form, convert them to int
new_terms = []

Expand All @@ -233,7 +242,8 @@ def set_fixed_variables(
if self.init_config:
new_init_config = {
k: self.init_config[k]
for k in self.init_config if int(k) not in fixed_transformed
for k in self.init_config
if int(k) not in fixed_transformed
}

return Problem(
Expand All @@ -244,17 +254,16 @@ def set_fixed_variables(
)

def evaluate(
self, configuration: Union[Dict[int, int], Dict[str,
int]]) -> float:
self, configuration: Union[Dict[int, int], Dict[str, int]]
) -> float:
"""Given a configuration/variable assignment,
return the cost function value of this problem.

:param configuration: The dictionary of
variable ids to their assigned value
"""
configuration_transformed = {
int(k): configuration[k]
for k in configuration
int(k): configuration[k] for k in configuration
} # if ids are given in string form, convert them to int
total_cost = 0
if self.terms:
Expand All @@ -275,5 +284,39 @@ def is_large(self) -> bool:
for term in self.terms:
set_vars.update(term.ids)

return (len(set_vars) >= Problem.NUM_VARIABLES_LARGE
and len(self.terms) >= Problem.NUM_TERMS_LARGE)
return (
len(set_vars) >= Problem.NUM_VARIABLES_LARGE
and len(self.terms) >= Problem.NUM_TERMS_LARGE
)

def download(self, workspace:"Workspace"):
"""Downloads the uploaded problem as an instance of `Problem`"""
if not self.uploaded_blob_uri:
raise Exception(
"Problem may not be downloaded before it is uploaded"
)
blob_client = BlobClient.from_blob_url(self.uploaded_blob_uri)
container_client = ContainerClient.from_container_url(
workspace._get_linked_storage_sas_uri(
blob_client.container_name
)
)
blob_name = blob_client.blob_name
blob = container_client.get_blob_client(blob_name)
contents = download_blob(blob.url)
return Problem.deserialize(contents, self.name)

def get_terms(self, id:int) -> List[Term]:
""" Given an index the function will return
a list of terms with that index
"""
terms = []
if self.terms != []:
for term in self.terms:
if id in term.ids:
terms.append(term)
return terms
else:
raise Exception("There are currently no terms in this problem. \
Please download the problem on the client or add terms to the \
problem to perform this operation")
Loading