Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/QOverlap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# QOverlap

QOverlap provides a reusable multi-qubit SWAP Test for estimating state overlap.

For pure states, measuring the ancilla in zero with probability P0 gives

|<psi|phi>|^2 = 2 * P0 - 1.

The implementation accepts caller-supplied state-preparation circuits, so it can
compare computational-basis states, variational states, encoded feature states,
or other equal-width preparations without duplicating their construction logic.

Example:

from pyqpanda3.core import QCircuit, H, X
from pyqpanda_alg.QOverlap import SwapTest

def plus_state(qubits):
circuit = QCircuit()
circuit << H(qubits[0])
return circuit

def one_state(qubits):
circuit = QCircuit()
circuit << X(qubits[0])
return circuit

result = SwapTest(
qubits_per_state=1,
prepare_left=plus_state,
prepare_right=one_state,
shots=2048,
).run()

print(result.overlap_squared)

The result object also reports the measured ancilla-zero probability, overlap
magnitude, dominant ancilla bitstring, and shot count.
153 changes: 153 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/QOverlap/SwapTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# 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.

"""Reusable multi-qubit SWAP Test for quantum-state overlap estimation.

For pure states |psi> and |phi>, the ancilla-zero probability is

p(0) = (1 + |<psi|phi>|**2) / 2,

so the squared overlap is 2*p(0)-1. The same circuit estimates Tr(rho*sigma)
for mixed-state inputs prepared by compatible caller circuits.
"""

from __future__ import annotations

from dataclasses import dataclass
import math
from typing import Any, Callable, Optional, Sequence

from pyqpanda3.core import CPUQVM, H, QProg, SWAP


CircuitFactory = Callable[[Sequence[Any]], Any]


@dataclass(frozen=True)
class SwapTestResult:
"""Measurement summary returned by SwapTest.run()."""

overlap_squared: float
overlap: float
zero_probability: float
bitstring: str
shots: int


def overlap_squared_from_zero_probability(zero_probability: float) -> float:
"""Convert ancilla P(0) to the ideal squared state overlap.

Shot noise or hardware noise can push the raw estimator slightly outside
the physical interval. The returned value is therefore clamped to [0, 1].
"""

if isinstance(zero_probability, bool) or not isinstance(
zero_probability, (int, float)
):
raise ValueError("zero_probability must be a finite real number")

zero_probability = float(zero_probability)
if not math.isfinite(zero_probability):
raise ValueError("zero_probability must be a finite real number")
if zero_probability < 0.0 or zero_probability > 1.0:
raise ValueError("zero_probability must be in [0, 1]")

return min(1.0, max(0.0, 2.0 * zero_probability - 1.0))


class SwapTest:
"""Estimate overlap between two equally sized prepared quantum states.

Parameters
----------
qubits_per_state:
Number of qubits in each state register.
prepare_left:
Callable taking the left register and returning its preparation circuit.
prepare_right:
Callable taking the right register and returning its preparation circuit.
shots:
Default number of CPU-simulator shots for run().

The implementation uses one ancilla plus two equal-width state registers.
Each corresponding register pair is joined by a SWAP gate controlled by
the ancilla, giving the standard multi-qubit SWAP Test without imposing a
specific state-preparation method on callers.
"""

def __init__(
self,
qubits_per_state: int,
prepare_left: CircuitFactory,
prepare_right: CircuitFactory,
shots: int = 1024,
):
if isinstance(qubits_per_state, bool) or not isinstance(qubits_per_state, int):
raise ValueError("qubits_per_state must be an integer")
if qubits_per_state <= 0:
raise ValueError("qubits_per_state must be positive")
if not callable(prepare_left) or not callable(prepare_right):
raise ValueError("prepare_left and prepare_right must be callable")
if isinstance(shots, bool) or not isinstance(shots, int) or shots <= 0:
raise ValueError("shots must be a positive integer")

self.qubits_per_state = qubits_per_state
self.prepare_left = prepare_left
self.prepare_right = prepare_right
self.shots = shots

def build_program(self):
"""Build the SWAP-test program and return its logical registers."""

qubits = QProg(1 + 2 * self.qubits_per_state).qubits()
ancilla = qubits[0]
left = qubits[1 : 1 + self.qubits_per_state]
right = qubits[1 + self.qubits_per_state :]

program = QProg()
program << self.prepare_left(left)
program << self.prepare_right(right)
program << H(ancilla)

for left_qubit, right_qubit in zip(left, right):
program << SWAP(left_qubit, right_qubit).control([ancilla])

program << H(ancilla)
return program, ancilla, left, right

def run(self, shots: Optional[int] = None) -> SwapTestResult:
"""Run the SWAP Test on the CPU simulator."""

if shots is None:
shots = self.shots
if isinstance(shots, bool) or not isinstance(shots, int) or shots <= 0:
raise ValueError("shots must be a positive integer")

program, ancilla, _, _ = self.build_program()
machine = CPUQVM()
machine.run(program, shots)
probabilities = machine.result().get_prob_dict([ancilla])

if not probabilities:
raise RuntimeError("SWAP Test returned no ancilla probabilities")

zero_probability = float(probabilities.get("0", 0.0))
overlap_squared = overlap_squared_from_zero_probability(zero_probability)
bitstring = max(probabilities, key=probabilities.get)

