2D/Planar Circuits#

Simulation of quantum circuits on 2D qubit layouts (superconducting, trapped-ion, neutral atom devices).

Overview#

Most near-term quantum processors have qubits arranged in 2D geometries: square grids (superconducting qubits), triangular lattices (trapped ions), or arbitrary 2D patterns (neutral atoms). Simulating these circuits efficiently requires mapping the 2D layout to a 1D Matrix Product State while minimizing the entanglement cost.

The Challenge

MPS are inherently 1D: they efficiently represent states with nearest-neighbor entanglement on a chain. A 2D circuit must be “flattened” to 1D, but this mapping determines simulation cost:

  • Good mapping: Nearby qubits in 2D remain nearby in 1D → low bond dimension χ

  • Bad mapping: 2D-adjacent qubits far apart in 1D → high χ, expensive simulation

Snake Ordering

The snake (or boustrophedon) pattern is optimal for square grids [Markov08]:

2D Grid (3×3):          1D MPS Ordering:

0 - 1 - 2              0 → 1 → 2
|   |   |                      ↓
3 - 4 - 5              5 ← 4 ← 3
|   |   |              ↓
6 - 7 - 8              6 → 7 → 8

This ensures:

  • Horizontal neighbors: distance 1 in MPS

  • Vertical neighbors: distance 1 in MPS (via snake wrap)

  • Average distance: O(1) vs. O(√n) for row-major ordering

SWAP Network Synthesis

For gates between non-adjacent qubits (after 1D mapping), insert SWAP gates to move qubits together:

\[\text{CX}(q_i, q_j) \to \text{SWAP}_i^{j-1} \cdot \text{CX}(q_{j-1}, q_j) \cdot \text{SWAP}_i^{j-1}\]

Cost: O(|i-j|) SWAP gates, O(|i-j|) circuit depth increase.

Key Features

  • Automatic mapping: Snake, Hilbert curve, or custom orderings

  • SWAP optimization: Minimize inserted SWAPs via A* search or greedy heuristics

  • Topology-aware: Supports square grid, heavy-hex (IBM), triangular, arbitrary

  • Adaptive χ: Increase bond dimension for entanglement hotspots

  • 2D measurement: Correlations and observables in original 2D coordinates

Topologies#

class atlas_q.planar_2d.Topology[source]#

2D qubit layout topologies.

SQUARE_GRID#

Regular square lattice

HEAVY_HEX#

IBM heavy-hex topology

TRIANGULAR#

Triangular lattice

CUSTOM#

User-defined topology

Data Structures#

class atlas_q.planar_2d.Qubit2D[source]#

Represents a qubit in 2D layout.

Parameters:
  • row (int) – Row index

  • col (int) – Column index

  • index_1d (int) – Index in 1D MPS ordering (optional)

class atlas_q.planar_2d.Layout2D[source]#

2D qubit layout specification.

Parameters:
  • rows (int) – Number of rows

  • cols (int) – Number of columns

  • topology (Topology) – Layout topology

  • coupling_map (list) – List of connected qubit pairs

  • qubits (dict) – Dictionary mapping (row, col) to Qubit2D

class atlas_q.planar_2d.MappingConfig[source]#

Configuration for 2D → 1D mapping.

Parameters:
  • strategy (str) – Mapping strategy (‘snake’, ‘row_major’, ‘col_major’, ‘hilbert’)

  • optimize_swaps (bool) – Optimize SWAP network

  • max_swap_layers (int) – Maximum SWAP layers (default 100)

  • chi_schedule (str) – Bond dimension schedule (‘adaptive’, ‘fixed’, ‘exponential’)

Classes#

class atlas_q.planar_2d.SnakeMapper(rows, cols)[source]#

Maps 2D qubit grid to 1D MPS using snake pattern.

Snake pattern minimizes long-range interactions:

0 → 1 → 2
        ↓
5 ← 4 ← 3
↓
6 → 7 → 8
Parameters:
  • rows (int) – Number of rows

  • cols (int) – Number of columns

Methods:

map_2d_to_1d(row, col)[source]#

Map (row, col) to 1D index.

Parameters:
  • row (int) – Row index

  • col (int) – Column index

Returns:

1D index in MPS ordering

Return type:

int

map_1d_to_2d(index_1d)[source]#

Map 1D index back to (row, col).

Parameters:

index_1d (int) – 1D index

Returns:

(row, col) tuple

Return type:

tuple

get_distance(row1, col1, row2, col2)[source]#

Compute Manhattan distance in snake ordering.

Parameters:
  • row1 (int) – First row

  • col1 (int) – First column

  • row2 (int) – Second row

  • col2 (int) – Second column

