Source code for dc_qiskit_algorithms.FlipFlopQuantumRam

# Copyright 2018 Carsten Blank
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import math
from typing import List, Union

from bitstring import BitArray
from qiskit import QuantumRegister, QuantumCircuit
from qiskit.circuit import Qubit

from .UniformRotation import cnry


[docs]class FFQramEntry(object): """ An DB entry of the FF QRAM scheme """ def __init__(self): """ Creates an entry with binary data & label as well as an (optional) amplitude """ self.probability_amplitude = 0.0 # type: float self.data = bytes() # type: bytes self.label = bytes() # type: bytes
[docs] def get_bits(self, bin_length=None): # type: (FFQramEntry) -> str """ Get the binary bit representation of data and label for state basis identification :return: a bit array """ b = self.data + self.label ba = BitArray(b) ba = ba.bin.lstrip('0') ba = ba.zfill(bin_length) if bin_length is not None else ba return ba
[docs] def bus_size(self): # type: (FFQramEntry) -> int """ Returns needed bus size for this entry :return: the length """ return len(self.get_bits(1))
[docs] def add_to_circuit(self, qc, bus, register): # type: (FFQramEntry, QuantumCircuit, Union[QuantumRegister, list], Qubit) -> QuantumCircuit """ This method adds the gates to encode this entry into the circuit :param qc: quantum circuit to apply the entry to :param bus: the registers for the bus :param register: the target register for the amplitude :return: the applied circuit """ theta = math.asin(self.probability_amplitude) if theta == 0: return qc bus_register = [] # type: List[Qubit] if isinstance(bus, QuantumRegister): bus_register = list(bus) else: bus_register = bus ba = self.get_bits(len(bus_register)) for i, b in enumerate(reversed(ba)): if b == "0": qc.x(bus_register[i]) cnry(qc, theta, bus_register, register) for i, b in enumerate(reversed(ba)): if b == "0": qc.x(bus_register[i]) return qc
def __str__(self): return "FFQramEntry(%.8f, %s)" % (self.probability_amplitude, self.get_bits().bin) @staticmethod def _count_set_bits(b): # type: (bytes) -> int """ Returns the number of ones in the byte array :param b: the data :return: the count """ raise DeprecationWarning("This method is as it stands not functional... there is no way to reconcile this.")
[docs]class FFQramDb(List[FFQramEntry]): """ The DB object with methods to create circuits """
[docs] def bus_size(self): # type: (FFQramDb) -> int """ From all entries get the maximum needed bus size :return: the bus size for the DB """ return max([e.bus_size() for e in self])
[docs] def add_to_circuit(self, qc, bus, register): # type: (FFQramDb, QuantumCircuit, Union[QuantumRegister, List[Qubit]], Qubit) -> None """ Add the DB to the circuit. :param qc: the quantum circuit :param bus: the bus register :param register: the target register for the amplitudes :return: the circuit after DB being applied """ for entry in self: entry.add_to_circuit(qc, bus, register)
[docs] def add_entry(self, pa, data, label): # type: (FFQramDb, float, bytes, bytes) -> None """ Add an entry to the (classical representation of) the DB. :param pa: probability amplitude :param data: binary representation of data :param label: binary representation of the label """ entry = FFQramEntry() entry.probability_amplitude = pa entry.data = data entry.label = label self.append(entry)
[docs] def add_entry_int(self, pa, data, label): # type: (FFQramDb, float, int, int) -> None """ Add an entry to the (classical representation of) the DB. :param pa: probability amplitude :param data: the integer value of the data :param label: the integer value of the label """ raise DeprecationWarning("This method is as it stands not functional... there is no way to reconcile this.")
[docs]def add_vector(db, vec): # type: (FFQramDb, List[complex]) -> None """ Add a vector to the DB. It makes sense to give an empty DB. :param db: The FFQRAM DB :param vec: the vector to be added """ import numpy as np vector = np.asarray(vec) l2_norm = np.linalg.norm(vector) unit_vector = vector / l2_norm number_of_bytes = int(np.ceil(np.log2(len(vector))) // 8 + 1) for i, v in enumerate(unit_vector): if abs(v) > 1e-6: label_as_bytes = (i).to_bytes(number_of_bytes, byteorder='big') db.add_entry(v, b'', label_as_bytes)