return SwapTestResult(
overlap_squared=overlap_squared,
overlap=math.sqrt(overlap_squared),
zero_probability=zero_probability,
bitstring=bitstring,
shots=shots,
)
9 changes: 9 additions & 0 deletions pyqpanda-algorithm/pyqpanda_alg/QOverlap/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""Quantum-state overlap estimation with the SWAP Test."""

from .SwapTest import SwapTest, SwapTestResult, overlap_squared_from_zero_probability

__all__ = [
"SwapTest",
"SwapTestResult",
"overlap_squared_from_zero_probability",
]
109 changes: 55 additions & 54 deletions pyqpanda-algorithm/pyqpanda_alg/__init__.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,55 @@
'''
A Quantum Optimization Algorithm Set, based on pyqpanda.

The **QMengJi** is a collection of fundamental quantum optimization algorithms and
functions that are commonly used in developer's optimization problems.

The QMengJi provides standardized set of tools and building blocks for writing quantum programs.

Some key functions included in the QMengJi are:

Quantum Approximate Optimization Algorithm : This is a quantum algorithm that can be used to search the lowest energy
eigenstate of a Hamiltonian. It is considered to be one of the candidate algorithms for quantum advantage.
Developer can construct object by QAOA(problem, arg1, arg2…) and directly call QAOA.run(args) to optimize their
user-defined problem.

Overall, the QMengJi provides a standardized set of tools for developers, allowing them to optimize functions with
binary variables, such as combinatorial optimization problems, that may have many practical implications.
Developers can use quantum algorithms directly to obtain results without knowing anything about quantum computing, or
build their own suitable quantum circuits to obtain more customized results according to their requirements.It is an
important resource for solving optimization problems and advancing research on quantum optimization algorithms.

'''
'''
pyqpanda-algorithm Python\n
Copyright (C) Origin Quantum 2017-2023\n
Licensed Under Apache Licence 2.0
'''

import warnings
warnings.filterwarnings("ignore", category=SyntaxWarning)

from . import QAOA
# from . import VQE
# from . import HHL
# from . import QAOA
from . import QARM
from . import QKmeans
# from . import QLuoShu
from . import QPCA
# from . import QSolver
from . import QSVM
# from . import extensions
# import warnings

#QFinance
from . import QUBO
from . import QCmp
from . import QAE
from . import QSVD
from . import QSVR
from . import Grover
from . import QmRMR
from . import QSEncode

'''
A Quantum Optimization Algorithm Set, based on pyqpanda.

The **QMengJi** is a collection of fundamental quantum optimization algorithms and
functions that are commonly used in developer's optimization problems.

The QMengJi provides standardized set of tools and building blocks for writing quantum programs.

Some key functions included in the QMengJi are:

Quantum Approximate Optimization Algorithm : This is a quantum algorithm that can be used to search the lowest energy
eigenstate of a Hamiltonian. It is considered to be one of the candidate algorithms for quantum advantage.
Developer can construct object by QAOA(problem, arg1, arg2…) and directly call QAOA.run(args) to optimize their
user-defined problem.

Overall, the QMengJi provides a standardized set of tools for developers, allowing them to optimize functions with
binary variables, such as combinatorial optimization problems, that may have many practical implications.
Developers can use quantum algorithms directly to obtain results without knowing anything about quantum computing, or
build their own suitable quantum circuits to obtain more customized results according to their requirements.It is an
important resource for solving optimization problems and advancing research on quantum optimization algorithms.

'''
'''
pyqpanda-algorithm Python\n
Copyright (C) Origin Quantum 2017-2023\n
Licensed Under Apache Licence 2.0
'''

import warnings
warnings.filterwarnings("ignore", category=SyntaxWarning)

from . import QAOA
# from . import VQE
# from . import HHL
# from . import QAOA
from . import QARM
from . import QKmeans
# from . import QLuoShu
from . import QPCA
# from . import QSolver
from . import QSVM
# from . import extensions
# import warnings

#QFinance
from . import QUBO
from . import QCmp
from . import QAE
from . import QSVD
from . import QSVR
from . import Grover
from . import QOverlap
from . import QmRMR
from . import QSEncode

24 changes: 24 additions & 0 deletions test/QOverlap/Test_swap_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import math

import pytest

from pyqpanda_alg.QOverlap import overlap_squared_from_zero_probability


@pytest.mark.parametrize(
("zero_probability", "expected"),
[(0.5, 0.0), (0.75, 0.5), (1.0, 1.0), (0.4, 0.0)],
)
def test_overlap_squared_from_zero_probability(zero_probability, expected):
assert math.isclose(
overlap_squared_from_zero_probability(zero_probability),
expected,
rel_tol=0.0,
abs_tol=1e-12,
)


@pytest.mark.parametrize("value", [-0.01, 1.01, float("nan"), float("inf")])
def test_overlap_decoder_rejects_invalid_probability(value):
with pytest.raises(ValueError):
overlap_squared_from_zero_probability(value)
39 changes: 20 additions & 19 deletions test/pytest.ini
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
[pytest]
testpaths =
QAlgBase
QAOA
QRAM
QPCA
QSVM


python_files =
test_*.py
Test_*.py

addopts = -vs --alluredir=./allure-results --clean-alluredir


log_level = INFO


[pytest]
testpaths =
QAlgBase
QAOA
QOverlap
QRAM
QPCA
QSVM


python_files =
test_*.py
Test_*.py

addopts = -vs --alluredir=./allure-results --clean-alluredir


log_level = INFO


log_format = %(asctime)s - %(name)s - %(levelname)s - %(message)s