Skip to content

[open-systems] Phased classical simulation #1590

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

Open
wants to merge 53 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
a9d5d7f
notey
mpharrigan Mar 5, 2025
62e9fee
ctrl
mpharrigan Mar 5, 2025
ac2db81
qdtype
mpharrigan Mar 5, 2025
fbca42b
ctrl spec
mpharrigan Mar 5, 2025
4dfe53a
controlled
mpharrigan Mar 5, 2025
0f3b5a1
controlled
mpharrigan Mar 5, 2025
d8bbe49
data types
mpharrigan Mar 5, 2025
a747b51
on classical vals
mpharrigan Mar 5, 2025
497d7ee
dtypes
mpharrigan Mar 5, 2025
9bba4e4
registers
mpharrigan Mar 5, 2025
efe6f0f
registers
mpharrigan Mar 5, 2025
e145433
bloq ctrl spec
mpharrigan Mar 5, 2025
dedc304
cast
mpharrigan Mar 5, 2025
9fc5300
bloq dtypes
mpharrigan Mar 5, 2025
e0f2b41
controlled
mpharrigan Mar 5, 2025
c58116c
bloq dtypes
mpharrigan Mar 5, 2025
535c8ef
ctrl
mpharrigan Mar 5, 2025
9e97cc9
bloq dtypes
mpharrigan Mar 5, 2025
f283249
bloq dtypes
mpharrigan Mar 5, 2025
a26cdab
bloq dtypes
mpharrigan Mar 5, 2025
f9bd77d
bloq dtypes
mpharrigan Mar 5, 2025
a10a331
bloq dtypes
mpharrigan Mar 5, 2025
1c758d4
bloq dtypes
mpharrigan Mar 5, 2025
f57cdcc
drawing
mpharrigan Mar 5, 2025
d0773f1
drawing
mpharrigan Mar 5, 2025
ba39913
annotations
mpharrigan Mar 5, 2025
300b8ba
bits
mpharrigan Mar 5, 2025
bad1f36
bits
mpharrigan Mar 5, 2025
d668e62
init
mpharrigan Mar 5, 2025
e699973
init
mpharrigan Mar 5, 2025
85907da
controlled docs
mpharrigan Mar 5, 2025
96f2cbb
lint
mpharrigan Mar 5, 2025
919bdd9
fixes
mpharrigan Mar 5, 2025
b05d94d
Merge remote-tracking branch 'origin/main' into 2025-03/classical-1
mpharrigan Mar 5, 2025
40ef237
format
mpharrigan Mar 5, 2025
22e3184
autogenerate notebooks
mpharrigan Mar 5, 2025
aabe689
Merge remote-tracking branch 'origin/main' into 2025-03/classical-1
mpharrigan Mar 5, 2025
70bac9a
add notebook to toc
mpharrigan Mar 5, 2025
6e93114
fix musical score serialization
mpharrigan Mar 5, 2025
8951104
phased classical sim
mpharrigan Mar 5, 2025
9e1bb8c
docstring
mpharrigan Mar 5, 2025
7492027
Merge remote-tracking branch 'origin/main' into 2025-03/classical-1
mpharrigan Mar 10, 2025
8fb94c6
Merge branch '2025-03/classical-1' into 2025-03/classical-sim-1
mpharrigan Mar 10, 2025
3a395f7
stuff
mpharrigan Mar 10, 2025
fa68016
Merge remote-tracking branch 'origin/main' into 2025-03/classical-1
mpharrigan Mar 13, 2025
63ed9b4
Merge branch '2025-03/classical-1' into 2025-03/classical-sim-1
mpharrigan Mar 13, 2025
678ba7b
Merge remote-tracking branch 'origin/main' into 2025-03/classical-1
mpharrigan Apr 7, 2025
bb6b510
Merge branch '2025-03/classical-1' into 2025-03/classical-sim-1
mpharrigan Apr 7, 2025
5c79a89
Merge remote-tracking branch 'origin/main' into 2025-03/classical-1
mpharrigan Apr 9, 2025
d0b77d6
Merge branch '2025-03/classical-1' into 2025-03/classical-sim-1
mpharrigan Apr 9, 2025
3d09d66
Signature.n_xbits
mpharrigan Apr 9, 2025
9e62a54
Merge branch '2025-03/classical-1' into 2025-03/classical-sim-1
mpharrigan Apr 9, 2025
de0c07a
Merge remote-tracking branch 'origin/main' into 2025-03/classical-sim-1
mpharrigan Apr 9, 2025
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
25 changes: 22 additions & 3 deletions qualtran/_infra/bloq.py
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@
GeneralizerT,
SympySymbolAllocator,
)
from qualtran.simulation.classical_sim import ClassicalValT
from qualtran.simulation.classical_sim import ClassicalValRetT, ClassicalValT


def _decompose_from_build_composite_bloq(bloq: 'Bloq') -> 'CompositeBloq':
@@ -184,13 +184,13 @@ def adjoint(self) -> 'Bloq':

def on_classical_vals(
self, **vals: Union['sympy.Symbol', 'ClassicalValT']
) -> Mapping[str, 'ClassicalValT']:
) -> Mapping[str, 'ClassicalValRetT']:
"""How this bloq operates on classical data.

Override this method if your bloq represents classical, reversible logic. For example:
quantum circuits composed of X and C^nNOT gates are classically simulable.

Bloq definers should override this method. If you already have an instance of a `Bloq`,
Bloq authors should override this method. If you already have an instance of a `Bloq`,
consider calling `call_clasically(**vals)` which will do input validation before
calling this function.

@@ -215,6 +215,25 @@ def on_classical_vals(
except NotImplementedError as e:
raise NotImplementedError(f"{self} does not support classical simulation: {e}") from e

def basis_state_phase(self, **vals: 'ClassicalValT') -> Union[complex, None]:
"""How this bloq phases classical basis states.

