Пример #1
0
def verify_ops(*op_tree, max_test_value=2**100, trinary_input=False, depth=1):
    if trinary_input:
        raise NotImplementedError
        # TODO
    qubits = set()
    op_list = tuple(ops.flatten_op_tree(op_tree))
    for op in op_list:
        qubits.update(op.qubits)
    qubits = sorted(qubits)
    num_qubits = len(qubits)
    sub_ops = tuple(ops.flatten_op_tree(decompose_depth(op_list, d=depth)))
    for i in range(min(2**num_qubits, max_test_value)):
        bits = tuple(map(int, reversed('{:0{}b}'.format(i, num_qubits))))
        state = trit_list_to_state(qubits, bits)
        state2 = state.copy()
        # Apply gate directly
        for op in op_list:
            op.apply_to_ternary_state(state)
        # Apply gate decomposition
        for sub_op in sub_ops:
            sub_op.apply_to_ternary_state(state2)
        # Verify that the two agree
        if state != state2:
            input_state_str = ''.join(map(str, bits))
            output_state_str = ''.join(map(str, (state[q] for q in qubits)))
            output_state2_str = ''.join(map(str, (state2[q] for q in qubits)))
            raise RuntimeError(
                'Gate {!r} decomposition is invalid for input {}: {} != {}'.format(
                op_list, input_state_str, output_state_str, output_state2_str))
Пример #2
0
def test_inverse_of_invertible_op_tree():
    def rev_freeze(root):
        return ops.freeze_op_tree(ops.inverse_of_invertible_op_tree(root))

    operations = [
        ops.Operation(_FlipGate(i), [ops.NamedQubit(str(i))])
        for i in range(10)
    ]
    expected = [
        ops.Operation(_FlipGate(~i), [ops.NamedQubit(str(i))])
        for i in range(10)
    ]

    # Just an item.
    assert rev_freeze(operations[0]) == expected[0]

    # Flat list.
    assert rev_freeze(operations) == tuple(expected[::-1])

    # Tree.
    assert (rev_freeze(
        (operations[1:5], operations[0],
         operations[5:])) == (tuple(expected[5:][::-1]), expected[0],
                              tuple(expected[1:5][::-1])))

    # Flattening after reversing is equivalent to reversing then flattening.
    t = (operations[1:5], operations[0], operations[5:])
    assert (tuple(ops.flatten_op_tree(rev_freeze(t))) == tuple(
        rev_freeze(ops.flatten_op_tree(t))))
Пример #3
0
def assert_equivalent_op_tree(x: ops.OP_TREE, y: ops.OP_TREE):
    """Ensures that the two OP_TREEs are equivalent.

    Args:
        x: OP_TREE one
        y: OP_TREE two
    Returns:
        None
    Raises:
         AssertionError if x != y
    """

    a = list(ops.flatten_op_tree(x))
    b = list(ops.flatten_op_tree(y))
    assert a == b
Пример #4
0
def _kak_decomposition_to_operations(
    q0: 'cirq.Qid',
    q1: 'cirq.Qid',
    kak: linalg.KakDecomposition,
    allow_partial_czs: bool,
    atol: float = 1e-8,
) -> List[ops.Operation]:
    """Assumes that the decomposition is canonical."""
    b0, b1 = kak.single_qubit_operations_before
    pre = [_do_single_on(b0, q0, atol=atol), _do_single_on(b1, q1, atol=atol)]
    a0, a1 = kak.single_qubit_operations_after
    post = [_do_single_on(a0, q0, atol=atol), _do_single_on(a1, q1, atol=atol)]

    return list(
        cast(
            Iterable[ops.Operation],
            ops.flatten_op_tree([
                pre,
                _non_local_part(q0,
                                q1,
                                kak.interaction_coefficients,
                                allow_partial_czs,
                                atol=atol),
                post,
            ]),
        ))
