Skip to content

Commit 71a84d2

Browse files
authored
Split util_bloqs.py into individual files (#1006)
* Split * Join * Bookkeeping * Partition * Allocate * Free * Arbitrary Clifford * Cast * Power * Complete the split * update resolver dict
1 parent fcf4ddc commit 71a84d2

24 files changed

Lines changed: 1235 additions & 874 deletions

qualtran/bloqs/arithmetic/addition.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
SoquetT,
5757
)
5858
from qualtran.bloqs.basic_gates import CNOT, XGate
59-
from qualtran.bloqs.bookkeeping import util_bloqs
59+
from qualtran.bloqs.bookkeeping import ArbitraryClifford
6060
from qualtran.bloqs.mcmt.and_bloq import And
6161
from qualtran.bloqs.mcmt.multi_control_multi_target_pauli import MultiControlX
6262
from qualtran.cirq_interop import decompose_from_cirq_style_method
@@ -352,7 +352,7 @@ def _t_complexity_(self) -> TComplexity:
352352
def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
353353
return {
354354
(And(uncompute=self.is_adjoint), self.bitsize),
355-
(util_bloqs.ArbitraryClifford(n=2), 5 * self.bitsize),
355+
(ArbitraryClifford(n=2), 5 * self.bitsize),
356356
}
357357

358358
def __pow__(self, power: int):

qualtran/bloqs/arithmetic/subtraction.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
)
3434
from qualtran.bloqs.arithmetic.addition import Add, AddK
3535
from qualtran.bloqs.basic_gates import XGate
36-
from qualtran.bloqs.bookkeeping import util_bloqs
36+
from qualtran.bloqs.bookkeeping import Join, Split
3737
from qualtran.drawing import Text
3838

3939
if TYPE_CHECKING:
@@ -129,8 +129,8 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
129129
(XGate(), self.b_dtype.bitsize),
130130
(AddK(self.b_dtype.bitsize, k=1), 1),
131131
(Add(a_dtype, b_dtype), 1),
132-
(util_bloqs.Split(self.b_dtype), 1),
133-
(util_bloqs.Join(self.b_dtype), 1),
132+
(Split(self.b_dtype), 1),
133+
(Join(self.b_dtype), 1),
134134
}
135135

136136
def build_composite_bloq(self, bb: 'BloqBuilder', a: Soquet, b: Soquet) -> Dict[str, 'SoquetT']:

