diff --git a/qualtran/bloqs/basic_gates/hadamard.py b/qualtran/bloqs/basic_gates/hadamard.py index 477f11c44..7fcb1ddaa 100644 --- a/qualtran/bloqs/basic_gates/hadamard.py +++ b/qualtran/bloqs/basic_gates/hadamard.py @@ -64,6 +64,9 @@ def add_my_tensors( ) ) + def short_name(self) -> 'str': + return 'H' + def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: diff --git a/qualtran/bloqs/basic_gates/t_gate.py b/qualtran/bloqs/basic_gates/t_gate.py index 0db5e68cc..0e3ca231c 100644 --- a/qualtran/bloqs/basic_gates/t_gate.py +++ b/qualtran/bloqs/basic_gates/t_gate.py @@ -57,6 +57,9 @@ def signature(self) -> 'Signature': def t_complexity(self) -> 'TComplexity': return TComplexity(t=1) + def short_name(self) -> str: + return 'T' + def as_cirq_op( self, qubit_manager: 'cirq.QubitManager', q: 'CirqQuregT' ) -> Tuple['cirq.Operation', Dict[str, 'CirqQuregT']]: diff --git a/qualtran/bloqs/basic_gates/x_basis.py b/qualtran/bloqs/basic_gates/x_basis.py index b89b93fa7..04d3cdbb7 100644 --- a/qualtran/bloqs/basic_gates/x_basis.py +++ b/qualtran/bloqs/basic_gates/x_basis.py @@ -164,6 +164,9 @@ def add_my_tensors( ) ) + def short_name(self) -> str: + return 'X' + def on_classical_vals(self, q: int) -> Dict[str, 'ClassicalValT']: return {'q': (q + 1) % 2} diff --git a/qualtran/bloqs/basic_gates/z_basis.py b/qualtran/bloqs/basic_gates/z_basis.py index 4c793457f..86d082129 100644 --- a/qualtran/bloqs/basic_gates/z_basis.py +++ b/qualtran/bloqs/basic_gates/z_basis.py @@ -171,6 +171,9 @@ class ZGate(Bloq): def signature(self) -> 'Signature': return Signature.build(q=1) + def short_name(self) -> 'str': + return 'Z' + def add_my_tensors( self, tn: qtn.TensorNetwork, diff --git a/qualtran/bloqs/on_each.py b/qualtran/bloqs/on_each.py new file mode 100644 index 000000000..fa3877951 --- /dev/null +++ b/qualtran/bloqs/on_each.py @@ -0,0 +1,57 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Classes to apply single qubit bloq to multiple qubits.""" +from functools import cached_property +from typing import Dict + +import attrs + +from qualtran import Bloq, BloqBuilder, Register, Signature, SoquetT + + +@attrs.frozen +class OnEach(Bloq): + """Add a single-qubit (unparameterized) bloq on each of n qubits. + + Args: + n: the number of qubits to add the bloq to. + gate: A single qubit gate. The single qubit register must be named q. + + Registers: + - q: an n-qubit register. + """ + + n: int + gate: Bloq + + def __attrs_post_init__(self): + assert len(self.gate.signature) == 1, "Gate must only have a single register." + assert self.gate.signature[0].bitsize == 1, "Must be single qubit gate." + assert self.gate.signature[0].name == 'q', "Register must be named q." + + @cached_property + def signature(self) -> Signature: + reg = Register('q', bitsize=self.n) + return Signature([reg]) + + def short_name(self) -> str: + return rf'{self.gate.short_name()}⨂{self.n}' + + def build_composite_bloq(self, bb: BloqBuilder, *, q: SoquetT) -> Dict[str, SoquetT]: + + qs = bb.split(q) + for i in range(self.n): + qs[i] = bb.add(self.gate, q=qs[i]) + return {'q': bb.join(qs)} diff --git a/qualtran/bloqs/on_each_test.py b/qualtran/bloqs/on_each_test.py new file mode 100644 index 000000000..08edb3e8b --- /dev/null +++ b/qualtran/bloqs/on_each_test.py @@ -0,0 +1,32 @@ +# Copyright 2023 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from functools import reduce + +import numpy as np + +import qualtran.testing as qlt_testing +from qualtran.bloqs.basic_gates import Hadamard, XGate +from qualtran.bloqs.on_each import OnEach + + +def test_valid_bloq(): + on_each = OnEach(10, XGate()) + qlt_testing.assert_valid_bloq_decomposition(on_each) + + +def test_tensor_contract(): + bloq = OnEach(5, Hadamard()) + tensor = bloq.tensor_contract() + single_had = Hadamard().tensor_contract() + np.testing.assert_allclose(tensor, reduce(np.kron, (single_had,) * 5))