azure-quantum 3.2.0__py3-none-any.whl → 3.4.0__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.
- azure/quantum/_client/_version.py +1 -1
- azure/quantum/_workspace_connection_params.py +3 -6
- azure/quantum/cirq/targets/ionq.py +1 -1
- azure/quantum/cirq/targets/quantinuum.py +1 -1
- azure/quantum/job/job.py +2 -2
- azure/quantum/qiskit/backends/ionq.py +4 -4
- azure/quantum/qiskit/backends/quantinuum.py +0 -8
- azure/quantum/target/__init__.py +0 -1
- azure/quantum/target/ionq.py +3 -34
- azure/quantum/target/quantinuum.py +2 -16
- azure/quantum/target/target.py +3 -32
- azure/quantum/target/target_factory.py +1 -5
- azure/quantum/version.py +1 -1
- {azure_quantum-3.2.0.dist-info → azure_quantum-3.4.0.dist-info}/METADATA +13 -20
- {azure_quantum-3.2.0.dist-info → azure_quantum-3.4.0.dist-info}/RECORD +17 -25
- azure/quantum/_authentication/__init__.py +0 -9
- azure/quantum/_authentication/_chained.py +0 -119
- azure/quantum/_authentication/_default.py +0 -153
- azure/quantum/_authentication/_token.py +0 -83
- azure/quantum/target/microsoft/elements/__init__.py +0 -1
- azure/quantum/target/microsoft/elements/dft/__init__.py +0 -6
- azure/quantum/target/microsoft/elements/dft/job.py +0 -171
- azure/quantum/target/microsoft/elements/dft/target.py +0 -316
- {azure_quantum-3.2.0.dist-info → azure_quantum-3.4.0.dist-info}/WHEEL +0 -0
- {azure_quantum-3.2.0.dist-info → azure_quantum-3.4.0.dist-info}/top_level.txt +0 -0
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import warnings
|
|
2
|
-
|
|
3
|
-
from azure.quantum.job.base_job import ContentType
|
|
4
|
-
from azure.quantum.job.job import Job
|
|
5
|
-
from azure.quantum.target.target import Target
|
|
6
|
-
from azure.quantum.workspace import Workspace
|
|
7
|
-
from azure.quantum.target.params import InputParams
|
|
8
|
-
from typing import Any, Dict, Type, Union, List
|
|
9
|
-
from .job import MicrosoftElementsDftJob
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
import copy
|
|
12
|
-
import json
|
|
13
|
-
from collections import defaultdict
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class MicrosoftElementsDft(Target):
|
|
17
|
-
"""
|
|
18
|
-
Microsoft Elements Dft target from the microsoft-elements provider.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
target_names = [
|
|
22
|
-
"microsoft.dft"
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def __init__(
|
|
27
|
-
self,
|
|
28
|
-
workspace: "Workspace",
|
|
29
|
-
name: str = "microsoft.dft",
|
|
30
|
-
**kwargs
|
|
31
|
-
):
|
|
32
|
-
"""
|
|
33
|
-
Initializes a new DFT target.
|
|
34
|
-
|
|
35
|
-
:param workspace: Associated workspace
|
|
36
|
-
:type workspace: Workspace
|
|
37
|
-
:param name: Target name
|
|
38
|
-
"""
|
|
39
|
-
# There is only a single target name for this target
|
|
40
|
-
assert name == self.target_names[0]
|
|
41
|
-
|
|
42
|
-
# make sure to not pass argument twice
|
|
43
|
-
kwargs.pop("provider_id", None)
|
|
44
|
-
|
|
45
|
-
super().__init__(
|
|
46
|
-
workspace=workspace,
|
|
47
|
-
name=name,
|
|
48
|
-
input_data_format="microsoft.xyz.v1",
|
|
49
|
-
output_data_format="microsoft.dft-results.v1",
|
|
50
|
-
provider_id="microsoft-elements",
|
|
51
|
-
content_type=ContentType.text_plain,
|
|
52
|
-
**kwargs
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def submit(self,
|
|
57
|
-
input_data: Any,
|
|
58
|
-
name: str = "azure-quantum-dft-job",
|
|
59
|
-
shots: int = None,
|
|
60
|
-
input_params: Union[Dict[str, Any], InputParams, None] = None,
|
|
61
|
-
**kwargs) -> MicrosoftElementsDftJob:
|
|
62
|
-
"""
|
|
63
|
-
Submit DFT job to Azure Quantum Services.
|
|
64
|
-
|
|
65
|
-
:param input_data: Input data
|
|
66
|
-
:type input_data: Any
|
|
67
|
-
:param name: Job name
|
|
68
|
-
:type name: str
|
|
69
|
-
:param shots: Number of shots. Ignored in DFT job. Defaults to None
|
|
70
|
-
:type shots: int
|
|
71
|
-
:param input_params: Input parameters
|
|
72
|
-
:type input_params: Dict[str, Any]
|
|
73
|
-
:return: Azure Quantum job
|
|
74
|
-
:rtype: Job
|
|
75
|
-
"""
|
|
76
|
-
|
|
77
|
-
if shots is not None:
|
|
78
|
-
warnings.warn("The 'shots' parameter is ignored in Microsoft Elements Dft job.")
|
|
79
|
-
|
|
80
|
-
if isinstance(input_data, list):
|
|
81
|
-
|
|
82
|
-
if len(input_data) < 1:
|
|
83
|
-
raise ValueError("Input data list has no elements.")
|
|
84
|
-
|
|
85
|
-
if all(isinstance(task,str) for task in input_data):
|
|
86
|
-
qcschema_data = self.assemble_qcschema_from_files(input_data, input_params)
|
|
87
|
-
|
|
88
|
-
qcschema_blobs = {}
|
|
89
|
-
for i in range(len(qcschema_data)):
|
|
90
|
-
qcschema_blobs[f"inputData_{i}"] = self._encode_input_data(qcschema_data[i])
|
|
91
|
-
|
|
92
|
-
toc_str = self._create_table_of_contents(input_data, list(qcschema_blobs.keys()))
|
|
93
|
-
elif all(isinstance(task,dict) for task in input_data):
|
|
94
|
-
qcschema_blobs = {}
|
|
95
|
-
for i in range(len(input_data)):
|
|
96
|
-
qcschema_blobs[f"inputData_{i}"] = self._encode_input_data(input_data[i])
|
|
97
|
-
toc_str = '{"description": "QcSchema Objects were given for input."}'
|
|
98
|
-
else:
|
|
99
|
-
raise ValueError(f"Unsupported batch submission. Please use List[str] or List[dict].")
|
|
100
|
-
toc = self._encode_input_data(toc_str)
|
|
101
|
-
|
|
102
|
-
input_params = {} if input_params is None else input_params
|
|
103
|
-
return self._get_job_class().from_input_data_container(
|
|
104
|
-
workspace=self.workspace,
|
|
105
|
-
name=name,
|
|
106
|
-
target=self.name,
|
|
107
|
-
input_data=toc,
|
|
108
|
-
batch_input_blobs=qcschema_blobs,
|
|
109
|
-
input_params={ 'numberOfFiles': len(input_data), "inputFiles": list(qcschema_blobs.keys()), **input_params },
|
|
110
|
-
content_type=kwargs.pop('content_type', self.content_type),
|
|
111
|
-
encoding=kwargs.pop('encoding', self.encoding),
|
|
112
|
-
provider_id=self.provider_id,
|
|
113
|
-
input_data_format=kwargs.pop('input_data_format', 'microsoft.qc-schema.v1'),
|
|
114
|
-
output_data_format=kwargs.pop('output_data_format', self.output_data_format),
|
|
115
|
-
session_id=self.get_latest_session_id(),
|
|
116
|
-
**kwargs
|
|
117
|
-
)
|
|
118
|
-
else:
|
|
119
|
-
return super().submit(
|
|
120
|
-
input_data=input_data,
|
|
121
|
-
name=name,
|
|
122
|
-
shots=shots,
|
|
123
|
-
input_params=input_params,
|
|
124
|
-
**kwargs
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
@classmethod
|
|
130
|
-
def assemble_qcschema_from_files(self, input_data: Union[List[str]], input_params: Dict) -> List[Dict]:
|
|
131
|
-
"""
|
|
132
|
-
Convert a list of files to a list of QcSchema objects that are ready for submission.
|
|
133
|
-
|
|
134
|
-
:param input_data: Input data
|
|
135
|
-
:type input_data: List[str]
|
|
136
|
-
:param input_params: Input parameters
|
|
137
|
-
:type input_params: Dict[str, Any]
|
|
138
|
-
:rtype: List[Dict]
|
|
139
|
-
"""
|
|
140
|
-
|
|
141
|
-
self._check_file_paths(input_data)
|
|
142
|
-
|
|
143
|
-
qcshema_objects = []
|
|
144
|
-
for file in input_data:
|
|
145
|
-
file_path = Path(file)
|
|
146
|
-
|
|
147
|
-
file_data = file_path.read_text()
|
|
148
|
-
if file_path.suffix == '.xyz':
|
|
149
|
-
mol = self._xyz_to_qcschema_mol(file_data)
|
|
150
|
-
new_qcschema = self._new_qcshema( input_params, mol )
|
|
151
|
-
qcshema_objects.append(new_qcschema)
|
|
152
|
-
elif file_path.suffix == '.json':
|
|
153
|
-
if input_params is not None and len(input_params.keys()) > 0:
|
|
154
|
-
warnings.warn('Input parameters were given along with a QcSchema file which contains parameters, using QcSchema parameters as is.')
|
|
155
|
-
with open(file_path, 'r') as f:
|
|
156
|
-
qcshema_objects.append( json.load(f) )
|
|
157
|
-
else:
|
|
158
|
-
raise ValueError(f"File type '{file_path.suffix}' for file '{file_path}' is not supported.")
|
|
159
|
-
|
|
160
|
-
return qcshema_objects
|
|
161
|
-
|
|
162
|
-
@classmethod
|
|
163
|
-
def _check_file_paths( self, input_data: List[str]):
|
|
164
|
-
"""Check the file types and make sure they are supported by our parsers."""
|
|
165
|
-
|
|
166
|
-
warn_task_count = 1000
|
|
167
|
-
if len(input_data) >= warn_task_count:
|
|
168
|
-
warnings.warn(f'Number of tasks is greater than {warn_task_count}.')
|
|
169
|
-
|
|
170
|
-
supported_ext = ['.xyz', '.json']
|
|
171
|
-
prev_ext = None
|
|
172
|
-
for path_str in input_data:
|
|
173
|
-
path = Path(path_str)
|
|
174
|
-
|
|
175
|
-
if not path.exists():
|
|
176
|
-
raise FileNotFoundError(f"File {path_str} does not exist.")
|
|
177
|
-
|
|
178
|
-
if path.suffix not in supported_ext:
|
|
179
|
-
raise ValueError(f"'{path.suffix}' file type is not supported. Please use one of {supported_ext}.")
|
|
180
|
-
|
|
181
|
-
if prev_ext is not None and prev_ext != path.suffix:
|
|
182
|
-
raise ValueError(f"Multiple file types were provided ('{path.suffix}', '{prev_ext}'). Please submit only one file type.")
|
|
183
|
-
else:
|
|
184
|
-
prev_ext = path.suffix
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
@classmethod
|
|
188
|
-
def _new_qcshema( self, input_params: Dict[str,Any], mol: Dict[str,Any], ) -> Dict[str, Any]:
|
|
189
|
-
"""
|
|
190
|
-
Create a new default qcshema object.
|
|
191
|
-
"""
|
|
192
|
-
|
|
193
|
-
self._sanity_check_params(input_params, mol)
|
|
194
|
-
|
|
195
|
-
if input_params.get("driver").lower() == "go":
|
|
196
|
-
copy_input_params = copy.deepcopy(input_params)
|
|
197
|
-
copy_input_params["driver"] = "gradient"
|
|
198
|
-
new_object = {
|
|
199
|
-
"schema_name": "qcschema_optimization_input",
|
|
200
|
-
"schema_version": 1,
|
|
201
|
-
"initial_molecule": mol,
|
|
202
|
-
}
|
|
203
|
-
if copy_input_params.get("go_keywords"):
|
|
204
|
-
new_object["keywords"] = copy_input_params.pop("go_keywords")
|
|
205
|
-
new_object["input_specification"] = copy_input_params
|
|
206
|
-
return new_object
|
|
207
|
-
elif input_params.get("driver").lower() == "bomd":
|
|
208
|
-
copy_input_params = copy.deepcopy(input_params)
|
|
209
|
-
copy_input_params["driver"] = "gradient"
|
|
210
|
-
new_object = {
|
|
211
|
-
"schema_name": "madft_molecular_dynamics_input",
|
|
212
|
-
"schema_version": 1,
|
|
213
|
-
"initial_molecule": mol,
|
|
214
|
-
}
|
|
215
|
-
if copy_input_params.get("bomd_keywords"):
|
|
216
|
-
new_object["keywords"] = copy_input_params.pop("bomd_keywords")
|
|
217
|
-
new_object["input_specification"] = copy_input_params
|
|
218
|
-
return new_object
|
|
219
|
-
else:
|
|
220
|
-
new_object = copy.deepcopy(input_params)
|
|
221
|
-
new_object.update({
|
|
222
|
-
"schema_name": "qcschema_input",
|
|
223
|
-
"schema_version": 1,
|
|
224
|
-
"molecule": mol,
|
|
225
|
-
})
|
|
226
|
-
return new_object
|
|
227
|
-
|
|
228
|
-
@classmethod
|
|
229
|
-
def _sanity_check_params(self, input_params, mol):
|
|
230
|
-
|
|
231
|
-
# QM/MM is not supported for GO, BOMD and Hessian.
|
|
232
|
-
driver = input_params.get("driver",'').lower()
|
|
233
|
-
if driver in ["go", "bomd", "hessian"]:
|
|
234
|
-
if "extras" in mol and "mm_charges" in mol["extras"]:
|
|
235
|
-
raise ValueError(f"'{driver}' does not support QM/MM.")
|
|
236
|
-
|
|
237
|
-
# Top level params
|
|
238
|
-
self._check_dict_for_required_keys(input_params, 'input_params', ['driver', 'model'])
|
|
239
|
-
|
|
240
|
-
# Check Model params
|
|
241
|
-
self._check_dict_for_required_keys(input_params['model'], 'input_params["model"]', ['method', 'basis'])
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
@classmethod
|
|
245
|
-
def _check_dict_for_required_keys(self, input_params: dict, dict_name: str, required_keys: list[str]):
|
|
246
|
-
"""Check dictionary for required keys and if it doesn't have then raise ValueError."""
|
|
247
|
-
|
|
248
|
-
for required_key in required_keys:
|
|
249
|
-
if required_key not in input_params.keys():
|
|
250
|
-
raise ValueError(f"Required key ({required_key}) was not provided in {dict_name}.")
|
|
251
|
-
|
|
252
|
-
@classmethod
|
|
253
|
-
def _xyz_to_qcschema_mol(self, file_data: str ) -> Dict[str, Any]:
|
|
254
|
-
"""
|
|
255
|
-
Convert xyz format to qcschema molecule.
|
|
256
|
-
"""
|
|
257
|
-
|
|
258
|
-
lines = file_data.split("\n")
|
|
259
|
-
if len(lines) < 3 or not lines[0]:
|
|
260
|
-
raise ValueError("Invalid xyz format.")
|
|
261
|
-
n_atoms = int(lines.pop(0))
|
|
262
|
-
comment = lines.pop(0)
|
|
263
|
-
mol = defaultdict(list)
|
|
264
|
-
mol['extras'] = defaultdict(list)
|
|
265
|
-
bohr_to_angstrom = 0.52917721092
|
|
266
|
-
for line in lines:
|
|
267
|
-
if line:
|
|
268
|
-
elements = line.split()
|
|
269
|
-
if len(elements) == 4:
|
|
270
|
-
symbol, x, y, z = elements
|
|
271
|
-
mol["symbols"].append(symbol)
|
|
272
|
-
mol["geometry"] += [float(x)/bohr_to_angstrom, float(y)/bohr_to_angstrom, float(z)/bohr_to_angstrom]
|
|
273
|
-
elif len(elements) == 5:
|
|
274
|
-
symbol, x, y, z, q = elements
|
|
275
|
-
if symbol[0] != '-':
|
|
276
|
-
raise ValueError("Invalid xyz format. Molecular Mechanics atoms requires '-' at the beginning of the atom type.")
|
|
277
|
-
mol["extras"]["mm_symbols"].append(symbol.replace('-', ''))
|
|
278
|
-
mol["extras"]["mm_geometry"] += [float(x)/bohr_to_angstrom, float(y)/bohr_to_angstrom, float(z)/bohr_to_angstrom]
|
|
279
|
-
mol["extras"]["mm_charges"].append(float(q))
|
|
280
|
-
else:
|
|
281
|
-
raise ValueError("Invalid xyz format.")
|
|
282
|
-
else:
|
|
283
|
-
break
|
|
284
|
-
|
|
285
|
-
# Convert defaultdict to dict
|
|
286
|
-
mol = dict(mol)
|
|
287
|
-
mol["extras"] = dict(mol["extras"])
|
|
288
|
-
|
|
289
|
-
if len(mol["symbols"])+len(mol["extras"].get("mm_symbols",[])) != n_atoms:
|
|
290
|
-
raise ValueError("Number of inputs does not match the number of atoms in xyz file.")
|
|
291
|
-
|
|
292
|
-
return mol
|
|
293
|
-
|
|
294
|
-
@classmethod
|
|
295
|
-
def _get_job_class(cls) -> Type[Job]:
|
|
296
|
-
return MicrosoftElementsDftJob
|
|
297
|
-
|
|
298
|
-
@classmethod
|
|
299
|
-
def _create_table_of_contents(cls, input_files: List[str], input_blobs: List[str]) -> Dict[str,Any]:
|
|
300
|
-
"""Create the table of contents for a batched job that contains a description of file and the mapping between the file names and the blob names"""
|
|
301
|
-
|
|
302
|
-
assert len(input_files) == len(input_blobs), "Internal error: number of blobs is not that same as the number of files."
|
|
303
|
-
|
|
304
|
-
toc = []
|
|
305
|
-
for i in range(len(input_files)):
|
|
306
|
-
toc.append(
|
|
307
|
-
{
|
|
308
|
-
"inputFileName": input_files[i],
|
|
309
|
-
"qcschemaBlobName": input_blobs[i],
|
|
310
|
-
}
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
"description": "This files contains the mapping between the xyz file name that were submitted and the qcschema blobs that are used for the calculation.",
|
|
315
|
-
"tableOfContents": toc,
|
|
316
|
-
}
|
|
File without changes
|
|
File without changes
|