Source code for qrisp.interface.virtual_backend
"""
\********************************************************************************
* Copyright (c) 2023 the Qrisp authors
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
"""
from qrisp.interface import BackendClient
[docs]
class VirtualBackend(BackendClient):
"""
This class provides a virtual backend for circuit execution.
Virtual means that the server is running on the same machine as a separate
Python thread. This structure allows setting up convenient wrappers for foreign/
modified circuit dispatching code.
Circuits can be run using ``virtual_backend_instance.run(qc)``.
The function that should be used to run a circuit can be specified during
construction using the ``run_func`` parameter.
Parameters
----------
run_func : function
A function that recieves a QuantumCircuit, an integer specifiying the amount of
shots and a token in the form of a string. It returns the counts as a dictionary
of bitstrings.
name : str, optional
A name for the virtual backend. The default is None.
port : int, optional
The port on which to listen. The default is None.
Examples
--------
We set up a VirtualBackend, which prints the received QuantumCircuit and returns the
results of the QASM simulator. It is required that the run_func specifies a default
value for the `shots` parameter. ::
def run_func(qasm_str, shots = 1000, token = ""):
from qiskit import QuantumCircuit
qiskit_qc = QuantumCircuit.from_qasm_str(qasm_str)
print(qiskit_qc)
from qiskit_aer import AerSimulator
qiskit_backend = AerSimulator()
#Run Circuit on the Qiskit backend
return qiskit_backend.run(qiskit_qc, shots = shots).result().get_counts()
>>> from qrisp.interface import VirtualBackend
>>> example_backend = VirtualBackend(run_func)
>>> from qrisp import QuantumFloat
>>> qf = QuantumFloat(3)
>>> qf[:] = 4
>>> qf.get_measurement(backend = example_backend)
┌─┐
qf.0: ─────┤M├──────
└╥┘┌─┐
qf.1: ──────╫─┤M├───
┌───┐ ║ └╥┘┌─┐
qf.2: ┤ X ├─╫──╫─┤M├
└───┘ ║ ║ └╥┘
cb_0: 1/══════╩══╬══╬═
0 ║ ║
cb_1: 1/═════════╩══╬═
0 ║
cb_2: 1/════════════╩═
{4: 1.0}
"""
[docs]
def __init__(self, run_func, port=None):
from qrisp.interface import BackendServer
self.port = port
if port is None:
self.run_func = run_func
else:
# Create BackendServer
self.backend_server = BackendServer(run_func, "localhost", port=port)
# Run the server (runs in the background)
self.backend_server.start()
# Connect client
super().__init__(api_endpoint="localhost", port=port)
def run(self, qc, shots=None, token=""):
"""
Executes the function run_func specified at object creation.
Parameters
----------
qc : QuantumCircuit
The QuantumCircuit to run.
shots : int, optional
The amount of shots to perform.
Returns
-------
res : dict
A dictionary containing the measurement results.
"""
if self.port is None:
return self.run_func(qc.qasm(), shots, token)
else:
return super().run(qc, shots)