示例#1
0
def state_vector_has_stabilizer(state_vector: np.ndarray, stabilizer: DensePauliString) -> bool:
    """Checks that the state_vector is stabilized by the given stabilizer.

    The stabilizer should not modify the value of the state_vector, up to the
    global phase.

    Args:
        state_vector: An input state vector. Is not mutated by this function.
        stabilizer: A potential stabilizer of the above state_vector as a
          DensePauliString.

    Returns:
        Whether the stabilizer stabilizes the supplied state.
    """

    qubits = LineQubit.range(protocols.num_qubits(stabilizer))
    args = act_on_state_vector_args.ActOnStateVectorArgs(
        target_tensor=state_vector.copy(),
        available_buffer=np.empty_like(state_vector),
        qubits=qubits,
        prng=np.random.RandomState(),
        log_of_measurement_results={},
    )
    protocols.act_on(stabilizer, args, qubits)
    return np.allclose(args.target_tensor, state_vector)
示例#2
0
def assert_act_on_clifford_tableau_effect_matches_unitary(val: Any) -> None:
    """Checks that act_on with CliffordTableau generates stabilizers that
    stabilize the final state vector. Does not work with Operations or Gates
    expecting non-qubit Qids."""

    # pylint: disable=unused-variable
    __tracebackhide__ = True
    # pylint: enable=unused-variable

    num_qubits_val = protocols.num_qubits(val)

    if not protocols.has_unitary(val) or \
            protocols.qid_shape(val) != (2,) * num_qubits_val:
        return None

    qubits = LineQubit.range(protocols.num_qubits(val) * 2)
    qubit_map = {qubit: i for i, qubit in enumerate(qubits)}

    circuit = Circuit()
    for i in range(num_qubits_val):
        circuit.append([
            common_gates.H(qubits[i]),
            common_gates.CNOT(qubits[i], qubits[-i - 1])
        ])
    if hasattr(val, "on"):
        circuit.append(val.on(*qubits[:num_qubits_val]))
    else:
        circuit.append(val.with_qubits(*qubits[:num_qubits_val]))

    tableau = _final_clifford_tableau(circuit, qubit_map)
    if tableau is None:
        return None

    state_vector = np.reshape(final_state_vector(circuit, qubit_order=qubits),
                              protocols.qid_shape(qubits))

    assert all(
        state_vector_has_stabilizer(state_vector, stab)
        for stab in tableau.stabilizers()), (
            "act_on clifford tableau is not consistent with "
            "final_state_vector simulation.\n\nval: {!r}".format(val))
示例#3
0
def assert_all_implemented_act_on_effects_match_unitary(
        val: Any,
        assert_tableau_implemented: bool = False,
        assert_ch_form_implemented: bool = False) -> None:
    """Uses val's effect on final_state_vector to check act_on(val)'s behavior.

    Checks that act_on with CliffordTableau or StabilizerStateCHForm behaves
    consistently with act_on through final state vector. Does not work with
    Operations or Gates expecting non-qubit Qids. If either of the
    assert_*_implmented args is true, fails if the corresponding method is not
    implemented for the test circuit.

    Args:
        val: A gate or operation that may be an input to protocols.act_on.
        assert_tableau_implemented: asserts that protocols.act_on() works with
          val and ActOnCliffordTableauArgs inputs.
        assert_ch_form_implemented: asserts that protocols.act_on() works with
          val and ActOnStabilizerStateChFormArgs inputs.
    """

    # pylint: disable=unused-variable
    __tracebackhide__ = True
    # pylint: enable=unused-variable

    num_qubits_val = protocols.num_qubits(val)

    if (protocols.is_parameterized(val) or not protocols.has_unitary(val)
            or protocols.qid_shape(val) != (2, ) * num_qubits_val):
        if assert_tableau_implemented or assert_ch_form_implemented:
            assert False, ("Could not assert if any act_on methods were "
                           "implemented. Operating on qudits or with a "
                           "non-unitary or parameterized operation is "
                           "unsupported.\n\nval: {!r}".format(val))
        return None

    qubits = LineQubit.range(protocols.num_qubits(val) * 2)
    qubit_map = {qubit: i for i, qubit in enumerate(qubits)}

    circuit = Circuit()
    for i in range(num_qubits_val):
        circuit.append([
            common_gates.H(qubits[i]),
            common_gates.CNOT(qubits[i], qubits[-i - 1])
        ])
    if hasattr(val, "on"):
        circuit.append(val.on(*qubits[:num_qubits_val]))
    else:
        circuit.append(val.with_qubits(*qubits[:num_qubits_val]))

    state_vector = np.reshape(final_state_vector(circuit, qubit_order=qubits),
                              protocols.qid_shape(qubits))

    tableau = _final_clifford_tableau(circuit, qubit_map)
    if tableau is None:
        assert (
            not assert_tableau_implemented
        ), "Failed to generate final tableau for the test circuit.\n\nval: {!r}".format(
            val)
    else:
        assert all(
            state_vector_has_stabilizer(state_vector, stab)
            for stab in tableau.stabilizers()), (
                "act_on clifford tableau is not consistent with "
                "final_state_vector simulation.\n\nval: {!r}".format(val))

    stabilizer_ch_form = _final_stabilizer_state_ch_form(circuit, qubit_map)
    if stabilizer_ch_form is None:
        assert not assert_ch_form_implemented, ("Failed to generate final "
                                                "stabilizer state CH form "
                                                "for the test circuit."
                                                "\n\nval: {!r}".format(val))
    else:
        np.testing.assert_allclose(
            np.reshape(stabilizer_ch_form.state_vector(),
                       protocols.qid_shape(qubits)),
            state_vector,
            atol=1e-07,
            err_msg=
            f"stabilizer_ch_form.state_vector disagrees with state_vector for {val!r}",
            verbose=True,
        )
