def _parity_interaction(q0: ops.QubitId, q1: ops.QubitId, rads: float, tolerance: float, gate: Optional[ops.ReversibleEffect] = None): """Yields a ZZ interaction framed by the given operation.""" if abs(rads) < tolerance: return h = rads * -2 / np.pi if gate is not None: g = cast(ops.Gate, gate) yield g.on(q0), g.on(q1) # If rads is ±pi/4 radians within tolerance, single full-CZ suffices. if _is_trivial_angle(rads, tolerance): yield ops.CZ.on(q0, q1) else: yield _easy_direction_partial_cz(q0, q1, -2 * h) yield ops.Z(q0)**h yield ops.Z(q1)**h if gate is not None: g = cast(ops.Gate, gate.inverse()) yield g.on(q0), g.on(q1)
def _parity_interaction(q0: 'cirq.Qid', q1: 'cirq.Qid', rads: float, atol: float, gate: Optional[ops.Gate] = None): """Yields a ZZ interaction framed by the given operation.""" if abs(rads) < atol: return h = rads * -2 / np.pi if gate is not None: g = cast(ops.Gate, gate) yield g.on(q0), g.on(q1) # If rads is ±pi/4 radians within tolerance, single full-CZ suffices. if _is_trivial_angle(rads, atol): yield ops.CZ.on(q0, q1) else: yield ops.CZ(q0, q1)**(-2 * h) yield ops.Z(q0)**h yield ops.Z(q1)**h if gate is not None: g = protocols.inverse(gate) yield g.on(q0), g.on(q1)
def _decompose_(self, qubits): from cirq import ops a, b = qubits return [ ops.GlobalPhaseOperation(self.global_phase), ops.MatrixGate(self.single_qubit_operations_before[0]).on(a), ops.MatrixGate(self.single_qubit_operations_before[1]).on(b), np.exp(1j * ops.X(a) * ops.X(b) * self.interaction_coefficients[0]), np.exp(1j * ops.Y(a) * ops.Y(b) * self.interaction_coefficients[1]), np.exp(1j * ops.Z(a) * ops.Z(b) * self.interaction_coefficients[2]), ops.MatrixGate(self.single_qubit_operations_after[0]).on(a), ops.MatrixGate(self.single_qubit_operations_after[1]).on(b), ]
def _potential_cross_whole_w(moment_index: int, op: ops.Operation, tolerance: float, state: _OptimizerState) -> None: """Grabs or cancels a held W gate against an existing W gate. [Where W(a) is shorthand for PhasedX(phase_exponent=a).] Uses the following identity: ───W(a)───W(b)─── ≡ ───Z^-a───X───Z^a───Z^-b───X───Z^b─── ≡ ───Z^-a───Z^-a───Z^b───X───X───Z^b─── ≡ ───Z^-a───Z^-a───Z^b───Z^b─── ≡ ───Z^2(b-a)─── """ state.deletions.append((moment_index, op)) _, phase_exponent = cast(Tuple[float, float], _try_get_known_phased_pauli(op)) q = op.qubits[0] a = state.held_w_phases.get(q) b = phase_exponent if a is None: # Collect the gate. state.held_w_phases[q] = b else: # Cancel the gate. state.held_w_phases[q] = None t = 2 * (b - a) if not decompositions.is_negligible_turn(t / 2, tolerance): leftover_phase = ops.Z(q)**t state.inline_intos.append((moment_index, leftover_phase))
def _potential_cross_whole_w(moment_index: int, op: ops.Operation, tolerance: float, state: _OptimizerState) -> None: """Grabs or cancels a held W gate against an existing W gate. Uses the following identity: ───W(a)───W(b)─── ≡ ───Z^-a───X───Z^a───Z^-b───X───Z^b─── ≡ ───Z^-a───Z^-a───Z^b───X───X───Z^b─── ≡ ───Z^-a───Z^-a───Z^b───Z^b─── ≡ ───Z^2(b-a)─── """ state.deletions.append((moment_index, op)) w = cast(ExpWGate, _try_get_known_w(op)) q = op.qubits[0] a = state.held_w_phases.get(q) b = cast(float, w.axis_half_turns) if a is None: # Collect the gate. state.held_w_phases[q] = b else: # Cancel the gate. state.held_w_phases[q] = None t = 2 * (b - a) if not decompositions.is_negligible_turn(t / 2, tolerance): leftover_phase = ops.Z(q)**t state.inline_intos.append((moment_index, leftover_phase))
def xmon_op_from_proto(proto: operations_pb2.Operation) -> 'cirq.Operation': """Convert the proto to the corresponding operation. See protos in api/google/v1 for specification of the protos. Args: proto: Operation proto. Returns: The operation. """ param = _parameterized_value_from_proto qubit = _qubit_from_proto if proto.HasField('exp_w'): exp_w = proto.exp_w return ops.PhasedXPowGate( exponent=param(exp_w.half_turns), phase_exponent=param(exp_w.axis_half_turns), ).on(qubit(exp_w.target)) if proto.HasField('exp_z'): exp_z = proto.exp_z return ops.Z(qubit(exp_z.target))**param(exp_z.half_turns) if proto.HasField('exp_11'): exp_11 = proto.exp_11 return ops.CZ(qubit(exp_11.target1), qubit(exp_11.target2))**param(exp_11.half_turns) if proto.HasField('measurement'): meas = proto.measurement return ops.MeasurementGate(num_qubits=len(meas.targets), key=meas.key, invert_mask=tuple(meas.invert_mask)).on( *[qubit(q) for q in meas.targets]) raise ValueError(f'invalid operation: {proto}')
def test_to_from_braket_common_one_qubit_gates(): """These gates should stay the same (i.e., not get decomposed) when converting Cirq -> Braket -> Cirq. """ rots = [ops.rx, ops.ry, ops.rz] angles = [1 / 5, 3 / 5, -4 / 5] qubit = LineQubit(0) cirq_circuit = Circuit( # Paulis. ops.X(qubit), ops.Y(qubit), ops.Z(qubit), # Single-qubit rotations. [rot(angle).on(qubit) for rot, angle in zip(rots, angles)], # Rz alter egos. ops.T(qubit), ops.T(qubit)**-1, ops.S(qubit), ops.S(qubit)**-1, # Rx alter egos. ops.X(qubit)**0.5, ops.X(qubit)**-0.5, ) test_circuit = from_braket(to_braket(cirq_circuit)) assert _equal(test_circuit, cirq_circuit, require_qubit_equality=True)
def _sqrt_iswap_inv(a: 'cirq.Qid', b: 'cirq.Qid', use_sqrt_iswap_inv: bool = True) -> 'cirq.OP_TREE': """Optree implementing `cirq.SQRT_ISWAP_INV(a, b)` using √iSWAPs. Args: a: The first qubit. b: The second qubit. use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. Returns: `cirq.SQRT_ISWAP_INV(a, b)` or equivalent unitary implemented using `cirq.SQRT_ISWAP`. """ return (ops.SQRT_ISWAP_INV(a, b) if use_sqrt_iswap_inv else [ops.Z(a), ops.SQRT_ISWAP(a, b), ops.Z(a)])
def _potential_cross_whole_w( op: ops.Operation, atol: float, held_w_phases: Dict[ops.Qid, value.TParamVal]) -> 'cirq.OP_TREE': """Grabs or cancels a held W gate against an existing W gate. [Where W(a) is shorthand for PhasedX(phase_exponent=a).] Uses the following identity: ───W(a)───W(b)─── ≡ ───Z^-a───X───Z^a───Z^-b───X───Z^b─── ≡ ───Z^-a───Z^-a───Z^b───X───X───Z^b─── ≡ ───Z^-a───Z^-a───Z^b───Z^b─── ≡ ───Z^2(b-a)─── """ _, phase_exponent = cast(Tuple[value.TParamVal, value.TParamVal], _try_get_known_phased_pauli(op)) q = op.qubits[0] a = held_w_phases.get(q, None) b = phase_exponent if a is None: # Collect the gate. held_w_phases[q] = b else: # Cancel the gate. del held_w_phases[q] t = 2 * (b - a) if not single_qubit_decompositions.is_negligible_turn(t / 2, atol): return ops.Z(q)**t return []
def dump_phases(qubits, index): for q in qubits: p = turns_state[q] if not is_negligible_turn(p, self.tolerance): dump_op = ops.Z(q)**(p * 2) insertions.append((index, dump_op)) turns_state[q] = 0
def controlled_op_to_operations(control: ops.QubitId, target: ops.QubitId, operation: np.ndarray, tolerance: float = 0.0) -> List[ops.Operation]: """Decomposes a controlled single-qubit operation into Z/XY/CZ gates. Args: control: The control qubit. target: The qubit to apply an operation to, when the control is on. operation: The single-qubit operation being controlled. tolerance: A limit on the amount of error introduced by the construction. Returns: A list of Operations that apply the controlled operation. """ u, z_phase, global_phase = single_qubit_op_to_framed_phase_form(operation) if abs(z_phase - 1) <= tolerance: return [] u_gates = single_qubit_matrix_to_gates(u, tolerance) if u_gates and isinstance(u_gates[-1], ops.ZPowGate): # Don't keep border operations that commute with CZ. del u_gates[-1] ops_before = [gate(target) for gate in u_gates] ops_after = protocols.inverse(ops_before) effect = ops.CZ(control, target)**(cmath.phase(z_phase) / math.pi) kickback = ops.Z(control)**(cmath.phase(global_phase) / math.pi) return list( ops.flatten_op_tree( (ops_before, effect, kickback if abs(global_phase - 1) > tolerance else [], ops_after)))
def _Z( q: int, args: sim.ActOnCliffordTableauArgs, operations: List[ops.Operation], qubits: List['cirq.Qid'], ): protocols.act_on(ops.Z, args, qubits=[qubits[q]], allow_decompose=False) operations.append(ops.Z(qubits[q]))
def dump_tracked_phase(qubits: Iterable[ops.Qid], index: int) -> None: """Zeroes qubit_phase entries by emitting Z gates.""" for q in qubits: p = qubit_phase[q] if not decompositions.is_negligible_turn(p, self.tolerance): dump_op = ops.Z(q)**(p * 2) insertions.append((index, dump_op)) qubit_phase[q] = 0
def _cphase_symbols_to_sqrt_iswap(a: 'cirq.Qid', b: 'cirq.Qid', turns: 'cirq.TParamVal', use_sqrt_iswap_inv: bool = True): """Implements `cirq.CZ(a, b) ** turns` using two √iSWAPs and single qubit rotations. Output unitary: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, g]] where: g = exp(i·π·t). Args: a: The first qubit. b: The second qubit. turns: The rotational angle (t) that specifies the gate, where g = exp(i·π·t/2). use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. Yields: A `cirq.OP_TREE` representing the decomposition. """ theta = sympy.Mod(turns, 2.0) * sympy.pi # -1 if theta > pi. Adds a hacky fudge factor so theta=pi is not 0 sign = sympy.sign(sympy.pi - theta + 1e-9) # For sign = 1: theta. For sign = -1, 2pi-theta theta_prime = (sympy.pi - sign * sympy.pi) + sign * theta phi = sympy.asin(np.sqrt(2) * sympy.sin(theta_prime / 4)) xi = sympy.atan(sympy.tan(phi) / np.sqrt(2)) yield ops.rz(sign * 0.5 * theta_prime).on(a) yield ops.rz(sign * 0.5 * theta_prime).on(b) yield ops.rx(xi).on(a) yield ops.X(b)**(-sign * 0.5) yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) yield ops.rx(-2 * phi).on(a) yield ops.Z(a) yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) yield ops.Z(a) yield ops.rx(xi).on(a) yield ops.X(b)**(sign * 0.5)
def xmon_op_from_proto_dict(proto_dict: Dict) -> 'cirq.Operation': """Convert the proto dictionary to the corresponding operation. See protos in api/google/v1 for specification of the protos. Args: proto_dict: Dictionary representing the proto. Keys are always strings, but values may be types correspond to a raw proto type or another dictionary (for messages). Returns: The operation. Raises: ValueError if the dictionary does not contain required values corresponding to the proto. """ def raise_missing_fields(gate_name: str): raise ValueError('{} missing required fields: {}'.format( gate_name, proto_dict)) param = _parameterized_value_from_proto_dict qubit = _qubit_from_proto_dict if 'exp_w' in proto_dict: exp_w = proto_dict['exp_w'] if ('half_turns' not in exp_w or 'axis_half_turns' not in exp_w or 'target' not in exp_w): raise_missing_fields('ExpW') return ops.PhasedXPowGate( exponent=param(exp_w['half_turns']), phase_exponent=param(exp_w['axis_half_turns']), ).on(qubit(exp_w['target'])) if 'exp_z' in proto_dict: exp_z = proto_dict['exp_z'] if 'half_turns' not in exp_z or 'target' not in exp_z: raise_missing_fields('ExpZ') return ops.Z(qubit(exp_z['target']))**param(exp_z['half_turns']) if 'exp_11' in proto_dict: exp_11 = proto_dict['exp_11'] if ('half_turns' not in exp_11 or 'target1' not in exp_11 or 'target2' not in exp_11): raise_missing_fields('Exp11') return ops.CZ(qubit(exp_11['target1']), qubit(exp_11['target2']))**param(exp_11['half_turns']) if 'measurement' in proto_dict: meas = proto_dict['measurement'] invert_mask = cast(Tuple[Any, ...], ()) if 'invert_mask' in meas: invert_mask = tuple( _load_json_bool(x) for x in meas['invert_mask']) if 'key' not in meas or 'targets' not in meas: raise_missing_fields('Measurement') return ops.MeasurementGate( num_qubits=len(meas['targets']), key=meas['key'], invert_mask=invert_mask).on(*[qubit(q) for q in meas['targets']]) raise ValueError('invalid operation: {}'.format(proto_dict))
def nonoptimal_toffoli_circuit(q0: 'cirq.Qid', q1: 'cirq.Qid', q2: 'cirq.Qid') -> circuits.Circuit: ret = circuits.Circuit( ops.Y(q2)**0.5, ops.X(q2), ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.CNOT(q1, q2), ops.Z(q2)**-0.25, ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.CNOT(q0, q1), ops.CNOT(q1, q2), ops.CNOT(q2, q1), ops.CNOT(q1, q2), ops.Z(q2)**0.25, ops.Z(q1)**0.25, ops.CNOT(q0, q1), ops.Z(q0)**0.25, ops.Z(q1)**-0.25, ops.CNOT(q0, q1), ops.Y(q2)**0.5, ops.X(q2), ) return ret
def _decompose(self, qubits): # qubits = [c1, c2, ..., cn, T] # Will "bootstrap" an ancilla yield ops.H(qubits[-1]) yield CnxLinearBorrowedBit(*(qubits[:-2] + [qubits[-1]] + [qubits[-2]])).default_decompose() yield ops.Z(qubits[-1])**-0.25 yield ops.CNOT(qubits[-2], qubits[-1]) yield ops.Z(qubits[-1])**0.25 yield CnxLinearBorrowedBit(*(qubits[:-2] + [qubits[-1]] + [qubits[-2]])).default_decompose() yield ops.Z(qubits[-1])**-0.25 yield ops.CNOT(qubits[-2], qubits[-1]) yield ops.Z(qubits[-1])**0.25 yield ops.H(qubits[-1]) # Perform a +1 Gate on all of the top bits with bottom bit as borrowed yield IncrementLinearWithBorrowedBitOp(*qubits) # Perform -rt Z gates for i in range(1, len(qubits) - 1): yield ops.Z(qubits[i])**(-1 * 1/(2**(len(qubits) - i))) # Perform a -1 Gate on the top bits for i in range(len(qubits) - 1): yield ops.X(qubits[i]) yield IncrementLinearWithBorrowedBitOp(*qubits) for i in range(len(qubits) - 1): yield ops.X(qubits[i]) # Perform rt Z gates for i in range(1, len(qubits) - 1): yield ops.Z(qubits[i])**(1/(2**(len(qubits) - i))) yield ops.Z(qubits[0])**(1/(2**(len(qubits) - 1)))
def test_leaves_big(): m = circuits.DropNegligible(0.001) q = ops.QubitId() c = circuits.Circuit([circuits.Moment([ops.Z(q)**0.1])]) assert m.optimization_at(c, 0, c.operation_at(q, 0)) is None d = circuits.Circuit(c.moments) m.optimize_circuit(d) assert d == c
def test_removes_identity_sequence(): q = ops.QubitId() assert_optimizes(before=circuits.Circuit([ circuits.Moment([ops.Z(q)]), circuits.Moment([ops.H(q)]), circuits.Moment([ops.X(q)]), circuits.Moment([ops.H(q)]), ]), after=circuits.Circuit())
def test_text_diagrams(): a = ops.NamedQubit('a') b = ops.NamedQubit('b') circuit = Circuit.from_ops(ops.SWAP(a, b), ops.X(a), ops.Y(a), ops.Z(a), ops.CZ(a, b), ops.CNOT(a, b), ops.CNOT(b, a), ops.H(a)) assert circuit.to_text_diagram().strip() == """ a: ───×───X───Y───Z───@───@───X───H─── │ │ │ │ b: ───×───────────────@───X───@─────── """.strip()
def dump_tracked_phase(qubits: Iterable[ops.Qid]) -> 'cirq.OP_TREE': """Zeroes qubit_phase entries by emitting Z gates.""" for q in qubits: p, key = qubit_phase[q], last_phased_xz_op[q] qubit_phase[q] = 0 if not (key or single_qubit_decompositions.is_negligible_turn( p, atol)): yield ops.Z(q)**(p * 2) elif key: phased_xz_replacements[key] = phased_xz_replacements[ key].with_z_exponent(p * 2)
def test_inefficient_circuit_correct(): t = 0.1 v = 0.11 q0 = ops.QubitId() q1 = ops.QubitId() assert_optimization_not_broken( circuits.Circuit.from_ops( ops.H(q1), ops.CNOT(q0, q1), ops.H(q1), ops.CNOT(q0, q1), ops.CNOT(q1, q0), ops.H(q0), ops.CNOT(q0, q1), ops.Z(q0)**t, ops.Z(q1)**-t, ops.CNOT(q0, q1), ops.H(q0), ops.Z(q1)**v, ops.CNOT(q0, q1), ops.Z(q0)**-v, ops.Z(q1)**-v, ))
def _decompose_(self) -> ops.OP_TREE: if len(self.pauli_string) <= 0: return qubits = self.qubits any_qubit = qubits[0] to_z_ops = ops.freeze_op_tree(self.pauli_string.to_z_basis_ops()) xor_decomp = tuple(xor_nonlocal_decompose(qubits, any_qubit)) yield to_z_ops yield xor_decomp if isinstance(self.half_turns, sympy.Symbol): if self.pauli_string.negated: yield ops.X(any_qubit) yield ops.Z(any_qubit)**self.half_turns if self.pauli_string.negated: yield ops.X(any_qubit) else: half_turns = self.half_turns * (-1 if self.pauli_string.negated else 1) yield ops.Z(any_qubit)**half_turns yield protocols.inverse(xor_decomp) yield protocols.inverse(to_z_ops)
def test_clears_known_empties_even_at_zero_tolerance(): m = circuits.DropNegligible(0.001) q = ops.QubitId() q2 = ops.QubitId() c = circuits.Circuit.from_ops( ops.Z(q)**0, ops.Y(q)**0.0000001, ops.X(q)**-0.0000001, ops.CZ(q, q2)**0) m.optimize_circuit(c) assert c == circuits.Circuit([circuits.Moment()] * 4)
def test_clears_small(): m = circuits.DropNegligible(0.001) q = ops.QubitId() c = circuits.Circuit([circuits.Moment([ops.Z(q)**0.000001])]) assert (m.optimization_at(c, 0, c.operation_at(q, 0)) == circuits.PointOptimizationSummary(clear_span=1, clear_qubits=[q], new_operations=[])) m.optimize_circuit(c) assert c == circuits.Circuit([circuits.Moment()])
def _iswap_symbols_to_sqrt_iswap( a: 'cirq.Qid', b: 'cirq.Qid', turns: 'cirq.TParamVal', use_sqrt_iswap_inv: bool = True ): """Implements `cirq.ISWAP(a, b) ** turns` using two √iSWAPs and single qubit rotations. Output unitary: [[1 0 0 0], [0 c is 0], [0 is c 0], [0 0 0 1]] where c = cos(π·t/2), s = sin(π·t/2). Args: a: The first qubit. b: The second qubit. turns: The rotational angle (t) that specifies the gate, where c = cos(π·t/2), s = sin(π·t/2). use_sqrt_iswap_inv: If True, `cirq.SQRT_ISWAP_INV` is used instead of `cirq.SQRT_ISWAP`. Yields: A `cirq.OP_TREE` representing the decomposition. """ yield ops.Z(a) ** 0.75 yield ops.Z(b) ** 0.25 yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) yield ops.Z(a) ** (-turns / 2 + 1) yield ops.Z(b) ** (turns / 2) yield _sqrt_iswap_inv(a, b, use_sqrt_iswap_inv) yield ops.Z(a) ** 0.25 yield ops.Z(b) ** -0.25
def test_works_with_basic_gates(): a = ops.NamedQubit('a') b = ops.NamedQubit('b') basics = [ ops.X(a), ops.Y(a)**0.5, ops.Z(a), ops.CZ(a, b)**-0.25, ops.CNOT(a, b), ops.H(b), ops.SWAP(a, b) ] assert list(ops.inverse_of_invertible_op_tree(basics)) == [ ops.SWAP(a, b), ops.H(b), ops.CNOT(a, b), ops.CZ(a, b)**0.25, ops.Z(a), ops.Y(a)**-0.5, ops.X(a), ]
def decompose_phased_iswap_into_syc(phase_exponent: float, a: ops.Qid, b: ops.Qid) -> ops.OP_TREE: """Decompose PhasedISwap with an exponent of 1. This should only be called if the Gate has an exponent of 1 - otherwise, decompose_phased_iswap_into_syc_precomputed should be used instead. The advantage of using this function is that the resulting circuit will be smaller. Args: phase_exponent: The exponent on the Z gates. a: First qubit id to operate on b: Second qubit id to operate on Returns: a Cirq program implementing the Phased ISWAP gate """ yield ops.Z(a) ** phase_exponent, yield ops.Z(b) ** -phase_exponent, yield decompose_iswap_into_syc(a, b), yield ops.Z(a) ** -phase_exponent, yield ops.Z(b) ** phase_exponent,
def test_job_equality(): eq = EqualsTester() q = ops.QubitId() q2 = ops.QubitId() # Equivalent empty jobs eq.add_equality_group(Job(), Job(Circuit()), Job(Circuit([])), Job(Circuit(), sweeps.Unit)) # Equivalent circuit, different instances eq.add_equality_group(Job(Circuit([Moment([ops.Z(q)])])), Job(Circuit([Moment([ops.Z(q)])]))) # Different Circuit c = Circuit([Moment([ops.CZ(q, q2)])]) eq.add_equality_group(Job(c)) ps1 = sweeps.Points('Example', [42.0]) ps2 = sweeps.Points('Example', [42.0]) ps3 = sweeps.Points('Example', [42.0, 1.4]) eq.add_equality_group(Job(c, ps1, 2), Job(c, ps2, 2)) eq.add_equality_group(Job(c, ps1, 4)) eq.add_equality_group(Job(c, ps3, 2))
def test_combines_sequence(): m = MergeRotations(0.000001) q = ops.QubitId() c = circuits.Circuit([ circuits.Moment([ops.X(q)**0.5]), circuits.Moment([ops.Z(q)**0.5]), circuits.Moment([ops.X(q)**-0.5]), ]) assert (m.optimization_at(c, 0, c.operation_at( q, 0)) == circuits.PointOptimizationSummary(clear_span=3, clear_qubits=[q], new_operations=ops.Y(q)**0.5))