Skip to content

Commit

Permalink
feat: enable specifying sync/async submission to real machine in esti…
Browse files Browse the repository at this point in the history
…mator
  • Loading branch information
Zhaoyilunnn committed Dec 13, 2024
1 parent bfc7185 commit 0cca5e6
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 15 deletions.
5 changes: 3 additions & 2 deletions quafu/algorithms/ansatz.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class QuantumNeuralNetwork(Ansatz):
"""A Wrapper of quantum circuit as QNN"""

# TODO(zhaoyilun): docs
def __init__(self, num_qubits: int, layers: List[Any], interface="torch", backend="sim"):
def __init__(self, num_qubits: int, layers: List[Any], interface="torch", backend="sim", sync: bool = False):
""""""
# Get transformer according to specified interface
self._transformer = InterfaceProvider.get(interface)
Expand All @@ -154,14 +154,15 @@ def __init__(self, num_qubits: int, layers: List[Any], interface="torch", backen
self._weights = None

self._backend = backend
self._sync = sync
super().__init__(num_qubits)

def __call__(self, inputs):
"""Compute outputs of QNN given input features"""
# pylint: disable=import-outside-toplevel
from quafu.algorithms.estimator import Estimator

estimator = Estimator(self, backend=self._backend)
estimator = Estimator(self, backend=self._backend, sync=self._sync)
return self._transformer.execute(self, inputs, estimator=estimator)

def _build(self):
Expand Down
39 changes: 27 additions & 12 deletions quafu/algorithms/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,26 @@ def execute_circuit(circ: QuantumCircuit, observables: Hamiltonian):
class Estimator:
"""Estimate expectation for quantum circuits and observables"""

def __init__(self, circ: QuantumCircuit, backend: str = "sim", task: Optional[Task] = None, **task_options) -> None:
def __init__(
self,
circ: QuantumCircuit,
backend: str = "sim",
sync: bool = False,
task: Optional[Task] = None,
**task_options,
) -> None:
"""
Args:
circ: quantum circuit.
backend: run on simulator (sim) or real machines (ScQ-PXX)
sync: specify whether to send tasks to real machines synchronously
task: task instance for real machine execution (should be none if backend is "sim")
task_options: options to config a task instance
"""
self._circ = circ
self._circ.get_parameter_grads() # parameter shift currently requires calling this for initialization
self._backend = backend
self._sync = sync
self._task = None
if backend != "sim":
if task is not None:
Expand Down Expand Up @@ -113,16 +122,22 @@ def _run_real_machine(self, observables: Hamiltonian, cache_key: Optional[str] =
for measure_base in measure_basis:
res = self._measure_obs(self._circ, measure_base=measure_base)
self._circ.gates = copy.deepcopy(inputs)
lst_task_id.append(res.taskid)

for tid in lst_task_id:
# retrieve task results
while True:
res = self._task.retrieve(tid)
if res.task_status == "Completed":
exec_res.append(res)
break
time.sleep(0.2)
if self._sync:
# directly add res to exec_res
exec_res.append(res)
else:
# record task id and retrieve later
lst_task_id.append(res.taskid)

if not self._sync:
for tid in lst_task_id:
# retrieve task results
while True:
res = self._task.retrieve(tid)
if res.task_status == "Completed":
exec_res.append(res)
break
time.sleep(0.2)

if cache_key is not None:
# put into cache
Expand Down Expand Up @@ -156,7 +171,7 @@ def _measure_obs(self, qc: QuantumCircuit, measure_base: Optional[List] = None)
elif base == "Y":
qc.rx(pos, np.pi / 2)

res = self._task.send(qc)
res = self._task.send(qc, wait=self._sync)
res.measure_base = measure_base

return res
Expand Down
4 changes: 3 additions & 1 deletion quafu/algorithms/gradients/vjp.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def run_circ(
circ: QuantumCircuit,
params: Optional[List[float]] = None,
backend: str = "sim",
sync: bool = False,
estimator: Optional[Estimator] = None,
):
"""Execute a circuit
Expand All @@ -44,11 +45,12 @@ def run_circ(
circ (QuantumCircuit): circ
params (Optional[List[float]]): params
backend (str): backend
sync (bool): specify whether to submit tasks synchronously when using real machines
estimator (Optional[Estimator]): estimator
"""
obs_list = _generate_expval_z(circ.num)
if estimator is None:
estimator = Estimator(circ, backend=backend)
estimator = Estimator(circ, backend=backend, sync=sync)
if params is None:
params = [g.paras for g in circ.parameterized_gates]
output = [estimator.run(obs, params, cache_key="00") for obs in obs_list]
Expand Down

0 comments on commit 0cca5e6

Please sign in to comment.