Esempio n. 1
0
    def optimize_circuit(self, circuit: circuits.Circuit):
        # Tracks qubit phases (in half turns; multiply by pi to get radians).
        qubit_phase = defaultdict(lambda: 0)  # type: Dict[ops.QubitId, float]

        def dump_tracked_phase(qubits: Iterable[ops.QubitId],
                               index: int) -> None:
            """Zeroes qubit_phase entries by emitting Z gates."""
            for q in qubits:
                p = qubit_phase[q]
                if not is_negligible_turn(p, self.tolerance):
                    dump_op = ops.Z(q)**(p * 2)
                    insertions.append((index, dump_op))
                qubit_phase[q] = 0

        deletions = []  # type: List[Tuple[int, ops.Operation]]
        inline_intos = []  # type: List[Tuple[int, ops.Operation]]
        insertions = []  # type: List[Tuple[int, ops.Operation]]
        for moment_index, moment in enumerate(circuit):
            for op in moment.operations:
                # Move Z gates into tracked qubit phases.
                h = _try_get_known_z_half_turns(op)
                if h is not None:
                    q = op.qubits[0]
                    qubit_phase[q] += h / 2
                    deletions.append((moment_index, op))
                    continue

                # Z gate before measurement is a no-op. Drop tracked phase.
                if ops.MeasurementGate.is_measurement(op):
                    for q in op.qubits:
                        qubit_phase[q] = 0

                # If there's no tracked phase, we can move on.
                phases = [qubit_phase[q] for q in op.qubits]
                if all(is_negligible_turn(p, self.tolerance) for p in phases):
                    continue

                # Try to move the tracked phasing over the operation.
                phased_op = op
                for i, p in enumerate(phases):
                    if not is_negligible_turn(p, self.tolerance):
                        phased_op = protocols.phase_by(phased_op, -p, i,
                                                       default=None)
                if phased_op is not None:
                    deletions.append((moment_index, op))
                    inline_intos.append((moment_index,
                                     cast(ops.Operation, phased_op)))
                else:
                    dump_tracked_phase(op.qubits, moment_index)

        dump_tracked_phase(qubit_phase.keys(), len(circuit))
        circuit.batch_remove(deletions)
        circuit.batch_insert_into(inline_intos)
        circuit.batch_insert(insertions)
Esempio n. 2
0
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.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))
Esempio n. 3
0
 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
Esempio n. 4
0
 def dump_phases(qubits, index):
     for q in qubits:
         p = turns_state[q]
         if not is_negligible_turn(p, self.tolerance):
             dump_op = ExpZGate(half_turns=p * 2).on(q)
             insertions.append((index, dump_op))
         turns_state[q] = 0
Esempio n. 5
0
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 = ExpZGate(half_turns=t).on(q)
            state.inline_intos.append((moment_index, leftover_phase))
Esempio n. 6
0
 def dump_tracked_phase(qubits: Iterable[ops.QubitId],
                        index: int) -> None:
     """Zeroes qubit_phase entries by emitting Z gates."""
     for q in qubits:
         p = qubit_phase[q]
         if not is_negligible_turn(p, self.tolerance):
             dump_op = ops.Z(q)**(p * 2)
             insertions.append((index, dump_op))
         qubit_phase[q] = 0
Esempio n. 7
0
    def optimize_circuit(self, circuit: circuits.Circuit):
        state = _OptimizerState()

        for moment_index, moment in enumerate(circuit):
            for op in moment.operations:
                affected = [q for q in op.qubits
                            if state.held_w_phases.get(q) is not None]

                # Collect, phase, and merge Ws.
                w = _try_get_known_w(op)
                if w is not None:
                    if decompositions.is_negligible_turn(
                            cast(float, w.exponent) - 1,
                            self.tolerance):
                        _potential_cross_whole_w(moment_index,
                                                 op,
                                                 self.tolerance,
                                                 state)
                    else:
                        _potential_cross_partial_w(moment_index, op, state)
                    continue

                if not affected:
                    continue

                # Absorb Z rotations.
                t = _try_get_known_z_half_turns(op)
                if t is not None:
                    _absorb_z_into_w(moment_index, op, state)
                    continue

                # Dump coherent flips into measurement bit flips.
                if ops.MeasurementGate.is_measurement(op):
                    _dump_into_measurement(moment_index, op, state)

                # Cross CZs using kickback.
                if _try_get_known_cz_half_turns(op) is not None:
                    if len(affected) == 1:
                        _single_cross_over_cz(moment_index,
                                              op,
                                              affected[0],
                                              state)
                    else:
                        _double_cross_over_cz(op, state)
                    continue

                # Don't know how to handle this situation. Dump the gates.
                _dump_held(op.qubits, moment_index, state)

        # Put anything that's still held at the end of the circuit.
        _dump_held(state.held_w_phases.keys(), len(circuit), state)

        circuit.batch_remove(state.deletions)
        circuit.batch_insert_into(state.inline_intos)
        circuit.batch_insert(state.insertions)
