Skip to content

Commit

Permalink
feat(protocols): add EntanglementProtocol
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrorrivero committed Jun 6, 2021
1 parent 6d7d25e commit 3af9290
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 12 deletions.
4 changes: 2 additions & 2 deletions qrand/platforms/qiskit/platform.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## _____ _____
## | __ \| __ \ AUTHOR: Pedro Rivero
## | |__) | |__) | ---------------------------------
## | ___/| _ / DATE: May 29, 2021
## | ___/| _ / DATE: June 6, 2021
## | | | | \ \ ---------------------------------
## |_| |_| \_\ https://github.com/pedrorrivero
##
Expand Down Expand Up @@ -99,7 +99,7 @@ def provider(self, provider: Optional[Provider]) -> None:
@staticmethod
def default_backend_filter(b: Backend) -> bool:
config: BackendConfiguration = b.configuration()
return config.memory and not config.simulator
return config.memory and not config.simulator and config.n_qubits > 2

def create_circuit(self, num_qubits: int) -> QiskitCircuit:
return QiskitCircuit(num_qubits)
Expand Down
148 changes: 138 additions & 10 deletions qrand/protocols/entanglement.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## _____ _____
## | __ \| __ \ AUTHOR: Pedro Rivero
## | |__) | |__) | ---------------------------------
## | ___/| _ / DATE: May 17, 2021
## | ___/| _ / DATE: June 6, 2021
## | | | | \ \ ---------------------------------
## |_| |_| \_\ https://github.com/pedrorrivero
##
Expand All @@ -20,24 +20,152 @@
## See the License for the specific language governing permissions and
## limitations under the License.

from typing import Literal
from typing import List, Literal, Optional, Tuple

from ..errors import raise_not_implemented_error
from ..platforms.factory import QuantumFactory
from ..helpers import (
ALPHABETS,
validate_natural,
validate_numeral,
validate_type,
)
from ..platforms import (
QuantumBackend,
QuantumCircuit,
QuantumFactory,
QuantumJob,
)
from .protocol import BareQuantumProtocol
from .result import ProtocolResult
from .result import BasicResult


###############################################################################
## ENTANGLEMENT PROTOCOL
###############################################################################
class EntanglementProtocol(BareQuantumProtocol):
def __init__(self) -> None:
raise_not_implemented_error("EntanglementProtocol", "HadamardProtocol")
"""
QRNG protocol with entanglement for public randomness testing [1]_.
Simple idealistic quantum entanglement based protocol for quantum random
number generation allowing a trusted third party to publicly perform
arbitrarily complex tests of randomness without any violation of the
secrecy of the generated bit sequences. The protocol diminishes also an
average time of the randomness testing (thus enabling arbitrary shortening
of this time with increasing number of entangled qubits).
Parameters
----------
max_bits: int, optional
The maximum number of usable bits to retrieve.
purify: int, default: True
Whether to discard odd parity measurements (even parity expected).
Attributes
----------
max_bits: int, optional
The maximum number of usable bits to retrieve.
purify: int
Whether to discard odd parity measurements (even parity expected).
Methods
-------
run(factory: QuantumFactory) -> BasicResult
Run QRNG protocol.
verify() -> Literal[False]
Verify protocol execution.
References
----------
.. [1] Jacak, J.E., Jacak, W.A., Donderowicz, W.A. et al. Quantum random
number generators with entanglement for public randomness testing.
Sci Rep 10, 164 (2020). https://doi.org/10.1038/s41598-019-56706-2
"""

def __init__(
self, max_bits: Optional[int] = None, purify: bool = True
) -> None:
self.max_bits: Optional[int] = max_bits
self.purify: bool = purify

############################### PUBLIC API ###############################
def run(self, factory: QuantumFactory) -> ProtocolResult:
pass
@property
def max_bits(self) -> Optional[int]:
"""
The maximum number of bits to retrieve.
"""
return self._max_bits

@max_bits.setter
def max_bits(self, max_bits: Optional[int]) -> None:
if max_bits is not None:
validate_natural(max_bits, zero=False)
self._max_bits: Optional[int] = max_bits

@property
def purify(self) -> bool:
"""
Whether to discard odd parity measurements (even parity expected).
"""
return self._purify

@purify.setter
def purify(self, purify: bool) -> None:
validate_type(purify, bool)
self._purify: bool = purify

def run(self, factory: QuantumFactory) -> BasicResult:
validate_type(factory, QuantumFactory)
backend: QuantumBackend = factory.retrieve_backend()
num_qubits, num_measurements = self._partition_job(backend)
circuit: QuantumCircuit = factory.create_circuit(num_qubits)
self._assemble_quantum_circuit(circuit)
job: QuantumJob = factory.create_job(
circuit, backend, num_measurements
)
measurements: List[str] = job.execute()
return self._parse_measurements(measurements)

def verify(self) -> Literal[False]:
pass
return False

############################### PRIVATE API ###############################
@staticmethod
def _assemble_quantum_circuit(circuit: QuantumCircuit) -> None:
validate_type(circuit, QuantumCircuit)
for q in range(1, circuit.num_qubits):
circuit.h(q)
circuit.cx(q, 0)
circuit.measure(q)
circuit.measure(0)

@staticmethod
def _check_even_parity(measurement: str) -> bool:
return measurement.count("1") % 2 == 0

def _parse_measurements(self, measurements: List[str]) -> BasicResult:
validate_type(measurements, list)
num_bits = len(measurements[0])
bit_sequences: List[str] = [""] * num_bits
for m in measurements:
validate_numeral(m, ALPHABETS["BINARY"])
if self.purify and not self._check_even_parity(m):
continue
for b in range(num_bits):
bit_sequences[b] += m[b]
bitstring: str = ""
validation_token: str = bit_sequences.pop(0)
_ = bit_sequences.pop()
for s in bit_sequences:
bitstring += s
return BasicResult(bitstring, validation_token)

def _partition_job(self, backend: QuantumBackend) -> Tuple[int, int]:
validate_type(backend, QuantumBackend)
if backend.max_qubits < 3:
raise RuntimeError(
"EntanglementProtocol needs at least three qubits to run."
)
if self.max_bits:
num_qubits: int = min(self.max_bits + 2, backend.max_qubits)
num_measurements: int = self.max_bits // (num_qubits - 2)
return num_qubits, min(num_measurements, backend.max_measurements)
return backend.max_qubits, backend.max_measurements

0 comments on commit 3af9290

Please sign in to comment.