Exercises: Microsoft Q
All of these run locally — pip install qdk, then from qdk import qsharp. No Azure account is
needed, including for the resource estimator. Solutions to starred exercises are in
Answers to Selected Exercises.
Warm-up
15.1 ★ Write and run a Q# operation producing a 3-qubit GHZ state. Return a Result[] and report
the histogram over 1000 shots.
15.2 Write a Q# function that computes $n!$ for Int input. Then try to add a use q = Qubit()
to it and record the exact compiler error.
15.3 ★ For each of the six rejected programs in §15.4, write the Python or Qiskit equivalent and determine whether it fails at all, and if so whether at import time, at call time, or silently. Present as a three-column table.
15.4 M(q) returns a Result, not a Bool or Int. Write a Q# operation that tries to add two
Result values and record the error. Then find the standard-library function that converts a Result
to a Bool.
Types and structure
15.5 ★ Write an operation taking (Double, Qubit) and call it with the arguments swapped. Compare
the resulting error message to what Python produces for the analogous mistake. Which tells you more,
and how much earlier?
15.6 ★★ Q# distinguishes let (immutable) from mutable/set. Write an operation using a
mutable accumulator inside a for loop. Then make it let and record the error. What class of bug
does this distinction prevent?
15.7 ★★ Write a Q# operation implementing Chapter 3's arbitrary single-qubit state preparation
$(\theta, \phi)$. Declare it is Adj + Ctl. Verify that Op followed by Adjoint Op returns the
qubit to $|0\rangle$ over 500 shots.
15.8 ★★ Take the operation from 15.7 and add a measurement inside it, keeping the is Adj
declaration. Record the error. Explain in two sentences why this rejection is mathematically necessary
rather than a design choice.
15.9 ★★ Implement a controlled version of your 15.7 operation by hand, without the Controlled
functor. Compare its gate count to what Controlled Op generates. Was the compiler's version better,
worse, or the same?
Qubit lifetime
15.10 ★ Reproduce §15.5's release error. Then fix it three different ways: Reset, ResetAll, and
by applying the inverse of whatever put the qubit in that state. Which is most robust, and why?
15.11 ★★ Confirm §15.5's limit: write an operation that reuses a qubit mid-body without resetting, resets at the end, and runs cleanly. Then write a version where the missing reset produces a measurably wrong answer, and show that Q# still accepts it.
15.12 ★★ Q# also has borrow for borrowing qubits in arbitrary (not necessarily $|0\rangle$)
states. Read its documentation and write an operation using it. What contract does borrow require
you to satisfy instead, and why does that make it useful for ancillas?
Resource estimation
15.13 ★ Estimate a 2-qubit circuit with H and CNOT only. Report physical qubits and the number
of T factories. Explain the factory count in one sentence.
15.14 ★ Add one T gate to 15.13's circuit and re-estimate. Report the ratio in physical qubits.
Then explain the jump in terms of transversality.
15.15 ★★ Reproduce §15.8's full T-count sweep for 0, 1, 3, 10, 30, and 100 T gates. Identify the
saturation point and explain what the estimator is trading at that point.
15.16 ★★ Run the same circuit under all four qubit technologies. Rank them by physical qubits, then by runtime. Do the rankings agree? What does that tell you about "which qubit technology is best"?
15.17 ★★ Using vqelab.resources.logical_counts, report both tCount and rotationCount
for: (a) a Toffoli, (b) a 3-controlled X, (c) a QFT on 4 qubits from Qiskit's library. Two of the
three have a T count of zero — explain why, given that CLIFFORD_T_BASIS contains rz. Then
price all three with estimate_resources and rank them by physical qubits. The cost ranking is the
reverse of the T-count ranking. Finally, re-price (c) with rotationCount forced to 0, the
mistake you would make by reading only the tCount field, and report the factor by which it
understates. What does this say about "T count" as a single-number summary of fault-tolerant cost?
15.18 ★★★ Chapter 13 §13.5's ZNE folded a circuit to 3×, 5×, and 7× its gate count. Estimate the fault-tolerant cost of the folded circuits. Does error mitigation make sense in a fault-tolerant setting? Defend your answer with numbers.
15.19 ★★★ Estimate Grover's algorithm for a 40-bit search space (Chapter 21 gives the circuit structure; roughly $2^{20}$ iterations, each with a Toffoli-heavy oracle). Compare the result to brute-force classical search. At what search size does the quantum approach win, accounting for the physical qubit cost?
15.20 ★★★ Reproduce Case Study 1's RSA table. Then compute the marginal cost of each additional key bit: how many physical qubits does moving from 2048 to 2049 bits add? From 2048 to 4096?
The scorecard
15.21 ★★ Take three bugs from Case Study 2's "missed" column and explain, for each, precisely what information a type system would need in order to catch it. Is that information available at compile time even in principle?
15.22 ★★ Chapter 8's parameter-ordering bug is impossible in both Q# and Cirq, for different reasons. State each reason. Then propose an API change to Qiskit that would make it impossible there too, and identify what it would cost in convenience.
15.23 ★★★ Write a Q# program containing Chapter 7's layout trap — an observable not mapped to the transpiled circuit's qubits. Confirm it compiles. Then write the smallest possible test that catches it. What does the comparison tell you about where verification effort belongs?
Project
15.24 ★★ (Project Checkpoint) Build vqelab/resources.py with logical_counts() (transpiling to
a Clifford+T basis first), estimate_resources(), estimate_circuit(), t_count_sweep(), and a
ResourceEstimate dataclass exposing factory_fraction. Write tests asserting:
- A Clifford-only circuit has T count 0.
- A Toffoli costs 7 T gates.
- A Clifford-only circuit requires zero T factories.
- Adding one T gate multiplies the physical qubit count by more than 3.
- At 10 T gates, factories exceed 90% of the machine.
- Physical qubits are monotonic in T count.
- A $10^{-4}$ error rate needs less than a tenth the qubits of $10^{-3}$.
- An end-to-end Qiskit circuit containing a Toffoli requires factories.
Tests 3, 4, and 7 assert properties of fault tolerance, not of your implementation — which is what makes them safe to depend on.
15.25 ★★★ Extend resources.py with compare_technologies(circuit), producing a table across all
four qubit parameter sets, and find_minimum_error_rate(circuit, qubit_budget), which answers: given
a hardware budget of $N$ physical qubits, what physical error rate would I need for this circuit to
fit? Run it on Case Study 1's RSA-2048 counts with a budget of one million qubits.
Going further
15.26 ★★★ Q# is not the only resource estimator. Find one other (Azure QRE's published models, or a research tool), estimate the same circuit in both, and account for any discrepancy. Which assumptions differ?
15.27 ★★★ §15.8 found that improving the physical error rate by 10× reduced qubit count by 27×. Derive the expected exponent from surface-code scaling ($d^2$ qubits per patch, $d$ set by the ratio of physical error rate to threshold) and compare it to the measured 27×. Does the estimator's model match the textbook scaling?