def test_intersection_and(): a = qp.Qubit('a') b = qp.Qubit('b') c = qp.Qubit('c') d = qp.Qubit('d') assert a & b & c == qp.QubitIntersection((a, b, c)) assert a & b & c & d == qp.QubitIntersection((a, b, c, d)) assert (a & b) & c == a & (b & c) assert (a & b) & (c & d) == a & (b & (c & d)) assert (a & b) & False == qp.QubitIntersection.NEVER assert False & (a & b) == qp.QubitIntersection.NEVER assert True & (a & b) == a & b
def test_and(): a = qp.Qubit('a') b = qp.Qubit('b') c = qp.Qubit('c') d = qp.Qubit('d') s = qp.QubitIntersection((c, d)) assert a & b == qp.QubitIntersection((a, b)) assert a & b & c == qp.QubitIntersection((a, b, c)) assert a & s == qp.QubitIntersection((a, c, d)) assert a & False == qp.QubitIntersection.NEVER assert a & True is a assert False & a == qp.QubitIntersection.NEVER assert True & a is a
def _control_qubit_exposer( val: Union['qp.Qubit', 'qp.QubitIntersection']) -> 'qp.QubitIntersection': if isinstance(val, qp.Qubit): return qp.QubitIntersection((val, )) assert isinstance(val, qp.QubitIntersection) return val
def __and__(self, other): if isinstance(other, Qubit): return qp.QubitIntersection((self, other)) if other in [False, 0]: return qp.QubitIntersection.NEVER if other in [True, 1]: return self return NotImplemented
def controlled_by(qubits: Union[bool, qp.Qubit, qp.QubitIntersection]): if isinstance(qubits, qp.Qubit): qubits = qp.QubitIntersection((qubits, )) if qubits is False: qubits = qp.QubitIntersection.NEVER if qubits is True: qubits = qp.QubitIntersection.ALWAYS return ControlledBy(qubits)
def init_storage_location(self, location: Any, controls: 'qp.QubitIntersection'): if self.rhs & (-1 << len(self.lhs)): location ^= self.invert return self.lhs ^= ~self.rhs location ^= qp.QubitIntersection(tuple(self.lhs)) & controls location ^= self.invert self.lhs ^= ~self.rhs
def clear_storage_location(self, location: Any, controls: 'qp.QubitIntersection'): if self.rhs & (-1 << len(self.lhs)): with qp.measurement_based_uncomputation(location) as b: if b: qp.phase_flip(self.invert) return with qp.measurement_based_uncomputation(location) as b: if b: self.lhs ^= ~self.rhs qp.phase_flip( qp.QubitIntersection(tuple(self.lhs)) & controls & b) qp.phase_flip(self.invert) self.lhs ^= ~self.rhs
def try_from(val: Any) -> Optional['qp.QubitIntersection']: if isinstance(val, (bool, int)): if val in [False, 0]: return qp.QubitIntersection.NEVER if val in [True, 1]: return qp.QubitIntersection.ALWAYS if isinstance(val, qp.Qubit): return qp.QubitIntersection((val,)) if isinstance(val, qp.QubitIntersection): return val return None
def phase_flip( condition: 'Union[bool, qp.Qubit, qp.QubitIntersection, qp.RValue[bool]]' = True): if isinstance(condition, qp.QubitIntersection): sink.global_sink.do_phase_flip(condition) elif condition is False or condition == qp.QubitIntersection.NEVER: pass elif condition is True: phase_flip(qp.QubitIntersection.ALWAYS) elif isinstance(condition, qp.Qubit): phase_flip(qp.QubitIntersection((condition, ))) elif isinstance(condition, (qp.Qubit, qp.RValue)): with qp.hold(condition) as q: qp.phase_flip(q) else: raise NotImplementedError( "Unknown phase flip condition: {!r}".format(condition))
def _control_qubit_manager( val: 'qp.Qubit.Control', name: str) -> ContextManager['qp.QubitIntersection']: if not isinstance(val, qp.Quint): if val is None or val in [True, 1, qp.QubitIntersection.ALWAYS]: return qp.EmptyManager(qp.QubitIntersection.ALWAYS) if val in [False, 0, qp.QubitIntersection.NEVER]: return qp.EmptyManager(qp.QubitIntersection.NEVER) if isinstance(val, qp.Qubit): return qp.EmptyManager(qp.QubitIntersection((val, ))) if isinstance(val, qp.QubitIntersection) and len(val.qubits) == 1: return qp.EmptyManager(val) if isinstance(val, qp.RValue): return qp.HeldRValueManager(val, name=name) raise TypeError( 'Expected a quantum control expression (a None, qubit, or RValue[bool]) ' 'but got {!r}.'.format(val))
assert qp.measure(qb) == b assert qp.measure(qc) == (a and b) def test_intersection_and(): a = qp.Qubit('a') b = qp.Qubit('b') c = qp.Qubit('c') d = qp.Qubit('d') assert a & b & c == qp.QubitIntersection((a, b, c)) assert a & b & c & d == qp.QubitIntersection((a, b, c, d)) assert (a & b) & c == a & (b & c) assert (a & b) & (c & d) == a & (b & (c & d)) assert (a & b) & False == qp.QubitIntersection.NEVER assert False & (a & b) == qp.QubitIntersection.NEVER assert True & (a & b) == a & b # HACK: workaround qubit name lifetime issues by hiding inside lambdas. @pytest.mark.parametrize('value', [ lambda: qp.QubitIntersection.NEVER, lambda: qp.QubitIntersection.ALWAYS, lambda: qp.QubitIntersection((qp.Qubit('a'),)), lambda: qp.QubitIntersection((qp.Qubit('a'), qp.Qubit('b'))), ]) def test_intersection_repr(value): cirq.testing.assert_equivalent_repr( value(), setup_code='import quantumpseudocode as qp')
def test_qubit_control(): @qp.semi_quantum def f(x: qp.Qubit.Control): return x q = qp.Qubit('a', 10) q2 = qp.Qubit('b', 8) # Note: The lack of capture context means we are implicitly asserting the following invokations perform no # quantum operations such as allocating a qubit. # Definitely false. assert f(False) == qp.QubitIntersection.NEVER assert f(qp.QubitIntersection.NEVER) == qp.QubitIntersection.NEVER # Definitely true. assert f(qp.QubitIntersection.ALWAYS) == qp.QubitIntersection.ALWAYS assert f(None) == qp.QubitIntersection.ALWAYS assert f(True) == qp.QubitIntersection.ALWAYS # Single qubit. assert f(q) == qp.QubitIntersection((q, )) assert f(qp.QubitIntersection((q, ))) == qp.QubitIntersection((q, )) # Multi qubit intersection. with qp.RandomSim(measure_bias=1): with qp.LogCirqCircuit() as circuit: v = f(q & q2) assert isinstance(v, qp.QubitIntersection) del v cirq.testing.assert_has_diagram(circuit, """ _f_x: ----alloc---X---Mxc-------cxM---release--- | a[10]: -----------@---------@------------------- | | b[8]: ------------@---------Z------------------- """, use_unicode_characters=False) # Arbitrary expression with qp.RandomSim(measure_bias=1): with qp.LogCirqCircuit() as circuit: rval = qp.Quint(qp.NamedQureg('a', 2)) > qp.Quint( qp.NamedQureg('b', 2)) v = f(rval) assert isinstance(v, qp.QubitIntersection) q = v.qubits[0] assert q.name == '_f_x' del q del v cirq.testing.assert_has_diagram(circuit, """ _do_if_less_than_or_equal: -----------alloc---@---X---@-------------------------------@---X---@---Mxc---cxM---release---------alloc---@---X---@-------------------------------@---X---@---Mxc---cxM---release------------------- | | | | | | | | | | | | _f_x: ------------------------alloc-----------|---|---|---------------X---------------|---|---|-------------------------Mxc-----------|---|---|-------------------------------|---|---|-------------------------cxM---release--- | | | | | | | | | | | | | a[0]: ----------------------------------------|---@---X---@---X---@---|---@---X---@---X---@---|---------------------------------------|---@---X---@---X---@-------@---X---@---X---@---|----------------------------------------- | | | | | | | | | | | | | | | | | | | | | a[1]: ----------------------------------------|-------|---|---@---X---@---X---@---|---|-------|---------------------------------------|-------|---|---@---X---Z---X---@---|---|-------|----------------------------------------- | | | | | | | | | | | | | | | | b[0]: ----------------------------------------X-------@---|-------|-------|-------|---@-------X---------------------------------------X-------@---|-------|-------|-------|---@-------X----------------------------------------- | | | | | | | | b[1]: ----------------------------------------------------X-------@-------@-------X---------------------------------------------------------------X-------@-------@-------X----------------------------------------------------- """, use_unicode_characters=False) with pytest.raises(TypeError, match='quantum control expression'): _ = f('test') with pytest.raises(TypeError, match='quantum control expression'): _ = f(qp.Quint(qp.NamedQureg('a', 10))) with pytest.raises(TypeError, match='quantum control expression'): _ = f(qp.Quint(qp.NamedQureg('a', 10)))