This is an automated email from the ASF dual-hosted git repository.
guanmingchiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git
The following commit(s) were added to refs/heads/main by this push:
new 8f4ccc3ff MAHOUT-681: Implement T-gate (π/8 gate) across all backends
(#693)
8f4ccc3ff is described below
commit 8f4ccc3ff5d4c8a37842a5c83316d06b08be0a30
Author: Shivam Mittal <[email protected]>
AuthorDate: Fri Dec 12 11:58:34 2025 +0530
MAHOUT-681: Implement T-gate (π/8 gate) across all backends (#693)
* Implement T-gate (π/8 gate) across all backends
- Add apply_t_gate() method to QuMat class with validation
- Implement T-gate support in Qiskit, Cirq, and Amazon Braket backends
- Restore T-gate documentation in basic_gates.md to match implementation
Fixes #681
* Refine T-gate docs and add coverage
* chore: satisfy pre-commit hooks
---
docs/basic_gates.md | 2 +-
qumat/amazon_braket_backend.py | 4 ++
qumat/cirq_backend.py | 5 ++
qumat/qiskit_backend.py | 5 ++
qumat/qumat.py | 15 +++++
testing/test_single_qubit_gates.py | 112 +++++++++++++++++++++++++++++++++++++
6 files changed, 142 insertions(+), 1 deletion(-)
diff --git a/docs/basic_gates.md b/docs/basic_gates.md
index 6fe2533f0..e688c6906 100644
--- a/docs/basic_gates.md
+++ b/docs/basic_gates.md
@@ -40,7 +40,7 @@ The Pauli Z gate introduces a phase flip without changing the
qubit's state. It
It's used for measuring the phase of a qubit.
-## T-Gate (π/8 Gate) (New Addition)
+## T-Gate (π/8 Gate)
The T-Gate applies a **π/4 phase shift** to the qubit. It is essential for
quantum computing because it, along with the Hadamard and CNOT gates, allows
for **universal quantum computation**. Mathematically:
\[ T|0⟩ = |0⟩ \]
diff --git a/qumat/amazon_braket_backend.py b/qumat/amazon_braket_backend.py
index 0121c70be..a5e8c1bbe 100644
--- a/qumat/amazon_braket_backend.py
+++ b/qumat/amazon_braket_backend.py
@@ -81,6 +81,10 @@ def apply_pauli_z_gate(circuit, qubit_index):
circuit.z(qubit_index)
+def apply_t_gate(circuit, qubit_index):
+ circuit.t(qubit_index)
+
+
def execute_circuit(circuit, backend, backend_config):
shots = backend_config["backend_options"].get("shots", 1)
parameter_values = backend_config.get("parameter_values", {})
diff --git a/qumat/cirq_backend.py b/qumat/cirq_backend.py
index 674d9d4d4..dc09b0856 100644
--- a/qumat/cirq_backend.py
+++ b/qumat/cirq_backend.py
@@ -95,6 +95,11 @@ def apply_pauli_z_gate(circuit, qubit_index):
circuit.append(cirq.Z(qubit))
+def apply_t_gate(circuit, qubit_index):
+ qubit = cirq.LineQubit(qubit_index)
+ circuit.append(cirq.T(qubit))
+
+
def execute_circuit(circuit, backend, backend_config):
# handle 0-qubit circuits before adding measurements
if not circuit.all_qubits():
diff --git a/qumat/qiskit_backend.py b/qumat/qiskit_backend.py
index e7156eada..94b773b89 100644
--- a/qumat/qiskit_backend.py
+++ b/qumat/qiskit_backend.py
@@ -85,6 +85,11 @@ def apply_pauli_z_gate(circuit, qubit_index):
circuit.z(qubit_index)
+def apply_t_gate(circuit, qubit_index):
+ # Apply a T gate (π/8 gate) on the specified qubit
+ circuit.t(qubit_index)
+
+
def execute_circuit(circuit, backend, backend_config):
# Add measurements if they are not already present
# Check if circuit already has measurement operations
diff --git a/qumat/qumat.py b/qumat/qumat.py
index c1d866de4..99791d8af 100644
--- a/qumat/qumat.py
+++ b/qumat/qumat.py
@@ -251,6 +251,21 @@ class QuMat:
self._validate_qubit_index(qubit_index)
self.backend_module.apply_pauli_z_gate(self.circuit, qubit_index)
+ def apply_t_gate(self, qubit_index):
+ """Apply a T-gate (π/8 gate) to the specified qubit.
+
+ Applies a relative pi/4 phase (multiplies the |1> state by e^{i*pi/4}).
+ Essential for universal quantum computation when combined with
+ Hadamard and CNOT gates.
+
+ :param qubit_index: Index of the qubit.
+ :type qubit_index: int
+ :raises RuntimeError: If the circuit has not been initialized.
+ """
+ self._ensure_circuit_initialized()
+ self._validate_qubit_index(qubit_index)
+ self.backend_module.apply_t_gate(self.circuit, qubit_index)
+
def execute_circuit(self, parameter_values=None):
"""Execute the quantum circuit and return the measurement results.
diff --git a/testing/test_single_qubit_gates.py
b/testing/test_single_qubit_gates.py
index 9b66ab4da..af1e379ea 100644
--- a/testing/test_single_qubit_gates.py
+++ b/testing/test_single_qubit_gates.py
@@ -527,6 +527,118 @@ class TestPauliZGate:
)
[email protected]("backend_name", TESTING_BACKENDS)
+class TestTGate:
+ """Test class for T gate functionality."""
+
+ @pytest.mark.parametrize(
+ "initial_state, expected_state",
+ [
+ ("0", "0"), # T leaves |0> unchanged
+ ("1", "1"), # T applies phase to |1>, measurement unchanged
+ ],
+ )
+ def test_t_gate_preserves_basis_states(
+ self, backend_name, initial_state, expected_state
+ ):
+ """T gate should preserve computational basis measurement outcomes."""
+ backend_config = get_backend_config(backend_name)
+ qumat = QuMat(backend_config)
+ qumat.create_empty_circuit(num_qubits=1)
+
+ if initial_state == "1":
+ qumat.apply_pauli_x_gate(0)
+
+ qumat.apply_t_gate(0)
+ results = qumat.execute_circuit()
+
+ prob = get_state_probability(
+ results, expected_state, num_qubits=1, backend_name=backend_name
+ )
+ assert prob > 0.95, (
+ f"Backend: {backend_name}, expected |{expected_state}> after T, "
+ f"got probability {prob:.4f}"
+ )
+
+ def test_t_gate_phase_visible_via_hzh(self, backend_name):
+ """T^4 = Z; H-Z-H should act like X and flip |0> to |1>."""
+ backend_config = get_backend_config(backend_name)
+ qumat = QuMat(backend_config)
+ qumat.create_empty_circuit(num_qubits=1)
+
+ qumat.apply_hadamard_gate(0)
+ for _ in range(4):
+ qumat.apply_t_gate(0)
+ qumat.apply_hadamard_gate(0)
+
+ results = qumat.execute_circuit()
+ prob = get_state_probability(
+ results, "1", num_qubits=1, backend_name=backend_name
+ )
+ assert prob > 0.95, (
+ f"Backend: {backend_name}, expected |1> after H-T^4-H, "
+ f"got probability {prob:.4f}"
+ )
+
+ def test_t_gate_eight_applications_identity(self, backend_name):
+ """T^8 should be identity."""
+ backend_config = get_backend_config(backend_name)
+ qumat = QuMat(backend_config)
+ qumat.create_empty_circuit(num_qubits=1)
+
+ for _ in range(8):
+ qumat.apply_t_gate(0)
+
+ results = qumat.execute_circuit()
+ prob = get_state_probability(
+ results, "0", num_qubits=1, backend_name=backend_name
+ )
+ assert prob > 0.95, (
+ f"Backend: {backend_name}, expected |0> after T^8, "
+ f"got probability {prob:.4f}"
+ )
+
+
[email protected](
+ "phase_applications",
+ [
+ 1, # single T
+ 2, # T^2 = S
+ 4, # T^4 = Z
+ ],
+)
+def test_t_gate_cross_backend_consistency(phase_applications):
+ """T gate should behave consistently across all backends."""
+ results_dict = {}
+
+ for backend_name in TESTING_BACKENDS:
+ backend_config = get_backend_config(backend_name)
+ qumat = QuMat(backend_config)
+ qumat.create_empty_circuit(num_qubits=1)
+
+ # Use H ... H sandwich to turn phase into amplitude when needed
+ qumat.apply_hadamard_gate(0)
+ for _ in range(phase_applications):
+ qumat.apply_t_gate(0)
+ qumat.apply_hadamard_gate(0)
+
+ results = qumat.execute_circuit()
+ prob_one = get_state_probability(
+ results, "1", num_qubits=1, backend_name=backend_name
+ )
+ results_dict[backend_name] = prob_one
+
+ backends = list(results_dict.keys())
+ for i in range(len(backends)):
+ for j in range(i + 1, len(backends)):
+ b1, b2 = backends[i], backends[j]
+ diff = abs(results_dict[b1] - results_dict[b2])
+ assert diff < 0.05, (
+ f"T gate inconsistent between {b1} and {b2} for
T^{phase_applications}: "
+ f"{results_dict[b1]:.4f} vs {results_dict[b2]:.4f}"
+ )
+
+
@pytest.mark.parametrize("backend_name", TESTING_BACKENDS)
class TestSingleQubitGatesEdgeCases:
"""Test class for edge cases of single-qubit gates."""