Returns:

Distance in 1D MPS ordering

Return type:

int

class atlas_q.planar_2d.SWAPRouter(layout)#

SWAP network synthesis for non-nearest-neighbor gates.

Parameters:

layout (Layout2D) – 2D qubit layout

Methods:

route_gate(qubit1, qubit2)#

Find SWAP path to make qubits adjacent.

Parameters:
  • qubit1 (int) – First qubit (1D index)

  • qubit2 (int) – Second qubit (1D index)

Returns:

List of SWAP operations

Return type:

list

optimize_swap_network(gates)#

Optimize full SWAP network for gate sequence.

Parameters:

gates (list) – List of gates

Returns:

Optimized gate sequence with SWAPs inserted

Return type:

list

class atlas_q.planar_2d.PlanarCircuitSimulator(layout, config)#

Simulator for 2D planar circuits.

Parameters:

Methods:

compile_circuit(gates_2d)#

Compile 2D circuit to 1D MPS-compatible circuit.

Parameters:

gates_2d (list) – Gates with 2D qubit indices

Returns:

Gates with 1D indices and inserted SWAPs

Return type:

list

run_circuit(gates_2d)#

Run 2D circuit using MPS backend.

Parameters:

gates_2d (list) – Gates with 2D qubit indices

Returns:

Final MPS state

Return type:

AdaptiveMPS

Examples#

Snake mapping for square grid:

from atlas_q.planar_2d import SnakeMapper

# 4×4 grid
mapper = SnakeMapper(rows=4, cols=4)

# Map 2D coordinates
idx_1d = mapper.map_2d_to_1d(row=1, col=2)
print(f"(1,2) → {idx_1d}")  # Output: (1,2) → 5

# Reverse mapping
row, col = mapper.map_1d_to_2d(idx_1d)
print(f"{idx_1d} → ({row},{col})")

# Check distance
dist = mapper.get_distance(0, 0, 3, 3)
print(f"Distance from (0,0) to (3,3): {dist}")

Simulate 2D circuit:

from atlas_q.planar_2d import Layout2D, Topology, PlanarCircuitSimulator, MappingConfig

# Create 5×5 square grid layout
layout = Layout2D(
    rows=5,
    cols=5,
    topology=Topology.SQUARE_GRID,
    coupling_map=[(i, i+1) for i in range(24)],  # Simplified
    qubits={}
)

config = MappingConfig(strategy='snake', optimize_swaps=True)
sim = PlanarCircuitSimulator(layout, config)

# Define 2D circuit
gates_2d = [
    ('H', [(0, 0)], []),
    ('H', [(0, 1)], []),
    ('CZ', [(0, 0), (0, 1)], []),  # Adjacent in 2D
    ('CZ', [(0, 0), (4, 4)], []),  # Non-adjacent, requires SWAPs
]

# Compile and run
mps = sim.run_circuit(gates_2d)
print(f"Final bond dimensions: {[t.shape for t in mps.tensors]}")

SWAP routing:

from atlas_q.planar_2d import SWAPRouter

router = SWAPRouter(layout)

# Route gate between distant qubits
swaps = router.route_gate(qubit1=0, qubit2=24)  # Corners of 5×5 grid
print(f"Required SWAPs: {swaps}")

# Optimize full circuit
optimized_gates = router.optimize_swap_network(gates_2d)

Adaptive bond dimension for 2D:

config = MappingConfig(
    strategy='snake',
    chi_schedule='adaptive'  # Increase χ for long-range gates
)
sim = PlanarCircuitSimulator(layout, config)

Performance Notes#

Mapping Quality Comparison

1D Mapping Strategies for 5×5 Grid#

Mapping

Avg Distance

Max Distance

χ Required

Row-major

2.5

8

χ ~ 64-128

Column-major

2.5

8

χ ~ 64-128

Snake

1.4

4

χ ~ 32-48

Hilbert curve

1.2

3

χ ~ 24-32

Snake and Hilbert curve mappings significantly reduce required bond dimension.

SWAP Overhead Scaling

For n×n grid with random gates:

  • No optimization: ~n² SWAPs per layer

  • Greedy optimization: ~n SWAPs per layer

  • Optimal (A*): ~√n SWAPs per layer (NP-hard, only practical for small circuits)

Bond Dimension Requirements

χ for Various 2D Grid Sizes (Snake Mapping)#

Grid Size

Total Qubits

Recommended χ

Memory (GPU)

3×3

9

16-24

100 MB

5×5

25

32-48

500 MB

7×7

49

48-64

2 GB

10×10

100

64-96

8 GB