qualtran/bloqs/bookkeeping/__init__.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
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.bookkeeping.util_bloqs import (
15-
Allocate,
16-
ArbitraryClifford,
17-
Cast,
18-
Free,
19-
Join,
20-
Partition,
21-
Power,
22-
Split,
23-
)
14+
"""Bloqs for virtual operations and register reshaping."""
15+
16+
from qualtran.bloqs.bookkeeping.allocate import Allocate
17+
from qualtran.bloqs.bookkeeping.arbitrary_clifford import ArbitraryClifford
18+
from qualtran.bloqs.bookkeeping.cast import Cast
19+
from qualtran.bloqs.bookkeeping.free import Free
20+
from qualtran.bloqs.bookkeeping.join import Join
21+
from qualtran.bloqs.bookkeeping.partition import Partition
22+
from qualtran.bloqs.bookkeeping.power import Power
23+
from qualtran.bloqs.bookkeeping.split import Split
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import abc
16+
from typing import Dict, Iterable, Optional, Sequence, Tuple, TYPE_CHECKING
17+
18+
from qualtran import Bloq, BloqBuilder, SoquetT
19+
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
20+
21+
if TYPE_CHECKING:
22+
23+
from qualtran import AddControlledT, CtrlSpec
24+
25+
26+
class _BookkeepingBloq(Bloq, metaclass=abc.ABCMeta):
27+
"""Base class for utility bloqs used for bookkeeping.
28+
29+
This bloq:
30+
- has trivial controlled versions, which pass through the control register.
31+
- does not affect T complexity.
32+
"""
33+
34+
def get_ctrl_system(
35+
self, ctrl_spec: Optional['CtrlSpec'] = None
36+
) -> Tuple['Bloq', 'AddControlledT']:
37+
def add_controlled(
38+
bb: 'BloqBuilder', ctrl_soqs: Sequence['SoquetT'], in_soqs: Dict[str, 'SoquetT']
39+
) -> Tuple[Iterable['SoquetT'], Iterable['SoquetT']]:
40+
# ignore `ctrl_soq` and pass it through for bookkeeping operation.
41+
out_soqs = bb.add_t(self, **in_soqs)
42+
return ctrl_soqs, out_soqs
43+
44+
return self, add_controlled
45+
46+
def _t_complexity_(self) -> 'TComplexity':
47+
return TComplexity()
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from functools import cached_property
15+
from typing import Any, Dict, Tuple, TYPE_CHECKING
16+
17+
import numpy as np
18+
from attrs import frozen
19+
20+
from qualtran import Bloq, QDType, Register, Side, Signature, SoquetT
21+
from qualtran.bloqs.bookkeeping._bookkeeping_bloq import _BookkeepingBloq
22+
from qualtran.drawing import directional_text_box, Text, WireSymbol
23+
24+
if TYPE_CHECKING:
25+
import quimb.tensor as qtn
26+
27+
28+
@frozen
29+
class Allocate(_BookkeepingBloq):
30+
"""Allocate an `n` bit register.
31+
32+
Attributes:
33+
dtype: the quantum data type of the allocated register.
34+
"""
35+
36+
dtype: QDType
37+
38+
@cached_property
39+
def signature(self) -> Signature:
40+
return Signature([Register('reg', self.dtype, side=Side.RIGHT)])
41+
42+
def adjoint(self) -> 'Bloq':
43+
from qualtran.bloqs.bookkeeping.free import Free
44+
45+
return Free(self.dtype)
46+
47+
def on_classical_vals(self) -> Dict[str, int]:
48+
return {'reg': 0}
49+
50+
def add_my_tensors(
51+
self,
52+
tn: 'qtn.TensorNetwork',
53+
tag: Any,
54+
*,
55+
incoming: Dict[str, 'SoquetT'],
56+
outgoing: Dict[str, 'SoquetT'],
57+
):
58+
import quimb.tensor as qtn
59+
60+
data = np.zeros(1 << self.dtype.num_qubits)
61+
data[0] = 1
62+
tn.add(qtn.Tensor(data=data, inds=(outgoing['reg'],), tags=['Allocate', tag]))
63+
64+
def wire_symbol(self, reg: Register, idx: Tuple[int, ...] = tuple()) -> 'WireSymbol':
65+
if reg is None:
66+
return Text('')
67+
assert reg.name == 'reg'
68+
return directional_text_box('alloc', Side.RIGHT)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import subprocess
15+
16+
import numpy as np
17+
import pytest
18+
19+
from qualtran import BloqBuilder, QAny
20+
from qualtran.bloqs.bookkeeping import Allocate, Free
21+
from qualtran.testing import execute_notebook
22+
23+
24+
def test_free_nonzero_state_vector_leads_to_unnormalized_state():
25+
from qualtran.bloqs.basic_gates.hadamard import Hadamard
26+
from qualtran.bloqs.basic_gates.on_each import OnEach
27+
28+
bb = BloqBuilder()
29+
qs1 = bb.add(Allocate(QAny(10)))
30+
qs2 = bb.add(OnEach(10, Hadamard()), q=qs1)
31+
no_return = bb.add(Free(QAny(10)), reg=qs2)
32+
assert np.allclose(bb.finalize().tensor_contract(), np.sqrt(1 / 2**10))
33+
34+
35+
@pytest.mark.notebook
36+
def test_notebook():
37+
execute_notebook('bookkeeping_bloqs')
38+
39+
40+
def test_no_circular_import():
41+
subprocess.check_call(['python', '-c', 'from qualtran.bloqs.bookkeeping import allocate'])
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from functools import cached_property
15+
from typing import Union
16+
17+
from attrs import frozen
18+
from sympy import Expr
19+
20+
from qualtran import Bloq, QAny, Register, Signature
21+
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
22+
23+
24+
@frozen
25+
class ArbitraryClifford(Bloq):
26+
"""A bloq representing an arbitrary `n`-qubit clifford operation.
27+
28+
In the surface code architecture, clifford operations are generally considered
29+
cheaper than non-clifford gates. Each clifford also has roughly the same cost independent
30+
of what particular operation it is doing.
31+
32+
You can use this to bloq to represent an arbitrary clifford operation e.g. in bloq_counts
33+
resource estimates where the details are unimportant for the resource estimation task
34+
at hand.
35+
"""
36+
37+
n: Union[int, Expr]
38+
39+
@cached_property
40+
def signature(self) -> Signature:
41+
return Signature([Register('x', QAny(bitsize=self.n))])
42+
43+
def _t_complexity_(self) -> 'TComplexity':
44+
return TComplexity(clifford=1)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import subprocess
15+
16+
17+
def test_no_circular_import():
18+
subprocess.check_call(
19+
['python', '-c', 'from qualtran.bloqs.bookkeeping import arbitrary_clifford']
20+
)
File renamed without changes.

