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

[QECGatesCost] Adjustments to match t_complexity rotations, part 2 #1323

Merged
merged 9 commits into from
Aug 21, 2024
3 changes: 3 additions & 0 deletions qualtran/bloqs/basic_gates/rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ def __pow__(self, power):
def adjoint(self) -> 'CZPowGate':
return attrs.evolve(self, exponent=-self.exponent)

def __str__(self):
return f'CZ**{self.exponent}'


@frozen
class XPowGate(CirqGateAsBloqBase):
Expand Down
3 changes: 3 additions & 0 deletions qualtran/bloqs/basic_gates/rotation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ def test_pretty_name():
assert _rx().pretty_name() == "Rx"
assert _rz().pretty_name() == "Rz"

assert str(CZPowGate(1.0)) == 'CZ**1.0'
assert str(CZPowGate(0.9)) == 'CZ**0.9'


def test_rx(bloq_autotester):
bloq_autotester(_rx)
Expand Down
4 changes: 4 additions & 0 deletions qualtran/bloqs/basic_gates/su2_rotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,14 @@ def pretty_name(self) -> str:
return 'SU_2'

def __str__(self):
if self.is_symbolic():
return f'SU_2({self.theta},{self.phi},{self.lambd},{self.global_shift})'
return f'SU_2({self.theta:.2f},{self.phi:.2f},{self.lambd:.2f},{self.global_shift:.2f})'

def wire_symbol(self, reg: Optional[Register], idx: Tuple[int, ...] = tuple()) -> 'WireSymbol':
if reg is None:
if self.is_symbolic():
return Text(f'({self.theta},{self.phi},{self.lambd},{self.global_shift})')
return Text(
f'({self.theta:.2f},{self.phi:.2f},{self.lambd:.2f},{self.global_shift:.2f})'
)
Expand Down
3 changes: 3 additions & 0 deletions qualtran/bloqs/basic_gates/x_basis_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from qualtran import BloqBuilder
from qualtran.bloqs.basic_gates import MinusState, PlusEffect, PlusState, XGate
from qualtran.resource_counting import GateCounts, get_cost_value, QECGatesCost
from qualtran.simulation.classical_sim import (
format_classical_truth_table,
get_classical_truth_table,
Expand Down Expand Up @@ -44,6 +45,8 @@ def test_plus_effect():
should_be = np.array([1, 1]) / np.sqrt(2)
np.testing.assert_allclose(should_be, vector)

assert get_cost_value(bloq, QECGatesCost()) == GateCounts()


def test_plus_state_effect():
bb = BloqBuilder()
Expand Down
3 changes: 3 additions & 0 deletions qualtran/bloqs/basic_gates/z_basis_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
_zgate,
)
from qualtran.cirq_interop.t_complexity_protocol import t_complexity, TComplexity
from qualtran.resource_counting import GateCounts, get_cost_value, QECGatesCost
from qualtran.resource_counting.classify_bloqs import bloq_is_clifford


Expand Down Expand Up @@ -80,6 +81,8 @@ def test_zero_state_manual():
(x,) = bloq.call_classically()
assert x == 0

assert get_cost_value(bloq, QECGatesCost()) == GateCounts()


def test_multiq_zero_state():
# Verifying the attrs trickery that I can plumb through *some*
Expand Down
5 changes: 0 additions & 5 deletions qualtran/bloqs/chemistry/trotter/grid_ham/qvr.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

from qualtran import Bloq, bloq_example, BloqDocSpec, QAny, Register, Signature
from qualtran.bloqs.basic_gates import Rz
from qualtran.cirq_interop.t_complexity_protocol import TComplexity

if TYPE_CHECKING:
from qualtran.resource_counting import BloqCountT, SympySymbolAllocator
Expand Down Expand Up @@ -56,10 +55,6 @@ def signature(self) -> Signature:
def pretty_name(self) -> str:
return 'e^{i*phi}'

def _t_complexity_(self) -> 'TComplexity':
# Upper bounding for the moment with just phi_bitsize * Rz rotation gates.
return self.phi_bitsize * Rz(0.0).t_complexity()

def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
theta = ssa.new_symbol('theta')
# need to update rotation bloq.
Expand Down
3 changes: 1 addition & 2 deletions qualtran/bloqs/chemistry/trotter/grid_ham/qvr_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# limitations under the License.
import pytest