Пример #5
0
    def __init__(
        self,
        clear_span: int,
        clear_qubits: Iterable['cirq.Qid'],
        new_operations: 'cirq.OP_TREE',
        preserve_moments: bool = False,
    ) -> None:
        """Inits PointOptimizationSummary.

        Args:
            clear_span: Defines the range of moments to affect. Specifically,
                refers to the indices in range(start, start+clear_span) where
                start is an index known from surrounding context.
            clear_qubits: Defines the set of qubits that should be cleared
                with each affected moment.
            new_operations: The operations to replace the cleared out
                operations with.
            preserve_moments: If set, `cirq.Moment` instances within
                `new_operations` will be preserved exactly. Normally the
                operations would be repacked to fit better into the
                target space, which may move them between moments.
                Please be advised that a PointOptimizer consuming this
                summary will flatten operations no matter what,
                see https://github.com/quantumlib/Cirq/issues/2406.
        """
        self.new_operations = tuple(
            ops.flatten_op_tree(new_operations,
                                preserve_moments=preserve_moments))
        self.clear_span = clear_span
        self.clear_qubits = tuple(clear_qubits)
Пример #6
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)))
Пример #7
0
def _flatten_to_known_matrix_ops(
        iter_ops: Iterable[ops.Operation],
        ext: Extensions) -> Generator[ops.Operation, None, None]:
    for op in iter_ops:
        # Check if the operation has a known matrix
        known_matrix_gate = ext.try_cast(op.gate, ops.KnownMatrixGate)
        if known_matrix_gate is not None:
            yield op
            continue

        # If not, check if it has a decomposition
        composite_gate = ext.try_cast(op.gate, ops.CompositeGate)
        if composite_gate is not None:
            # Recurse decomposition to get known matrix gates.
            op_tree = composite_gate.default_decompose(op.qubits)
            op_list = ops.flatten_op_tree(op_tree)
            for op in _flatten_to_known_matrix_ops(op_list, ext):
                yield op
            continue

        # Pass measurement gates through
        meas_gate = ext.try_cast(op.gate, ops.MeasurementGate)
        if meas_gate is not None:
            yield op
            continue

        # Otherwise, fail
        raise TypeError(
            'Operation without a known matrix or decomposition: {!r}'.format(
                op))
Пример #8
0
def _compute_samples_display_value(display: ops.SamplesDisplay,
        state: np.ndarray,
        qubit_order: ops.QubitOrder,
        qubit_map: Dict[ops.Qid, int]):
    n = len(qubit_map)
    state = np.reshape(state, (2,) * n * 2)
    basis_change = ops.flatten_op_tree(display.measurement_basis_change())
    for op in basis_change:
        # TODO: Use apply_channel similar to apply_unitary.
        indices = [qubit_map[qubit] for qubit in op.qubits]
        gate = cast(ops.GateOperation, op).gate
        unitary = protocols.unitary(gate)
        krauss_tensor = np.reshape(unitary,
                                   (2,) * gate.num_qubits() * 2)
        state = linalg.targeted_left_multiply(krauss_tensor,
                                               state,
                                               indices)
        # TODO add a test that fails if the below is not performed
        state = linalg.targeted_left_multiply(
            np.conjugate(krauss_tensor),
            state,
            [x + n for x in indices])
    state = state.reshape((2**n, 2**n))
    indices = [qubit_map[qubit] for qubit in display.qubits]
    samples = density_matrix_utils.sample_density_matrix(
        state, indices, display.num_samples)
    return display.value_derived_from_samples(samples)
