def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) if optimisation_level == 0: return SequencePass([ FlattenRegisters(), RenameQubitsPass(self._qm), DecomposeBoxes(), _aqt_rebase(), ]) elif optimisation_level == 1: return SequencePass([ DecomposeBoxes(), SynthesiseIBM(), FlattenRegisters(), RenameQubitsPass(self._qm), _aqt_rebase(), RemoveRedundancies(), EulerAngleReduction(OpType.Ry, OpType.Rx), ]) else: return SequencePass([ DecomposeBoxes(), FullPeepholeOptimise(), FlattenRegisters(), RenameQubitsPass(self._qm), _aqt_rebase(), RemoveRedundancies(), EulerAngleReduction(OpType.Ry, OpType.Rx), ])
def default_compilation_pass(self, optimisation_level: int = 1) -> BasePass: assert optimisation_level in range(3) if optimisation_level == 0: return SequencePass( [DecomposeClassicalExp(), DecomposeBoxes(), RebaseHQS()]) elif optimisation_level == 1: return SequencePass([ DecomposeClassicalExp(), DecomposeBoxes(), SynthesiseIBM(), RebaseHQS(), RemoveRedundancies(), SquashHQS(), ]) else: return SequencePass([ DecomposeClassicalExp(), DecomposeBoxes(), FullPeepholeOptimise(), RebaseHQS(), RemoveRedundancies(), SquashHQS(), ])
def _optimize(self, c): c_tket = pyzx_to_tk(c) cost = lambda c : c.n_gates_of_type(OpType.CX) comp = RepeatWithMetricPass(SequencePass([CommuteThroughMultis(), RemoveRedundancies()]), cost) comp.apply(c_tket) c_opt = tk_to_pyzx(c_tket) return c_opt
def run(d,fname): f = open(fname, "w") f.write("name,1q,2q,total,time\n") for fname in os.listdir(d): print("Processing %s..." % fname) circ = circuit_from_qasm(os.path.join(d, fname)) # Other useful optimizations include OptimisePhaseGadgets and PauliSimp. # We exclude them here because they make performance worse on our benchmarks. seq_pass=SequencePass([FullPeepholeOptimise(), RemoveRedundancies()]) start = time.perf_counter() seq_pass.apply(circ) stop = time.perf_counter() total_count = circ.n_gates two_count = circ.n_gates_of_type(OpType.CX) one_count = total_count - two_count # note: could potentially convert to other gate sets here with RebaseCustom print("\t Total %d, 1q %d, CNOT %d\n" % (total_count, one_count, two_count)) f.write("%s,%d,%d,%d,%f\n" % (fname, one_count, two_count, total_count, stop - start)) f.close()
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)
def test_symbolic(qvm) -> None: pi2 = Symbol("pi2") pi3 = Symbol("pi3") tkc = Circuit(2).Rx(pi2, 1).Rx(-pi3, 1).CX(1, 0) RemoveRedundancies().apply(tkc) prog = tk_to_pyquil(tkc) tkc2 = pyquil_to_tk(prog) assert tkc2.free_symbols() == {pi2, pi3} tkc2.symbol_substitution({pi2: pi / 2, pi3: -pi / 3}) backend = ForestStateBackend() state1 = backend.get_state(tkc2) state0 = np.array( [-0.56468689 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.82530523j]) assert np.allclose(state0, state1)
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)
def _optimize(self, c): c_tket = pyzx_to_tk(c) RemoveRedundancies().apply(c_tket) c_opt = tk_to_pyzx(c_tket) return c_opt
def _tk1_to_phasedxrz(a: float, b: float, c: float) -> Circuit: circ = Circuit(1) circ.Rz(a + c, 0) circ.add_gate(OpType.PhasedX, [b, a], [0]) RemoveRedundancies().apply(circ) return circ
OpType.Vdg, OpType.S, OpType.Sdg, OpType.H, }, _tk1_to_phasedxrz_clifford, ) regular_pass_0 = SequencePass([FlattenRegisters(), DecomposeBoxes(), RebaseCirq()]) regular_pass_1 = SequencePass( [ FlattenRegisters(), DecomposeBoxes(), SynthesiseIBM(), RebaseCirq(), RemoveRedundancies(), _cirq_squash, ] ) regular_pass_2 = SequencePass( [ FlattenRegisters(), DecomposeBoxes(), FullPeepholeOptimise(), RebaseCirq(), RemoveRedundancies(), _cirq_squash, ] ) clifford_pass_0 = SequencePass(
seqpass = SequencePass([DecomposeMultiQubitsIBM(), OptimisePhaseGadgets()]) # This pass will apply the two transforms in succession: cu = CompilationUnit(circ) seqpass.apply(cu) circ1 = cu.circuit print(circ1.get_commands()) # The `apply()` method for an elementary pass returns a boolean indicating whether or not the pass had any effect on the circuit. For a `SequencePass`, the return value indicates whether _any_ of the constituent passes had some effect. # # A `RepeatPass` repeatedly calls `apply()` on a pass until it returns `False`, indicating that there was no effect: from pytket.passes import CommuteThroughMultis, RemoveRedundancies, RepeatPass seqpass = SequencePass([CommuteThroughMultis(), RemoveRedundancies()]) reppass = RepeatPass(seqpass) # This pass will repeatedly apply `CommuteThroughMultis` (which commutes single-qubit operations through multi-qubit operations where possible towards the start of the circuit) and `RemoveRedundancies` (which cancels inverse pairs, merges coaxial rotations and removes redundant gates before measurement) until neither pass has any effect on the circuit. # # Let's use Qiskit's visualizer to see the effect on a circuit: from pytket.extensions.qiskit import tk_to_qiskit circ = Circuit(3) circ.X(0).Y(1).CX(0, 1).Z(0).Rx(1.3, 1).CX(0, 1).Rz(0.4, 0).Ry(0.53, 0).H(1).H(2).Rx(1.5,
orig_2qubitcount = c.twoqubitcount() 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()