Skip to content

Commit 098f7ea

Browse files
authored
Make Toffoli an atomic, leaf bloq (#1388)
* Make Toffoli an atomic, leaf bloq * Link issue
1 parent 21922ee commit 098f7ea

20 files changed

+110
-94
lines changed

qualtran/bloqs/arithmetic/conversions/ones_complement_to_twos_complement_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,18 @@
1616
_signed_to_twos,
1717
SignedIntegerToTwosComplement,
1818
)
19-
from qualtran.bloqs.basic_gates import TGate
19+
from qualtran.bloqs.basic_gates import Toffoli
2020

2121

2222
def test_signed_to_twos(bloq_autotester):
2323
bloq_autotester(_signed_to_twos)
2424

2525

26-
def test_signed_to_twos_complement_t_complexity():
26+
def test_signed_to_twos_complement_toffoli_count():
2727
bb = BloqBuilder()
2828
bitsize = 5
2929
q0 = bb.add_register('x', bitsize)
3030
q0 = bb.add(SignedIntegerToTwosComplement(bitsize), x=q0)
3131
cbloq = bb.finalize(x=q0)
3232
_, sigma = cbloq.call_graph()
33-
assert sigma[TGate()] == 4 * (5 - 2)
33+
assert sigma[Toffoli()] == (5 - 2)

qualtran/bloqs/basic_gates/toffoli.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,31 @@
1313
# limitations under the License.
1414
import itertools
1515
from functools import cached_property
16-
from typing import Dict, List, Optional, Set, Tuple, TYPE_CHECKING, Union
16+
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING, Union
1717

1818
import numpy as np
1919
from attrs import frozen
2020
from numpy.typing import NDArray
2121

22-
from qualtran import Bloq, bloq_example, BloqDocSpec, Connection, QBit, Register, Signature
23-
from qualtran.bloqs.basic_gates import TGate
22+
from qualtran import (
23+
Bloq,
24+
bloq_example,
25+
BloqDocSpec,
26+
CompositeBloq,
27+
Connection,
28+
DecomposeTypeError,
29+
QBit,
30+
Register,
31+
Signature,
32+
)
2433
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
25-
from qualtran.resource_counting import SympySymbolAllocator
2634

2735
if TYPE_CHECKING:
2836
import cirq
2937
import quimb.tensor as qtn
3038

3139
from qualtran.cirq_interop import CirqQuregT
3240
from qualtran.drawing import WireSymbol
33-
from qualtran.resource_counting import BloqCountT, SympySymbolAllocator
3441
from qualtran.simulation.classical_sim import ClassicalValT
3542

3643

@@ -56,8 +63,8 @@ def signature(self) -> Signature:
5663
def adjoint(self) -> 'Bloq':
5764
return self
5865

59-
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
60-
return {(TGate(), 4)}
66+
def decompose_bloq(self) -> 'CompositeBloq':
67+
raise DecomposeTypeError(f"{self} is atomic")
6168

6269
def _t_complexity_(self):
6370
return TComplexity(t=4)

qualtran/bloqs/basic_gates/toffoli_test.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import numpy as np
1818

1919
from qualtran import BloqBuilder
20-
from qualtran.bloqs.basic_gates import TGate, Toffoli, ZeroState
20+
from qualtran.bloqs.basic_gates import Toffoli, ZeroState
2121
from qualtran.bloqs.basic_gates.toffoli import _toffoli
2222
from qualtran.drawing.musical_score import Circle, ModPlus
2323
from qualtran.testing import assert_wire_symbols_match_expected
@@ -27,12 +27,9 @@ def test_toffoli(bloq_autotester):
2727
bloq_autotester(_toffoli)
2828

2929

30-
def test_toffoli_t_count():
31-
counts = Toffoli().bloq_counts()
32-
assert counts == {TGate(): 4}
33-
30+
def test_toffoli_sigma():
3431
_, sigma = Toffoli().call_graph()
35-
assert sigma == {TGate(): 4}
32+
assert sigma == {Toffoli(): 1}
3633

3734

3835
def test_toffoli_cirq():

qualtran/bloqs/chemistry/df/prepare_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from openfermion.resource_estimates.utils import power_two, QI, QR
1717

