azure-quantum 1.1.1.dev0__py3-none-any.whl → 1.1.2.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,382 +0,0 @@
1
- ##
2
- # Copyright (c) Microsoft Corporation. All rights reserved.
3
- # Licensed under the MIT License.
4
- ##
5
- import warnings
6
- import logging
7
-
8
- from typing import TYPE_CHECKING, Union, Any, Optional
9
- from enum import Enum
10
- from azure.quantum.job.base_job import ContentType
11
- from azure.quantum import Workspace, Job
12
- from azure.quantum.job.base_job import DEFAULT_TIMEOUT
13
- from azure.quantum.target.target import Target
14
-
15
- if TYPE_CHECKING:
16
- from azure.quantum.optimization.problem import Problem
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
- __all__ = [
21
- "RangeSchedule",
22
- "Solver",
23
- ]
24
-
25
-
26
-
27
- class RangeSchedule:
28
- def __init__(self, schedule_type: str, initial: float, final: float):
29
- """Constructor of RangeSchedule for solvers.
30
-
31
- :param schedule_type:
32
- str, type of the RangeSchedule
33
- currently only supports 'linear' and 'geometric'.
34
- :param initial:
35
- float, initial value of RangeSchedule
36
- :param final:
37
- float, final value of the RangeSchedule
38
- """
39
- self.schedule_type = schedule_type
40
- self.initial = initial
41
- self.final = final
42
- if not (
43
- self.schedule_type == "linear" or self.schedule_type == "geometric"
44
- ):
45
- raise ValueError(
46
- '"schedule_type" must be "linear" or "geometric"!'
47
- )
48
-
49
- class Solver(Target):
50
- def __init__(
51
- self,
52
- workspace: Workspace,
53
- name: str,
54
- provider_id: str,
55
- input_data_format="microsoft.qio.v2",
56
- output_data_format="microsoft.qio-results.v2",
57
- nested_params: bool = True,
58
- force_str_params: bool = False,
59
- params: dict = None,
60
- content_type : Optional[ContentType] = ContentType.json,
61
- **kwargs
62
- ):
63
- self.provider_id = provider_id
64
- self.nested_params = nested_params
65
- self.force_str_params = force_str_params
66
- self.params = {"params": {}} if nested_params else {}
67
- params = params or {}
68
- name = self._switch_name(name, **params)
69
-
70
- super().__init__(
71
- workspace=workspace,
72
- name=name,
73
- input_data_format=input_data_format,
74
- output_data_format=output_data_format,
75
- provider_id=provider_id,
76
- content_type = content_type,
77
- encoding="gzip",
78
- **kwargs
79
- )
80
-
81
- self._set_params(**params)
82
- self._check_params(**params)
83
-
84
-
85
- """Constants that define thresholds for submission warnings
86
- """
87
- SWEEPS_WARNING = 10000
88
- TIMEOUT_WARNING = 600
89
-
90
- def _switch_name(self, name, **params):
91
- return name
92
-
93
- def _check_params(self, **params):
94
- pass
95
-
96
- @staticmethod
97
- def _encode_input_data(data: "Problem") -> bytes:
98
- return data.to_blob()
99
-
100
- def submit(
101
- self,
102
- problem: Union[str, "Problem"],
103
- shots: int = None
104
- ) -> Job:
105
- """Submits a job to execution to the associated
106
- Azure Quantum Workspace.
107
-
108
- :param problem:
109
- The Problem to solve. It can be an instance of a Problem,
110
- or the URL of an Azure Storage Blob where the serialized version
111
- of a Problem has been uploaded.
112
- """
113
- if shots is not None:
114
- warnings.warn("The 'shots' parameter is ignored for solver job.")
115
-
116
- from azure.quantum.optimization import Problem
117
- if isinstance(problem, Problem):
118
- return super().submit(
119
- input_data=problem,
120
- name=problem.name,
121
- input_params=self.params,
122
- blob_name="inputData",
123
- content_type = problem.content_type
124
- )
125
-
126
- else:
127
- if hasattr(problem, "uploaded_blob_uri"):
128
- name = problem.name
129
- problem_uri = problem.uploaded_blob_uri
130
-
131
- elif isinstance(problem, str):
132
- name = "Optimization problem"
133
- problem_uri = problem
134
-
135
- else:
136
- raise ValueError("Cannot submit problem: should be of type str, Problem or have uploaded_blob_uri attribute.")
137
-
138
- # Create job from storage URI
139
- job = Job.from_storage_uri(
140
- workspace=self.workspace,
141
- name=name,
142
- target=self.name,
143
- input_data_uri=problem_uri,
144
- provider_id=self.provider_id,
145
- input_data_format=self.input_data_format,
146
- output_data_format=self.output_data_format,
147
- input_params=self.params,
148
- session_id=self.get_latest_session_id()
149
- )
150
-
151
- return job
152
-
153
- def optimize(self, problem: Union[str, "Problem"], timeout_secs: int=DEFAULT_TIMEOUT):
154
- """[Submits the Problem to the associated
155
- Azure Quantum Workspace and get the results.
156
-
157
- :param problem:
158
- The Problem to solve. It can be an instance of a Problem,
159
- or the URL of an Azure Storage Blob where the serialized version
160
- of a Problem has been uploaded.
161
- :type problem: Union[str, Problem]
162
- :param timeout_secs: Timeout in seconds, defaults to 300
163
- :type timeout_secs: int
164
- :return: Job results
165
- :rtype: dict
166
- """
167
- if not isinstance(problem, str):
168
- self.check_submission_warnings(problem)
169
-
170
- job = self.submit(problem)
171
- logger.info(f"Submitted job: '{job.id}'")
172
-
173
- return job.get_results(timeout_secs=timeout_secs)
174
-
175
- def set_one_param(self, name: str, value: Any):
176
- if value is not None:
177
- params = (
178
- self.params["params"] if self.nested_params else self.params
179
- )
180
- params[name] = str(value) if self.force_str_params else value
181
-
182
- def _set_params(self, **params):
183
- for param_name, param in params.items():
184
- self.set_one_param(param_name, param)
185
-
186
- def set_number_of_solutions(self, number_of_solutions: int):
187
- """Sets the number of solutions to return.
188
-
189
- Applies to all solvers.
190
- Default value is 1 if not supplied.
191
-
192
- :param number_of_solutions:
193
- Number of solutions to return. Must be a positive integer.
194
- """
195
- self.set_one_param("number_of_solutions", number_of_solutions)
196
-
197
- def check_submission_warnings(self, problem: "Problem"):
198
- # print a warning if we suspect the job
199
- # may take long based on its configured properties.
200
- is_large_problem = problem.is_large()
201
- if is_large_problem:
202
- if self.nested_params and "sweeps" in self.params["params"]:
203
- sweeps = int(self.params["params"]["sweeps"])
204
- # if problem is large and sweeps is large, warn.
205
- if sweeps >= Solver.SWEEPS_WARNING:
206
- logger.warning(
207
- f"There is a large problem submitted and \
208
- a large number of sweeps ({sweeps}) configured. \
209
- This submission could result in a long runtime."
210
- )
211
-
212
- # do a timeout check if param-free, to warn
213
- # new users who accidentally set high timeout values.
214
- if self.nested_params and "timeout" in self.params["params"]:
215
- timeout = int(self.params["params"]["timeout"])
216
- if timeout >= Solver.TIMEOUT_WARNING:
217
- logger.warning(
218
- f"A large timeout has been set for this submission \
219
- ({timeout}). \
220
- If this is intended, disregard this warning. \
221
- Otherwise, consider cancelling the job \
222
- and resubmitting with a lower timeout."
223
- )
224
-
225
- class ScheduleEvolution(Enum):
226
- INCREASING = 1
227
- DECREASING = 2
228
-
229
- def check_set_schedule(
230
- self,
231
- schedule_name: str,
232
- schedule_value: RangeSchedule,
233
- evolution: Optional[ScheduleEvolution] = None,
234
- lower_bound_exclusive: Optional[float] = None,
235
- lower_bound_inclusive: Optional[float] = None,
236
- ):
237
- """Set the parameter `schedule_name` from the value `schedule_value`
238
- and check that it is of type `RangeSchedule` and each end satisfies
239
- the specified bound.
240
-
241
- :param schedule_name:
242
- Name of the schedule parameter.
243
- :param schedule_value:
244
- Schedule value to be assigned and checked.
245
- :param evolution
246
- Expected schedule evolution (INCREASING or DECREASING)
247
- :lower_bound_exclusive:
248
- Exclusive lower bound for both ends of the schedule, optional.
249
- :lower_bound_inclusive:
250
- Inclusive lower bound for both ends of the schedule, optional.
251
- """
252
- if not (schedule_value is None):
253
- if not isinstance(schedule_value, RangeSchedule):
254
- raise ValueError(
255
- f"{schedule_name} must be of type RangeSchedule; found"
256
- f" type({schedule_name})={type(schedule_value).__name__}."
257
- )
258
- schedule_param = {
259
- "type": schedule_value.schedule_type,
260
- "initial": schedule_value.initial,
261
- "final": schedule_value.final,
262
- }
263
- if evolution is not None:
264
- if (evolution == self.ScheduleEvolution.INCREASING and
265
- schedule_value.initial > schedule_value.final):
266
- raise ValueError(
267
- f"Schedule for {schedule_name} must be increasing;"
268
- f" found {schedule_name}.initial"
269
- f"={schedule_value.initial}"
270
- f" > {schedule_value.final}"
271
- f"={schedule_name}.final."
272
- )
273
- if (evolution == self.ScheduleEvolution.DECREASING and
274
- schedule_value.initial < schedule_value.final):
275
- raise ValueError(
276
- f"Schedule for {schedule_name} must be decreasing;"
277
- f" found {schedule_name}.initial"
278
- f"={schedule_value.initial}"
279
- f" < {schedule_value.final}"
280
- f"={schedule_name}.final."
281
- )
282
- self.check_limit(
283
- f"{schedule_name}.initial",
284
- schedule_value.initial,
285
- lower_bound_exclusive=lower_bound_exclusive,
286
- lower_bound_inclusive=lower_bound_inclusive)
287
- self.check_limit(
288
- f"{schedule_name}.final",
289
- schedule_value.final,
290
- lower_bound_exclusive=lower_bound_exclusive,
291
- lower_bound_inclusive=lower_bound_inclusive)
292
- self.set_one_param(schedule_name, schedule_param)
293
-
294
- def check_set_positive_int(
295
- self,
296
- parameter_name: str,
297
- parameter_value: int):
298
- """Set the parameter `parameter_name` from the value `parameter_value`
299
- and check that it is a positive integer.
300
-
301
- :param parameter_name:
302
- Name of the parameter.
303
- :param parameter_value:
304
- Value to be assigned and checked.
305
- """
306
- if not (parameter_value is None):
307
- if not isinstance(parameter_value, int):
308
- raise ValueError(
309
- f"{parameter_name} must be of type int; found"
310
- f"type({parameter_name})"
311
- f"={type(parameter_value).__name__}.")
312
- if parameter_value <= 0:
313
- raise ValueError(
314
- f"{parameter_name} must be positive; found "
315
- f"{parameter_name}={parameter_value}.")
316
- self.set_one_param(parameter_name, parameter_value)
317
-
318
- def check_set_float(
319
- self,
320
- parameter_name: str,
321
- parameter_value: float,
322
- lower_bound_exclusive: Optional[float] = None,
323
- lower_bound_inclusive: Optional[float] = None,
324
- ):
325
- """Set the parameter `parameter_name` from the value `parameter_value`
326
- and check that it has a float value satisfying bounds.
327
-
328
- :param parameter_name:
329
- Name of the parameter.
330
- :param parameter_value:
331
- Value to be assigned and checked.
332
- :lower_bound_exclusive:
333
- Exclusive lower bound to check parameter_value against, optional.
334
- :lower_bound_inclusive:
335
- Inclusive lower bound to check parameter_value against, optional.
336
- """
337
- if not (parameter_value is None):
338
- if not (isinstance(parameter_value, float) or
339
- isinstance(parameter_value, int)):
340
- raise ValueError(f"{parameter_name} must be a float!")
341
- else:
342
- self.check_limit(
343
- parameter_name=parameter_name,
344
- parameter_value=parameter_value,
345
- lower_bound_exclusive=lower_bound_exclusive,
346
- lower_bound_inclusive=lower_bound_inclusive)
347
- self.set_one_param(parameter_name, parameter_value)
348
-
349
- def check_limit(
350
- self,
351
- parameter_name: str,
352
- parameter_value: Optional[float],
353
- lower_bound_exclusive: Optional[float] = None,
354
- lower_bound_inclusive: Optional[float] = None,
355
- ):
356
- """Check whether `parameter_value` satisfies a lower bound.
357
-
358
- :param parameter_name:
359
- Name of the parameter.
360
- :param parameter_value:
361
- Value to be checked.
362
- :lower_bound_exclusive:
363
- Exclusive lower bound to check parameter_value against, optional.
364
- :lower_bound_inclusive:
365
- Inclusive lower bound to check parameter_value against, optional.
366
- """
367
- if not (parameter_value is None):
368
- if (lower_bound_exclusive is not None and
369
- parameter_value <= lower_bound_exclusive):
370
- raise ValueError(
371
- f"{parameter_name} must be greater than "
372
- f"{lower_bound_exclusive}; "
373
- f"found {parameter_name}={parameter_value}."
374
- )
375
- if (lower_bound_inclusive is not None and
376
- parameter_value < lower_bound_inclusive):
377
- raise ValueError(
378
- f"{parameter_name} must be greater equal "
379
- f"{lower_bound_inclusive}; found "
380
- f"{parameter_name}={parameter_value}."
381
- )
382
-
@@ -1,7 +0,0 @@
1
- # coding=utf-8
2
- ##
3
- # Copyright (c) Microsoft Corporation. All rights reserved.
4
- # Licensed under the MIT License.
5
- ##
6
-
7
- from .solvers import *
@@ -1,130 +0,0 @@
1
- ##
2
- # Copyright (c) Microsoft Corporation. All rights reserved.
3
- # Licensed under the MIT License.
4
- ##
5
- import logging
6
- from typing import TYPE_CHECKING, Union, Optional
7
- from azure.quantum import Workspace
8
- from azure.quantum.target import Solver
9
- from azure.quantum import Job
10
-
11
- if TYPE_CHECKING:
12
- from azure.quantum.optimization import Problem
13
-
14
- logger = logging.getLogger(__name__)
15
- __all__ = ["SimulatedBifurcationMachine"]
16
-
17
-
18
- class SimulatedBifurcationMachine(Solver):
19
- target_names = (
20
- "toshiba.sbm.ising",
21
- )
22
- def __init__(
23
- self,
24
- workspace: Workspace,
25
- name="toshiba.sbm.ising",
26
- steps: Optional[int] = None,
27
- loops: Optional[int] = None,
28
- target: Optional[float] = None,
29
- maxout: Optional[int] = None,
30
- timeout: Optional[float] = None,
31
- dt: Optional[float] = None,
32
- C: Optional[float] = None,
33
- algo: Optional[str] = None,
34
- auto: Optional[bool] = None,
35
- **kwargs
36
- ):
37
- """The constructor of Toshiba's simulated bifurcation machine.
38
-
39
- This solver enables users to quickly obtain nearly optimal
40
- solutions for large combinatorial optimization problems.
41
- It is developed based on the theory described in the following paper:
42
- Goto, H., Tatsumura, K., & Dixon, A. R. (2019)
43
- Combinatorial optimization by simulating adiabatic bifurcations
44
- in nonlinear Hamiltonian systems, Science Advances,
45
- 5(4), DOI:10.1126/sciadv.aav2372
46
- :param steps:
47
- The number of steps in a computation request.
48
- The default is 0.
49
- The value 0 means auto step where SBM computation
50
- service dynamically determines the number of steps.
51
- The maximum is 100,000,000.
52
- :param loops:
53
- The number of loops in SBM computation.
54
- SBM computation service searches for a better solution
55
- while repeating loops as many times as is specified.
56
- The default is 1. If 0 (zero) is specified, computation
57
- will be repeated until a timeout occurs. The maximum is 10,000,000.
58
- :param target:
59
- The end condition of a computation request. When the
60
- evaluation value reaches this value, the computation will stop.
61
- If 0 is specified for the parameter loops,
62
- loops will be repeated either until
63
- the objective function reaches the value
64
- specified in the parameter target or until a timeout occurs.
65
- :param maxout:
66
- The upper limit of the number of solutions
67
- to be outputted. The default is 1.
68
- Until the limit specified by maxout is reached,
69
- SBM computation service outputs the
70
- obtained solutions in descending order
71
- of the value of the objective function.
72
- The maximum is 1,000.
73
- :param timeout:
74
- The maximum computation time (timeout) in seconds.
75
- The default is 10.
76
- When the computation time reaches the upper limit before
77
- completing the computation for steps * loops,
78
- the computation ends at that point.
79
- In this case, the execution result will be the
80
- best solution obtained thus far.
81
- If 0 is specified for the parameter loops, loops will be repeated
82
- until the time specified by the parameter timeout expires.
83
- The maximum is 360.
84
- :param dt:
85
- The time per step. The range of the value is greater than
86
- 0.0 and less than or equal to 1.0.
87
- :param C:
88
- Corresponds to the constant ξ0,
89
- appearing in the paper by Goto, Tatsumura,
90
- & Dixon (2019, p. 2), which is the theoretical basis of SBM.
91
- Specify the constant as a single-precision floating point
92
- number, equal to or more than 0.
93
- If the value is 0, the value C is automatically determined.
94
- :param algo:
95
- The type of SBM computation algorithm.
96
- The default is "2.0". One of "1.5" or "2.0".
97
- Depending on the type of problem, there may be differences
98
- in performance between the "1.5" and "2.0" algorithms.
99
- Try both and decide which yields better performance.
100
- :param auto:
101
- The parameter auto tuning flag. The default is "false."
102
- If the value is "true," SBM computation service searches for
103
- the values of the parameters automatically to obtain
104
- the best solution.
105
- Parameters other than `auto` are treated as follows
106
- in this case. `algo` and `dt` are ignored and tuned automatically.
107
- `loops` and `maxout` are ignored.
108
- `timeout` can be specified as the total computation time (sec).
109
- Other parameters are treated as defined
110
- """
111
- super().__init__(
112
- workspace=workspace,
113
- provider_id="toshiba",
114
- name=name,
115
- input_data_format="microsoft.qio.v2",
116
- output_data_format="microsoft.qio-results.v2",
117
- nested_params=False,
118
- force_str_params=False,
119
- **kwargs
120
- )
121
- self.set_one_param("steps", steps)
122
- self.set_one_param("loops", loops)
123
- self.set_one_param("target", target)
124
- self.set_one_param("maxout", maxout)
125
- self.set_one_param("timeout", timeout)
126
- self.set_one_param("dt", dt)
127
- self.set_one_param("C", C)
128
- self.set_one_param("algo", algo)
129
- self.set_one_param("auto", auto)
130
-