Spaces:
Runtime error
Runtime error
File size: 5,347 Bytes
91d3e9c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
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)
|