Qudit Circuit Basics¶

A gentle intro to ``tensorcircuit.quditcircuit.QuditCircuit``

Overview¶

This tutorial shows how to build and simulate qudit circuits (d‑level systems, where d ≥ 3) using tensorcircuit’s QuditCircuit API. Highlights

  • Create a QuditCircuit(nqudits, dim) with dimension dim ∈ [3, 36].

  • Single-qudit gates: X, Z, H, rotations RX/RY/RZ on selected levels (j, k).

  • Two‑qudit gates: RXX, RZZ, and the generalized controlled‑sum CSUM and controlled-phase CPHASE.

  • Obtain wavefunctions, probabilities, samples, expectations, and sub‑system projections.

  • Samples and bitstrings use base‑36 digits (0–9A–Z) where A = 10, ..., Z = 35.

Setup¶

[1]:
import tensorcircuit as tc
from tensorcircuit.quditcircuit import QuditCircuit

tc.set_backend("numpy")  # or "jax", "tensorflow", "pytorch"
print("tensorcircuit version:", tc.__version__)
tensorcircuit version: 1.3.0

Hello, Qutrit! (dim = 13)¶

We’ll prepare a single qudit (nqudits=1, dim=13), apply a generalized Hadamard H to put it into an equal superposition, and inspect the resulting state and probabilities.

[2]:
c = QuditCircuit(nqudits=1, dim=13)
c.h(0)  # generalized Hadamard on the only qudit
psi = c.wavefunction()  # state vector of length 13^1 = 13
probs = c.probability()  # probability vector (length 3)
print(r"\psi:", psi)
print("P:", probs)
\psi: [0.2773501+0.j 0.2773501+0.j 0.2773501+0.j 0.2773501+0.j 0.2773501+0.j
 0.2773501+0.j 0.2773501+0.j 0.2773501+0.j 0.2773501+0.j 0.2773501+0.j
 0.2773501+0.j 0.2773501+0.j 0.2773501+0.j]
P: [0.07692308 0.07692308 0.07692308 0.07692308 0.07692308 0.07692308
 0.07692308 0.07692308 0.07692308 0.07692308 0.07692308 0.07692308
 0.07692308]

Multi‑Qudit Basics¶

Let’s move to two qutrits and create a maximally entangled state using H and the qudit controlled‑sum CSUM.

The operator CSUM(control, target, cv=None) adds the control’s value to the target modulo dim. It’s a natural generalization of CNOT. If you pass cv, the gate activates only when the control equals that value (default is None).

[3]:
cq = QuditCircuit(nqudits=2, dim=3)  # two qutrits
cq.h(0)  # superpose control
cq.csum(0, 1)  # qudit CNOT analog (control=0, target=1)
psi = cq.wavefunction()
probs = cq.probability()
print(r"|\psi|^2 (length 3^2=9):", probs)
|\psi|^2 (length 3^2=9): [0.3333333 0.        0.        0.        0.3333333 0.        0.
 0.        0.3333333]

Sampling and Base‑36 Readout¶

Sampling returns strings in base‑dim using ``0-9A-Z``. For dim=3, the alphabet is 0,1,2:

[4]:
samples = cq.sample(batch=512, format="count_dict_bin")  # e.g., '00', '11', '22'
samples
[4]:
{'00': 160, '11': 171, '22': 181}

Single‑Qudit Rotations on Selected Levels¶

For a qudit, rotations target a two‑level subspace inside the d levels.

  • rx(index, theta, j=0, k=1) rotates between levels j and k about the X‑axis of that embedded SU(2).

  • ry(index, theta, j=0, k=1) similarly for Y.

  • rz(index, theta, j=0) applies a Z‑phase to a single level j.

Tip: (j, k) must be distinct integers in [0, dim-1].

[5]:
import numpy as np

