Esempio n. 1
0
 def default_compilation_pass(self,
                              optimisation_level: int = 1) -> BasePass:
     assert optimisation_level in range(3)
     passes = [DecomposeBoxes()]
     if optimisation_level == 1:
         passes.append(SynthesiseIBM())
     elif optimisation_level == 2:
         passes.append(FullPeepholeOptimise())
     passes.append(self._rebase_pass)
     if self._device_type == _DeviceType.QPU:
         passes.append(
             CXMappingPass(
                 self._tket_device,
                 NoiseAwarePlacement(self._tket_device),
                 directed_cx=False,
                 delay_measures=True,
             ))
         # If CX weren't supported by the device then we'd need to do another
         # rebase_pass here. But we checked above that it is.
     if optimisation_level == 1:
         passes.extend([RemoveRedundancies(), self._squash_pass])
     if optimisation_level == 2:
         passes.extend([
             CliffordSimp(False),
             SynthesiseIBM(),
             self._rebase_pass,
             self._squash_pass,
         ])
     return SequencePass(passes)
Esempio n. 2
0
 def default_compilation_pass(self,
                              optimisation_level: int = 1) -> BasePass:
     assert optimisation_level in range(3)
     passlist = [DecomposeBoxes()]
     if optimisation_level == 0:
         passlist.append(self._rebase_pass)
     elif optimisation_level == 1:
         passlist.append(SynthesiseIBM())
     else:
         passlist.append(FullPeepholeOptimise())
     if self._noise_model and self._device:
         passlist.append(
             CXMappingPass(
                 self._device,
                 NoiseAwarePlacement(self._device),
                 directed_cx=True,
                 delay_measures=False,
             ))
         if optimisation_level == 0:
             passlist.append(self._rebase_pass)
         elif optimisation_level == 1:
             passlist.append(SynthesiseIBM())
         else:
             passlist.extend([CliffordSimp(False), SynthesiseIBM()])
     return SequencePass(passlist)
Esempio n. 3
0
 def default_compilation_pass(self,
                              optimisation_level: int = 1) -> BasePass:
     assert optimisation_level in range(3)
     passlist = [
         DecomposeBoxes(),
         FlattenRegisters(),
     ]
     if optimisation_level == 1:
         passlist.append(SynthesiseIBM())
     elif optimisation_level == 2:
         passlist.append(FullPeepholeOptimise())
     passlist.append(
         CXMappingPass(
             self._device,
             NoiseAwarePlacement(self._device),
             directed_cx=False,
             delay_measures=True,
         ))
     if optimisation_level == 2:
         passlist.append(CliffordSimp(False))
     if optimisation_level > 0:
         passlist.append(SynthesiseIBM())
     passlist.append(RebaseQuil())
     if optimisation_level > 0:
         passlist.append(EulerAngleReduction(OpType.Rx, OpType.Rz))
     return SequencePass(passlist)
Esempio n. 4
0
def test_implicit_perm() -> None:
    c = Circuit(2)
    c.CX(0, 1)
    c.CX(1, 0)
    c.Ry(0.1, 1)
    c1 = c.copy()
    CliffordSimp().apply(c1)
    b = MyBackend()
    b.compile_circuit(c)
    b.compile_circuit(c1)
    assert c.implicit_qubit_permutation() != c1.implicit_qubit_permutation()
    for bo in [BasisOrder.ilo, BasisOrder.dlo]:
        s = b.get_state(c, bo)
        s1 = b.get_state(c1, bo)
        assert np.allclose(s, s1)
def test_swaps_basisorder() -> None:
    # Check that implicit swaps can be corrected irrespective of BasisOrder
    b = ProjectQBackend()
    c = Circuit(4)
    c.X(0)
    c.CX(0, 1)
    c.CX(1, 0)
    CliffordSimp(True).apply(c)
    assert c.n_gates_of_type(OpType.CX) == 1
    b.compile_circuit(c)
    s_ilo = b.get_state(c, basis=BasisOrder.ilo)
    s_dlo = b.get_state(c, basis=BasisOrder.dlo)
    correct_ilo = np.zeros((16, ))
    correct_ilo[4] = 1.0
    assert np.allclose(s_ilo, correct_ilo)
    correct_dlo = np.zeros((16, ))
    correct_dlo[2] = 1.0
    assert np.allclose(s_dlo, correct_dlo)
