Source code for qpu.ibm.cryptography.trng

from typing import Dict, List

from qiskit import IBMQ, Aer, QuantumCircuit, assemble, execute, transpile
from qiskit.providers.ibmq import IBMQBackend
from qiskit.providers.ibmq.exceptions import IBMQAccountCredentialsNotFound  # , IBMQAccountError
from qiskit.result.result import Result
from qiskit.visualization import plot_histogram

SortedBackendList = List[IBMQBackend]


[docs]def generate(bits: int = 5) -> QuantumCircuit: # Create a Quantum Circuit acting on the q register circuit = QuantumCircuit(bits, bits) # Add a H gate on qubit i (50/50 chance) for i in range(bits): circuit.h(i) # Map the quantum measurement to the classical bits circuit.measure(range(bits), range(bits)) return circuit
[docs]def simulate(circuit: QuantumCircuit, steps: int = 8000) -> Result: # Use Aer's qasm_simulator simulator = Aer.get_backend('qasm_simulator') # Execute the circuit on the qasm simulator job = execute(circuit, simulator, shots=steps) # Grab and return results from the job return job.result()
[docs]def _get_qpu_candidates(backends: List[IBMQBackend], circuit: QuantumCircuit) -> SortedBackendList: qpus = {} # Get all backends that we can execute for i, backend in enumerate(backends): # Is it a simulator? if 'simulator' in backend.name(): continue # Enough qubits? if len(backend.properties().qubits) < circuit.n_qubits: continue # Enough remaining jobs? if backend.remaining_jobs_count() == 0: continue # TODO: Is the required entanglement available? qpus[i] = backend.status().pending_jobs sorted_qpus = sorted(qpus.items(), key=lambda item: item[1]) return [backends[qpuinfo[0]] for qpuinfo in sorted_qpus]
[docs]def _run(backend: IBMQBackend, circuit: QuantumCircuit) -> Result: qobj = assemble(transpile(circuit, backend=backend), backend=backend) # TODO: configure amount of steps job = backend.run(qobj) return backend.retrieve_job(job.job_id()).result()
# TODO: Convert to async function
[docs]def run(circuit: QuantumCircuit, api_key: str = None, steps: int = 1) -> Result: # TODO: Think about moving the api_key to __init__ after converting this to a class # Use stored or supplied token try: IBMQ.disable_account() except IBMQAccountCredentialsNotFound: pass if api_key is None: provider = IBMQ.load_account() else: provider = IBMQ.enable_account(api_key) # TODO: fetch backends in __init__ (add refresh timer) # Fetch backends and find available qpu with enough qubits and least load backends = provider.backends() # Fetch qpus with least load and try it candidates = _get_qpu_candidates(backends, circuit) if len(candidates) == 0: raise RuntimeError('No matching qpu found (either no jobs available or unmappable circuit)') for backend in _get_qpu_candidates(backends, circuit): try: # Create qobj and run it on qpu result = _run(backend, circuit) break except Exception: # Something failed, try the next qpu continue # no qpu found that works :( raise RuntimeError('No qpu available that can handle the circuit') # Disable account IBMQ.disable_account() return result
[docs]def getCircuitAscii(circuit: QuantumCircuit) -> str: # Draw the circuit return circuit.draw()
[docs]def getResult(circuit: QuantumCircuit, result: Result) -> Dict[str, int]: return result.get_counts(circuit)
[docs]def plotResult(circuit: QuantumCircuit, result: Result) -> None: plot_histogram(result.get_counts(circuit), bar_labels=False).show()