def single_qubit_matrix_to_phased_x_z(mat: np.ndarray, atol: float = 0 ) -> List[ops.SingleQubitGate]: """Implements a single-qubit operation with a PhasedX and Z gate. If one of the gates isn't needed, it will be omitted. Args: mat: The 2x2 unitary matrix of the operation to implement. atol: A limit on the amount of error introduced by the construction. Returns: A list of gates that, when applied in order, perform the desired operation. """ xy_turn, xy_phase_turn, total_z_turn = ( _deconstruct_single_qubit_matrix_into_gate_turns(mat)) # Build the intended operation out of non-negligible XY and Z rotations. result = [ ops.PhasedXPowGate(exponent=2 * xy_turn, phase_exponent=2 * xy_phase_turn), ops.Z**(2 * total_z_turn) ] result = [g for g in result if protocols.trace_distance_bound(g) > atol] # Special case: XY half-turns can absorb Z rotations. if len(result) == 2 and abs(xy_turn) >= 0.5 - atol: return [ ops.PhasedXPowGate(phase_exponent=2 * xy_phase_turn + total_z_turn) ] return result
def decompose_cz_into_syc(a: ops.Qid, b: ops.Qid): """Decompose CZ into sycamore gates using precomputed coefficients""" yield ops.PhasedXPowGate(phase_exponent=0.5678998743900456, exponent=0.5863459345743176).on(a) yield ops.PhasedXPowGate(phase_exponent=0.3549946157441739).on(b) yield google.SYC.on(a, b) yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878, exponent=0.5228733015013345).on(b) yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a) yield google.SYC.on(a, b), yield ops.PhasedXPowGate(phase_exponent=-0.5987667922766213, exponent=0.4136540654256824).on(a), yield (ops.Z ** -0.9255092746611595).on(b), yield (ops.Z ** -1.333333333333333).on(a),
def __init__(self, qubits: Sequence['cirq.Qid'], prerotations: Optional[Sequence[Tuple[float, float]]] = None): """Initializes the rotation protocol and matrix for system. Args: qubits: Qubits to do the tomography on. prerotations: Tuples of (phase_exponent, exponent) parameters for gates to apply to the qubits before measurement. The actual rotation applied will be `cirq.PhasedXPowGate` with the specified values of phase_exponent and exponent. If None, we use [(0, 0), (0, 0.5), (0.5, 0.5)], which corresponds to rotation gates [I, X**0.5, Y**0.5]. """ if prerotations is None: prerotations = [(0, 0), (0, 0.5), (0.5, 0.5)] self.num_qubits = len(qubits) phase_exp_vals, exp_vals = zip(*prerotations) operations: List['cirq.Operation'] = [] sweeps: List['cirq.Sweep'] = [] for i, qubit in enumerate(qubits): phase_exp = sympy.Symbol(f'phase_exp_{i}') exp = sympy.Symbol(f'exp_{i}') gate = ops.PhasedXPowGate(phase_exponent=phase_exp, exponent=exp) operations.append(gate.on(qubit)) sweeps.append( study.Points(phase_exp, phase_exp_vals) + study.Points(exp, exp_vals)) self.rot_circuit = circuits.Circuit(operations) self.rot_sweep = study.Product(*sweeps) self.mat = self._make_state_tomography_matrix()
def _potential_cross_partial_w(moment_index: int, op: ops.Operation, state: _OptimizerState) -> None: """Cross the held W over a partial W gate. [Where W(a) is shorthand for PhasedX(phase_exponent=a).] Uses the following identity: ───W(a)───W(b)^t─── ≡ ───Z^-a───X───Z^a───W(b)^t────── (expand W(a)) ≡ ───Z^-a───X───W(b-a)^t───Z^a──── (move Z^a across, phasing axis) ≡ ───Z^-a───W(a-b)^t───X───Z^a──── (move X across, negating axis angle) ≡ ───W(2a-b)^t───Z^-a───X───Z^a─── (move Z^-a across, phasing axis) ≡ ───W(2a-b)^t───W(a)─── """ a = state.held_w_phases.get(op.qubits[0]) if a is None: return exponent, phase_exponent = cast(Tuple[float, float], _try_get_known_phased_pauli(op)) new_op = ops.PhasedXPowGate( exponent=exponent, phase_exponent=2 * a - phase_exponent).on(op.qubits[0]) state.deletions.append((moment_index, op)) state.inline_intos.append((moment_index, new_op))
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 _potential_cross_partial_w( op: ops.Operation, held_w_phases: Dict[ops.Qid, value.TParamVal], ) -> 'cirq.OP_TREE': """Cross the held W over a partial W gate. [Where W(a) is shorthand for PhasedX(phase_exponent=a).] Uses the following identity: ───W(a)───W(b)^t─── ≡ ───Z^-a───X───Z^a───W(b)^t────── (expand W(a)) ≡ ───Z^-a───X───W(b-a)^t───Z^a──── (move Z^a across, phasing axis) ≡ ───Z^-a───W(a-b)^t───X───Z^a──── (move X across, negating axis angle) ≡ ───W(2a-b)^t───Z^-a───X───Z^a─── (move Z^-a across, phasing axis) ≡ ───W(2a-b)^t───W(a)─── """ a = held_w_phases.get(op.qubits[0], None) if a is None: return op exponent, phase_exponent = cast( Tuple[value.TParamVal, value.TParamVal], _try_get_known_phased_pauli(op) ) new_op = ops.PhasedXPowGate(exponent=exponent, phase_exponent=2 * a - phase_exponent).on( op.qubits[0] ) return new_op
def _random_half_rotations(qubits: Sequence[ops.Qid], num_layers: int) -> List[List[ops.OP_TREE]]: rot_ops = [ops.X ** 0.5, ops.Y ** 0.5, ops.PhasedXPowGate(phase_exponent=0.25, exponent=0.5)] num_qubits = len(qubits) rand_nums = np.random.choice(3, (num_qubits, num_layers)) single_q_layers = [] # type: List[List[ops.OP_TREE]] for i in range(num_layers): single_q_layers.append([rot_ops[rand_nums[j, i]](qubits[j]) for j in range(num_qubits)]) return single_q_layers
def _dump_held(qubits: Iterable[ops.Qid], moment_index: int, state: _OptimizerState): # Note: sorting is to avoid non-determinism in the insertion order. for q in sorted(qubits): p = state.held_w_phases.get(q) if p is not None: dump_op = ops.PhasedXPowGate(phase_exponent=p).on(q) state.insertions.append((moment_index, dump_op)) state.held_w_phases.pop(q, None)
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 test_expw_matrix(half_turns, axis_half_turns): m1 = xmon_gates.ExpWGate(half_turns=half_turns, axis_half_turns=axis_half_turns).matrix if (version[0] == 0 and version[1] <= 3): m2 = google.ExpWGate(half_turns=half_turns, axis_half_turns=axis_half_turns).matrix() else: m2 = unitary(ops.PhasedXPowGate(exponent=half_turns, phase_exponent=axis_half_turns)) nptest.assert_array_almost_equal(m1, m2)
def _dump_held( qubits: Iterable[ops.Qid], held_w_phases: Dict[ops.Qid, value.TParamVal]) -> 'cirq.OP_TREE': # Note: sorting is to avoid non-determinism in the insertion order. for q in sorted(qubits): p = held_w_phases.get(q) if p is not None: dump_op = ops.PhasedXPowGate(phase_exponent=p).on(q) yield dump_op held_w_phases.pop(q, None)
def decompose_swap_into_syc(a: ops.Qid, b: ops.Qid): """Decompose SWAP into sycamore gates using precomputed coefficients""" yield ops.PhasedXPowGate(phase_exponent=0.44650378384076217, exponent=0.8817921214052824).on(a) yield ops.PhasedXPowGate(phase_exponent=-0.7656774060816165, exponent=0.6628666504604785).on(b) yield google.SYC.on(a, b) yield ops.PhasedXPowGate(phase_exponent=-0.6277589946716742, exponent=0.5659160932099687).on(a) yield google.SYC.on(a, b) yield ops.PhasedXPowGate(phase_exponent=0.28890767199499257, exponent=0.4340839067900317).on(b) yield ops.PhasedXPowGate(phase_exponent=-0.22592784059288928).on(a) yield google.SYC.on(a, b) yield ops.PhasedXPowGate(phase_exponent=-0.4691261557936808, exponent=0.7728525693920243).on(a) yield ops.PhasedXPowGate(phase_exponent=-0.8150261316932077, exponent=0.11820787859471782).on(b) yield (ops.Z ** -0.7384700844660306).on(b) yield (ops.Z ** -0.7034535141382525).on(a)
def decompose_iswap_into_syc(a: ops.Qid, b: ops.Qid): """Decompose ISWAP into sycamore gates using precomputed coefficients""" yield ops.PhasedXPowGate(phase_exponent=-0.27250925776964596, exponent=0.2893438375555899).on(a) yield google.SYC.on(a, b) yield ops.PhasedXPowGate(phase_exponent=0.8487591858680898, exponent=0.9749387200813147).on(b), yield ops.PhasedXPowGate(phase_exponent=-0.3582574564210601).on(a), yield google.SYC.on(a, b) yield ops.PhasedXPowGate(phase_exponent=0.9675022326694225, exponent=0.6908986856555526).on(a), yield google.SYC.on(a, b), yield ops.PhasedXPowGate(phase_exponent=0.9161706861686068, exponent=0.14818318325264102).on(b), yield ops.PhasedXPowGate(phase_exponent=0.9408341606787907).on(a), yield (ops.Z ** -1.1551880579397293).on(b), yield (ops.Z ** 0.31848343246696365).on(a),
def _expWGate(cmd, mapping, qubits): """ Translate a ExpW gate into a Cirq gate. Args: - cmd (:class:`projectq.ops.Command`) - a projectq command instance - mapping (:class:`dict`) - a dictionary of qubit mappings - qubits (list of :class:cirq.QubitID`) - cirq qubits Returns: - :class:`cirq.Operation` """ qb_pos = [mapping[qb.id] for qr in cmd.qubits for qb in qr] assert len(qb_pos) == 1 cirqGate = cop.PhasedXPowGate(exponent=cmd.gate.angle / cmath.pi, phase_exponent=cmd.gate.axis_angle / cmath.pi) if get_control_count(cmd) > 0: ctrl_pos = [mapping[qb.id] for qb in cmd.control_qubits] return cop.ControlledGate(cirqGate)( *[qubits[c] for c in ctrl_pos + qb_pos]) else: return cirqGate(*[qubits[idx] for idx in qb_pos])
def decompose_phased_iswap_into_syc_precomputed(theta: float, a: ops.Qid, b: ops.Qid) -> ops.OP_TREE: """Decompose PhasedISwap into sycamore gates using precomputed coefficients. This should only be called if the Gate has a phase_exponent of .25. If the gate has an exponent of 1, decompose_phased_iswap_into_syc should be used instead. Converting PhasedISwap gates to Sycamore is not supported if neither of these constraints are satisfied. This synthesize a PhasedISwap in terms of four sycamore gates. This compilation converts the gate into a circuit involving two CZ gates, which themselves are each represented as two Sycamore gates and single-qubit rotations Args: theta: rotation parameter 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.PhasedXPowGate(phase_exponent=0.41175161497166024, exponent=0.5653807577895922).on(a) yield ops.PhasedXPowGate(phase_exponent=1.0, exponent=0.5).on(b), yield (ops.Z**0.7099892314883478).on(b), yield (ops.Z**0.6746023442550453).on(a), yield SycamoreGate().on(a, b) yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878, exponent=0.5228733015013345).on(b) yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a) yield SycamoreGate().on(a, b), yield ops.PhasedXPowGate(phase_exponent=-0.5987667922766213, exponent=0.4136540654256824).on(a) yield (ops.Z**-0.9255092746611595).on(b) yield (ops.Z**-1.333333333333333).on(a) yield ops.rx(-theta).on(a) yield ops.rx(-theta).on(b) yield ops.PhasedXPowGate(phase_exponent=0.5678998743900456, exponent=0.5863459345743176).on(a) yield ops.PhasedXPowGate(phase_exponent=0.3549946157441739).on(b) yield SycamoreGate().on(a, b) yield ops.PhasedXPowGate(phase_exponent=-0.5154334589432878, exponent=0.5228733015013345).on(b) yield ops.PhasedXPowGate(phase_exponent=0.06774925307475355).on(a) yield SycamoreGate().on(a, b) yield ops.PhasedXPowGate(phase_exponent=-0.8151665352515929, exponent=0.8906746535691492).on(a) yield ops.PhasedXPowGate(phase_exponent=-0.07449072533884049, exponent=0.5).on(b) yield (ops.Z**-0.9255092746611595).on(b) yield (ops.Z**-0.9777346353961884).on(a)
def random_rotations_between_grid_interaction_layers_circuit( qubits: Iterable['cirq.GridQubit'], depth: int, *, # forces keyword arguments two_qubit_op_factory: Callable[ ['cirq.GridQubit', 'cirq.GridQubit', 'np.random.RandomState'], 'cirq.OP_TREE'] = lambda a, b, _: google.SYC(a, b), pattern: Sequence[GridInteractionLayer] = GRID_STAGGERED_PATTERN, single_qubit_gates: Sequence['cirq.Gate'] = (ops.X**0.5, ops.Y**0.5, ops.PhasedXPowGate( phase_exponent=0.25, exponent=0.5)), add_final_single_qubit_layer: bool = True, seed: value.RANDOM_STATE_LIKE = None, ) -> 'cirq.Circuit': """Generate a random quantum circuit. This construction is based on the circuits used in the paper https://www.nature.com/articles/s41586-019-1666-5. The generated circuit consists of a number of "cycles", this number being specified by `depth`. Each cycle is actually composed of two sub-layers: a layer of single-qubit gates followed by a layer of two-qubit gates. The single-qubit gates are chosen randomly from the gates specified by `single_qubit_gates`, but with the constraint that no qubit is acted upon by the same single-qubit gate in consecutive cycles. In the layer of two-qubit gates, which pairs of qubits undergo interaction is determined by `pattern`, which is a sequence of two-qubit interaction sets. The set of interactions in a two-qubit layer rotates through this sequence. The two-qubit operations themselves are generated by the call `two_qubit_op_factory(a, b, prng)`, where `a` and `b` are the qubits and `prng` is the pseudorandom number generator. At the end of the circuit, an additional layer of single-qubit gates is appended, subject to the same constraint regarding consecutive cycles described above. If only one choice of single-qubit gate is given, then the constraint that excludes repeating single-qubit gates in consecutive cycles is not enforced. Args: qubits: The qubits to use. depth: The number of cycles. two_qubit_op_factory: A factory to generate two-qubit operations. These operations will be generated with calls of the form `two_qubit_op_factory(a, b, prng)`, where `a` and `b` are the qubits to operate on and `prng` is the pseudorandom number generator. pattern: The pattern of grid interaction layers to use. single_qubit_gates: The single-qubit gates to use. add_final_single_qubit_layer: Whether to include a final layer of single-qubit gates after the last cycle. seed: A seed or random state to use for the pseudorandom number generator. """ prng = value.parse_random_state(seed) qubits = list(qubits) coupled_qubit_pairs = _coupled_qubit_pairs(qubits) circuit = circuits.Circuit() previous_single_qubit_layer = {} # type: Dict[cirq.GridQubit, cirq.Gate] if len(set(single_qubit_gates)) == 1: single_qubit_layer_factory = _FixedSingleQubitLayerFactory( {q: single_qubit_gates[0] for q in qubits}) # type: _SingleQubitLayerFactory else: single_qubit_layer_factory = _RandomSingleQubitLayerFactory( qubits, single_qubit_gates, prng) for i in range(depth): single_qubit_layer = single_qubit_layer_factory.new_layer( previous_single_qubit_layer) two_qubit_layer = _two_qubit_layer(coupled_qubit_pairs, two_qubit_op_factory, pattern[i % len(pattern)], prng) circuit.append([g.on(q) for q, g in single_qubit_layer.items()], strategy=circuits.InsertStrategy.NEW_THEN_INLINE) circuit.append(two_qubit_layer, strategy=circuits.InsertStrategy.EARLIEST) previous_single_qubit_layer = single_qubit_layer if add_final_single_qubit_layer: final_single_qubit_layer = single_qubit_layer_factory.new_layer( previous_single_qubit_layer) circuit.append([g.on(q) for q, g in final_single_qubit_layer.items()], strategy=circuits.InsertStrategy.NEW_THEN_INLINE) return circuit
def random_rotations_between_grid_interaction_layers_circuit( qubits: Iterable['cirq.GridQubit'], depth: int, *, # forces keyword arguments two_qubit_op_factory: Callable[ ['cirq.GridQubit', 'cirq.GridQubit', 'np.random.RandomState'], 'cirq.OP_TREE'] = lambda a, b, _: ops.CZPowGate()(a, b), pattern: Sequence[GridInteractionLayer] = GRID_STAGGERED_PATTERN, single_qubit_gates: Sequence['cirq.Gate'] = ( ops.X**0.5, ops.Y**0.5, ops.PhasedXPowGate(phase_exponent=0.25, exponent=0.5), ), add_final_single_qubit_layer: bool = True, seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, ) -> 'cirq.Circuit': """Generate a random quantum circuit of a particular form. This construction is based on the circuits used in the paper https://www.nature.com/articles/s41586-019-1666-5. The generated circuit consists of a number of "cycles", this number being specified by `depth`. Each cycle is actually composed of two sub-layers: a layer of single-qubit gates followed by a layer of two-qubit gates, controlled by their respective arguments, see below. The pairs of qubits in a given entangling layer is controlled by the `pattern` argument, see below. Args: qubits: The qubits to use. depth: The number of cycles. two_qubit_op_factory: A callable that returns a two-qubit operation. These operations will be generated with calls of the form `two_qubit_op_factory(q0, q1, prng)`, where `prng` is the pseudorandom number generator. pattern: A sequence of GridInteractionLayers, each of which determine which pairs of qubits are entangled. The layers in a pattern are iterated through sequentially, repeating until `depth` is reached. single_qubit_gates: Single-qubit gates are selected randomly from this sequence. No qubit is acted upon by the same single-qubit gate in consecutive cycles. If only one choice of single-qubit gate is given, then this constraint is not enforced. add_final_single_qubit_layer: Whether to include a final layer of single-qubit gates after the last cycle. seed: A seed or random state to use for the pseudorandom number generator. """ prng = value.parse_random_state(seed) qubits = list(qubits) coupled_qubit_pairs = _coupled_qubit_pairs(qubits) circuit = circuits.Circuit() previous_single_qubit_layer = circuits.Moment() single_qubit_layer_factory = _single_qubit_gates_arg_to_factory( single_qubit_gates=single_qubit_gates, qubits=qubits, prng=prng) for i in range(depth): single_qubit_layer = single_qubit_layer_factory.new_layer( previous_single_qubit_layer) circuit += single_qubit_layer two_qubit_layer = _two_qubit_layer(coupled_qubit_pairs, two_qubit_op_factory, pattern[i % len(pattern)], prng) circuit += two_qubit_layer previous_single_qubit_layer = single_qubit_layer if add_final_single_qubit_layer: circuit += single_qubit_layer_factory.new_layer( previous_single_qubit_layer) return circuit
def random_rotations_between_two_qubit_circuit( q0: 'cirq.Qid', q1: 'cirq.Qid', depth: int, two_qubit_op_factory: Callable[ ['cirq.Qid', 'cirq.Qid', 'np.random.RandomState'], 'cirq.OP_TREE'] = lambda a, b, _: ops.CZPowGate()(a, b), single_qubit_gates: Sequence['cirq.Gate'] = ( ops.X**0.5, ops.Y**0.5, ops.PhasedXPowGate(phase_exponent=0.25, exponent=0.5), ), add_final_single_qubit_layer: bool = True, seed: 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None, ) -> 'cirq.Circuit': """Generate a random two-qubit quantum circuit. This construction uses a similar structure to those in the paper https://www.nature.com/articles/s41586-019-1666-5. The generated circuit consists of a number of "cycles", this number being specified by `depth`. Each cycle is actually composed of two sub-layers: a layer of single-qubit gates followed by a layer of two-qubit gates, controlled by their respective arguments, see below. Args: q0: The first qubit q1: The second qubit depth: The number of cycles. two_qubit_op_factory: A callable that returns a two-qubit operation. These operations will be generated with calls of the form `two_qubit_op_factory(q0, q1, prng)`, where `prng` is the pseudorandom number generator. single_qubit_gates: Single-qubit gates are selected randomly from this sequence. No qubit is acted upon by the same single-qubit gate in consecutive cycles. If only one choice of single-qubit gate is given, then this constraint is not enforced. add_final_single_qubit_layer: Whether to include a final layer of single-qubit gates after the last cycle (subject to the same non-consecutivity constraint). seed: A seed or random state to use for the pseudorandom number generator. """ prng = value.parse_random_state(seed) circuit = circuits.Circuit() previous_single_qubit_layer = circuits.Moment() single_qubit_layer_factory = _single_qubit_gates_arg_to_factory( single_qubit_gates=single_qubit_gates, qubits=(q0, q1), prng=prng) for _ in range(depth): single_qubit_layer = single_qubit_layer_factory.new_layer( previous_single_qubit_layer) circuit += single_qubit_layer circuit += two_qubit_op_factory(q0, q1, prng) previous_single_qubit_layer = single_qubit_layer if add_final_single_qubit_layer: circuit += single_qubit_layer_factory.new_layer( previous_single_qubit_layer) return circuit
def random_one_qubit_gate(): return ops.PhasedXPowGate(phase_exponent=prng.rand(), exponent=prng.rand())