def test_swaps_basisorder() -> None:
    # Check that implicit swaps can be corrected irrespective of BasisOrder
    b = AerStateBackend()
    c = Circuit(4)
    c.X(0)
    c.CX(0, 1)
    c.CX(1, 0)
    c.CX(1, 3)
    c.CX(3, 1)
    c.X(2)
    cu = CompilationUnit(c)
    CliffordSimp(True).apply(cu)
    c1 = cu.circuit
    assert c1.n_gates_of_type(OpType.CX) == 2

    b.compile_circuit(c)
    b.compile_circuit(c1)

    handles = b.process_circuits([c, c1])
    s_ilo = b.get_state(c1, basis=BasisOrder.ilo)
    correct_ilo = b.get_state(c, basis=BasisOrder.ilo)

    assert np.allclose(s_ilo, correct_ilo)
    s_dlo = b.get_state(c1, basis=BasisOrder.dlo)
    correct_dlo = b.get_state(c, basis=BasisOrder.dlo)
    assert np.allclose(s_dlo, correct_dlo)

    qbs = c.qubits
    for result in b.get_results(handles):
        assert (result.get_state([qbs[1], qbs[2], qbs[3],
                                  qbs[0]]).real.tolist().index(1.0) == 6)
        assert (result.get_state([qbs[2], qbs[1], qbs[0],
                                  qbs[3]]).real.tolist().index(1.0) == 9)
        assert (result.get_state([qbs[2], qbs[3], qbs[0],
                                  qbs[1]]).real.tolist().index(1.0) == 12)

    bu = AerUnitaryBackend()
    u_ilo = bu.get_unitary(c1, basis=BasisOrder.ilo)
    correct_ilo = bu.get_unitary(c, basis=BasisOrder.ilo)
    assert np.allclose(u_ilo, correct_ilo)
    u_dlo = bu.get_unitary(c1, basis=BasisOrder.dlo)
    correct_dlo = bu.get_unitary(c, basis=BasisOrder.dlo)
    assert np.allclose(u_dlo, correct_dlo)
Esempio n. 7
0
 def default_compilation_pass(self,
                              optimisation_level: int = 1) -> BasePass:
     assert optimisation_level in range(3)
     passlist = [DecomposeBoxes()]
     if optimisation_level == 0:
         passlist.append(self._rebase_pass)
     elif optimisation_level == 1:
         passlist.append(SynthesiseIBM())
     elif optimisation_level == 2:
         passlist.append(FullPeepholeOptimise())
     passlist.append(
         CXMappingPass(
             self._device,
             NoiseAwarePlacement(self._device),
             directed_cx=False,
             delay_measures=(not self._mid_measure),
         ))
     if optimisation_level == 1:
         passlist.append(SynthesiseIBM())
     if optimisation_level == 2:
         passlist.extend([CliffordSimp(False), SynthesiseIBM()])
     if not self._legacy_gateset:
         passlist.extend([self._rebase_pass, RemoveRedundancies()])
     return SequencePass(passlist)
Esempio n. 8
0
# Now that we have a circuit, `pytket` can take this and start operating on it directly. For example, we can apply some basic compilation passes to simplify it.

from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit

tk_circ = qiskit_to_tk(state_prep_circ)

from pytket.passes import (
    SequencePass,
    CliffordSimp,
    DecomposeBoxes,
    KAKDecomposition,
    SynthesiseIBM,
)

DecomposeBoxes().apply(tk_circ)
optimise = SequencePass([KAKDecomposition(), CliffordSimp(False), SynthesiseIBM()])
optimise.apply(tk_circ)

# Display the optimised circuit:

print(tk_to_qiskit(tk_circ))

# The Backends in `pytket` abstract away the differences between different devices and simulators as much as possible, allowing painless switching between them. The `pytket_pyquil` package provides two Backends: `ForestBackend` encapsulates both running on physical devices via Rigetti QCS and simulating those devices on the QVM, and `ForestStateBackend` acts as a wrapper to the pyQuil Wavefunction Simulator.
#
# Both of these still have a few restrictions on the circuits that can be run. Each only supports a subset of the gate types available in `pytket`, and a real device or associated simulation will have restricted qubit connectivity. The Backend objects will contain a default compilation pass that will statisfy these constraints as much as possible, with minimal or no optimisation.
#
# The `ForestStateBackend` will allow us to view the full statevector (wavefunction) expected from a perfect execution of the circuit.

