Fundamental Algorithms
Overview
The unitarylab_algorithms.fundamental_algorithm package provides the core quantum primitives that form the foundation of more advanced algorithms:
| Algorithm | Class | Purpose |
|---|---|---|
| Grover Search | GroverAlgorithm | Quadratic speedup for unstructured search |
| Quantum Phase Estimation | QPEAlgorithm | Extract eigenphases of a unitary operator |
| Amplitude Amplification | AmplitudeAmplificationAlgorithm | Boost the measurement probability of the target state |
| Quantum Amplitude Estimation (QAE) | AmplitudeEstimationAlgorithm | Estimate the amplitude of the target state |
| Hadamard Test | HadamardTestAlgorithm | Estimate expectation values and state overlap |
| Hadamard Transform | HadamardTransformAlgorithm | -qubit global Hadamard transform |
status indicates whether the call completed normally; the accuracy of estimation-type algorithms’ results should be judged via their error, probability, or estimate fields. The status of amplitude amplification additionally reflects whether the target probability exceeds the initial probability. See the corresponding section for each algorithm’s specific determination method.
Grover Search
Background
Grover’s algorithm finds a target in an unsorted database of entries using oracle queries, compared to queries required classically. It is the optimal algorithm for unstructured quantum search, and also serves as an important subroutine in many other algorithms.
The algorithm achieves amplification by iterating the Grover diffusion operator (inversion about the mean) together with an Oracle that flips the phase of the target state; the number of iterations is automatically computed from the initial success probability .
Import
from unitarylab_algorithms import GroverAlgorithm.run() Parameters
def run(self, n: int, target: str, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| Parameter | Type | Default | Description |
|---|---|---|---|
n | int | — (required) | Number of qubits in the data register |
target | str | — (required) | Target state as a binary string (e.g., '101' for 3 qubits) |
Return Value
{
'status': 'ok', # Always 'ok'; does not reflect true search success/failure, see note above
'circuit_path': '/path/to/grover_algorithm_circuit.svg',
'plot': [{'format': 'txt', 'filename': 'grover_algorithm_result.txt'}],
'circuit': <Circuit>,
'Amplified target-state probability': 0.9453,
'Result': '101', # The bit string actually measured with highest probability -- compare with target to determine true success/failure
}Example
from unitarylab_algorithms import GroverAlgorithm
algo = GroverAlgorithm()
result = algo.run(n=3, target='101')
is_really_success = (result['Result'] == '101') # True success/failure determination; do not rely on result['status']
print(is_really_success)Quick Demo
from unitarylab_algorithms.fundamental_algorithm.grover.algorithm import test
test(n=3, target='101')Notes
status='ok'indicates the call completed; to determine whether the target was hit, compareresult['Result']with thetargetyou passed in.- The length of
targetshould in principle equaln(the web frontend’sparameters.jsonstates this as well), but the Python API performs no explicit length validation — a length mismatch will not raise a clearValueError; instead it will trigger a low-level error or produce an unexpected circuit when building the multi-controlled Oracle circuit (mcx). Be sure the two match.
Quantum Phase Estimation (QPE)
Background
QPE extracts the eigenphase of a unitary operator , where . With ancilla qubits, the phase estimation precision is .
QPE is a key subroutine in Shor’s algorithm, HHL, and quantum chemistry simulation.
Import
from unitarylab_algorithms import QPEAlgorithm.run() Parameters
def run(self, U: Circuit, d: int,
prepare_target: Optional[Circuit] = None, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| Parameter | Type | Default | Description |
|---|---|---|---|
U | Circuit | — (required) | Unitary operator circuit whose eigenphase is to be estimated |
d | int | — (required) | Number of phase register qubits (precision ) |
prepare_target | Circuit | None | None | Circuit preparing the eigenstate (defaults to ); if provided, its qubit count must match U, otherwise a ValueError is raised |
Building the QPE Circuit Directly
QPEAlgorithm also provides a utility method for embedding QPE into a larger circuit:
from unitarylab import Circuit
from unitarylab_algorithms import QPEAlgorithm
U = Circuit(1)
U.z(0)
algo = QPEAlgorithm()
qpe_circuit = algo.build_qpe_circuit(U=U, d=4)Return Value
{
'status': 'ok', # Indicates the estimation process has completed
'circuit_path': '/path/to/quantum_phase_estimation_algorithm_circuit.svg',
'plot': [{'format': 'txt', 'filename': 'quantum_phase_estimation_algorithm_result.txt'}],
'circuit': <Circuit>,
'Estimated phase': 0.125,
'Best phase bit string': '0010',
'Best phase probability': 0.98,
'Computation time (s)': 0.0123,
'Phase probabilities': [('0010', 0.98), ('0011', 0.01), ('0001', 0.005)], # The top 3 candidate phases by probability
}Example
from unitarylab.core import Circuit
from unitarylab_algorithms import QPEAlgorithm
# The T gate has eigenphase π/4, i.e. φ = 1/8 = 0.125 in units of 2π
U = Circuit(1)
U.t(0)
algo = QPEAlgorithm()
result = algo.run(U=U, d=4)
print(result['Estimated phase']) # Approximately 0.125Quick Demo
from unitarylab_algorithms.fundamental_algorithm.qpe.algorithm import test
test(p=0.25, n=3)Notes
status='ok'indicates the estimation process completed; assess precision by comparingEstimated phasewith the theoretical value.- The module-level
test(p, n)function’sprepresents the eigenphase (as a fraction in units of ): the T gate corresponds top=0.125, and the S gate corresponds top=0.25. Alternatively, you can build the unitary circuitUdirectly as shown in the example above.
Amplitude Amplification
Background
Amplitude amplification is a generalization of Grover’s algorithm: given a state preparation unitary and an oracle that marks the “good” states, it amplifies the amplitude of the good states by repeatedly applying a Grover-like reflection operator. The number of iterations is automatically inferred from the initial success probability , or can be specified manually.
Import
from unitarylab_algorithms import AmplitudeAmplificationAlgorithm.run() Parameters
def run(self, U: Circuit, good_zero_qubits: List[int], p: float,
reps: Optional[int] = None, backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| Parameter | Type | Default | Description |
|---|---|---|---|
U | Circuit | — (required) | State preparation circuit (excluding the ancilla qubit) |
good_zero_qubits | List[int] | — (required) | Qubit indices that must be in the target state |
p | float | — (required) | Initial success probability; when reps=None, used to automatically compute the iteration count, in which case must hold, otherwise a ValueError is raised; regardless of whether reps is explicitly passed, it is used for log display and the final status determination (target_prob > p) |
reps | int | None | None | Manually specified iteration count (overrides the -based automatic calculation when provided; in this case p is no longer constrained by , but still participates in the final status determination, i.e. target_prob > p) |
Return Value
This algorithm is the only one among the 6 algorithms in this package whose top-level status genuinely reflects success or failure (is_success = target_prob > p):
{
'status': 'ok', # Genuinely reflects whether the amplified target-state probability actually exceeds the initial probability p
'circuit_path': '/path/to/amplitude_amplification_algorithm_circuit.svg',
'plot': [{'format': 'txt', 'filename': 'amplitude_amplification_algorithm_result.txt'}],
'circuit': <Circuit>,
'Amplified Target Probability': 0.98,
'Initial Success Probability': 0.1,
'Repetitions': 3,
'Computation Time (s)': 0.0234,
'Data register size': 2,
}Example
from unitarylab_algorithms import AmplitudeAmplificationAlgorithm
algo = AmplitudeAmplificationAlgorithm()
result = algo.run(U=my_circuit, good_zero_qubits=[0], p=0.1, reps=3)
print(result['status'])Quick Demo
from unitarylab_algorithms.fundamental_algorithm.amplitude_amplification.algorithm import test
test(p=0.1, reps=3)Notes
pis used by the algorithm to compute the iteration count only whenreps=None, in which case must hold; oncerepsis explicitly passed,ponly participates as the “initial probability” in log display and the finalstatusdetermination (target_prob > p), and no longer affects the iteration count itself.- Unlike algorithms such as Grover / QPE / Hadamard Transform, this algorithm’s
statuscan safely be used in business logic to judge the true amplification effect.
Quantum Amplitude Estimation (QAE)
Background
Quantum Amplitude Estimation (QAE) estimates the amplitude of the target state within a state preparation unitary . It combines amplitude amplification with QPE, achieving a root-mean-square error of using ancilla qubits.
Import
from unitarylab_algorithms import AmplitudeEstimationAlgorithm.run() Parameters
def run(self, U: Circuit, good_zero_qubits: List[int], d: int = 6,
backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| Parameter | Type | Default | Description |
|---|---|---|---|
U | Circuit | — (required) | State preparation unitary |
good_zero_qubits | List[int] | — (required) | Qubit indices defining the target state |
d | int | 6 | Number of phase register qubits (precision ) |
Note:
.run()itself has nopparameter —ponly appears in the module-leveltest(p=0.36, d=6)function, where it is used to construct a test state preparation circuitU; when calling the Python API directly, you need to buildUyourself.
Return Value
{
'status': 'ok', # Indicates the estimation process has completed
'circuit_path': '/path/to/amplitude_estimation_algorithm_circuit.svg',
'plot': [{'format': 'txt', 'filename': 'amplitude_estimation_algorithm_result.txt'}],
'circuit': <Circuit>,
'Target amplitude': 0.36,
'Most likely phase (bits)': '001001',
'Phase': 0.140625,
'Computation time (s)': 0.0456,
'Total qubits': 9,
}Example
from unitarylab_algorithms import AmplitudeEstimationAlgorithm
algo = AmplitudeEstimationAlgorithm()
result = algo.run(U=my_circuit, good_zero_qubits=[0], d=6)
print(result['Target amplitude'])Quick Demo
from unitarylab_algorithms.fundamental_algorithm.amplitude_estimation.algorithm import test
test(p=0.36, d=6)Notes
status='ok'indicates the estimation process completed; compareTarget amplitudewith the theoretical value to assess precision..run()has nopparameter — onlytest()does; when calling the Python API you must buildU(the state preparation circuit) andgood_zero_qubitsyourself.
Hadamard Test
Background
The Hadamard test uses a single ancilla qubit to estimate the expectation value of a unitary operator with respect to a state . It supports three modes:
expectation— Estimates (estimates the imaginary part whenimag=True)swap_test— Estimates the overlap between two statesphase_estimation— Performs single-qubit phase estimation
Import
from unitarylab_algorithms import HadamardTestAlgorithm.run() Parameters
def run(self, mode: str = "expectation", U: Optional[Circuit] = None,
prepare_psi: Optional[Circuit] = None, prepare_phi: Optional[Circuit] = None,
imag: bool = False, shots: int = 20000,
backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| Parameter | Type | Default | Description |
|---|---|---|---|
mode | str | 'expectation' | Run mode: one of 'expectation', 'swap_test', 'phase_estimation'; other values raise a ValueError |
U | Circuit | None | None | Unitary operator circuit (required in expectation/phase_estimation mode, otherwise raises a ValueError; not used in swap_test mode) |
prepare_psi | Circuit | None | None | Circuit preparing $ |
prepare_phi | Circuit | None | None | Circuit preparing $ |
imag | bool | False | Extract the imaginary part (valid only in expectation mode) |
shots | int | 20000 | Number of measurement shots for statistical sampling; when shots<=0, no binomial sampling noise is simulated, and the exact expectation value is returned directly |
The default value of
shotsfor.run()itself is20000(introducing sampling noise), whereas the module-leveltest()function and the web frontend’sparameters.jsonboth default toshots=0(exact computation, no noise). When you directly instantiateHadamardTestAlgorithm().run(...)without explicitly passingshots, you get an estimate with sampling noise, which differs from the exact value shown by default bytest()/the web frontend.
Return Value
Unlike the other 5 algorithms, circuit_path here is a list of paths rather than a single string — in expectation mode it has 1 element (main), in swap_test mode it has 1 element (real), and in phase_estimation mode it has 2 elements (real, imag):
{
'status': 'ok', # Always 'ok'; the Hadamard test is a pure estimator with no inherent success/failure determination
'circuit_path': ['/path/to/HadamardTest_expectation_main.svg'],
'plot': [{'format': 'txt', 'filename': 'hadamard_test_algorithm_result.txt'}],
'circuit': <Circuit>, # One of the circuits built under the given mode (a representative circuit)
'Estimated Value': 0.7071,
'Computation Time (s)': 0.0089,
}Example
from unitarylab_algorithms import HadamardTestAlgorithm
algo = HadamardTestAlgorithm()
result = algo.run(mode='expectation', U=my_U, prepare_psi=my_psi, shots=0) # Explicitly pass shots=0 to get the exact value
print(result['Estimated Value'])Quick Demo
from unitarylab_algorithms.fundamental_algorithm.hadamard_test.algorithm import test
test(U=[[1, 0], [0, 1]], psi=[1, 2], shots=0)Notes
.run()andtest()/the web frontend have inconsistentshotsdefaults (20000vs.0); if you want reproducible exact results, explicitly passshots=0.circuit_pathis a list rather than a string, unlike other algorithms in this package (HadamardTransformAlgorithm, etc.) — be mindful of this type difference when handling the return value.- This module’s
__init__.py__all__exports only'HadamardTestAlgorithm', not'test'(even though thetestfunction itself has been imported); thereforefrom ...hadamard_test import *will not bring intest. If you need the quick-demo function, import it directly from thehadamard_test.algorithmmodule, as shown in the example above.
Hadamard Transform
Background
The -qubit Hadamard transform applies a Hadamard gate to every qubit simultaneously, mapping the computational basis state to an equal-weight superposition of all basis states (when starting from ). The transform is its own inverse (reflexive).
mode='superposition' generates the superposition state and verifies whether the probability of each basis state is uniform (theoretical value ); mode='reflexive_test' first prepares a random state, applies the Hadamard transform twice in succession, and verifies whether it recovers the original state.
Import
from unitarylab_algorithms import HadamardTransformAlgorithm.run() Parameters
def run(self, n: int = 3, mode: str = "superposition", backend='torch', device='cpu', dtype=np.complex128) -> Dict[str, Any]| Parameter | Type | Default | Description |
|---|---|---|---|
n | int | 3 | Number of qubits; must be , otherwise raises a ValueError |
mode | str | 'superposition' | 'superposition' (generates the superposition state) or 'reflexive_test' (verifies reflexivity); other values raise a ValueError |
Return Value
{
'status': 'ok', # Indicates the transform process has completed
'circuit_path': '/path/to/hadamard_transform_algorithm_circuit.svg',
'plot': [{'format': 'txt', 'filename': 'hadamard_transform_algorithm_result.txt'}],
'circuit': <Circuit>,
'Computation time (s)': 0.0034,
'Probability distribution': {'000': 0.125, '001': 0.125, ...}, # Non-empty only in superposition mode; an empty dict {} in reflexive_test mode
'State vector': array([...]),
}Example
from unitarylab_algorithms import HadamardTransformAlgorithm
algo = HadamardTransformAlgorithm()
result = algo.run(n=4, mode='superposition')
print(result['Probability distribution'])Quick Demo
from unitarylab_algorithms.fundamental_algorithm.hadamard_transform.algorithm import test
test(n=3)Notes
status='ok'indicates the transform process completed. When you need to verify uniformity or reflexivity, check the returnedProbability distribution,State vector, or the summary in the result text.- When
mode='reflexive_test',Probability distributionis always an empty dict{}(this field is only computed insuperpositionmode) — do not mistake this for an algorithm error.