Source code for qolumbina.programs.hidden_subgroup_problem.hidden_shift

# 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)