from qualtran.bloqs.basic_gates import Rz
from qualtran.bloqs.chemistry.trotter.grid_ham.qvr import _qvr, QuantumVariableRotation


Expand All @@ -24,4 +23,4 @@ def test_kinetic_energy(bloq_autotester):
@pytest.mark.parametrize('bitsize', [8, 16, 32])
def test_qvr_t_complexity(bitsize: int):
bloq = QuantumVariableRotation(bitsize)
assert bloq.t_complexity() == bitsize * Rz(0.0).t_complexity()
assert bloq.t_complexity().rotations == bitsize
7 changes: 0 additions & 7 deletions qualtran/bloqs/phase_estimation/lp_resource_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
)
from qualtran.bloqs.basic_gates import CZPowGate, GlobalPhase, Hadamard, OnEach, Ry, Rz, XGate
from qualtran.bloqs.mcmt import MultiControlZ
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
from qualtran.symbolics import acos, HasLength, is_symbolic, pi, SymbolicInt

if TYPE_CHECKING:
Expand Down Expand Up @@ -94,12 +93,6 @@ def build_call_graph(self, ssa: 'SympySymbolAllocator') -> Set['BloqCountT']:
}
return ret

def _t_complexity_(self) -> 'TComplexity':
# Uses self.bitsize controlled-Rz rotations which decomposes into
# 2 single-qubit rotations and 3 cliffords
# TODO: Once a CRz exists, this can be updated.
return TComplexity(rotations=2 * self.bitsize + 1, clifford=2 + 3 * self.bitsize)


@attrs.frozen
class LPResourceState(GateWithRegisters):
Expand Down
4 changes: 2 additions & 2 deletions qualtran/bloqs/phase_estimation/lp_resource_state_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def test_t_complexity(n):
qlt_testing.assert_equivalent_bloq_counts(
bloq, [ignore_split_join, ignore_alloc_free, generalize_rotation_angle]
)
lprs_interim_count = 3 * TComplexity(rotations=2 * n + 1, clifford=2 + 3 * n)
lprs_interim_count = 3 * TComplexity(rotations=n + 1, clifford=2 + n)
multi_control_pauli_count = TComplexity(t=4 * n, clifford=17 * n + 5)
misc_count = TComplexity(rotations=3, clifford=5)

Expand All @@ -140,5 +140,5 @@ def test_t_complexity(n):
@pytest.mark.parametrize('bitsize', [*range(1, 14, 2)])
def test_interim_lp2s_interim_prep_t_complexity(bitsize: int):
assert t_complexity(LPRSInterimPrep(bitsize)) == TComplexity(
rotations=2 * bitsize + 1, clifford=2 + 3 * bitsize
rotations=bitsize + 1, clifford=2 + bitsize
)
11 changes: 10 additions & 1 deletion qualtran/resource_counting/_bloq_counts.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@

from ._call_graph import get_bloq_callee_counts
from ._costing import CostKey
from .classify_bloqs import bloq_is_clifford, bloq_is_rotation, bloq_is_t_like
from .classify_bloqs import (
bloq_is_clifford,
bloq_is_rotation,
bloq_is_state_or_effect,
bloq_is_t_like,
)

if TYPE_CHECKING:
from qualtran import Bloq
Expand Down Expand Up @@ -269,6 +274,10 @@ def compute(self, bloq: 'Bloq', get_callee_cost: Callable[['Bloq'], GateCounts])
if bloq_is_clifford(bloq):
return GateCounts(clifford=1)

# States and effects
if bloq_is_state_or_effect(bloq):
return GateCounts()

# Bookkeeping, empty bloqs
if isinstance(bloq, _BookkeepingBloq) or isinstance(bloq, (GlobalPhase, Identity)):
return GateCounts()
Expand Down
7 changes: 7 additions & 0 deletions qualtran/resource_counting/classify_bloqs.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,10 @@ def bloq_is_rotation(b: Bloq) -> bool:
return True

return False


def bloq_is_state_or_effect(b: Bloq) -> bool:
from qualtran.bloqs.basic_gates.x_basis import _XVector
from qualtran.bloqs.basic_gates.z_basis import _ZVector

return isinstance(b, (_XVector, _ZVector))
Loading