Beispiel #1
0
def _fix_single_qubit_gates_around_kak_interaction(
    *,
    desired: 'cirq.KakDecomposition',
    operations: List['cirq.Operation'],
    qubits: Sequence['cirq.Qid'],
) -> Iterator['cirq.Operation']:
    """Adds single qubit operations to complete a desired interaction.

    Args:
        desired: The kak decomposition of the desired operation.
        qubits: The pair of qubits that is being operated on.
        operations: A list of operations that composes into the desired kak
            interaction coefficients, but may not have the desired before/after
            single qubit operations or the desired global phase.

    Returns:
        A list of operations whose kak decomposition approximately equals the
        desired kak decomposition.
    """
    actual = linalg.kak_decomposition(circuits.Circuit(operations))

    def dag(a: np.ndarray) -> np.ndarray:
        return np.transpose(np.conjugate(a))

    for k in range(2):
        g = ops.MatrixGate(
            dag(actual.single_qubit_operations_before[k])
            @ desired.single_qubit_operations_before[k])
        yield g(qubits[k])
    yield from operations
    for k in range(2):
        g = ops.MatrixGate(desired.single_qubit_operations_after[k] @ dag(
            actual.single_qubit_operations_after[k]))
        yield g(qubits[k])
    yield ops.GlobalPhaseOperation(desired.global_phase / actual.global_phase)
Beispiel #2
0
 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 map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
     op_untagged = op.untagged
     if (
         deep
         and isinstance(op_untagged, circuits.CircuitOperation)
         and merged_circuit_op_tag not in op.tags
     ):
         return op_untagged.replace(
             circuit=_rewrite_merged_k_qubit_unitaries(
                 op_untagged.circuit,
                 context=context,
                 k=k,
                 rewriter=rewriter,
                 merged_circuit_op_tag=merged_circuit_op_tag,
             ).freeze()
         ).with_tags(*op.tags)
     if not (protocols.num_qubits(op) <= k and protocols.has_unitary(op)):
         return op
     if rewriter:
         return rewriter(
             cast(circuits.CircuitOperation, op_untagged)
             if merged_circuit_op_tag in op.tags
             else circuits.CircuitOperation(circuits.FrozenCircuit(op))
         )
     return ops.MatrixGate(protocols.unitary(op)).on(*op.qubits)
Beispiel #4
0
def test_to_braket_raises_on_unsupported_gates():
    for num_qubits in range(3, 5):
        print(num_qubits)
        qubits = [LineQubit(int(qubit)) for qubit in range(num_qubits)]
        op = ops.MatrixGate(_rotation_of_pi_over_7(num_qubits)).on(*qubits)
        circuit = Circuit(op)
        with pytest.raises(ValueError):
            to_braket(circuit)
Beispiel #5
0
 def map_func(op: 'cirq.Operation', _) -> 'cirq.OP_TREE':
     if not (protocols.num_qubits(op) <= k and protocols.has_unitary(op)):
         return op
     if rewriter:
         return rewriter(
             cast(circuits.CircuitOperation, op.untagged
                  ) if merged_circuit_op_tag in op.tags else circuits.
             CircuitOperation(circuits.FrozenCircuit(op)))
     return ops.MatrixGate(protocols.unitary(op)).on(*op.qubits)
Beispiel #6
0
def _decompose_single_ctrl(matrix: np.ndarray, control: 'cirq.Qid',
                           target: 'cirq.Qid') -> List['cirq.Operation']:
    """Decomposes controlled gate with one control.

    See [1], chapter 5.1.
    """
    a, b, c, delta = _decompose_abc(matrix)

    result = [
        ops.ZPowGate(exponent=delta / np.pi).on(control),
        ops.MatrixGate(c).on(target),
        ops.CNOT.on(control, target),
        ops.MatrixGate(b).on(target),
        ops.CNOT.on(control, target),
        ops.MatrixGate(a).on(target),
    ]

    # Remove no-ops.
    result = [g for g in result if not _is_identity(unitary(g))]

    return result
