Spaces:
Runtime error
Runtime error
from typing import Dict | |
from qiskit import QuantumCircuit, Aer, execute | |
from quantum_perceptron.utils import ( | |
assert_negative, | |
assert_bits, | |
create_hypergraph_state, | |
get_vector_from_int | |
) | |
class Perceptron: | |
def __init__(self, | |
num_qubits: int, | |
weight: int = 1, | |
input: int = 1): | |
""" | |
This class creates a quantum perceptron instance which has | |
capability calculate input * weight. Note that we are not applying | |
any non-linearity. Our perceptron design is as per | |
https://arxiv.org/pdf/1811.02266.pdf | |
Args: | |
num_qubits: `int` denoting number of qubits in perceptron | |
weight: `int` denoting the weight of the perceptron. | |
input: `int` denoting the data to input to the perceptron. | |
""" | |
self.num_qubits = num_qubits | |
assert self.num_qubits > 0, "Number qubits must be positive" | |
assert_negative(weight) | |
self.weight = weight | |
assert_negative(input) | |
self.input = input | |
assert_bits(self.weight, self.num_qubits) | |
assert_bits(self.input, self.num_qubits) | |
self.build_flag = False | |
self.build_circuit() | |
def Ui(self): | |
""" | |
Sub-circuit to transform input data. | |
""" | |
if not self.build_flag: | |
raise RuntimeError("Ui() cannot be called independently.") | |
Ui = QuantumCircuit(self.num_qubits) | |
# Applying hadamard to first num_qubits | |
for q in range(self.num_qubits): | |
Ui.h(q) | |
# Extracting vectors for input | |
input_vector = get_vector_from_int(self.input, self.num_qubits) | |
# Applying hypergraph state corresponding to input. | |
Ui = create_hypergraph_state(Ui, | |
input_vector, | |
self.num_qubits) | |
Ui = Ui.to_gate() | |
Ui.name = "U_i" | |
return Ui | |
def Uw(self): | |
""" | |
Sub-circuit to transform weight data. | |
""" | |
if not self.build_flag: | |
raise RuntimeError("Ui() cannot be called independently.") | |
Uw = QuantumCircuit(self.num_qubits) | |
# Extracting vectors for weight | |
input_vector = get_vector_from_int(self.weight, self.num_qubits) | |
# Applying hypergraph state corresponding to weight. | |
Uw = create_hypergraph_state(Uw, | |
input_vector, | |
self.num_qubits) | |
# Applying hadamard to first num_qubits | |
for q in range(self.num_qubits): | |
Uw.h(q) | |
# Applying X gate to first num_qubits | |
for q in range(self.num_qubits): | |
Uw.x(q) | |
Uw = Uw.to_gate() | |
Uw.name = "U_w" | |
return Uw | |
def build_circuit(self): | |
""" | |
Build quantum circuit corresponding to single perceptron combining | |
input data and weight of the perceptron. | |
""" | |
# Creating circuit with num_qubits + 1 (ancilla) qubit. | |
self.circuit = QuantumCircuit(1 + self.num_qubits, 1) | |
def toggle_build_flag(): | |
""" | |
Toggle the build circuit flag. Used to monitor Ui and Uf circuits | |
to ensure that those functions are not called seperately but from | |
the `build_circuit()` function. | |
""" | |
self.build_flag = not self.build_flag | |
# Append Ui for processing input | |
toggle_build_flag() | |
# self.Ui() | |
self.circuit.append( | |
self.Ui(), | |
list(range(self.num_qubits)) | |
) | |
toggle_build_flag() | |
# Append Uf for processing input | |
toggle_build_flag() | |
self.circuit.append( | |
self.Uw(), | |
list(range(self.num_qubits)) | |
) | |
toggle_build_flag() | |
# Toffoli gate at the end with target as ancilla qubit | |
self.circuit.mcx( | |
control_qubits=list(range(self.num_qubits)), | |
target_qubit=self.num_qubits | |
) | |
# Measure the last qubit. | |
self.circuit.measure(self.num_qubits, 0) | |
def measure_circuit(self, num_iters: int = 1000) -> Dict[str, int]: | |
""" | |
Measure the perceptron and get the counts of the final results. | |
Args: | |
num_iters: `int` denoting number of iterations to execute circuit. | |
Returns: `dict` containing the measurement frequencies. | |
""" | |
if not hasattr(self, 'circuit'): | |
raise RuntimeError("The circuit hasn't yet built.", | |
"Please call build_circuit() first.") | |
backend = Aer.get_backend('qasm_simulator') | |
# Execute the circuit | |
job = execute(self.circuit, backend, shots=num_iters) | |
# Get result and counts | |
result = job.result() | |
counts = result.get_counts(self.circuit) | |
return dict(counts) | |
def save_circuit_image(self, | |
file_path: str, | |
output_format: str = "mpl"): | |
""" | |
Save circuit to the image file. | |
""" | |
if not hasattr(self, 'circuit'): | |
raise RuntimeError("The circuit hasn't yet built.", | |
"Please call build_circuit() first.") | |
self.circuit.draw(output=output_format, filename=file_path) | |