From 123b83aa0d3c1ea09c62ab6b77400501cb790a10 Mon Sep 17 00:00:00 2001 From: Anurudh Peduri <7265746+anurudhp@users.noreply.github.com> Date: Fri, 24 Jan 2025 10:16:18 -0800 Subject: [PATCH] Fix `CSwap` bloq in mod division (#1528) * fix mod division cswap * cswapapprox doc - relative phase --- qualtran/bloqs/mod_arithmetic/mod_division.py | 23 ++++++++----------- .../bloqs/mod_arithmetic/mod_division_test.py | 6 ++--- qualtran/bloqs/swap_network/cswap_approx.py | 2 +- .../bloqs/swap_network/swap_network.ipynb | 2 +- 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/qualtran/bloqs/mod_arithmetic/mod_division.py b/qualtran/bloqs/mod_arithmetic/mod_division.py index d3472103b..ba734d4b4 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_division.py +++ b/qualtran/bloqs/mod_arithmetic/mod_division.py @@ -38,16 +38,13 @@ from qualtran.bloqs.arithmetic.bitwise import BitwiseNot, XorK from qualtran.bloqs.arithmetic.comparison import LinearDepthHalfGreaterThan from qualtran.bloqs.arithmetic.controlled_addition import CAdd -from qualtran.bloqs.basic_gates import CNOT, TwoBitCSwap, XGate +from qualtran.bloqs.basic_gates import CNOT, CSwap, TwoBitCSwap, XGate from qualtran.bloqs.mcmt import And, MultiAnd from qualtran.bloqs.mod_arithmetic.mod_multiplication import ModDbl -from qualtran.bloqs.swap_network import CSwapApprox -from qualtran.resource_counting import BloqCountDictT -from qualtran.resource_counting._call_graph import SympySymbolAllocator from qualtran.symbolics import HasLength, is_symbolic if TYPE_CHECKING: - from qualtran.resource_counting import BloqCountDictT + from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator from qualtran.simulation.classical_sim import ClassicalValT from qualtran.symbolics import SymbolicInt @@ -260,14 +257,12 @@ def on_classical_vals( def build_composite_bloq( self, bb: 'BloqBuilder', u: Soquet, v: Soquet, r: Soquet, s: Soquet, a: Soquet ) -> Dict[str, 'SoquetT']: - # CSwapApprox is a CSWAP with a phase flip. - # Since we are doing two SWAPs the overal phase is correct. - a, u, v = bb.add(CSwapApprox(self.bitsize), ctrl=a, x=u, y=v) - a, r, s = bb.add(CSwapApprox(self.bitsize), ctrl=a, x=r, y=s) + a, u, v = bb.add(CSwap(self.bitsize), ctrl=a, x=u, y=v) + a, r, s = bb.add(CSwap(self.bitsize), ctrl=a, x=r, y=s) return {'u': u, 'v': v, 'r': r, 's': s, 'a': a} - def build_call_graph(self, ssa: SympySymbolAllocator) -> 'BloqCountDictT': - return {CSwapApprox(self.bitsize): 2} + def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': + return {CSwap(self.bitsize): 2} @frozen @@ -379,8 +374,8 @@ def build_composite_bloq( r = bb.add(ModDbl(QMontgomeryUInt(self.bitsize), self.mod), x=r) - a, u, v = bb.add(CSwapApprox(self.bitsize), ctrl=a, x=u, y=v) - a, r, s = bb.add(CSwapApprox(self.bitsize), ctrl=a, x=r, y=s) + a, u, v = bb.add(CSwap(self.bitsize), ctrl=a, x=u, y=v) + a, r, s = bb.add(CSwap(self.bitsize), ctrl=a, x=r, y=s) s_arr = bb.split(s) s_arr[-1] = bb.add(XGate(), q=s_arr[-1]) @@ -395,7 +390,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT': CNOT(): 3, XGate(): 2, ModDbl(QMontgomeryUInt(self.bitsize), self.mod): 1, - CSwapApprox(self.bitsize): 2, + CSwap(self.bitsize): 2, TwoBitCSwap(): self.bitsize - 1, } diff --git a/qualtran/bloqs/mod_arithmetic/mod_division_test.py b/qualtran/bloqs/mod_arithmetic/mod_division_test.py index 934a26967..44165ece2 100644 --- a/qualtran/bloqs/mod_arithmetic/mod_division_test.py +++ b/qualtran/bloqs/mod_arithmetic/mod_division_test.py @@ -74,10 +74,8 @@ def test_kaliski_mod_bloq_counts(bitsize, mod): def test_kaliski_symbolic_cost(): n, p = sympy.symbols('n p') b = KaliskiModInverse(n, p) - cost = get_cost_value(b, QECGatesCost()).total_t_and_ccz_count() - # We have some T gates since we use CSwapApprox instead of n CSWAPs. - total_toff = (cost['n_t'] / 4 + cost['n_ccz']) * sympy.Integer(1) - total_toff = total_toff.expand() + total_toff = get_cost_value(b, QECGatesCost()).total_toffoli_only() + total_toff = sympy.expand(total_toff) # The toffoli cost from Litinski https://arxiv.org/abs/2306.08585 is 26n^2 + 2n. # The cost of Kaliski is 2*n*(cost of an iteration) + (cost of computing $p - x$) diff --git a/qualtran/bloqs/swap_network/cswap_approx.py b/qualtran/bloqs/swap_network/cswap_approx.py index 7058ff684..7019e1316 100644 --- a/qualtran/bloqs/swap_network/cswap_approx.py +++ b/qualtran/bloqs/swap_network/cswap_approx.py @@ -42,7 +42,7 @@ class CSwapApprox(GateWithRegisters): r"""Approximately implements a multi-target controlled swap unitary using only $4n$ T-gates. Implements $\mathrm{CSWAP}_n = |0 \rangle\langle 0| I + |1 \rangle\langle 1| \mathrm{SWAP}_n$ - such that the output state is correct up to a global phase factor of +1 / -1. + such that the output state is correct up to a relative phase factor of +1/-1 in the standard basis. This is useful when the incorrect phase can be absorbed in a garbage state of an algorithm and thus ignored. See the reference for more details. diff --git a/qualtran/bloqs/swap_network/swap_network.ipynb b/qualtran/bloqs/swap_network/swap_network.ipynb index 49c22e5c4..ee164c884 100644 --- a/qualtran/bloqs/swap_network/swap_network.ipynb +++ b/qualtran/bloqs/swap_network/swap_network.ipynb @@ -41,7 +41,7 @@ "Approximately implements a multi-target controlled swap unitary using only $4n$ T-gates.\n", "\n", "Implements $\\mathrm{CSWAP}_n = |0 \\rangle\\langle 0| I + |1 \\rangle\\langle 1| \\mathrm{SWAP}_n$\n", - "such that the output state is correct up to a global phase factor of +1 / -1.\n", + "such that the output state is correct up to a relative phase factor of +1/-1 in the standard basis.\n", "\n", "This is useful when the incorrect phase can be absorbed in a garbage state of an algorithm\n", "and thus ignored. See the reference for more details.\n",