Simulation Time (per gate, NVIDIA A100)

  • 3×3 grid, χ=24: ~3 ms/gate

  • 5×5 grid, χ=32: ~12 ms/gate

  • 7×7 grid, χ=48: ~45 ms/gate

Best Practices#

Choosing Mapping Strategy

  1. Snake ordering (default): Best for square grids, simple and effective

  2. Hilbert curve: Slightly better for very large grids (>10×10), more complex

  3. Row/column-major: Avoid unless specific hardware constraints require it

  4. Custom: For irregular topologies (heavy-hex, triangular)

SWAP Optimization

# Enable SWAP optimization (recommended)
config = MappingConfig(
    strategy='snake',
    optimize_swaps=True,      # Use greedy SWAP minimization
    max_swap_layers=100       # Limit search depth
)

# For small circuits, use optimal routing
if num_gates < 50:
    config.router_algorithm = 'astar'  # Optimal but slow
else:
    config.router_algorithm = 'greedy'  # Fast heuristic

Adaptive Bond Dimension

For circuits with variable entanglement:

config = MappingConfig(
    strategy='snake',
    chi_schedule='adaptive',
    chi_min=16,
    chi_max=64,
    chi_threshold=1e-8  # Truncation threshold
)

sim = PlanarCircuitSimulator(layout, config)

χ starts at chi_min and grows to chi_max based on entanglement.

Monitoring Performance

mps = sim.run_circuit(gates_2d)

# Check bond dimensions
stats = mps.stats_summary()
print(f"Max χ: {stats['max_chi']}")
print(f"Avg χ: {stats['avg_chi']:.1f}")

# Count inserted SWAPs
compiled_gates = sim.compile_circuit(gates_2d)
swap_count = sum(1 for g in compiled_gates if g[0] == 'SWAP')
print(f"Inserted SWAPs: {swap_count}")

# If too many SWAPs, circuit may not be 2D-local
if swap_count > len(gates_2d):
    print("Warning: SWAP overhead > gate count, consider circuit cutting")

Troubleshooting

  • High χ required: Check if gates are truly local in 2D; consider circuit cutting for long-range gates

  • Too many SWAPs: Gates not respecting 2D locality; reorder operations or use different mapping

  • Memory errors: Reduce χ_max or use smaller grid sections

  • Slow compilation: Use ‘greedy’ router instead of ‘astar’ for large circuits

Limitations#

MPS vs. PEPS for 2D

2D Simulation Method Comparison#

Method

Advantages

Limitations

MPS + Snake

Fast, standard tools, χ ~ 32-64

SWAP overhead, χ grows with depth

PEPS

No SWAP, natural 2D, χ ~ 4-8

Slower contractions, experimental

Circuit Cutting

Handles arbitrary connectivity

Exponential sampling cost

Use MPS + Snake when:

  • Grid is small to medium (≤ 10×10)

  • Circuit depth moderate (≤ 20 layers)

  • Gates mostly 2D-local

Use PEPS when:

  • Grid is large (> 10×10)

  • Circuit has deep 2D structure

  • Can tolerate slower per-gate cost for lower χ

Use Circuit Cutting when:

  • Grid connectivity complex (heavy-hex, arbitrary)

  • Long-range gates frequent

  • Willing to pay classical sampling overhead

Use Cases#

Superconducting Qubit Devices

  • IBM Quantum processors (heavy-hex topology)

  • Google Sycamore (54-qubit grid)

  • Rigetti Aspen (square grid variants)

Example: Simulating Google’s 53-qubit supremacy circuit on 7×8 grid with snake mapping, χ=48.

Trapped-Ion Systems

  • IonQ (all-to-all connectivity, but often use 2D layouts)

  • Honeywell (linear chains, extendable to 2D)

Example: 10×10 triangular lattice for quantum simulation of magnetic models.

Neutral Atom Processors

  • QuEra/Harvard (arbitrary 2D patterns)

  • Pasqal (programmable geometries)

Example: Custom 2D layout optimized for QAOA on MaxCut problems.

Quantum Simulation

  • 2D Ising model dynamics

  • Hubbard model on square lattice

  • Surface code error correction

See Also#

References#

[Markov08]
    1. Markov & Y. Shi, “Simulating quantum computation by contracting tensor networks,” SIAM Journal on Computing 38, 963 (2008).

[Pednault17]
  1. Pednault et al., “Breaking the 49-qubit barrier in the simulation of quantum circuits,” arXiv:1710.05867 (2017).

[Boixo18]
  1. Boixo et al., “Characterizing quantum supremacy in near-term devices,” Nature Physics 14, 595 (2018).

[Daley22]
    1. Daley et al., “Practical quantum advantage in quantum simulation,” Nature 607, 667 (2022).