Override this method if your bloq represents classical logic with basis-state
dependent phase factors. This corresponds to bloqs whose matrix representation
(in the standard basis) is a generalized permutation matrix: a permutation matrix
where each entry can be +1, -1 or any complex number with unit absolute value.
Alternatively, this corresponds to bloqs composed from classical operations
(X, CNOT, Toffoli, ...) and diagonal operations (T, CZ, CCZ, ...).

Bloq authors should override this method. If you are using an instantiated bloq object,
call TODO and not this method directly.

If this method is implemented, `on_classical_vals` must also be implemented.
If `on_classical_vals` is implemented but this method is not implemented, it is assumed
that the bloq does not alter the phase.
"""
return None

def call_classically(
self, **vals: Union['sympy.Symbol', 'ClassicalValT']
) -> Tuple['ClassicalValT', ...]:
16 changes: 14 additions & 2 deletions qualtran/_infra/controlled.py
Original file line number Diff line number Diff line change
@@ -47,7 +47,7 @@
from qualtran.cirq_interop import CirqQuregT
from qualtran.drawing import WireSymbol
from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator
from qualtran.simulation.classical_sim import ClassicalValT
from qualtran.simulation.classical_sim import ClassicalValRetT, ClassicalValT

ControlBit: TypeAlias = int
"""A control bit, either 0 or 1."""
@@ -432,7 +432,7 @@ def signature(self) -> 'Signature':
# Prepend register(s) corresponding to `ctrl_spec`.
return Signature(self.ctrl_regs + tuple(self.subbloq.signature))

def on_classical_vals(self, **vals: 'ClassicalValT') -> Mapping[str, 'ClassicalValT']:
def on_classical_vals(self, **vals: 'ClassicalValT') -> Mapping[str, 'ClassicalValRetT']:
"""Classical action of controlled bloqs.

This involves conditionally doing the classical action of `subbloq`. All implementers
@@ -453,6 +453,18 @@ def on_classical_vals(self, **vals: 'ClassicalValT') -> Mapping[str, 'ClassicalV

return vals

def basis_state_phase(self, **vals: 'ClassicalValT') -> Union[complex, None]:
"""Phasing action of controlled bloqs.

This involves conditionally doing the phasing action of `subbloq`. All implementers
of `_ControlledBase` should provide a decomposition that satisfies this phase funciton.
"""
ctrl_vals = [vals[reg_name] for reg_name in self.ctrl_reg_names]
other_vals = {reg.name: vals[reg.name] for reg in self.subbloq.signature}
if self.ctrl_spec.is_active(*ctrl_vals):
return self.subbloq.basis_state_phase(**other_vals)
return None

def _tensor_data(self):
"""Dense tensor encoding a controlled unitary.

10 changes: 10 additions & 0 deletions qualtran/bloqs/basic_gates/z_basis.py
Original file line number Diff line number Diff line change
@@ -52,6 +52,7 @@

from qualtran.cirq_interop import CirqQuregT
from qualtran.resource_counting import BloqCountDictT, SympySymbolAllocator
from qualtran.simulation.classical_sim import ClassicalValT

_ZERO = np.array([1, 0], dtype=np.complex128)
_ONE = np.array([0, 1], dtype=np.complex128)
@@ -359,6 +360,15 @@ def get_ctrl_system(self, ctrl_spec: 'CtrlSpec') -> Tuple['Bloq', 'AddControlled
self, ctrl_spec, current_ctrl_bit=1, bloq_with_ctrl=self, ctrl_reg_name='q1'
)

def on_classical_vals(self, **vals: 'ClassicalValT') -> Dict[str, 'ClassicalValT']:
# Diagonal, but causes phases: see `basis_state_phase`
return vals

def basis_state_phase(self, q1: int, q2: int) -> Optional[complex]:
if q1 == 1 and q2 == 1:
return -1
return 1


@bloq_example
def _cz() -> CZ:
31 changes: 31 additions & 0 deletions qualtran/bloqs/basic_gates/z_basis_test.py
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@
IntState,
OneEffect,
OneState,
XGate,
ZeroEffect,
ZeroState,
ZGate,
@@ -245,3 +246,33 @@ def test_cz_manual():

assert ZGate().controlled() == CZ()
assert t_complexity(cz) == TComplexity(clifford=1)

with pytest.raises(ValueError, match='.*phase.*'):
cz.call_classically(q1=1, q2=1)


def test_cz_phased_classical():
cz = CZ()
from qualtran.simulation.classical_sim import do_phased_classical_simulation

final_vals, phase = do_phased_classical_simulation(cz, {'q1': 0, 'q2': 1})
assert final_vals['q1'] == 0
assert final_vals['q2'] == 1
assert phase == 1

final_vals, phase = do_phased_classical_simulation(cz, {'q1': 1, 'q2': 1})
assert final_vals['q1'] == 1
assert final_vals['q2'] == 1
assert phase == -1

bb = BloqBuilder()
q1 = bb.add(ZeroState())
q2 = bb.add(ZeroState())
q1 = bb.add(XGate(), q=q1)
q2 = bb.add(XGate(), q=q2)
q1, q2 = bb.add(CZ(), q1=q1, q2=q2)
cbloq = bb.finalize(q1=q1, q2=q2)
final_vals, phase = do_phased_classical_simulation(cbloq, {})
assert final_vals['q1'] == 1
assert final_vals['q2'] == 1
assert phase == -1
Loading