from pytket.extensions.pyquil import ForestStateBackend

state_backend = ForestStateBackend()
Esempio n. 9
0
tk_circ = qiskit_to_tk(q_circ)

backend = FakeMelbourne()
coupling_list = backend.configuration().coupling_map
coupling_map = CouplingMap(coupling_list)

characterisation = process_characterisation(backend)
directed_arc = Device(
    characterisation.get("NodeErrors", {}),
    characterisation.get("EdgeErrors", {}),
    characterisation.get("Architecture", Architecture([])),
)

comp_tk = tk_circ.copy()

DecomposeBoxes().apply(comp_tk)
FullPeepholeOptimise().apply(comp_tk)
CXMappingPass(directed_arc,
              NoiseAwarePlacement(directed_arc),
              directed_cx=True,
              delay_measures=True).apply(comp_tk)
DecomposeSwapsToCXs(directed_arc).apply(comp_tk)
cost = lambda c: c.n_gates_of_type(OpType.CX)
comp = RepeatWithMetricPass(
    SequencePass(
        [CommuteThroughMultis(),
         RemoveRedundancies(),
         CliffordSimp(False)]), cost)
comp.apply(comp_tk)
SynthesiseIBM().apply(comp_tk)
    c_tket = pyzx_to_tk(c)
    _pass.apply(c_tket)
    RebasePyZX().apply(c_tket)
    c_opt = tk_to_pyzx(c_tket)

    opt_tcount = c_opt.tcount()
    opt_2qubitcount = c_opt.twoqubitcount()

    # Quick and dirty. In theory, should depend on score function
    if orig_tcount == opt_tcount and orig_2qubitcount == opt_2qubitcount:
        return False, (c, g)
    return True, (c_opt, c_opt.to_graph())

remove_redundancies = partial(tket_pass_base, _pass=RemoveRedundancies())
pauli_simp = partial(tket_pass_base, _pass=PauliSimp())
clifford_simp = partial(tket_pass_base, _pass=CliffordSimp())
# FIXME: Have to put into appropriate gate set first
kak_decomposition = partial(tket_pass_base, _pass=KAKDecomposition())

### ADVANCED ACTIONS

def basic_optimization(c, g):
    orig_tcount = c.tcount()
    orig_2qubitcount = c.twoqubitcount()

    c_opt = zx.basic_optimization(c)

    opt_tcount = c_opt.tcount()
    opt_2qubitcount = c_opt.twoqubitcount()
    if orig_tcount == opt_tcount and orig_2qubitcount == opt_2qubitcount:
        return False, (c, g)
from pytket.extensions.qiskit import qiskit_to_tk, tk_to_qiskit

tk_circ = qiskit_to_tk(state_prep_circ)

from pytket.passes import (
    SequencePass,
    CliffordSimp,
    DecomposeBoxes,
    KAKDecomposition,
    SynthesiseIBM,
)

DecomposeBoxes().apply(tk_circ)
optimise = SequencePass(
    [KAKDecomposition(),
     CliffordSimp(False),
     SynthesiseIBM()])
optimise.apply(tk_circ)

# Display the optimised circuit:

print(tk_to_qiskit(tk_circ))

# The Backends in `pytket` abstract away the differences between different devices and simulators as much as possible, allowing painless switching between them. The `pytket_pyquil` package provides two Backends: `ForestBackend` encapsulates both running on physical devices via Rigetti QCS and simulating those devices on the QVM, and `ForestStateBackend` acts as a wrapper to the pyQuil Wavefunction Simulator.
#
# Both of these still have a few restrictions on the circuits that can be run. Each only supports a subset of the gate types available in `pytket`, and a real device or associated simulation will have restricted qubit connectivity. The Backend objects will contain a default compilation pass that will statisfy these constraints as much as possible, with minimal or no optimisation.
#
# The `ForestStateBackend` will allow us to view the full statevector (wavefunction) expected from a perfect execution of the circuit.

from pytket.extensions.pyquil import ForestStateBackend