Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve interface for bloqs with specialized single-qubit-controlled versions #1451

Merged
merged 32 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
710c3b7
get_ctrl_system for bloqs with custom single-qubit-controlled impleme…
anurudhp Oct 8, 2024
bab48c8
replace uses of old interface
anurudhp Oct 8, 2024
c6bf154
replace uses of old interface
anurudhp Oct 8, 2024
439bf06
specialize when `ctrl_spec.num_qubits == 1`
anurudhp Oct 8, 2024
2be4510
add test example of bloq with a separate controlled bloq
anurudhp Oct 9, 2024
a8819b7
Merge branch 'main' into 2024/10/08-custom-ctrl-system
anurudhp Oct 9, 2024
163b402
Merge branch 'main' into 2024/10/08-custom-ctrl-system
mpharrigan Oct 10, 2024
6bcd466
refactor: pass parameters instead of using protocol
anurudhp Oct 15, 2024
eaf572a
`CtrlSpec.get_single_control_bit` to get the correct control bit in t…
anurudhp Oct 15, 2024
35e396e
cleanup
anurudhp Oct 15, 2024
6aa3189
use new single control bit method
anurudhp Oct 16, 2024
0746161
test ctrl bit
anurudhp Oct 16, 2024
3049d98
`control` -> `ctrl`
anurudhp Oct 16, 2024
36f903e
don't pass `bloq`
anurudhp Oct 16, 2024
e137d3e
use callable
anurudhp Oct 16, 2024
2bac28d
update examples
anurudhp Oct 16, 2024
acfe808
mypy
anurudhp Oct 16, 2024
154083e
add helper method which accepts bloqs instead of a callable
anurudhp Oct 16, 2024
cbe3b19
Merge branch 'main' into 2024/10/08-custom-ctrl-system
anurudhp Oct 16, 2024
a75b245
upgrade more usecases
anurudhp Oct 16, 2024
7ee5c8a
Merge branch 'main' into 2024/10/08-custom-ctrl-system
mpharrigan Oct 17, 2024
1be03d0
Merge branch 'main' into 2024/10/08-custom-ctrl-system
mpharrigan Oct 17, 2024
534f5f1
typo
anurudhp Oct 18, 2024
bef2774
Merge branch 'main' into 2024/10/08-custom-ctrl-system
anurudhp Oct 18, 2024
5213602
fix bug in adder
anurudhp Oct 18, 2024
be71bba
rename file to `specialized_ctrl`
anurudhp Oct 18, 2024
160479b
rename function to `get_ctrl_system_1bit_cv`
anurudhp Oct 18, 2024
2ffa8c1
Merge branch 'main' into 2024/10/08-custom-ctrl-system
anurudhp Oct 20, 2024
4a758a8
mypy
anurudhp Oct 20, 2024
0bd9f27
cleanup design
anurudhp Oct 21, 2024
bdcf674
add exposed helpers with clearer types
anurudhp Oct 21, 2024
982df48
Merge branch 'main' into 2024/10/08-custom-ctrl-system
anurudhp Oct 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions qualtran/_infra/controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Sequence,
Tuple,
TYPE_CHECKING,
TypeAlias,
Union,
)

Expand All @@ -45,6 +46,9 @@
from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator
from qualtran.simulation.classical_sim import ClassicalValT

ControlBit: TypeAlias = int
"""A control bit, either 0 or 1."""