Esempio n. 8
0
    def optimize_circuit(self, circuit: circuits.Circuit):
        state = _OptimizerState()

        for moment_index, moment in enumerate(circuit):
            for op in moment.operations:
                affected = [q for q in op.qubits
                            if state.held_w_phases.get(q) is not None]

                # Collect, phase, and merge Ws.
                w = _try_get_known_w(op)
                if w is not None:
                    if decompositions.is_negligible_turn(
                            cast(float, w.half_turns) - 1,
                            self.tolerance):
                        _potential_cross_whole_w(moment_index,
                                                 op,
                                                 self.tolerance,
                                                 state)
                    else:
                        _potential_cross_partial_w(moment_index, op, state)
                    continue

                if not affected:
                    continue

                # Absorb Z rotations.
                t = _try_get_known_z_half_turns(op)
                if t is not None:
                    _absorb_z_into_w(moment_index, op, state)
                    continue

                # Dump coherent flips into measurement bit flips.
                if ops.MeasurementGate.is_measurement(op):
                    _dump_into_measurement(moment_index, op, state)

                # Cross CZs using kickback.
                if _try_get_known_cz_half_turns(op) is not None:
                    if len(affected) == 1:
                        _single_cross_over_cz(moment_index,
                                              op,
                                              affected[0],
                                              state)
                    else:
                        _double_cross_over_cz(op, state)
                    continue

                # Don't know how to handle this situation. Dump the gates.
                _dump_held(op.qubits, moment_index, state)

        # Put anything that's still held at the end of the circuit.
        _dump_held(state.held_w_phases.keys(), len(circuit), state)

        circuit.batch_remove(state.deletions)
        circuit.batch_insert_into(state.inline_intos)
        circuit.batch_insert(state.insertions)
Esempio n. 9
0
    def optimize_circuit(self, circuit: circuits.Circuit):
        turns_state = defaultdict(lambda: 0)  # type: Dict[ops.QubitId, float]

        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

        deletions = []  # type: List[Tuple[int, ops.Operation]]
        inline_intos = []  # type: List[Tuple[int, ops.Operation]]
        insertions = []  # type: List[Tuple[int, ops.Operation]]
        for moment_index, moment in enumerate(circuit):
            for op in moment.operations:
                h = _try_get_known_z_half_turns(op)
                if h is not None:
                    q = op.qubits[0]
                    turns_state[q] += h / 2
                    deletions.append((moment_index, op))
                    continue

                if ops.MeasurementGate.is_measurement(op):
                    for q in op.qubits:
                        turns_state[q] = 0

                phases = [turns_state[q] for q in op.qubits]
                if all(is_negligible_turn(p, self.tolerance) for p in phases):
                    continue

                phased_op = op
                for i, p in enumerate(phases):
                    if p and phased_op is not None:
                        phased_op = protocols.phase_by(phased_op,
                                                       -p,
                                                       i,
                                                       default=None)

                if phased_op is not None:
                    deletions.append((moment_index, op))
                    inline_intos.append(
                        (moment_index, cast(ops.Operation, phased_op)))
                else:
                    dump_phases(op.qubits, moment_index)

        dump_phases(turns_state.keys(), len(circuit))
        circuit.batch_remove(deletions)
        circuit.batch_insert_into(inline_intos)
        circuit.batch_insert(insertions)