Rank: 57 / 549 | Score: 220 / 400
Quantum circuit challenge organized by Yale University in collaboration with BlueQubit. The goal was to find the peak bitstring (dominant amplitude) of increasingly complex quantum circuits in QASM format.
A "peaked circuit" is a quantum circuit designed so that one specific bitstring has a significantly higher probability amplitude than all others. The challenge is to find that bitstring efficiently without running a full statevector simulation when the qubit count makes that infeasible.
| Problem | Name | Qubits | Points | Answer | Score |
|---|---|---|---|---|---|
| P1 | Little Peak | 4 | 10 | 1001 |
10/10 |
| P2 | Small Bump | 12 | 20 | 111010100110 |
20/20 |
| P3 | Tiny Ripple | 30 | 30 | 000110111010100110100001111100 |
30/30 |
| P4 | Gentle Mound | 40 | 40 | 0001001110100001100110110100001101110000 |
40/40 |
| P5 | Soft Rise | 50 | 50 | 10011000011001010100101101101010000010110011011000 |
50/50 |
| P6 | Low Hill | 60 | 60 | — | 0/60 |
| P7 | Rolling Ridge | 42 | 70 | 101101010100001000100011001011101011000100 |
70/70 |
| P8 | Bold Peak | 58 | 80 | — | 0/80 |
| P9 | Grand Summit | 69 | 90 | — | 0/90 |
| P10 | Eternal Mountain | 56 | 100 | — | 0/100 |
Answer: 1001
With only 4 qubits, the full statevector has 2^4 = 16 amplitudes. Exact statevector simulation is trivial. After running the circuit and measuring, 1001 appeared with overwhelming frequency across all shots, confirming it as the peak. The circuit's gate structure was simple enough that the peak was visible immediately from the output distribution.
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
qc = QuantumCircuit.from_qasm_file('P1_little_peak.qasm')
qc.measure_all()
sim = AerSimulator(method='statevector')
result = sim.run(qc, shots=1024).result()
counts = result.get_counts()
print(max(counts, key=counts.get))Answer: 111010100110
12 qubits means 2^12 = 4096 amplitudes — still well within statevector limits. Same approach as P1. The peak bitstring 111010100110 dominated the output distribution clearly across 1024 shots.
Answer: 000110111010100110100001111100
30 qubits requires 2^30 ~ 1 billion amplitudes, which needs around 8GB of memory. This was feasible on BlueQubit's LARGE notebook (157GB RAM). The first submission attempt returned a wrong answer due to bit ordering — the second run with corrected measurement ordering gave the correct result. Peak confidence was around 10%, meaning the circuit was moderately entangling but the dominant bitstring was still clearly identifiable.
Answer: 0001001110100001100110110100001101110000
40 qubits. BlueQubit's LARGE notebook handled it through optimized memory management. The circuit's relatively low depth and entanglement structure kept the peak bitstring prominent at ~22% probability, making it easy to identify from sampling.
Answer: 10011000011001010100101101101010000010110011011000
50 qubits. The circuit showed a near-flat distribution initially, suggesting high entanglement. Increased shot count and ran multiple times to confirm the dominant bitstring. The peak appeared consistently at ~22% probability across runs, confirming the answer.
Answer: 101101010100001000100011001011101011000100
The key insight was analyzing the qubit connectivity graph. By building an adjacency graph from all two-qubit gates in the circuit, it became clear the circuit decomposed into independent subcircuits with no entanglement between them. Each subcircuit was simulated independently using exact statevector, and the results were concatenated in the correct qubit order to form the full 42-bit peak bitstring. Peak confidence per subcircuit was ~41%.
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from collections import defaultdict
qc = QuantumCircuit.from_qasm_file('P7_rolling_ridge.qasm')
adj = defaultdict(set)
for gate in qc.data:
qubits = [qc.find_bit(q).index for q in gate.qubits]
if len(qubits) == 2:
adj[qubits[0]].add(qubits[1])
adj[qubits[1]].add(qubits[0])
visited = set()
components = []
for q in range(qc.num_qubits):
if q not in visited:
comp = []
stack = [q]
while stack:
node = stack.pop()
if node not in visited:
visited.add(node)
comp.append(node)
stack.extend(adj[node] - visited)
components.append(sorted(comp))
print(f"Components: {[len(c) for c in components]}")
sim = AerSimulator(method='statevector')
full_peak = ['0'] * qc.num_qubits
for comp in components:
sub = QuantumCircuit(len(comp))
mapping = {old: new for new, old in enumerate(comp)}
for gate in qc.data:
idxs = [qc.find_bit(q).index for q in gate.qubits]
if all(i in mapping for i in idxs):
sub.append(gate.operation, [mapping[i] for i in idxs])
sub.measure_all()
compiled = transpile(sub, sim, optimization_level=3)
result = sim.run(compiled, shots=512).result()
counts = result.get_counts()
peak = max(counts, key=counts.get)
for bit_pos, qubit in enumerate(comp):
full_peak[qc.num_qubits - 1 - qubit] = peak[len(comp) - 1 - bit_pos]
print(''.join(full_peak))For the unsolved circuits, the following approaches were attempted and failed:
BlueQubit cloud GPU/CPU — statevector backend capped at 34-35 qubits. All circuits here were 56-69 qubits, so every cloud submission returned a validation error.
Local MPS with low bond dimension (32) — ran fast but was too approximate. Produced bitstrings of wrong values. Bond dimension 32 cannot capture the entanglement structure of these deep circuits accurately enough.
Local MPS with full bond dimension, high shots — theoretically correct but took 30-60+ minutes per circuit on BlueQubit's LARGE notebook. Ran out of time before any completed.
The correct approach based on post-hackathon analysis:
- PyZX algebraic simplification — use
zx.simplify.clifford_simp()to collapse redundant gates using ZX-calculus. For circuits like P9 and P10, this reduces gate count from 5000+ down to under 400, making MPS feasible. - Qiskit Level 3 transpilation with approximation_degree=0.99 — particularly effective for P6, which responded well to approximate transpilation alone.
- MPS simulation with bond dimension 128 — after PyZX simplification, MPS simulation with BD=128 resolves the probability peak in reasonable time.
import pyzx as zx
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
qc = QuantumCircuit.from_qasm_file('P10_eternal_mountain.qasm')
circuit = zx.Circuit.from_qasm(qc.qasm())
zx.simplify.clifford_simp(circuit.to_graph())
simplified = circuit.to_basic_gates()
qc2 = QuantumCircuit.from_qasm_str(simplified.to_qasm())
qc2.measure_all()
sim = AerSimulator(method='matrix_product_state')
compiled = transpile(qc2, basis_gates=['u', 'cx'], optimization_level=3)
result = sim.run(compiled, shots=256).result()
counts = result.get_counts()
print(max(counts, key=counts.get))pip install qiskit qiskit-aer pyzxAll circuits were run on BlueQubit's LARGE notebook environment (157GB RAM, Python 3.11).