Custom Quantum Gates
Create custom quantum gates from unitary matrices, build oracles, and compose multi-controlled operations with pyqpanda3.
Problem
pyqpanda3 ships with 37+ built-in gates covering standard operations -- Pauli gates, rotations, CNOT, SWAP, TOFFOLI, and more. However, several important scenarios demand gates beyond the standard set:
Problem-specific unitaries. An algorithm may require a unitary that has no standard name, such as a custom coin operator for quantum walks or a structured mixing operator for QAOA variants.
Oracle construction. Grover's search, Deutsch-Jozsa, and other oracle-based algorithms need phase-flip or bit-flip oracles derived from a classical function's truth table.
Non-standard gate sets. When compiling to specific hardware with a limited native gate set, you may need to define custom decomposition building blocks.
Subroutine re-use. You may want to package a frequently used gate sequence into a single object that can be inverted (
.dagger()), controlled (.control()), or embedded in multiple programs.
In all of these cases, you need the ability to define a gate from its unitary matrix or compose one from existing primitives.
Solution
pyqpanda3 provides two primary mechanisms for creating custom gates, plus composition tools for building complex operations from simpler parts:
Step 1: Define the unitary matrix
Every quantum gate is described by a unitary matrix numpy as a complex-valued array.
Step 2: Create the gate
Use core.Oracle(qubits, matrix) to instantiate a gate from an arbitrary unitary matrix. The function validates that the matrix is unitary and that its dimensions match the number of target qubits.
For named gates with standard parameters, use core.create_gate(name, qubits, params).
Step 3: Compose and control
Apply .control(qubit) to add a control qubit, .dagger() to obtain the inverse, and embed the result in a QCircuit or QProg using the << operator.
Step 4: Verify and execute
Use .matrix() to retrieve the gate's matrix representation and verify correctness. Then execute on CPUQVM or another simulator backend.
Code
Example 1: Single-qubit gate from a 2x2 unitary matrix
Create a custom single-qubit rotation around an axis in the X-Z plane. The gate applies the rotation
where
import numpy as np
from pyqpanda3 import core
# Define a custom rotation axis and angle
alpha = np.pi / 6 # 30 degrees from Z toward X
theta = np.pi / 3 # rotation angle
# Build the 2x2 unitary matrix
# R_{hat_n}(theta) = cos(theta/2)*I - i*sin(theta/2)*(sin(alpha)*X + cos(alpha)*Z)
cos_half = np.cos(theta / 2)
sin_half = np.sin(theta / 2)
custom_matrix = np.array([
[cos_half - 1j * sin_half * np.cos(alpha),
-1j * sin_half * np.sin(alpha)],
[-1j * sin_half * np.sin(alpha),
cos_half + 1j * sin_half * np.cos(alpha)]
], dtype=complex)
# Create the custom gate on qubit 0
qubits = [0]
custom_gate = core.Oracle(qubits, custom_matrix)
# Verify unitarity
mat = custom_gate.matrix()
product = mat @ mat.conj().T
is_unitary = np.allclose(product, np.eye(2))
print(f"Gate is unitary: {is_unitary}") # True
# Use in a circuit
prog = core.QProg()
prog << custom_gate
prog << core.measure([0], [0])
# Execute
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")Example 2: Two-qubit gate from a 4x4 unitary matrix
Implement the square-root-of-SWAP gate, which is a standard gate in quantum computing but not always available as a primitive:
import numpy as np
from pyqpanda3 import core
# Define the sqrt(SWAP) matrix
a = (1 + 1j) / 2 # (1+i)/2
b = (1 - 1j) / 2 # (1-i)/2
sqrt_swap_matrix = np.array([
[1, 0, 0, 0],
[0, a, b, 0],
[0, b, a, 0],
[0, 0, 0, 1]
], dtype=complex)
# Create the gate acting on qubits 1 and 2
sqrt_swap_gate = core.Oracle([1, 2], sqrt_swap_matrix)
# Verify: applying it twice should give a full SWAP
mat = sqrt_swap_gate.matrix()
double_mat = mat @ mat
swap_matrix = np.array([
[1, 0, 0, 0],
[0, 0, 1, 0],
[0, 1, 0, 0],
[0, 0, 0, 1]
], dtype=complex)
print(f"sqrt(SWAP)^2 == SWAP: {np.allclose(double_mat, swap_matrix)}") # True
# Use in a program
prog = core.QProg()
prog << core.X(1) # prepare |10>
prog << sqrt_swap_gate # apply sqrt(SWAP)
prog << core.measure([1, 2], [0, 1])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")Example 3: Multi-controlled gate using .control()
Build a multi-controlled Z gate (CCZ) by chaining .control() on a Z gate. The CCZ gate applies a phase flip only when all control qubits are
import numpy as np
from pyqpanda3 import core
# Method 1: Chain .control() calls
z_gate = core.Z(2) # Z on target qubit 2
cz_gate = z_gate.control(1) # add control qubit 1
ccz_gate = cz_gate.control(0) # add second control qubit 0
# Verify the 8x8 matrix
mat = ccz_gate.matrix()
# CCZ should have -1 at position [7,7] (all qubits |111>)
# and +1 on all other diagonal entries
expected = np.eye(8, dtype=complex)
expected[7, 7] = -1
print(f"CCZ matrix correct: {np.allclose(mat, expected)}") # True
# Method 2: Use the vector form of control()
ccz_gate2 = core.Z(2).control([0, 1])
# Use in a program: prepare |111> and apply CCZ
prog = core.QProg()
prog << core.X(0) << core.X(1) << core.X(2) # |111>
prog << ccz_gate
prog << core.measure([0, 1, 2], [0, 1, 2])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")
# Always measures 111 (CCZ only changes phase, not computational basis)Example 4: Custom oracle for Grover's algorithm
Build a phase oracle that marks a specific computational basis state by flipping its phase. This is the core subroutine in Grover's search.
import numpy as np
from pyqpanda3 import core
def phase_oracle(n_qubits: int, target_state: int) -> core.QGate:
"""Create a phase oracle that marks |target_state> with a -1 phase.
Args:
n_qubits: Number of qubits in the search space.
target_state: Integer index of the state to mark (0 to 2^n - 1).
Returns:
A QGate implementing the phase oracle.
"""
dim = 2 ** n_qubits
matrix = np.eye(dim, dtype=complex)
matrix[target_state, target_state] = -1
qubits = list(range(n_qubits))
return core.Oracle(qubits, matrix)
def grover_diffusion(n_qubits: int) -> core.QCircuit:
"""Build the Grover diffusion operator (2|s><s| - I).
This amplifies the amplitude of the marked state.
"""
dim = 2 ** n_qubits
# |s> = uniform superposition, so |s><s| = (1/dim) * ones matrix
matrix = (2.0 / dim) * np.ones((dim, dim), dtype=complex) - np.eye(dim, dtype=complex)
qubits = list(range(n_qubits))
circ = core.QCircuit()
oracle_as_diffusion = core.Oracle(qubits, matrix)
circ << oracle_as_diffusion
return circ
# --- Run Grover's search for |101> (state 5) on 3 qubits ---
n = 3
target = 5 # binary 101
# Build the oracle and diffusion operator
oracle = phase_oracle(n, target)
diffusion = grover_diffusion(n)
# Number of Grover iterations (optimal for unstructured search)
iterations = int(np.round(np.pi / 4 * np.sqrt(2 ** n)))
print(f"Grover iterations: {iterations}")
# Construct the full program
prog = core.QProg()
# Step 1: Initialize uniform superposition
for q in range(n):
prog << core.H(q)
# Step 2: Apply Grover iterations
for _ in range(iterations):
prog << oracle
prog << diffusion
# Step 3: Measure
prog << core.measure(list(range(n)), list(range(n)))
# Execute
machine = core.CPUQVM()
machine.run(prog, 1000)
counts = machine.result().get_counts()
print(f"Grover search results: {counts}")
# Should heavily favor the target state 101 (5)The circuit structure for a single Grover iteration is:
Example 5: Inverse gates using .dagger()
The .dagger() method returns the Hermitian conjugate (adjoint) of a gate, which is its inverse for unitary operations. This is essential for uncomputation patterns.
import numpy as np
from pyqpanda3 import core
# Create a custom gate
theta = 1.234
custom_matrix = np.array([
[np.cos(theta / 2), -1j * np.sin(theta / 2)],
[-1j * np.sin(theta / 2), np.cos(theta / 2)]
], dtype=complex)
gate = core.Oracle([0], custom_matrix)
gate_inv = gate.dagger()
# Verify that gate * dagger == identity
mat = gate.matrix()
mat_inv = gate_inv.matrix()
product = mat @ mat_inv
print(f"gate * dagger == I: {np.allclose(product, np.eye(2))}") # True
# --- Uncomputation pattern ---
# Use an auxiliary qubit to compute XOR, then uncompute
prog = core.QProg()
prog << core.H(0) # superposition on qubit 0
prog << core.X(1) # qubit 1 = |1>
# Compute: XOR of qubits 0 and 1 onto auxiliary qubit 2
compute = core.QCircuit()
compute << core.CNOT(0, 2) << core.CNOT(1, 2)
prog << compute
# Use the auxiliary qubit (apply a phase based on it)
prog << core.Z(2)
# Uncompute: restore auxiliary qubit to |0>
prog << compute.dagger()
prog << core.measure([0, 1, 2], [0, 1, 2])
machine = core.CPUQVM()
machine.run(prog, 1000)
counts = machine.result().get_counts()
print(f"Results: {counts}")
# Qubit 2 (auxiliary) should always measure 0Example 6: Verifying gate unitarity
Before using a custom matrix in an oracle, verify that it satisfies the unitarity condition
import numpy as np
from pyqpanda3 import core
def is_unitary(matrix: np.ndarray, atol: float = 1e-10) -> bool:
"""Check whether a matrix is unitary within tolerance.
A matrix U is unitary if U^dagger * U = I.
"""
n = matrix.shape[0]
if matrix.shape != (n, n):
return False
product = matrix.conj().T @ matrix
return np.allclose(product, np.eye(n), atol=atol)
def random_unitary(n: int) -> np.ndarray:
"""Generate a random n x n unitary matrix using QR decomposition."""
# Generate a random complex matrix
z = (np.random.randn(n, n) + 1j * np.random.randn(n, n)) / np.sqrt(2)
# QR decomposition: Q is unitary
q, r = np.linalg.qr(z)
# Ensure consistent phase (diagonal of R is real-positive)
d = np.diag(r)
ph = d / np.abs(d)
q = q @ np.diag(ph)
return q
# Generate and verify a random single-qubit unitary
U1 = random_unitary(2)
print(f"Random 2x2 is unitary: {is_unitary(U1)}") # True
# Create a gate from it
gate = core.Oracle([0], U1)
mat = gate.matrix()
print(f"Gate matrix matches input: {np.allclose(mat, U1)}") # True
# Generate and verify a random two-qubit unitary
U2 = random_unitary(4)
print(f"Random 4x4 is unitary: {is_unitary(U2)}") # True
gate2 = core.Oracle([0, 1], U2)
mat2 = gate2.matrix()
print(f"Gate matrix matches input: {np.allclose(mat2, U2)}") # True
# The Oracle constructor itself validates unitarity and raises on failure
try:
bad_matrix = np.array([[1, 0], [1, 0]], dtype=complex)
core.Oracle([0], bad_matrix)
except (ValueError, RuntimeError) as e:
print(f"Oracle rejected non-unitary matrix: {e}")Example 7: Building a Toffoli gate from basic gates
The Toffoli gate (CCX) is a doubly-controlled X gate. While pyqpanda3 provides core.TOFFOLI() directly, constructing one from simpler gates demonstrates the decomposition pattern that applies to any multi-controlled operation.
import numpy as np
from pyqpanda3 import core
def toffoli_decomposed(ctrl1: int, ctrl2: int, target: int) -> core.QCircuit:
"""Build a Toffoli gate from H, T, Tdg, CNOT gates.
This uses the standard decomposition with 6 CNOT gates.
"""
circ = core.QCircuit()
# Step 1: H on target
circ << core.H(target)
# Step 2: CNOT(ctrl2, target)
circ << core.CNOT(ctrl2, target)
# Step 3: Tdg on target
circ << core.T(target).dagger()
# Step 4: CNOT(ctrl1, target)
circ << core.CNOT(ctrl1, target)
# Step 5: T on target
circ << core.T(target)
# Step 6: CNOT(ctrl2, target)
circ << core.CNOT(ctrl2, target)
# Step 7: Tdg on target
circ << core.T(target).dagger()
# Step 8: CNOT(ctrl1, target)
circ << core.CNOT(ctrl1, target)
# Step 9: T on ctrl2 and target
circ << core.T(ctrl2)
circ << core.T(target)
# Step 10: H on target
circ << core.H(target)
# Step 11: CNOT(ctrl1, ctrl2)
circ << core.CNOT(ctrl1, ctrl2)
# Step 12: T on ctrl1, Tdg on ctrl2
circ << core.T(ctrl1)
circ << core.T(ctrl2).dagger()
# Step 13: CNOT(ctrl1, ctrl2)
circ << core.CNOT(ctrl1, ctrl2)
return circ
# Build the decomposed Toffoli
decomposed = toffoli_decomposed(0, 1, 2)
# Compare with the native Toffoli
native_toffoli = core.TOFFOLI(0, 1, 2)
# Both should produce the same 8x8 matrix (up to global phase)
mat_decomp = decomposed.matrix()
mat_native = native_toffoli.matrix()
# Check equivalence (allow global phase difference)
phase = mat_decomp[0, 0] / mat_native[0, 0] if abs(mat_native[0, 0]) > 1e-10 else 1.0
equivalent = np.allclose(mat_decomp, phase * mat_native)
print(f"Decomposed Toffoli == native Toffoli (up to phase): {equivalent}") # True
# Use in a program
prog = core.QProg()
prog << core.X(0) << core.X(1) # controls = |11>
prog << decomposed # target flips from |0> to |1>
prog << core.measure([0, 1, 2], [0, 1, 2])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")
# Should always measure 111The decomposition structure:
Example 8: Custom rotation gate
Implement a rotation gate around an arbitrary Bloch-sphere axis
import numpy as np
from pyqpanda3 import core
def rotation_gate(axis: tuple, angle: float, qubit: int) -> core.QGate:
"""Create a rotation gate around an arbitrary axis.
Args:
axis: A unit vector (nx, ny, nz) specifying the rotation axis.
angle: Rotation angle in radians.
qubit: Target qubit index.
Returns:
A QGate implementing the rotation.
"""
nx, ny, nz = axis
norm = np.sqrt(nx**2 + ny**2 + nz**2)
assert abs(norm - 1.0) < 1e-10, f"Axis must be a unit vector, got norm={norm}"
cos_half = np.cos(angle / 2)
sin_half = np.sin(angle / 2)
# Pauli matrices
I = np.eye(2, dtype=complex)
X = np.array([[0, 1], [1, 0]], dtype=complex)
Y = np.array([[0, -1j], [1j, 0]], dtype=complex)
Z = np.array([[1, 0], [0, -1]], dtype=complex)
# R_n(theta) = cos(theta/2)*I - i*sin(theta/2)*(nx*X + ny*Y + nz*Z)
matrix = cos_half * I - 1j * sin_half * (nx * X + ny * Y + nz * Z)
return core.Oracle([qubit], matrix)
# Rotate around axis (1/sqrt(3), 1/sqrt(3), 1/sqrt(3)) by pi/2
axis = (1/np.sqrt(3), 1/np.sqrt(3), 1/np.sqrt(3))
gate = rotation_gate(axis, np.pi / 2, 0)
# Verify: rotation by 2*pi should give -I (up to global phase)
full_rotation = rotation_gate(axis, 2 * np.pi, 0)
mat = full_rotation.matrix()
print(f"R(2pi) ≈ -I: {np.allclose(mat, -np.eye(2))}") # True
# Use the custom rotation in a circuit
prog = core.QProg()
prog << core.H(0) # |+>
prog << rotation_gate(axis, np.pi / 4, 0) # custom rotation
prog << core.measure([0], [0])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")
# Chain with .control() to create a controlled version
controlled_rot = gate.control(1)
prog2 = core.QProg()
prog2 << core.H(1) # control in superposition
prog2 << core.H(0) # target in superposition
prog2 << controlled_rot # controlled rotation
prog2 << core.measure([0, 1], [0, 1])
machine.run(prog2, 1000)
print(f"Controlled rotation results: {machine.result().get_counts()}")Example 9: create_gate() for named gate construction
The core.create_gate() function constructs a gate by name, qubits, and parameters. This is useful for dynamic gate creation where the gate type is determined at runtime.
from pyqpanda3 import core
# Create gates by name (string matching the gate type)
h_gate = core.create_gate("H", [0], [])
rx_gate = core.create_gate("RX", [1], [1.5708]) # RX with pi/2
cnot_gate = core.create_gate("CNOT", [0, 1], [])
# Verify they match the factory-function versions
print(f"H matrix match: {len(h_gate.matrix()) == len(core.H(0).matrix())}")
print(f"Gate name: {h_gate.name()}") # "H"
print(f"Gate name: {rx_gate.name()}") # "RX"
print(f"Parameters: {rx_gate.parameters()}") # [1.5708]
# Build a circuit using dynamically created gates
prog = core.QProg()
prog << h_gate
prog << cnot_gate
prog << rx_gate
prog << core.measure([0, 1], [0, 1])
machine = core.CPUQVM()
machine.run(prog, 1000)
print(f"Results: {machine.result().get_counts()}")Example 10: Complete workflow -- custom Grover oracle with verification
This example puts everything together: define a custom oracle, verify it, run Grover's algorithm, and check the results.
import numpy as np
from pyqpanda3 import core
def make_bitflip_oracle(n_qubits: int, marked_items: list[int]) -> core.QGate:
"""Create a bit-flip oracle that flips the target qubit for marked items.
Unlike the phase oracle, this oracle applies X to an ancilla qubit.
The matrix has the form diag(I_ancilla ⊗ U_f) where U_f flips for
marked states.
For simplicity, this returns the full (n+1)-qubit matrix as an Oracle.
"""
total = n_qubits + 1 # n data qubits + 1 ancilla
dim = 2 ** total
matrix = np.eye(dim, dtype=complex)
for item in marked_items:
# For each marked computational-basis state, flip the ancilla
# State |item>|0> maps to |item>|1> and vice versa
idx0 = item * 2 # |item>|0>
idx1 = item * 2 + 1 # |item>|1>
matrix[idx0, idx0] = 0
matrix[idx0, idx1] = 1
matrix[idx1, idx0] = 1
matrix[idx1, idx1] = 0
qubits = list(range(total))
return core.Oracle(qubits, matrix)
def grover_phase_oracle(n_qubits: int, marked_items: list[int]) -> core.QGate:
"""Create a phase oracle marking multiple items with a -1 phase."""
dim = 2 ** n_qubits
matrix = np.eye(dim, dtype=complex)
for item in marked_items:
matrix[item, item] = -1
qubits = list(range(n_qubits))
return core.Oracle(qubits, matrix)
def grover_diffusion_matrix(n_qubits: int) -> np.ndarray:
"""Build the Grover diffusion operator as a matrix."""
dim = 2 ** n_qubits
return np.eye(dim, dtype=complex) * (-1) + (2.0 / dim) * np.ones((dim, dim), dtype=complex)
# --- Full Grover example ---
n = 3
marked = [2, 5] # mark states |010> and |101>
# Build oracle and diffusion
oracle = grover_phase_oracle(n, marked)
diff_matrix = grover_diffusion_matrix(n)
diffusion = core.Oracle(list(range(n)), diff_matrix)
# Calculate optimal number of iterations
theta = np.arcsin(len(marked) / 2**n)
iterations = max(1, int(np.round(np.pi / (2 * theta) - 0.5)))
print(f"Marked states: {marked}")
print(f"Theta: {theta:.4f} rad")
print(f"Optimal iterations: {iterations}")
# Build program
prog = core.QProg()
# Initialize uniform superposition
for q in range(n):
prog << core.H(q)
# Grover iterations
for _ in range(iterations):
prog << oracle
prog << diffusion
# Measure
prog << core.measure(list(range(n)), list(range(n)))
# Execute
machine = core.CPUQVM()
machine.run(prog, 1000)
counts = machine.result().get_counts()
print(f"\nGrover results (marking states {marked}):")
for state, count in sorted(counts.items(), key=lambda x: -x[1]):
print(f" |{state}> : {count}")Explanation
When to use custom gates vs built-in gates
| Scenario | Recommended approach |
|---|---|
| Standard gates (H, X, RX, CNOT, etc.) | Use built-in factory functions: core.H(0), core.RX(0, theta) |
| Most general single-qubit gate | Use core.U4(0, a, b, c, d) with four parameters |
| Arbitrary unitary on 1-2 qubits | Use core.Oracle(qubits, matrix) with a numpy matrix |
| Gate determined at runtime | Use core.create_gate(name, qubits, params) |
| Multi-controlled standard gate | Use gate.control(qubit) chaining |
| Complex subroutine | Compose a QCircuit, then use .dagger() and .control() |
As a rule, prefer built-in gates whenever they suffice. They are optimized in the simulator backend and produce cleaner OriginIR output. Reserve core.Oracle() for cases where no standard gate matches your required unitary.
Unitary matrix requirements
The core.Oracle() function enforces two constraints:
Unitarity: The matrix
must satisfy . If the matrix is not unitary, the constructor raises an exception. Dimension matching: For
target qubits, the matrix must be . For example, a gate on 2 qubits requires a matrix. No duplicate qubits: Each qubit index in the qubits list must be unique.
To generate a valid unitary matrix programmatically, use the QR decomposition of a random complex matrix:
def random_unitary(dim):
z = (np.random.randn(dim, dim) + 1j * np.random.randn(dim, dim)) / np.sqrt(2)
q, r = np.linalg.qr(z)
d = np.diag(r)
ph = d / np.abs(d)
return q @ np.diag(ph)Or construct structured unitaries from known decompositions (Euler angles for single-qubit gates, KAK decomposition for two-qubit gates).
Decomposition strategies for large unitaries
For gates acting on 3 or more qubits, the unitary matrix grows as
Analytical decomposition. If you know the circuit structure (e.g., QFT), compose it from standard gates using
QCircuitrather than specifying a matrix.Controlled operations. Build multi-controlled gates by chaining
.control()on simpler gates. For example, a CCCCZ (4-controlled Z) is justZ(target).control(c1).control(c2).control(c3).control(c4).Oracle construction patterns. For phase oracles, construct the identity matrix and flip the sign at the target indices. For bit-flip oracles, swap the appropriate rows/columns.
Circuit synthesis. For arbitrary unitaries on 2 qubits, the KAK (Cartan) decomposition requires at most 3 CNOT gates. For larger unitaries, the Cosine-Sine Decomposition (CSD) recursively breaks down the problem.
Oracle construction patterns
Two common oracle patterns arise in quantum algorithms:
Phase oracle -- marks target states with a
where
def phase_oracle(n, marked):
dim = 2 ** n
matrix = np.eye(dim, dtype=complex)
for m in marked:
matrix[m, m] = -1
return core.Oracle(list(range(n)), matrix)Bit-flip oracle -- flips an ancilla qubit based on the function value:
This is constructed by swapping rows in the matrix to XOR the ancilla with the function output.
Performance considerations
Matrix size limits.
core.Oracle()stores the fullmatrix. For , the matrix occupies significant memory ( complex numbers = 16 MB for ). Prefer gate-level composition for large qubit counts. Simulator overhead. The
CPUQVMsimulator applies Oracle gates via direct matrix multiplication on the state vector. Larger Oracle matrices lead to slower state evolution. Decomposing a large Oracle into a circuit of smaller gates (CNOT + single-qubit) can be faster due to sparse gate application..dagger()cost. Calling.dagger()on aQGatereturns a new gate with a flag set. The matrix is computed lazily when.matrix()is called. On aQCircuit,.dagger()reverses the gate order and daggers each gate individually, which is efficient..control()cost. Adding a control qubit expands the gate matrix fromto . The matrix has the block structure:
For deeply chained controls, consider whether a TOFFOLI-based decomposition would be more efficient.
- Matrix retrieval. The
.matrix()method computes the matrix representation on demand. For gates with known decompositions (e.g.,H,RX), this is fast. For Oracle gates, it returns the stored matrix directly. For circuits, it multiplies all constituent gate matrices, which is expensive for large circuits.
API reference summary
| API | Purpose | Signature |
|---|---|---|
core.Oracle() | Gate from unitary matrix | Oracle(qubits: list, matrix: np.ndarray) -> QGate |
core.create_gate() | Gate by name and params | create_gate(name: str, qubits: list, params: list) -> QGate |
gate.dagger() | Inverse gate | Returns a new QGate |
gate.control(qubit) | Add one control qubit | Returns new QGate |
gate.control([q1, q2]) | Add multiple controls | Returns new QGate |
gate.matrix() | Get unitary matrix | matrix(expanded=False) -> np.ndarray |
circuit.dagger() | Inverse circuit | Returns a new QCircuit |
circuit.control([qubits]) | Controlled circuit | Returns new QCircuit |
circuit.matrix() | Circuit unitary | Returns np.ndarray |
Next steps:
- Circuit Construction -- full gate and circuit API reference
- Simulation -- running programs on simulator backends
- Grover's Search -- complete Grover's algorithm tutorial
- Deutsch-Jozsa -- oracle-based algorithm tutorial