c = QuditCircuit(nqudits=1, dim=5)  # a ququint
c.h(0)  # start in equal superposition
c.rx(0, theta=np.pi / 3, j=1, k=3)  # rotate levels 1 and 3
c.rz(0, theta=np.pi / 5, j=4)  # add a phase to level 4
psi = c.wavefunction()
probs = c.probability()
psi, probs
[5]:
(array([0.4472136 +0.j        , 0.38729832-0.2236068j ,
        0.4472136 +0.j        , 0.38729832-0.2236068j ,
        0.3618034 +0.26286554j], dtype=complex64),
 array([0.19999999, 0.19999997, 0.19999999, 0.19999997, 0.20000002],
       dtype=float32))

Two‑Qudit Interactions: RXX, RZZ¶

You can couple two qudits by acting on chosen subspaces of each:

  • rxx(q1, q2, theta, j1=0, k1=1, j2=0, k2=1)

  • rzz(q1, q2, theta, j1=0, k1=1, j2=0, k2=1)

Both gates are the natural generalizations of qubit XX/ZZ rotations but restricted to the (j, k) subspaces.

[6]:
c2 = QuditCircuit(nqudits=2, dim=4)  # two ququarts
c2.h(0)
c2.h(1)
c2.rxx(0, 1, theta=np.pi / 4, j1=0, k1=2, j2=1, k2=3)
c2.rzz(0, 1, theta=np.pi / 7, j1=0, k1=1, j2=0, k2=1)
c2.probability()
[6]:
array([0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625,
       0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625, 0.0625],
      dtype=float32)

Expectation Values of Local Operators¶

expectation(*ops) computes the expectation for one or more local observables. Each observable is a pair (op, [site_indices]) where op is a tensor (matrix) with appropriate dimension.

[7]:
# Example: build a diagonal operator on a single qutrit (dim=3)
import numpy as np

c = QuditCircuit(1, dim=3)
c.h(0)
op = np.diag([0.0, 0.5, 1.0])  # acts on subspace levels 0,1,2
expval = c.expectation((op, [0]))
expval
[7]:
array(0.49999997+0.j, dtype=complex64)

Apply Arbitrary Gate¶

Just directly using any API by feeding the corresponding unitary

[8]:
d = 36
c = tc.QuditCircuit(2, dim=d)
h_matrix = tc.quditgates.h_matrix_func(d)
c.any(0, unitary=h_matrix)
csum_matrix = tc.quditgates.csum_matrix_func(d)
c.any(0, 1, unitary=csum_matrix)
c.sample(1024, format="count_dict_bin")
[8]:
{'00': 29,
 '11': 35,
 '22': 29,
 '33': 41,
 '44': 25,
 '55': 28,
 '66': 28,
 '77': 35,
 '88': 32,
 '99': 27,
 'AA': 38,
 'BB': 35,
 'CC': 29,
 'DD': 31,
 'EE': 30,
 'FF': 22,
 'GG': 26,
 'HH': 19,
 'II': 26,
 'JJ': 24,
 'KK': 37,
 'LL': 27,
 'MM': 34,
 'NN': 27,
 'OO': 31,
 'PP': 31,
 'QQ': 28,
 'RR': 26,
 'SS': 23,
 'TT': 27,
 'UU': 32,
 'VV': 27,
 'WW': 19,
 'XX': 27,
 'YY': 22,
 'ZZ': 17}

Notes & Tips¶

  • Dimensions: QuditCircuit validates dim and keeps it consistent across the circuit.

  • Wavefunction & Probability: wavefunction() returns the state; probability() returns a length‑dim^n vector.

  • Sampling: sample(batch, format="str") returns base‑36 strings for readability; use format=None for raw integers.

  • Controlled Operations: csum(control, target, cv=None) generalizes CNOT; cv picks the active control value.

  • Backend: Switch via tc.set_backend("numpy" | "jax" | "tensorflow" | "pytorch") as needed.

  • Interoperability: You can still obtain matrix() for the full unitary or quoperator() MPO‑like forms for advanced workflows.

All the functions are similar to the tc.Circuit