Пример #9
0
    def insert(
            self,
            index: int,
            operation_tree: ops.OP_TREE,
            strategy: InsertStrategy = InsertStrategy.NEW_THEN_INLINE) -> int:
        """Inserts operations into the middle of the circuit.

        Args:
            index: The index to insert all of the operations at.
            operation_tree: An operation or tree of operations.
            strategy: How to pick/create the moment to put operations into.

        Returns:
            The insertion index that will place operations just after the
            operations that were inserted by this method.

        Raises:
            IndexError: Bad insertion index.
            ValueError: Bad insertion strategy.
        """
        if not 0 <= index <= len(self.moments):
            raise IndexError('Insert index out of range: {}'.format(index))

        k = index
        for op in ops.flatten_op_tree(operation_tree):
            p = self._pick_or_create_inserted_op_moment_index(k, op, strategy)
            while p >= len(self.moments):
                self.moments.append(Moment())
            self.moments[p] = self.moments[p].with_operation(op)
            k = max(k, p + 1)
            if strategy is InsertStrategy.NEW_THEN_INLINE:
                strategy = InsertStrategy.INLINE
        return k
Пример #10
0
def get_logical_operations(
        operations: 'cirq.OP_TREE',
        initial_mapping: Dict[ops.Qid, ops.Qid]) -> Iterable['cirq.Operation']:
    """Gets the logical operations specified by the physical operations and
    initial mapping.

    Args:
        operations: The physical operations.
        initial_mapping: The initial mapping of physical to logical qubits.

    Raises:
        ValueError: A non-permutation physical operation acts on an unmapped
            qubit.
    """
    mapping = initial_mapping.copy()
    for op in cast(Iterable['cirq.Operation'],
                   ops.flatten_op_tree(operations)):
        if isinstance(op, ops.GateOperation) and isinstance(
                op.gate, PermutationGate):
            op.gate.update_mapping(mapping, op.qubits)
        else:
            for q in op.qubits:
                if mapping.get(q) is None:
                    raise ValueError(
                        f'Operation {op} acts on unmapped qubit {q}.')
            yield op.transform_qubits(mapping.__getitem__)
Пример #11
0
 def from_ops(
     *operations: 'cirq.OP_TREE',
     can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits,
 ) -> 'CircuitDag':
     dag = CircuitDag(can_reorder=can_reorder)
     for op in ops.flatten_op_tree(operations):
         dag.append(cast(ops.Operation, op))
     return dag
Пример #12
0
 def convert(self, op: ops.Operation) -> ops.OP_TREE:
     converted = self._convert_one(op)
     if converted is op:
         return converted
     return [
         self.convert(cast(ops.Operation, e))
         for e in ops.flatten_op_tree(converted)
     ]
Пример #13
0
def _verify_unique_measurement_keys(circuit: circuits.Circuit):
    result = collections.Counter(
        key for op in ops.flatten_op_tree(iter(circuit)) for key in protocols.measurement_keys(op)
    )
    if result:
        duplicates = [k for k, v in result.most_common() if v > 1]
        if duplicates:
            raise ValueError('Measurement key {} repeated'.format(",".join(duplicates)))
Пример #14
0
def _evaluate_ternary_circuit(op_tree, state):
    for op in ops.flatten_op_tree(op_tree):
        if hasattr(op, 'apply_to_ternary_state'):
            op.apply_to_ternary_state(state)
        else:
            _evaluate_ternary_circuit(
                op.default_decompose(),
                state)
Пример #15
0
    def _write_operations(self,
                          op_tree: ops.OP_TREE,
                          output: Callable[[str], None],
                          output_line_gap: Callable[[int], None],
                          top=True) -> None:
        for op in ops.flatten_op_tree(op_tree):
            qasm_op = extension.try_cast(  # type: ignore
                ops.QasmConvertibleOperation, op)
            if qasm_op is not None:
                out = qasm_op.known_qasm_output(self.args)
                if out is not None:
                    output(out)
                    continue

            if isinstance(op, ops.GateOperation):
                comment = 'Gate: {!s}'.format(op.gate)
            else:
                comment = 'Operation: {!s}'.format(op)
            comp_op = extension.try_cast(  # type: ignore
                ops.CompositeOperation, op)
            if comp_op is not None:
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                self._write_operations(comp_op.default_decompose(),
                                       output,
                                       output_line_gap,
                                       top=False)
                if top:
                    output_line_gap(1)
                continue

            mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None
            if mat is not None and len(op.qubits) == 1:
                u_op = QasmUGate.from_matrix(mat).on(*op.qubits)
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                output(cast(str, u_op.known_qasm_output(self.args)))
                if top:
                    output_line_gap(1)
                continue

            if mat is not None and len(op.qubits) == 2:
                u_op = QasmTwoQubitGate.from_matrix(mat).on(*op.qubits)
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                self._write_operations((u_op, ),
                                       output,
                                       output_line_gap,
                                       top=False)
                if top:
                    output_line_gap(1)
                continue

            raise ValueError(
                'Cannot output operation as QASM: {!r}'.format(op))