示例#4
0
 def nodes_as_linequbits(self) -> List['cirq.LineQubit']:
     """Get the graph nodes as cirq.LineQubit"""
     return [LineQubit(x) for x in sorted(self.graph.nodes)]
def tk_to_cirq(tkcirc: Circuit) -> cirq.circuits.Circuit:
    """Converts a tket :py:class:`Circuit` object to a Cirq :py:class:`Circuit`.

    :param tkcirc: The input tket :py:class:`Circuit`

    :return: The Cirq :py:class:`Circuit` corresponding to the input circuit
    """
    qmap = {}
    line_name = None
    grid_name = None
    # Since Cirq can only support registers of up to 2 dimensions, we explicitly
    # check for 3-dimensional registers whose third dimension is trivial.
    # SquareGrid architectures are of this form.
    indices = [qb.index for qb in tkcirc.qubits]
    is_flat_3d = all(idx[2] == 0 for idx in indices if len(idx) == 3)
    for qb in tkcirc.qubits:
        if len(qb.index) == 0:
            qmap.update({qb: cirq.ops.NamedQubit(qb.reg_name)})
        elif len(qb.index) == 1:
            if line_name != None and line_name != qb.reg_name:
                raise NotImplementedError(
                    "Cirq can only support a single linear register")
            line_name = qb.reg_name
            qmap.update({qb: LineQubit(qb.index[0])})
        elif len(qb.index) == 2 or (len(qb.index) == 3 and is_flat_3d):
            if grid_name != None and grid_name != qb.reg_name:
                raise NotImplementedError(
                    "Cirq can only support a single grid register")
            grid_name = qb.reg_name
            qmap.update({qb: GridQubit(qb.index[0], qb.index[1])})
        else:
            raise NotImplementedError(
                "Cirq can only support registers of dimension <=2")
    oplst = []
    for command in tkcirc:
        op = command.op
        optype = op.type
        try:
            gatetype = _ops2cirq_mapping[optype]
        except KeyError as error:
            raise NotImplementedError("Cannot convert tket Op to Cirq gate: " +
                                      op.get_name()) from error
        if optype == OpType.Measure:
            qid = qmap[command.args[0]]
            bit = command.args[1]
            cirqop = cirq.ops.measure(qid, key=bit.__repr__())
        else:
            qids = [qmap[qbit] for qbit in command.args]
            params = op.params
            if len(params) == 0:
                cirqop = gatetype(*qids)
            elif optype == OpType.PhasedX:
                cirqop = gatetype(phase_exponent=params[1],
                                  exponent=params[0])(*qids)
            elif optype == OpType.FSim:
                cirqop = gatetype(theta=float(params[0] * pi),
                                  phi=float(params[1] * pi))(*qids)
            elif optype == OpType.PhasedISWAP:
                cirqop = gatetype(phase_exponent=params[0],
                                  exponent=params[1])(*qids)
            else:
                cirqop = gatetype(exponent=params[0])(*qids)
        oplst.append(cirqop)

    try:
        coeff = cmath.exp(float(tkcirc.phase) * cmath.pi * 1j)
        if coeff != 1.0:
            oplst.append(cirq.ops.GlobalPhaseOperation(coeff))
    except ValueError:
        warning(
            "Global phase is dependent on a symbolic parameter, so cannot adjust for "
            "phase")

    return cirq.circuits.Circuit(*oplst)