18-
from qualtran.bloqs.basic_gates import TGate
18+
from qualtran.bloqs.basic_gates import Toffoli
1919
from qualtran.bloqs.chemistry.df.prepare import (
2020
_indexed_data,
2121
_prep_inner,
@@ -70,7 +70,7 @@ def test_outerprep_t_counts():
7070
assert toff == cost1a_mod + cost1b + cost1cd
7171

7272

73-
def test_indexed_data_t_counts():
73+
def test_indexed_data_toffoli_counts():
7474
num_spin_orb = 108
7575
num_aux = 360
7676
num_bits_rot_aa = 7
@@ -79,12 +79,12 @@ def test_indexed_data_t_counts():
7979
num_aux=num_aux, num_spin_orb=num_spin_orb, num_eig=num_eig, num_bits_rot_aa=num_bits_rot_aa
8080
)
8181
_, counts = in_l_data_l.call_graph()
82-
toff = counts[TGate()] // 4
82+
toff = counts[Toffoli()]
8383
in_l_data_l = OutputIndexedData(
8484
num_aux=num_aux, num_spin_orb=num_spin_orb, num_eig=num_eig, num_bits_rot_aa=num_bits_rot_aa
8585
).adjoint()
8686
_, counts = in_l_data_l.call_graph()
87-
toff += counts[TGate()] // 4
87+
toff += counts[Toffoli()]
8888
# captured from cost2 in openfermion df.compute_cost
8989
nxi = (num_spin_orb // 2 - 1).bit_length()
9090
nlxi = (num_eig + num_spin_orb // 2 - 1).bit_length()

qualtran/bloqs/chemistry/df/select_bloq_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from openfermion.resource_estimates.utils import QI, QR
1616

17-
from qualtran.bloqs.basic_gates import TGate
17+
from qualtran.bloqs.basic_gates import Toffoli
1818
from qualtran.bloqs.chemistry.df.select_bloq import ProgRotGateArray
1919

2020

@@ -27,12 +27,12 @@ def test_rotations():
2727
num_aux=num_aux, num_eig=num_eig, num_spin_orb=num_spin_orb, num_bits_rot=num_bits_rot
2828
)
2929
_, counts = rot.call_graph()
30-
toff = counts[TGate()] // 4
30+
toff = counts[Toffoli()]
3131
rot = ProgRotGateArray(
3232
num_aux=num_aux, num_eig=num_eig, num_spin_orb=num_spin_orb, num_bits_rot=num_bits_rot
3333
).adjoint()
3434
_, counts = rot.call_graph()
35-
toff += counts[TGate()] // 4
35+
toff += counts[Toffoli()]
3636
toff *= 2 # cost is for the two applications of the (rot, rot^) pair
3737
# the rot gate array includes the offset addition, qrom and cost for applying the rotations.
3838
# it does not include the swaps and the controlled Z which is included in the openfermion costs.

qualtran/bloqs/chemistry/pbc/first_quantization/prepare_t_test.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from qualtran.bloqs.basic_gates import TGate
15+
from qualtran.bloqs.basic_gates import Toffoli
1616
from qualtran.bloqs.chemistry.pbc.first_quantization.prepare import (
1717
UniformSuperpostionIJFirstQuantization,
1818
)
@@ -34,15 +34,14 @@ def test_prepare_kinetic_t_counts():
3434
expected_cost = (14 * n_eta + 8 * b_r - 36) + 2 * (2 * num_bits_p + 9)
3535
uni = UniformSuperpostionIJFirstQuantization(eta, num_bits_rot_aa=b_r)
3636
_, counts = uni.call_graph()
37-
qual_cost = counts[TGate()]
37+
qual_cost = counts[Toffoli()]
3838
uni = UniformSuperpostionIJFirstQuantization(eta, num_bits_rot_aa=b_r).adjoint()
3939
_, counts = uni.call_graph()
40-
qual_cost += counts[TGate()]
40+
qual_cost += counts[Toffoli()]
4141
prep = PrepareTFirstQuantization(num_bits_p, eta, num_bits_rot_aa=b_r)
4242
_, counts = prep.call_graph()
43-
qual_cost += counts[TGate()]
43+
qual_cost += counts[Toffoli()]
4444
prep = PrepareTFirstQuantization(num_bits_p, eta, num_bits_rot_aa=b_r).adjoint()
4545
_, counts = prep.call_graph()
46-
qual_cost += counts[TGate()]
47-
qual_cost //= 4
46+
qual_cost += counts[Toffoli()]
4847
assert qual_cost == expected_cost

qualtran/bloqs/chemistry/pbc/first_quantization/projectile/prepare_t_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
import pytest
1616

17-
from qualtran.bloqs.basic_gates import TGate
17+
from qualtran.bloqs.basic_gates import Toffoli
1818
from qualtran.bloqs.chemistry.pbc.first_quantization.projectile.prepare_t import (
1919
_prep_power_two_proj,
2020
_prep_t_proj,
@@ -40,13 +40,12 @@ def test_prepare_kinetic_t_proj_counts():
4040
qual_cost = 0
4141
prep = PrepareTFirstQuantizationWithProj(num_bits_p, num_bits_n, eta, num_bits_rot_aa=b_r)
4242
_, counts = prep.call_graph()
43-
qual_cost += counts[TGate()]
43+
qual_cost += counts[Toffoli()]
4444
prep = PrepareTFirstQuantizationWithProj(
4545
num_bits_p, num_bits_n, eta, num_bits_rot_aa=b_r
4646
).adjoint()
4747
_, counts = prep.call_graph()
48-
qual_cost += counts[TGate()]
49-
qual_cost //= 4
48+
qual_cost += counts[Toffoli()]
5049
assert qual_cost == expected_cost
5150

5251

qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_and_prepare_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import numpy as np
1616
import pytest
1717

18-
from qualtran.bloqs.basic_gates import TGate
1918
from qualtran.bloqs.chemistry.pbc.first_quantization.projectile.select_and_prepare import (
2019
_prep_first_quant,
2120
_sel_first_quant,
@@ -68,7 +67,7 @@ def test_select_t_costs():
6867
assert cost == expected_cost
6968

7069

71-
def test_prepare_t_costs():
70+
def test_prepare_toffoli_costs():
7271
num_bits_p = 6
7372
num_bits_n = 8
7473
eta = 10
@@ -90,7 +89,7 @@ def test_prepare_t_costs():
9089
num_bits_rot_aa=b_r,
9190
num_bits_t=num_bits_t,
9291
)
93-
cost += prep_first_quant.call_graph()[1][TGate()] // 4
92+
cost += get_cost_value(prep_first_quant, QECGatesCost()).total_toffoli_only()
9493
prep_first_quant = PrepareFirstQuantizationWithProj(
9594
num_bits_p,
9695
num_bits_n,
@@ -102,7 +101,7 @@ def test_prepare_t_costs():
102101
num_bits_rot_aa=b_r,
103102
num_bits_t=num_bits_t,
104103
).adjoint()
105-
cost += prep_first_quant.call_graph()[1][TGate()] // 4
104+
cost += get_cost_value(prep_first_quant, QECGatesCost()).total_toffoli_only()
106105
n_eta = (eta - 1).bit_length()
107106
expected_cost = 6 * num_bits_t + 2 # C1
108107
expected_cost += 14 * n_eta + 8 * b_r - 36 # C2

qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_t_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
from qualtran.bloqs.basic_gates import TGate
14+
from qualtran.bloqs.basic_gates import Toffoli
1515
from qualtran.bloqs.chemistry.pbc.first_quantization.projectile.select_t import (
1616
_sel_t_proj,
1717
SelectTFirstQuantizationWithProj,
@@ -26,4 +26,4 @@ def test_select_kinetic_t_counts():
2626
num_bits_n = 6
2727
sel = SelectTFirstQuantizationWithProj(num_bits_n, 10)
2828
_, counts = sel.call_graph()
29-
assert counts[TGate()] // 4 == 5 * (num_bits_n - 1) + 2 + 1
29+
assert counts[Toffoli()] == 5 * (num_bits_n - 1) + 2 + 1

qualtran/bloqs/chemistry/pbc/first_quantization/projectile/select_uv_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,18 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
from qualtran.bloqs.basic_gates import TGate
1514
from qualtran.bloqs.chemistry.pbc.first_quantization.projectile.select_uv import (
1615
_sel_uv_proj,
1716
SelectUVFirstQuantizationWithProj,
1817
)
18+
from qualtran.resource_counting import get_cost_value, QECGatesCost
1919

2020

2121
def test_sel_uv_proj(bloq_autotester):
2222
bloq_autotester(_sel_uv_proj)
2323

2424

25-
def test_select_uv_t_counts():
25+
def test_select_uv_toffoli_counts():
2626
num_bits_p = 6
2727
num_bits_n = 9
2828
eta = 10
@@ -32,8 +32,7 @@ def test_select_uv_t_counts():
3232
expected_cost += 3 * num_bits_p + 3 * num_bits_n
3333
expected_cost += 3 * (2 * num_bits_n * num_bits_nuc_pos - num_bits_n * (num_bits_n + 1) - 1)
3434
sel = SelectUVFirstQuantizationWithProj(num_bits_p, num_bits_n, eta, eta, num_bits_nuc_pos)
35-
_, counts = sel.call_graph()
36-
qual_cost = counts[TGate()] // 4
35+
qual_cost = get_cost_value(sel, QECGatesCost()).total_toffoli_only()
3736
# -6 due to different cost of addition.
3837
qual_cost += 6
3938
assert qual_cost == expected_cost

0 commit comments

Comments
 (0)