microsoft/qdk

Public

mirrored from https://github.com/microsoft/qdkAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.28.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

source/pip/qsharp/openqasm/_run.py

195lines · modecode

1# Copyright (c) Microsoft Corporation.
2# Licensed under the MIT License.
3
4from time import monotonic
5from typing import Any, Callable, cast, Dict, List, Optional, Tuple, Union
6from .._fs import read_file, list_directory, resolve
7from .._http import fetch_github
8from .._native import QasmError, Output, run_qasm_program # type: ignore
9from .._qsharp import (
10 BitFlipNoise,
11 DepolarizingNoise,
12 PauliNoise,
13 PhaseFlipNoise,
14 ShotResult,
15 StateDump,
16 StateDumpData,
17 get_interpreter,
18 ipython_helper,
19 python_args_to_interpreter_args,
20 NoiseConfig,
21)
22from .. import telemetry_events
23from ._ipython import display_or_print
24
25
26def run(
27 source: Union[str, Callable],
28 shots: int = 1024,
29 *args: Any,
30 on_result: Optional[Callable[[ShotResult], None]] = None,
31 save_events: bool = False,
32 noise: Optional[
33 Union[
34 Tuple[float, float, float],
35 PauliNoise,
36 BitFlipNoise,
37 PhaseFlipNoise,
38 DepolarizingNoise,
39 NoiseConfig,
40 ]
41 ] = None,
42 qubit_loss: Optional[float] = None,
43 as_bitstring: bool = False,
44 **kwargs: Any,
45) -> List[Any]:
46 """
47 Runs the given OpenQASM program for the given number of shots.
48 Either a full program or a callable with arguments must be provided.
49 Each shot uses an independent instance of the simulator.
50
51 :param source: An OpenQASM program. Alternatively, a callable can be provided,
52 which must be an already imported global callable.
53 :type source: str or Callable
54 :param shots: The number of shots to run. Defaults to ``1024``.
55 :type shots: int
56 :param *args: The arguments to pass to the callable, if one is provided.
57 :param on_result: A callback function that will be called with each result.
58 Only used when a callable is provided.
59 :type on_result: Callable
60 :param save_events: If true, the output of each shot will be saved. If false, they will be printed.
61 Only used when a callable is provided.
62 :type save_events: bool
63 :param noise: The noise to use in simulation.
64 :type noise: Union[Tuple[float, float, float], PauliNoise, BitFlipNoise, PhaseFlipNoise, DepolarizingNoise, NoiseConfig]
65 :param qubit_loss: The probability of qubit loss in simulation.
66 :type qubit_loss: float
67 :param as_bitstring: If true, the result registers will be converted to bitstrings.
68 :type as_bitstring: bool
69 :param **kwargs: Additional keyword arguments for compiling the source program. Common options:
70
71 - ``name`` (str): The name of the circuit. This is used as the entry point for the program.
72 - ``target_profile`` (TargetProfile): The target profile to use for code generation.
73 - ``search_path`` (str): The optional search path for resolving file references.
74 - ``output_semantics`` (OutputSemantics): The output semantics for the compilation.
75 - ``seed`` (int): The seed to use for the random number generator.
76 :return: A list of results or runtime errors. If ``save_events`` is true, a list of ``ShotResult`` values is returned.
77 :rtype: List[Any]
78 :raises QasmError: If there is an error generating, parsing, or analyzing the OpenQASM source.
79 :raises QSharpError: If there is an error interpreting the input.
80 :raises ValueError: If the number of shots is less than 1.
81 :raises QasmError: If ``on_result`` or ``save_events`` are used when running OpenQASM programs.
82 """
83
84 ipython_helper()
85
86 if shots < 1:
87 raise ValueError("The number of shots must be greater than 0.")
88
89 telemetry_events.on_run_qasm(
90 shots, noise=noise is not None, qubit_loss=qubit_loss is not None
91 )
92 start_time = monotonic()
93
94 results: List[ShotResult] = []
95
96 def on_save_events(output: Output) -> None:
97 # Append the output to the last shot's output list
98 results[-1]["events"].append(output)
99 if output.is_matrix():
100 results[-1]["matrices"].append(output)
101 elif output.is_state_dump():
102 dump_data = cast(StateDumpData, output.state_dump())
103 results[-1]["dumps"].append(StateDump(dump_data))
104 elif output.is_message():
105 results[-1]["messages"].append(str(output))
106
107 callable = None
108 source_str: Optional[str] = None
109 if isinstance(source, Callable) and hasattr(source, "__global_callable"):
110 args = python_args_to_interpreter_args(args)
111 callable = source.__global_callable
112 elif isinstance(source, str):
113 source_str = source
114
115 noise_config = None
116 if isinstance(noise, NoiseConfig):
117 noise_config = noise
118 noise = None
119
120 if callable:
121 for _ in range(shots):
122 results.append(
123 {
124 "result": None,
125 "events": [],
126 "matrices": [],
127 "dumps": [],
128 "messages": [],
129 }
130 )
131 run_results = get_interpreter().run(
132 source_str,
133 on_save_events if save_events else display_or_print,
134 noise_config,
135 noise,
136 qubit_loss=qubit_loss,
137 callable=callable,
138 args=args,
139 )
140 results[-1]["result"] = run_results
141
142 if on_result:
143 on_result(results[-1])
144
145 if not save_events:
146 # If we are not saving events, we can just return the results
147 # as a list of results.
148 results = [result["result"] for result in results]
149 else:
150 # running the QASM program in isolation means we can't use the
151 # interpreter to run the program, so we can't cache the compilation
152 # results. This means we need to compile the program for each
153 # shot, or we push the shots into the QASM program and compile it once.
154 #
155 # This breaks the output streaming and event saving.
156 if on_result or save_events:
157 raise QasmError(
158 "The `on_result` and `save_events` parameters are not supported when running QASM programs."
159 )
160
161 if source_str is None:
162 raise QasmError(
163 "source must be a string or a callable with __global_callable attribute"
164 )
165
166 # remove any entries from kwargs with a None key or None value
167 kwargs = {k: v for k, v in kwargs.items() if k is not None and v is not None}
168
169 if "search_path" not in kwargs:
170 kwargs["search_path"] = "."
171
172 kwargs["shots"] = shots
173
174 results = run_qasm_program(
175 source_str,
176 display_or_print,
177 noise_config,
178 noise,
179 qubit_loss,
180 read_file,
181 list_directory,
182 resolve,
183 fetch_github,
184 **kwargs,
185 )
186
187 durationMs = (monotonic() - start_time) * 1000
188 telemetry_events.on_run_qasm_end(durationMs, shots)
189
190 if as_bitstring:
191 from ._utils import as_bitstring as convert_to_bitstring
192
193 results = convert_to_bitstring(results)
194
195 return results
196