Пример #16
0
 def from_ops(*operations: ops.OP_TREE,
              can_reorder: Callable[[ops.Operation, ops.Operation],
                                    bool] = _disjoint_qubits,
              device: devices.Device = devices.UnconstrainedDevice
              ) -> 'CircuitDag':
     dag = CircuitDag(can_reorder=can_reorder, device=device)
     for op in ops.flatten_op_tree(operations):
         dag.append(op)
     return dag
Пример #17
0
 def from_ops(
     *operations: 'cirq.OP_TREE',
     can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits,
     device: devices.Device = devices.UNCONSTRAINED_DEVICE,
 ) -> 'CircuitDag':
     dag = CircuitDag(can_reorder=can_reorder, device=device)
     for op in ops.flatten_op_tree(operations):
         dag.append(cast(ops.Operation, op))
     return dag
Пример #18
0
def _verify_unique_measurement_keys(circuit: 'cirq.AbstractCircuit'):
    result = collections.Counter(
        key for op in ops.flatten_op_tree(iter(circuit))
        for key in protocols.measurement_key_names(op))
    if result:
        duplicates = [k for k, v in result.most_common() if v > 1]
        if duplicates:
            raise ValueError(
                f"Measurement key {','.join(duplicates)} repeated")
Пример #19
0
 def from_ops(*operations: ops.OP_TREE,
              can_reorder: Callable[[ops.Operation, ops.Operation],
                                    bool] = _disjoint_qubits,
              device: devices.Device = devices.UnconstrainedDevice
              ) -> 'CircuitDag':
     dag = CircuitDag(can_reorder=can_reorder, device=device)
     for op in ops.flatten_op_tree(operations):
         dag.append(op)
     return dag
Пример #20
0
    def _write_operations(self,
                          op_tree: ops.OP_TREE,
                          output: Callable[[str], None],
                          output_line_gap: Callable[[int], None],
                          top=True) -> None:
        for op in ops.flatten_op_tree(op_tree):
            qasm_op = self.ext.try_cast(ops.QasmConvertableOperation, op)
            if qasm_op is not None:
                out = qasm_op.known_qasm_output(self.args)
                if out is not None:
                    output(out)
                    continue

            if isinstance(op, ops.GateOperation):
                comment = 'Gate: {!s}'.format(op.gate)
            else:
                comment = 'Operation: {!s}'.format(op)
            comp_op = self.ext.try_cast(ops.CompositeOperation, op)
            if comp_op is not None:
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                self._write_operations(comp_op.default_decompose(),
                                       output,
                                       output_line_gap,
                                       top=False)
                if top:
                    output_line_gap(1)
                continue

            matrix_op = self.ext.try_cast(ops.KnownMatrix, op)
            if matrix_op is not None and len(op.qubits) == 1:
                u_op = QasmUGate.from_matrix(matrix_op.matrix())(*op.qubits)
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                output(u_op.known_qasm_output(self.args))
                if top:
                    output_line_gap(1)
                continue

            if matrix_op is not None and len(op.qubits) == 2:
                u_op = QasmTwoQubitGate.from_matrix(matrix_op.matrix()
                                                    )(*op.qubits)
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                self._write_operations((u_op,),
                                       output,
                                       output_line_gap,
                                       top=False)
                if top:
                    output_line_gap(1)
                continue

            raise ValueError('Cannot output operation as QASM: {!r}'.format(op))
