ashutosh1919's picture
Adding Perceptron and its simulation demo notebook
91d3e9c
raw
history blame contribute delete
No virus
5.35 kB
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)