# This original code is sourced from:
# https://github.com/SRI-International/QC-App-Oriented-Benchmarks/blob/master/hidden_shift/qiskit/hs_kernel.py
#
# Original repository link:
# https://github.com/SRI-International/QC-App-Oriented-Benchmarks?tab=Apache-2.0-1-ov-file
#
#
# This program is adapted for use as a benchmark in controlled software testing experiments.
# Modifications made to the original code include:
# - Stucture reorganization:
# - Modify the code in the `QuantumCircuit` class
# - Add type hints for better code readability
# - Remove measurements from subcircuits, as they can be added in the main circuit if needed
# - Remove statements for displaying the circuit
# - Remove the input argument $num_qubits$ from the class constructor, as it can be inferred from the length of `hidden_bits`
# - Input validation and error handling:
# - Strictly enforce the length of `hidden_bits` to match an even number of qubits
#
# Copyright [yyyy] [name of copyright owner]
# 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.
'''
Hidden Shift Benchmark Program - Qiskit Kernel
(C) Quantum Economic Development Consortium (QED-C) 2024.
'''
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from typing import List
# ---------- benchmark registration ----------
from ..benchmark_registry import register_benchmark
from pathlib import Path
@register_benchmark(
Path(__file__).stem,
family=Path(__file__).resolve().parent.name,
description="Hidden Shift Benchmark Program",
class_name="HiddenShift",
source={
"repo": "https://github.com/SRI-International/QC-App-Oriented-Benchmarks?tab=Apache-2.0-1-ov-file",
"file": "hidden_shift/qiskit/hs_kernel.py",
"sdk": "Qiskit",
"available_doc": True
},
testability_refactoring=[
"Structure reorganization",
"Input validation"
]
)
def create_hidden_shift(
hidden_bits: list[int],
if_barrier: bool = True
):
return HiddenShift(
hidden_bits=hidden_bits,
if_barrier=if_barrier
)
[docs]
class HiddenShift(QuantumCircuit):
f"""
Hidden Shift Benchmark Program Circuit:
"""
def __init__(
self,
hidden_bits: list[int],
if_barrier: bool = True,
name: str | None = None
):
r"""
Args:
hidden_bits: List of bits representing the hidden shift, i.e.,
:math:`[s_0, s_1, \dots, s_{n-1}]`.
if_barrier : Whether to include barriers in the circuit. Defaults to ``True``.
name: Name of the circuit. Defaults to ``None``.
Raises:
ValueError: If the length of ``hidden_bits`` is not even, as the bent
function used in this benchmark is only achievable for even number of qubits.
"""
self._hidden_bits = hidden_bits
self._num_qubits = len(hidden_bits)
self._if_barrier = if_barrier
if self._num_qubits % 2 != 0:
raise ValueError(
f"The number of qubits must be even ({self._num_qubits});"
f"otherwise, the bent function is not achievable.")
super().__init__(self._num_qubits, name=name or f"HiddenShift")
# Build the circuit
self._build()
[docs]
def Uf_oracle(self, num_qubits: int, hidden_bits: list[int]) -> QuantumCircuit:
r"""
Generate :math:`U_f` oracle where :math:`U_f\ket{x} = f(x)\ket{x}`,
:math:`f(x) = \{-1,1\}`
Arguments:
num_qubits : Number of qubits
hidden_bits : List of bits representing the hidden shift
"""
# Initialize qubits qubits
qr = QuantumRegister(num_qubits)
qc = QuantumCircuit(qr, name="Uf")
# Perform X on each qubit that matches a bit in secret string
#s = ('{0:0'+str(num_qubits)+'b}').format(secret_int)
for i_qubit in range(num_qubits):
if hidden_bits[i_qubit]==1:
qc.x(qr[i_qubit])
for i_qubit in range(0,num_qubits-1,2):
qc.cz(qr[i_qubit], qr[i_qubit+1])
# Perform X on each qubit that matches a bit in secret string
#s = ('{0:0'+str(num_qubits)+'b}').format(secret_int)
for i_qubit in range(num_qubits):
if hidden_bits[i_qubit]==1:
qc.x(qr[i_qubit])
return qc
[docs]
def Ug_oracle(self, num_qubits: int) -> QuantumCircuit:
r"""
Generate :math:`U_g` oracle where :math:`U_g\ket{x} = g(x)\ket{x}`,
:math:`g(x) = f(x+s)`
Arguments:
num_qubits : Number of qubits
"""
# Initialize first n qubits
qr = QuantumRegister(num_qubits)
qc = QuantumCircuit(qr, name="Ug")
for i_qubit in range(0,num_qubits-1,2):
qc.cz(qr[i_qubit], qr[i_qubit+1])
return qc
def _build(self) -> None:
num_qubits = self._num_qubits
hidden_bits = self._hidden_bits
# allocate qubits
qr = QuantumRegister(num_qubits)
qc = QuantumCircuit(qr)
# Start with Hadamard on all input qubits
for i_qubit in range(num_qubits):
qc.h(qr[i_qubit])
if self._if_barrier:
qc.barrier()
# Generate Uf oracle where Uf|x> = f(x)|x>, f(x) = {-1,1}
Uf = self.Uf_oracle(num_qubits, hidden_bits)
qc.append(Uf,qr)
if self._if_barrier:
qc.barrier()
# Again do Hadamard on all qubits
for i_qubit in range(num_qubits):
qc.h(qr[i_qubit])
if self._if_barrier:
qc.barrier()
# Generate Ug oracle where Ug|x> = g(x)|x>, g(x) = f(x+s)
Ug = self.Ug_oracle(num_qubits)
qc.append(Ug,qr)
if self._if_barrier:
qc.barrier()
# End with Hadamard on all qubits
for i_qubit in range(num_qubits):
qc.h(qr[i_qubit])
if self._if_barrier:
qc.barrier()
# collapse the sub-circuit levels used in this benchmark (for qiskit)
qc2 = qc.decompose()
self.compose(qc2, inplace=True)