qualtran/bloqs/bookkeeping/cast.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
from functools import cached_property
15+
from typing import Any, Dict, Tuple, TYPE_CHECKING
16+
17+
import attrs
18+
import numpy as np
19+
from attrs import frozen
20+
21+
from qualtran import Bloq, QDType, Register, Side, Signature, SoquetT
22+
from qualtran.bloqs.bookkeeping._bookkeeping_bloq import _BookkeepingBloq
23+
24+
if TYPE_CHECKING:
25+
import quimb.tensor as qtn
26+
27+
from qualtran.cirq_interop import CirqQuregT
28+
from qualtran.simulation.classical_sim import ClassicalValT
29+
30+
31+
@frozen
32+
class Cast(_BookkeepingBloq):
33+
"""Cast a register from one n-bit QDType to another QDType.
34+
35+
36+
Args:
37+
inp_dtype: Input QDType to cast from.
38+
out_dtype: Output QDType to cast to.
39+
shape: shape of the register to cast.
40+
41+
Registers:
42+
in: input register to cast from.
43+
out: input register to cast to.
44+
"""
45+
46+
inp_dtype: QDType
47+
out_dtype: QDType
48+
shape: Tuple[int, ...] = attrs.field(
49+
default=tuple(), converter=lambda v: (v,) if isinstance(v, int) else tuple(v)
50+
)
51+
52+
def __attrs_post_init__(self):
53+
if isinstance(self.inp_dtype.num_qubits, int):
54+
if self.inp_dtype.num_qubits != self.out_dtype.num_qubits:
55+
raise ValueError("Casting only permitted between same sized registers.")
56+
57+
def adjoint(self) -> 'Bloq':
58+
return Cast(inp_dtype=self.out_dtype, out_dtype=self.inp_dtype)
59+
60+
@cached_property
61+
def signature(self) -> Signature:
62+
return Signature(
63+
[
64+
Register('reg', dtype=self.inp_dtype, shape=self.shape, side=Side.LEFT),
65+
Register('reg', dtype=self.out_dtype, shape=self.shape, side=Side.RIGHT),
66+
]
67+
)
68+
69+
def add_my_tensors(
70+
self,
71+
tn: 'qtn.TensorNetwork',
72+
tag: Any,
73+
*,
74+
incoming: Dict[str, 'SoquetT'],
75+
outgoing: Dict[str, 'SoquetT'],
76+
):
77+
import quimb.tensor as qtn
78+
79+
tn.add(
80+
qtn.Tensor(
81+
data=np.eye(2**self.inp_dtype.num_qubits, 2**self.inp_dtype.num_qubits),
82+
inds=[outgoing['reg']] + [incoming['reg']],
83+
tags=['Cast', tag],
84+
)
85+
)
86+
87+
def on_classical_vals(self, reg: int) -> Dict[str, 'ClassicalValT']:
88+
# TODO: Actually cast the values https://github.com/quantumlib/Qualtran/issues/734
89+
return {'reg': reg}
90+
91+
def as_cirq_op(self, qubit_manager, reg: 'CirqQuregT') -> Tuple[None, Dict[str, 'CirqQuregT']]:
92+
return None, {'reg': reg}

0 commit comments

Comments
 (0)