Пример #21
0
def get_logical_operations(
        operations: ops.OP_TREE,
        initial_mapping: Dict[ops.Qid, ops.Qid]) -> Iterable[ops.Operation]:
    mapping = initial_mapping.copy()
    for op in cast(Iterable[ops.Operation], ops.flatten_op_tree(operations)):
        if (isinstance(op, ops.GateOperation)
                and isinstance(op.gate, PermutationGate)):
            op.gate.update_mapping(mapping, op.qubits)
        else:
            yield op.transform_qubits(mapping.__getitem__)
Пример #22
0
 def _decompose(self, op: ops.Operation) -> ops.OP_TREE:
     """Recursively decompose composite gates into an OP_TREE of gates."""
     skip = self.no_decomp(op)
     if skip and (skip is not NotImplemented):
         return op
     composite_op = self.extension.try_cast(ops.CompositeOperation, op)
     if composite_op is None:
         return op
     op_iter = ops.flatten_op_tree(composite_op.default_decompose())
     return (self._decompose(op) for op in op_iter)
Пример #23
0
def decompose_depth(*operations, d=1):
    if d <= 0:
        yield from operations
        return
    for op in ops.flatten_op_tree(operations):
        composite_op = extension.try_cast(ops.CompositeOperation, op)
        if composite_op is not None:
            yield from decompose_depth(composite_op.default_decompose(), d=d-1)
        else:
            yield op
Пример #24
0
 def _decompose(self, op: ops.Operation) -> ops.OP_TREE:
     """Recursively decompose composite gates into an OP_TREE of gates."""
     skip = self.no_decomp(op)
     if skip and (skip is not NotImplemented):
         return op
     composite_op = self.extension.try_cast(ops.CompositeOperation, op)
     if composite_op is None:
         return op
     op_iter = ops.flatten_op_tree(composite_op.default_decompose())
     return (self._decompose(op) for op in op_iter)
Пример #25
0
    def _write_operations(self,
                          op_tree: ops.OP_TREE,
                          output: Callable[[str], None],
                          output_line_gap: Callable[[int], None],
                          top=True) -> None:
        for op in ops.flatten_op_tree(op_tree):
            out = protocols.qasm(op, args=self.args, default=None)
            if out is not None:
                output(out)
                continue

            if isinstance(op, ops.GateOperation):
                comment = 'Gate: {!s}'.format(op.gate)
            else:
                comment = 'Operation: {!s}'.format(op)

            decomp = protocols.decompose_once(op, None)
            if decomp is not None:
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                self._write_operations(decomp,
                                       output,
                                       output_line_gap,
                                       top=False)
                if top:
                    output_line_gap(1)
                continue

            mat = protocols.unitary(op, None) if len(op.qubits) <= 2 else None
            if mat is not None and len(op.qubits) == 1:
                u_op = QasmUGate.from_matrix(mat).on(*op.qubits)
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                output(cast(str, protocols.qasm(u_op, args=self.args)))
                if top:
                    output_line_gap(1)
                continue

            if mat is not None and len(op.qubits) == 2:
                u_op = QasmTwoQubitGate.from_matrix(mat).on(*op.qubits)
                if top:
                    output_line_gap(1)
                    output('// {}\n'.format(comment))
                self._write_operations((u_op,),
                                       output,
                                       output_line_gap,
                                       top=False)
                if top:
                    output_line_gap(1)
                continue

            raise ValueError('Cannot output operation as QASM: {!r}'.format(op))
Пример #26
0
def update_mapping(mapping: Dict[ops.Qid, LogicalIndex], operations: 'cirq.OP_TREE') -> None:
    """Updates a mapping (in place) from qubits to logical indices according to
    a set of permutation gates. Any gates other than permutation gates are
    ignored.

    Args:
        mapping: The mapping to update.
        operations: The operations to update according to.
    """
    for op in ops.flatten_op_tree(operations):
        if isinstance(op, ops.GateOperation) and isinstance(op.gate, PermutationGate):
            op.gate.update_mapping(mapping, op.qubits)