def _cvs_convert(
cvs: Union[
Expand Down Expand Up @@ -250,6 +254,18 @@ def from_cirq_cv(
bloq_cvs.append(curr_cvs)
return CtrlSpec(tuple(qdtypes), tuple(bloq_cvs))

def get_single_ctrl_bit(self) -> ControlBit:
"""If controlled by a single qubit, return the control bit, otherwise raise"""
if self.num_qubits != 1:
raise ValueError(f"expected a single qubit control, got {self.num_qubits}")

(qdtype,) = self.qdtypes
(cv,) = self.cvs
(idx,) = Register('', qdtype, cv.shape).all_idxs()
(control_bit,) = qdtype.to_bits(cv[idx])

return int(control_bit)


class AddControlledT(Protocol):
"""The signature for the `add_controlled` callback part of `ctrl_system`.
Expand Down
20 changes: 20 additions & 0 deletions qualtran/_infra/controlled_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,26 @@ def test_ctrl_spec_to_cirq_cv_roundtrip():
assert CtrlSpec.from_cirq_cv(cirq_cv, qdtypes=ctrl_spec.qdtypes, shapes=ctrl_spec.shapes)


@pytest.mark.parametrize(
"ctrl_spec", [CtrlSpec(), CtrlSpec(cvs=[1]), CtrlSpec(cvs=np.atleast_2d([1]))]
)
def test_ctrl_spec_single_bit_one(ctrl_spec: CtrlSpec):
assert ctrl_spec.get_single_ctrl_bit() == 1


@pytest.mark.parametrize(
"ctrl_spec", [CtrlSpec(cvs=0), CtrlSpec(cvs=[0]), CtrlSpec(cvs=np.atleast_2d([0]))]
)
def test_ctrl_spec_single_bit_zero(ctrl_spec: CtrlSpec):
assert ctrl_spec.get_single_ctrl_bit() == 0


@pytest.mark.parametrize("ctrl_spec", [CtrlSpec(cvs=[1, 1]), CtrlSpec(qdtypes=QUInt(2), cvs=0)])
def test_ctrl_spec_single_bit_raises(ctrl_spec: CtrlSpec):
with pytest.raises(ValueError):
ctrl_spec.get_single_ctrl_bit()


def _test_cirq_equivalence(bloq: Bloq, gate: 'cirq.Gate'):
import cirq

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,27 @@
import numpy as np
from numpy.typing import NDArray

from qualtran import bloq_example, BloqDocSpec, BQUInt, QAny, QBit, Register, Signature
from qualtran import (
AddControlledT,
Bloq,
bloq_example,
BloqDocSpec,
BQUInt,
CtrlSpec,
QAny,
QBit,
Register,
Signature,
)
from qualtran._infra.gate_with_registers import total_bits
from qualtran._infra.single_qubit_controlled import SpecializedSingleQubitControlledExtension
from qualtran.bloqs.basic_gates import CSwap
from qualtran.bloqs.multiplexers.apply_gate_to_lth_target import ApplyGateToLthQubit
from qualtran.bloqs.multiplexers.select_base import SelectOracle
from qualtran.bloqs.multiplexers.selected_majorana_fermion import SelectedMajoranaFermion


@attrs.frozen
class SelectHubbard(SelectOracle, SpecializedSingleQubitControlledExtension): # type: ignore[misc]
class SelectHubbard(SelectOracle):
r"""The SELECT operation optimized for the 2D Hubbard model.

In contrast to SELECT for an arbitrary chemistry Hamiltonian, we:
Expand Down Expand Up @@ -180,6 +190,21 @@ def __str__(self):
return f'C{s}'
return s

def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']:
from qualtran.bloqs.mcmt.bloq_with_specialized_single_qubit_control import (
get_ctrl_system_for_bloq_with_specialized_single_qubit_control,
)

return get_ctrl_system_for_bloq_with_specialized_single_qubit_control(
ctrl_spec=ctrl_spec,
current_ctrl_bit=self.control_val,
bloq_without_ctrl=attrs.evolve(self, control_val=None),
get_ctrl_bloq_and_ctrl_reg_name=lambda cv: (
attrs.evolve(self, control_val=cv),
'control',
),
)


@bloq_example
def _sel_hubb() -> SelectHubbard:
Expand Down
33 changes: 30 additions & 3 deletions qualtran/bloqs/chemistry/sparse/select_bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,23 @@
from functools import cached_property
from typing import Dict, Optional, Tuple, TYPE_CHECKING

import attrs
import cirq
from attrs import frozen

from qualtran import bloq_example, BloqBuilder, BloqDocSpec, BQUInt, QAny, QBit, Register, SoquetT
from qualtran._infra.single_qubit_controlled import SpecializedSingleQubitControlledExtension
from qualtran import (
AddControlledT,
Bloq,
bloq_example,
BloqBuilder,
BloqDocSpec,
BQUInt,
CtrlSpec,
QAny,
QBit,
Register,
SoquetT,
)
from qualtran.bloqs.basic_gates import SGate
from qualtran.bloqs.multiplexers.select_base import SelectOracle
from qualtran.bloqs.multiplexers.selected_majorana_fermion import SelectedMajoranaFermion
Expand All @@ -30,7 +42,7 @@


@frozen
class SelectSparse(SpecializedSingleQubitControlledExtension, SelectOracle): # type: ignore[misc]
class SelectSparse(SelectOracle):
r"""SELECT oracle for the sparse Hamiltonian.

Implements the two applications of Fig. 13.
Expand Down Expand Up @@ -157,6 +169,21 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT':
c_maj_y = SelectedMajoranaFermion(sel_pa, target_gate=cirq.Y)
return {SGate(): 1, maj_x: 1, c_maj_x: 1, maj_y: 1, c_maj_y: 1}

def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']:
from qualtran.bloqs.mcmt.bloq_with_specialized_single_qubit_control import (
get_ctrl_system_for_bloq_with_specialized_single_qubit_control,
)

return get_ctrl_system_for_bloq_with_specialized_single_qubit_control(
ctrl_spec=ctrl_spec,
current_ctrl_bit=self.control_val,
bloq_without_ctrl=attrs.evolve(self, control_val=None),
get_ctrl_bloq_and_ctrl_reg_name=lambda cv: (
attrs.evolve(self, control_val=cv),
'control',
),
)


@bloq_example
def _sel_sparse() -> SelectSparse:
Expand Down
17 changes: 15 additions & 2 deletions qualtran/bloqs/chemistry/thc/select_bloq.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,19 @@
from attrs import evolve, frozen

from qualtran import (
AddControlledT,
Bloq,
bloq_example,
BloqBuilder,
BloqDocSpec,
BQUInt,
CtrlSpec,
QAny,
QBit,
Register,
Signature,
SoquetT,
)
from qualtran._infra.single_qubit_controlled import SpecializedSingleQubitControlledExtension
from qualtran.bloqs.basic_gates import CSwap, Toffoli, XGate
from qualtran.bloqs.chemistry.black_boxes import ApplyControlledZs
from qualtran.bloqs.multiplexers.select_base import SelectOracle
Expand Down Expand Up @@ -120,7 +121,7 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> 'BloqCountDictT':


@frozen
class SelectTHC(SpecializedSingleQubitControlledExtension, SelectOracle): # type: ignore[misc]
class SelectTHC(SelectOracle):
r"""SELECT for THC Hamiltonian.

Args:
Expand Down Expand Up @@ -313,6 +314,18 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str

return out_soqs

def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']:
from qualtran.bloqs.mcmt.bloq_with_specialized_single_qubit_control import (
get_ctrl_system_for_bloq_with_specialized_single_qubit_control,
)

return get_ctrl_system_for_bloq_with_specialized_single_qubit_control(
ctrl_spec=ctrl_spec,
current_ctrl_bit=self.control_val,
bloq_without_ctrl=evolve(self, control_val=None),
get_ctrl_bloq_and_ctrl_reg_name=lambda cv: (evolve(self, control_val=cv), 'control'),
)


@bloq_example
def _thc_sel() -> SelectTHC:
Expand Down
21 changes: 18 additions & 3 deletions qualtran/bloqs/for_testing/random_select_and_prepare.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
from functools import cached_property
from typing import Iterator, Optional, Tuple

import attrs
import cirq
import numpy as np
from attrs import frozen
from numpy.typing import NDArray

from qualtran import BloqBuilder, BQUInt, QBit, Register, SoquetT
from qualtran._infra.single_qubit_controlled import SpecializedSingleQubitControlledExtension
from qualtran import AddControlledT, Bloq, BloqBuilder, BQUInt, CtrlSpec, QBit, Register, SoquetT
from qualtran.bloqs.block_encoding.lcu_block_encoding import SelectBlockEncoding
from qualtran.bloqs.for_testing.matrix_gate import MatrixGate
from qualtran.bloqs.multiplexers.select_base import SelectOracle
Expand Down Expand Up @@ -84,7 +84,7 @@ def alphas(self):


@frozen
class TestPauliSelectOracle(SpecializedSingleQubitControlledExtension, SelectOracle): # type: ignore[misc]
class TestPauliSelectOracle(SelectOracle): # type: ignore[misc]
r"""Paulis acting on $m$ qubits, controlled by an $n$-qubit register.

Given $2^n$ multi-qubit-Paulis (acting on $m$ qubits) $U_j$,
Expand Down Expand Up @@ -149,6 +149,21 @@ def decompose_from_registers(
op = op.controlled_by(*quregs['control'], control_values=[self.control_val])
yield op

def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlledT']:
from qualtran.bloqs.mcmt.bloq_with_specialized_single_qubit_control import (
get_ctrl_system_for_bloq_with_specialized_single_qubit_control,
)

return get_ctrl_system_for_bloq_with_specialized_single_qubit_control(
ctrl_spec=ctrl_spec,
current_ctrl_bit=self.control_val,
bloq_without_ctrl=attrs.evolve(self, control_val=None),
get_ctrl_bloq_and_ctrl_reg_name=lambda cv: (
attrs.evolve(self, control_val=cv),
'control',
),
)


def random_qubitization_walk_operator(
select_bitsize: int, target_bitsize: int, *, random_state: np.random.RandomState
Expand Down
Loading
Loading