oqubit 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
oqubit/__init__.py ADDED
@@ -0,0 +1,47 @@
1
+ from .core.qubit import Qubit
2
+ from .core.statevector import StateVector
3
+ from .core.operators import Operator, Gate
4
+ from .gates.single import X,Y,Z,H,S,T,SX
5
+ from .gates.controlled import CX,CY,CZ,CS,CH,CT,CSX
6
+ from .gates.multi import SWAP,ISWAP,SQRT_SWAP,CCX,CSWAP
7
+ from .measurement.measurement import measure
8
+ from .measurement.sampling import sample
9
+ from .circuit.circuit import Circuit
10
+ from .circuit.instruction import Instruction
11
+ from .algorithms.deutsch import deutsch
12
+ from .algorithms.deutsch_jozsa import deutsch_jozsa
13
+ from .algorithms.bernstein_vazirani import bernstein_vazirani
14
+ from .algorithms.superdense_coding import encode,decode
15
+ __all__=["Qubit",
16
+ "StateVector",
17
+ "Operator",
18
+ "Gate",
19
+ "X",
20
+ "Y",
21
+ "Z",
22
+ "H",
23
+ "S",
24
+ "T",
25
+ "SX",
26
+ "CX",
27
+ "CY",
28
+ "CZ",
29
+ "CS",
30
+ "CH",
31
+ "CT",
32
+ "CSX",
33
+ "SWAP",
34
+ "ISWAP",
35
+ "SQRT_SWAP",
36
+ "CCX",
37
+ "CSWAP",
38
+ "measure",
39
+ "sample",
40
+ "Circuit",
41
+ "Instruction",
42
+ "deutsch",
43
+ "deutsch_jozsa",
44
+ "bernstein_vazirani",
45
+ "encode",
46
+ "decode",
47
+ ]
@@ -0,0 +1,5 @@
1
+ from .deutsch import deutsch
2
+ from .deutsch_jozsa import deutsch_jozsa
3
+ from .bernstein_vazirani import bernstein_vazirani
4
+ from .superdense_coding import encode,decode
5
+ __all__=["deutsch","deutsch_jozsa","bernstein_vazirani","encode","decode",]
@@ -0,0 +1,60 @@
1
+ """
2
+ Bernstein–Vazirani algorithm.
3
+
4
+ This module implements the Bernstein–Vazirani algorithm for recovering
5
+ a hidden binary string ``s`` from a Boolean function of the form
6
+
7
+ f(x) = s · x (mod 2)
8
+
9
+ where ``s`` and ``x`` are binary strings of equal length.
10
+
11
+ The algorithm determines the complete hidden string using a single
12
+ quantum-oracle evaluation.
13
+
14
+ Notes
15
+ -----
16
+ The implementation constructs the oracle from elementary X and
17
+ controlled-X gates. The oracle therefore represents the transformation
18
+
19
+ U_f |x>|y> = |x>|y XOR f(x)>.
20
+
21
+ The first ``n`` qubits form the input register and the final qubit
22
+ is the oracle ancilla.
23
+
24
+ For a secret string
25
+
26
+ s = s_0 s_1 ... s_(n-1),
27
+
28
+ the oracle applies a controlled-X gate from input qubit ``i`` to the
29
+ ancilla whenever ``s_i == 1``.
30
+ """
31
+ from __future__ import annotations
32
+ from typing import Final
33
+ from ..circuit import Circuit
34
+ __all__ = ["bernstein_vazirani"]
35
+ def _validate_secret(secret: str) -> None:
36
+ if not isinstance(secret, str):
37
+ raise TypeError("secret must be a string.")
38
+ if not secret:
39
+ raise ValueError("secret must not be empty.")
40
+ if any(bit not in "01" for bit in secret):
41
+ raise ValueError("secret must contain only binary digits '0' and '1'.")
42
+ def _apply_oracle(circuit: Circuit,secret: str,) -> None:
43
+ ancilla = len(secret)
44
+ for qubit, bit in enumerate(secret):
45
+ if bit == "1":
46
+ circuit.cx(qubit, ancilla)
47
+ def bernstein_vazirani(secret: str) -> str:
48
+ _validate_secret(secret)
49
+ num_qubits = len(secret)
50
+ ancilla = num_qubits
51
+ circuit = Circuit(num_qubits + 1)
52
+ circuit.x(ancilla)
53
+ for qubit in range(num_qubits + 1):
54
+ circuit.h(qubit)
55
+ _apply_oracle(circuit,secret,)
56
+ for qubit in range(num_qubits):
57
+ circuit.h(qubit)
58
+ state = circuit.run()
59
+ result = circuit.measure(state=state,qubits=tuple(range(num_qubits)),)
60
+ return "".join(str(bit) for bit in result)
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+ from collections.abc import Callable
3
+ from typing import Literal
4
+ from ..circuit import Circuit
5
+ __all__ = ["deutsch"]
6
+ DeutschResult = Literal["constant", "balanced"]
7
+ def _validate_function(function: Callable[[int], int],) -> tuple[int, int]:
8
+ if not callable(function):
9
+ raise TypeError("function must be callable.")
10
+ f0 = function(0)
11
+ f1 = function(1)
12
+ if f0 not in (0, 1) or f1 not in (0, 1):
13
+ raise ValueError("function must return either 0 or 1.")
14
+ return f0, f1
15
+ def _apply_oracle(circuit: Circuit,f0: int,f1: int,) -> None:
16
+ if f0 == 0 and f1 == 0:
17
+ return
18
+ if f0 == 1 and f1 == 1:
19
+ circuit.x(1)
20
+ return
21
+ if f0 == 0 and f1 == 1:
22
+ circuit.cx(0, 1)
23
+ return
24
+ circuit.x(1)
25
+ circuit.cx(0, 1)
26
+ circuit.x(1)
27
+ def deutsch(function: Callable[[int], int],) -> DeutschResult:
28
+ f0, f1 = _validate_function(function)
29
+ circuit = Circuit(2)
30
+ circuit.x(1)
31
+ circuit.h(0)
32
+ circuit.h(1)
33
+ _apply_oracle(circuit, f0, f1)
34
+ circuit.h(0)
35
+ state = circuit.run()
36
+ result = circuit.measure(state=state,qubits=0,)
37
+ return "constant" if result == 0 else "balanced"
@@ -0,0 +1,121 @@
1
+ """
2
+ Deutsch–Jozsa algorithm.
3
+
4
+ This module implements the Deutsch–Jozsa algorithm for Boolean
5
+ functions of the form
6
+
7
+ f : {0, 1}^n -> {0, 1}
8
+
9
+ under the promise that ``f`` is either constant or balanced.
10
+
11
+ The algorithm determines whether the function is constant or
12
+ balanced using a single quantum-oracle evaluation.
13
+
14
+ Notes
15
+ -----
16
+ The implementation constructs the oracle from elementary X and
17
+ controlled-X gates. The oracle therefore represents the transformation
18
+
19
+ U_f |x>|y> = |x>|y XOR f(x)>.
20
+
21
+ The first ``n`` qubits form the input register and the final qubit
22
+ is the oracle ancilla.
23
+ """
24
+ from __future__ import annotations
25
+ from collections.abc import Callable, Iterable
26
+ from itertools import product
27
+ from typing import Literal
28
+ from ..circuit import Circuit
29
+ __all__ = ["deutsch_jozsa"]
30
+ DeutschJozsaResult = Literal["constant", "balanced"]
31
+ def _validate_num_qubits(num_qubits: int) -> None:
32
+ if not isinstance(num_qubits, int):
33
+ raise TypeError("num_qubits must be an integer.")
34
+ if isinstance(num_qubits, bool):
35
+ raise TypeError("num_qubits must be an integer.")
36
+ if num_qubits < 1:
37
+ raise ValueError("num_qubits must be at least 1.")
38
+ def _validate_function(function: Callable[[tuple[int, ...]], int],num_qubits: int,) -> dict[tuple[int, ...], int]:
39
+ if not callable(function):
40
+ raise TypeError("function must be callable.")
41
+ truth_table: dict[tuple[int, ...], int] = {}
42
+ for bits in product((0, 1), repeat=num_qubits):
43
+ value = function(bits)
44
+ if not isinstance(value, int) or isinstance(value, bool):
45
+ raise TypeError("function must return an integer value of 0 or 1.")
46
+ if value not in (0, 1):
47
+ raise ValueError("function must return either 0 or 1.")
48
+ truth_table[bits] = value
49
+ return truth_table
50
+ def _classify_truth_table(truth_table: dict[tuple[int, ...], int],) -> DeutschJozsaResult:
51
+ values = tuple(truth_table.values())
52
+ total = len(values)
53
+ ones = sum(values)
54
+ if ones == 0 or ones == total:
55
+ return "constant"
56
+ if ones * 2 == total:
57
+ return "balanced"
58
+ raise ValueError("function must be either constant or balanced.")
59
+ def _apply_oracle(circuit: Circuit,truth_table: dict[tuple[int, ...], int],num_qubits: int,) -> None:
60
+ ancilla = num_qubits
61
+ for bits, value in truth_table.items():
62
+ if value == 0:
63
+ continue
64
+ if num_qubits == 1:
65
+ if bits[0] == 1:
66
+ circuit.cx(0, ancilla)
67
+ else:
68
+ circuit.x(0)
69
+ circuit.cx(0, ancilla)
70
+ circuit.x(0)
71
+ continue
72
+ if num_qubits == 2:
73
+ _apply_two_controlled_x(
74
+ circuit,
75
+ bits,
76
+ ancilla,
77
+ )
78
+ continue
79
+ raise NotImplementedError(
80
+ "Deutsch–Jozsa oracles with more than 2 input qubits "
81
+ "require multi-controlled gates, which are not yet "
82
+ "exposed by the current OQubit Circuit API."
83
+ )
84
+ def _apply_two_controlled_x(circuit: Circuit,bits: tuple[int, ...],target: int,) -> None:
85
+ control0 = 0
86
+ control1 = 1
87
+ zero_controls = [
88
+ index
89
+ for index, bit in enumerate(bits)
90
+ if bit == 0
91
+ ]
92
+ for qubit in zero_controls:
93
+ circuit.x(qubit)
94
+ circuit.ccx(control0,control1,target,)
95
+ for qubit in reversed(zero_controls):
96
+ circuit.x(qubit)
97
+ def deutsch_jozsa(function: Callable[[tuple[int, ...]], int],num_qubits: int,) -> DeutschJozsaResult:
98
+ _validate_num_qubits(num_qubits)
99
+ truth_table = _validate_function(function,num_qubits,)
100
+ _classify_truth_table(truth_table)
101
+ circuit = Circuit(num_qubits + 1)
102
+ ancilla = num_qubits
103
+ circuit.x(ancilla)
104
+ for qubit in range(num_qubits + 1):
105
+ circuit.h(qubit)
106
+ _apply_oracle(
107
+ circuit,
108
+ truth_table,
109
+ num_qubits,
110
+ )
111
+ for qubit in range(num_qubits):
112
+ circuit.h(qubit)
113
+ state = circuit.run()
114
+ result = circuit.measure(
115
+ state=state,
116
+ qubits=tuple(range(num_qubits)),
117
+ )
118
+
119
+ if all(bit == 0 for bit in result):
120
+ return "constant"
121
+ return "balanced"
@@ -0,0 +1,121 @@
1
+ """
2
+ Deutsch–Jozsa algorithm.
3
+
4
+ This module implements the Deutsch–Jozsa algorithm for Boolean
5
+ functions of the form
6
+
7
+ f : {0, 1}^n -> {0, 1}
8
+
9
+ under the promise that ``f`` is either constant or balanced.
10
+
11
+ The algorithm determines whether the function is constant or
12
+ balanced using a single quantum-oracle evaluation.
13
+
14
+ Notes
15
+ -----
16
+ The implementation constructs the oracle from elementary X and
17
+ controlled-X gates. The oracle therefore represents the transformation
18
+
19
+ U_f |x>|y> = |x>|y XOR f(x)>.
20
+
21
+ The first ``n`` qubits form the input register and the final qubit
22
+ is the oracle ancilla.
23
+ """
24
+ from __future__ import annotations
25
+ from collections.abc import Callable, Iterable
26
+ from itertools import product
27
+ from typing import Literal
28
+ from ..circuit import Circuit
29
+ __all__ = ["deutsch_jozsa"]
30
+ DeutschJozsaResult = Literal["constant", "balanced"]
31
+ def _validate_num_qubits(num_qubits: int) -> None:
32
+ if not isinstance(num_qubits, int):
33
+ raise TypeError("num_qubits must be an integer.")
34
+ if isinstance(num_qubits, bool):
35
+ raise TypeError("num_qubits must be an integer.")
36
+ if num_qubits < 1:
37
+ raise ValueError("num_qubits must be at least 1.")
38
+ def _validate_function(function: Callable[[tuple[int, ...]], int],num_qubits: int,) -> dict[tuple[int, ...], int]:
39
+ if not callable(function):
40
+ raise TypeError("function must be callable.")
41
+ truth_table: dict[tuple[int, ...], int] = {}
42
+ for bits in product((0, 1), repeat=num_qubits):
43
+ value = function(bits)
44
+ if not isinstance(value, int) or isinstance(value, bool):
45
+ raise TypeError("function must return an integer value of 0 or 1.")
46
+ if value not in (0, 1):
47
+ raise ValueError("function must return either 0 or 1.")
48
+ truth_table[bits] = value
49
+ return truth_table
50
+ def _classify_truth_table(truth_table: dict[tuple[int, ...], int],) -> DeutschJozsaResult:
51
+ values = tuple(truth_table.values())
52
+ total = len(values)
53
+ ones = sum(values)
54
+ if ones == 0 or ones == total:
55
+ return "constant"
56
+ if ones * 2 == total:
57
+ return "balanced"
58
+ raise ValueError("function must be either constant or balanced.")
59
+ def _apply_oracle(circuit: Circuit,truth_table: dict[tuple[int, ...], int],num_qubits: int,) -> None:
60
+ ancilla = num_qubits
61
+ for bits, value in truth_table.items():
62
+ if value == 0:
63
+ continue
64
+ if num_qubits == 1:
65
+ if bits[0] == 1:
66
+ circuit.cx(0, ancilla)
67
+ else:
68
+ circuit.x(0)
69
+ circuit.cx(0, ancilla)
70
+ circuit.x(0)
71
+ continue
72
+ if num_qubits == 2:
73
+ _apply_two_controlled_x(
74
+ circuit,
75
+ bits,
76
+ ancilla,
77
+ )
78
+ continue
79
+ raise NotImplementedError(
80
+ "Deutsch–Jozsa oracles with more than 2 input qubits "
81
+ "require multi-controlled gates, which are not yet "
82
+ "exposed by the current OQubit Circuit API."
83
+ )
84
+ def _apply_two_controlled_x(circuit: Circuit,bits: tuple[int, ...],target: int,) -> None:
85
+ control0 = 0
86
+ control1 = 1
87
+ zero_controls = [
88
+ index
89
+ for index, bit in enumerate(bits)
90
+ if bit == 0
91
+ ]
92
+ for qubit in zero_controls:
93
+ circuit.x(qubit)
94
+ circuit.ccx(control0,control1,target,)
95
+ for qubit in reversed(zero_controls):
96
+ circuit.x(qubit)
97
+ def deutsch_jozsa(function: Callable[[tuple[int, ...]], int],num_qubits: int,) -> DeutschJozsaResult:
98
+ _validate_num_qubits(num_qubits)
99
+ truth_table = _validate_function(function,num_qubits,)
100
+ _classify_truth_table(truth_table)
101
+ circuit = Circuit(num_qubits + 1)
102
+ ancilla = num_qubits
103
+ circuit.x(ancilla)
104
+ for qubit in range(num_qubits + 1):
105
+ circuit.h(qubit)
106
+ _apply_oracle(
107
+ circuit,
108
+ truth_table,
109
+ num_qubits,
110
+ )
111
+ for qubit in range(num_qubits):
112
+ circuit.h(qubit)
113
+ state = circuit.run()
114
+ result = circuit.measure(
115
+ state=state,
116
+ qubits=tuple(range(num_qubits)),
117
+ )
118
+
119
+ if result==0:
120
+ return "constant"
121
+ return "balanced"
@@ -0,0 +1,87 @@
1
+ """
2
+ Quantum Fourier Transform (QFT).
3
+
4
+ This module provides a circuit-level implementation of the Quantum
5
+ Fourier Transform.
6
+
7
+ The QFT on n qubits is defined as:
8
+
9
+ |x> -> 1 / sqrt(2^n) * sum_y exp(2πixy / 2^n) |y>
10
+
11
+ The implementation uses:
12
+ - Hadamard gates
13
+ - Controlled phase rotations
14
+ - SWAP gates for final bit reversal
15
+
16
+ Notes
17
+ -----
18
+ The QFT is implemented as a circuit transformation. It does not
19
+ directly manipulate state vectors or simulator internals.
20
+
21
+ Examples
22
+ --------
23
+ >>> from oqubit.circuit import Circuit
24
+ >>> from oqubit.algorithms.qft import qft
25
+
26
+ >>> circuit = Circuit(3)
27
+ >>> qft(circuit)
28
+
29
+ The resulting circuit contains the QFT operation on all three qubits.
30
+
31
+ A subset of qubits can also be transformed:
32
+
33
+ >>> circuit = Circuit(5)
34
+ >>> qft(circuit, qubits=[1, 2, 3])
35
+ """
36
+ from __future__ import annotations
37
+ import math
38
+ from collections.abc import Sequence
39
+ from oqubit.circuit import Circuit
40
+ from oqubit.gates import H, SWAP
41
+ from oqubit.gates.controlled import ControlledPhase
42
+ __all__ = ["qft"]
43
+
44
+ def qft(
45
+ circuit: Circuit,
46
+ qubits: Sequence[int] | None = None,
47
+ ) -> Circuit:
48
+ if not isinstance(circuit, Circuit):
49
+ raise TypeError("circuit must be an instance of Circuit.")
50
+ if qubits is None:
51
+ qubit_indices = list(range(circuit.num_qubits))
52
+ else:
53
+ if isinstance(qubits, (str, bytes)):
54
+ raise TypeError("qubits must be a sequence of integers.")
55
+ qubit_indices = list(qubits)
56
+ if not all(isinstance(q, int) for q in qubit_indices):
57
+ raise TypeError("qubits must contain only integers.")
58
+ if not qubit_indices:
59
+ raise ValueError("QFT requires at least one qubit.")
60
+ if len(set(qubit_indices)) != len(qubit_indices):
61
+ raise ValueError("QFT qubit indices must be unique.")
62
+ for qubit in qubit_indices:
63
+ if qubit < 0 or qubit >= circuit.num_qubits:
64
+ raise ValueError(
65
+ f"Qubit index {qubit} is outside the circuit."
66
+ )
67
+ n = len(qubit_indices)
68
+ for j in range(n):
69
+ target = qubit_indices[j]
70
+ circuit.add(H, target)
71
+ for k in range(2, n - j + 1):
72
+ control = qubit_indices[j + k - 1]
73
+ angle = 2.0 * math.pi / (2**k)
74
+ circuit.add(
75
+ ControlledPhase(angle),
76
+ control,
77
+ target,
78
+ )
79
+ for i in range(n // 2):
80
+ circuit.add(
81
+ SWAP,
82
+ qubit_indices[i],
83
+ qubit_indices[n - i - 1],
84
+ )
85
+
86
+ return circuit
87
+
@@ -0,0 +1,28 @@
1
+ """
2
+ Superdense Coding algorithm.
3
+
4
+ Superdense coding transmits two classical bits using one qubit
5
+ and a previously shared entangled Bell pair.
6
+ """
7
+ from ..circuit import Circuit
8
+ __all__ = ["encode", "decode"]
9
+ def encode(bit0, bit1):
10
+ if bit0 not in (0, 1):
11
+ raise ValueError("bit0 must be 0 or 1.")
12
+ if bit1 not in (0, 1):
13
+ raise ValueError("bit1 must be 0 or 1.")
14
+ circuit = Circuit(2)
15
+ circuit.h(0)
16
+ circuit.cx(0, 1)
17
+ if bit1:
18
+ circuit.x(0)
19
+ if bit0:
20
+ circuit.z(0)
21
+ return circuit
22
+ def decode(circuit):
23
+ if not isinstance(circuit, Circuit):
24
+ raise TypeError("circuit must be an OQubit Circuit.")
25
+ circuit.cx(0, 1)
26
+ circuit.h(0)
27
+ state = circuit.run()
28
+ return circuit.measure(state=state,qubits=(0, 1),)
@@ -0,0 +1,3 @@
1
+ from .circuit import Circuit
2
+ from .instruction import Instruction
3
+ __all__=["Circuit","Instruction"]