Пример #27
0
def verify_decomposition_inverse(*op_tree, max_test_value=2**100, depth=1):
    qubits = set()
    op_list = tuple(ops.flatten_op_tree(op_tree))
    for op in op_list:
        qubits.update(op.qubits)
    qubits = sorted(qubits)
    num_qubits = len(qubits)
    sub_ops = tuple(ops.flatten_op_tree(decompose_depth(op_list, d=depth)))
    sub_ops_inv = tuple(ops.flatten_op_tree(decompose_depth(ops.inverse(op_list), d=depth)))

    for trits in itertools.product((0,1,2), repeat=num_qubits):
        state = trit_list_to_state(qubits, trits)
        state_orig = state.copy()
        for op in sub_ops:
            op.apply_to_ternary_state(state)
        for op in sub_ops_inv:
            op.apply_to_ternary_state(state)
        if state != state_orig:
            input_state_str = ''.join(map(str, trits))
            output_state_str = ''.join(map(str, (state[q] for q in qubits)))
            raise RuntimeError(
                'Gate {!r} inverse is invalid for input {} != {}'.format(
                op_list, input_state_str, output_state_str))
Пример #28
0
    def from_ops(
        *operations: 'cirq.OP_TREE',
        can_reorder: Callable[['cirq.Operation', 'cirq.Operation'], bool] = _disjoint_qubits,
        device: 'cirq.Device' = devices.UNCONSTRAINED_DEVICE,
    ) -> 'CircuitDag':
        if device == devices.UNCONSTRAINED_DEVICE:
            dag = CircuitDag(can_reorder=can_reorder)
        else:
            with _compat.block_overlapping_deprecation(re.escape(circuit._DEVICE_DEP_MESSAGE)):
                dag = CircuitDag(can_reorder=can_reorder, device=device)

        for op in ops.flatten_op_tree(operations):
            dag.append(cast(ops.Operation, op))
        return dag
Пример #29
0
    def _write_operations(
        self,
        op_tree: 'cirq.OP_TREE',
        output: Callable[[str], None],
        output_line_gap: Callable[[int], None],
    ) -> None:
        def keep(op: 'cirq.Operation') -> bool:
            return protocols.qasm(op, args=self.args, default=None) is not None

        def fallback(op):
            if len(op.qubits) not in [1, 2]:
                return NotImplemented

            mat = protocols.unitary(op, None)
            if mat is None:
                return NotImplemented

            if len(op.qubits) == 1:
                return QasmUGate.from_matrix(mat).on(*op.qubits)
            return QasmTwoQubitGate.from_matrix(mat).on(*op.qubits)

        def on_stuck(bad_op):
            return ValueError(
                'Cannot output operation as QASM: {!r}'.format(bad_op))

        for main_op in ops.flatten_op_tree(op_tree):
            decomposed = protocols.decompose(main_op,
                                             keep=keep,
                                             fallback_decomposer=fallback,
                                             on_stuck_raise=on_stuck)

            qasms = [protocols.qasm(op, args=self.args) for op in decomposed]

            should_annotate = decomposed != [main_op
                                             ] or qasms[0].count('\n') > 1
            if should_annotate:
                output_line_gap(1)
                if isinstance(main_op, ops.GateOperation):
                    x = str(main_op.gate).replace('\n', '\n //')
                    output('// Gate: {!s}\n'.format(x))
                else:
                    x = str(main_op).replace('\n', '\n //')
                    output('// Operation: {!s}\n'.format(x))

            for qasm in qasms:
                output(qasm)

            if should_annotate:
                output_line_gap(1)