Beispiel #7
0
    def _rewrite(self, operations: List[ops.Operation]) -> Optional[ops.OP_TREE]:
        if not operations:
            return None
        q = operations[0].qubits[0]

        # Custom rewriter?
        if self._rewriter is not None:
            return self._rewriter(operations)

        unitary = linalg.dot(*(protocols.unitary(op) for op in operations[::-1]))

        # Custom synthesizer?
        if self._synthesizer is not None:
            return self._synthesizer(q, unitary)

        # Just use the default.
        return ops.MatrixGate(unitary).on(q)
Beispiel #8
0
def _register_custom_gate(gate_json: Any, registry: Dict[str, CellMaker]):
    if not isinstance(gate_json, Dict):
        raise ValueError(
            f'Custom gate json must be a dictionary.\n' f'Custom gate json={gate_json!r}.'
        )

    if 'id' not in gate_json:
        raise ValueError(
            f'Custom gate json must have an id key.\n' f'Custom gate json={gate_json!r}.'
        )
    identifier = gate_json['id']
    if identifier in registry:
        raise ValueError(f'Custom gate with duplicate identifier: {identifier!r}')

    if 'matrix' in gate_json and 'circuit' in gate_json:
        raise ValueError(
            f'Custom gate json cannot have both a matrix and a circuit.\n'
            f'Custom gate json={gate_json!r}.'
        )

    if 'matrix' in gate_json:
        if not isinstance(gate_json['matrix'], str):
            raise ValueError(
                f'Custom gate matrix json must be a string.\n' f'Custom gate json={gate_json!r}.'
            )
        gate = ops.MatrixGate(parse_matrix(gate_json['matrix']))
        registry[identifier] = CellMaker(
            identifier=identifier,
            size=gate.num_qubits(),
            maker=lambda args: gate(*args.qubits[::-1]),
        )

    elif 'circuit' in gate_json:
        comp = _parse_cols_into_composite_cell(gate_json['circuit'], registry)
        registry[identifier] = CellMaker(
            identifier=identifier,
            size=comp.height,
            maker=lambda args: comp.with_line_qubits_mapped_to(list(args.qubits)),
        )

    else:
        raise ValueError(
            f'Custom gate json must have a matrix or a circuit.\n'
            f'Custom gate json={gate_json!r}.'
        )
Beispiel #9
0
def decompose_multi_controlled_rotation(
        matrix: np.ndarray, controls: List['cirq.Qid'],
        target: 'cirq.Qid') -> List['cirq.Operation']:
    """Implements action of multi-controlled unitary gate.

    Returns a sequence of operations, which is equivalent to applying
    single-qubit gate with matrix `matrix` on `target`, controlled by
    `controls`.

    Result is guaranteed to consist exclusively of 1-qubit, CNOT and CCNOT
    gates.

    If matrix is special unitary, result has length `O(len(controls))`.
    Otherwise result has length `O(len(controls)**2)`.

    References:
        [1] Barenco, Bennett et al.
            Elementary gates for quantum computation. 1995.
            https://arxiv.org/pdf/quant-ph/9503016.pdf

    Args:
        matrix - 2x2 numpy unitary matrix (of real or complex dtype).
        controls - control qubits.
        targets - target qubits.

    Returns:
        A list of operations which, applied in a sequence, are equivalent to
        applying `MatrixGate(matrix).on(target).controlled_by(*controls)`.
    """
    assert is_unitary(matrix)
    assert matrix.shape == (2, 2)

    if len(controls) == 0:
        return [ops.MatrixGate(matrix).on(target)]
    elif len(controls) == 1:
        return _decompose_single_ctrl(matrix, controls[0], target)
    elif is_special_unitary(matrix):
        return _decompose_su(matrix, controls, target)
    else:
        return _decompose_recursive(matrix, 1.0, controls, target, [])