Пример #30
0
 def __init__(self, clear_span: int, clear_qubits: Iterable[ops.QubitId],
              new_operations: ops.OP_TREE) -> None:
     """
     Args:
         clear_span: Defines the range of moments to affect. Specifically,
             refers to the indices in range(start, start+clear_span) where
             start is an index known from surrounding context.
         clear_qubits: Defines the set of qubits that should be cleared
             with each affected moment.
         new_operations: The operations to replace the cleared out
             operations with.
     """
     self.new_operations = tuple(ops.flatten_op_tree(new_operations))
     self.clear_span = clear_span
     self.clear_qubits = tuple(clear_qubits)
Пример #31
0
def is_topologically_sorted(
    dag: 'cirq.CircuitDag',
    operations: 'cirq.OP_TREE',
    equals: Callable[[ops.Operation, ops.Operation], bool] = operator.eq,
) -> bool:
    """Whether a given order of operations is consistent with the DAG.

    For example, suppose the (transitive reduction of the) circuit DAG is

         ╭─> Op2 ─╮
    Op1 ─┤        ├─> Op4
         ╰─> Op3 ─╯

    Then [Op1, Op2, Op3, Op4] and [Op1, Op3, Op2, Op4] (and any operations
    tree that flattens to one of them) are topologically sorted according
    to the DAG, and any other ordering of the four operations is not.

    Evaluates to False when the set of operations is different from those
    in the nodes of the DAG, regardless of the ordering.

    Args:
        dag: The circuit DAG.
        operations: The ordered operations.
        equals: The function to determine equality of operations. Defaults to
            `operator.eq`.

    Returns:
        Whether or not the operations given are topologically sorted
        according to the DAG.
    """

    remaining_dag = dag.copy()
    frontier = [
        node for node in remaining_dag.nodes() if not remaining_dag.pred[node]
    ]
    for operation in cast(Iterable[ops.Operation],
                          ops.flatten_op_tree(operations)):
        for i, node in enumerate(frontier):
            if equals(node.val, operation):
                frontier.pop(i)
                succ = remaining_dag.succ[node]
                remaining_dag.remove_node(node)
                frontier.extend(new_node for new_node in succ
                                if not remaining_dag.pred[new_node])
                break
        else:
            return False
    return not bool(frontier)
Пример #32
0
def operations_to_part_lens(
    qubit_order: Sequence['cirq.Qid'],
    op_tree: 'cirq.OP_TREE',
) -> Tuple[int, ...]:
    qubit_sort_key = functools.partial(operator.indexOf, qubit_order)
    op_parts = [tuple(sorted(op.qubits, key=qubit_sort_key)) for op in ops.flatten_op_tree(op_tree)]
    singletons = [
        (q,) for q in set(qubit_order).difference(*op_parts)
    ]  # type: List[Tuple['cirq.Qid', ...]]
    part_sort_key = lambda p: min(qubit_sort_key(q) for q in p)
    parts = tuple(tuple(part) for part in sorted(singletons + op_parts, key=part_sort_key))

    if sum(parts, ()) != tuple(qubit_order):
        raise ValueError('sum(parts, ()) != tuple(qubit_order)')

    return tuple(len(part) for part in parts)
Пример #33
0
 def __init__(self,
              clear_span: int,
              clear_qubits: Iterable[ops.QubitId],
              new_operations: ops.OP_TREE) -> None:
     """
     Args:
         clear_span: Defines the range of moments to affect. Specifically,
             refers to the indices in range(start, start+clear_span) where
             start is an index known from surrounding context.
         clear_qubits: Defines the set of qubits that should be cleared
             with each affected moment.
         new_operations: The operations to replace the cleared out
             operations with.
     """
     self.new_operations = tuple(ops.flatten_op_tree(new_operations))
     self.clear_span = clear_span
     self.clear_qubits = tuple(clear_qubits)
Пример #34
0
def decompose_once(val: Any,
                   default=RaiseTypeErrorIfNotProvided,
                   *args,
                   **kwargs):
    """Decomposes a value into operations, if possible.

    This method decomposes the value exactly once, instead of decomposing it
    and then continuing to decomposing the decomposed operations recursively
    until some criteria is met (which is what `cirq.decompose` does).

    Args:
        val: The value to call `_decompose_` on, if possible.
        default: A default result to use if the value doesn't have a
            `_decompose_` method or that method returns `NotImplemented` or
            `None`. If not specified, non-decomposable values cause a
            `TypeError`.
        args: Positional arguments to forward into the `_decompose_` method of
            `val`.  For example, this is used to tell gates what qubits they are
            being applied to.
        kwargs: Keyword arguments to forward into the `_decompose_` method of
            `val`.

    Returns:
        The result of `val._decompose_(*args, **kwargs)`, if `val` has a
        `_decompose_` method and it didn't return `NotImplemented` or `None`.
        Otherwise `default` is returned, if it was specified. Otherwise an error
        is raised.

    Raises:
        TypeError: `val` didn't have a `_decompose_` method (or that method returned
            `NotImplemented` or `None`) and `default` wasn't set.
    """
    method = getattr(val, '_decompose_', None)
    decomposed = NotImplemented if method is None else method(*args, **kwargs)

    if decomposed is not NotImplemented and decomposed is not None:
        return list(ops.flatten_op_tree(decomposed))

    if default is not RaiseTypeErrorIfNotProvided:
        return default
    if method is None:
        raise TypeError(
            f"object of type '{type(val)}' has no _decompose_ method.")
    raise TypeError("object of type '{}' does have a _decompose_ method, "
                    "but it returned NotImplemented or None.".format(
                        type(val)))
Пример #35
0
def _kak_decomposition_to_operations(q0: ops.QubitId,
                                     q1: ops.QubitId,
                                     a0: np.ndarray,
                                     a1: np.ndarray,
                                     x: float,
                                     y: float,
                                     z: float,
                                     b0: np.ndarray,
                                     b1: np.ndarray,
                                     allow_partial_czs: bool,
                                     tolerance: float = 1e-8
                                     ) -> List[ops.Operation]:
    """Assumes that the decomposition is canonical."""
    pre = [_do_single_on(b0, q0, tolerance), _do_single_on(b1, q1, tolerance)]
    post = [_do_single_on(a0, q0, tolerance), _do_single_on(a1, q1, tolerance)]

    return list(ops.flatten_op_tree([
        pre,
        _non_local_part(q0, q1, x, y, z, allow_partial_czs, tolerance),
        post,
    ]))
Пример #36
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.RotZGate):
        # Don't keep border operations that commute with CZ.
        del u_gates[-1]

    ops_before = [gate(target) for gate in u_gates]
    ops_after = ops.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)))
Пример #37
0
    def __init__(self,
                 operations: ops.OP_TREE,
                 qubits: Tuple[ops.QubitId, ...],
                 header: str = '',
                 precision: int = 10,
                 version: str = '2.0',
                 ext: extension.Extensions = None) -> None:
        self.operations = tuple(ops.flatten_op_tree(operations))
        self.qubits = qubits
        self.header = header
        if ext is None:
            ext = extension.Extensions()
        self.ext = ext
        self.measurements = tuple(cast(ops.GateOperation, op)
                                  for op in self.operations
                                  if ops.MeasurementGate.is_measurement(op))

        meas_key_id_map, meas_comments = self._generate_measurement_ids()
        self.meas_comments = meas_comments
        qubit_id_map = self._generate_qubit_ids()
        self.args = ops.QasmOutputArgs(precision=precision,
                                       version=version,
                                       qubit_id_map=qubit_id_map,
                                       meas_key_id_map=meas_key_id_map)
Пример #38
0
 def convert(self, op: ops.Operation) -> ops.OP_TREE:
     converted = self._convert_one(op)
     if converted is op:
         return converted
     return [self.convert(e) for e in ops.flatten_op_tree(converted)]