def _basis_gates_to_decomposer_2q(basis_gates, pulse_optimize=None): kak_gate = _choose_kak_gate(basis_gates) euler_basis = _choose_euler_basis(basis_gates) if isinstance(kak_gate, RZXGate): backup_optimizer = TwoQubitBasisDecomposer( CXGate(), euler_basis=euler_basis, pulse_optimize=pulse_optimize) return XXDecomposer(euler_basis=euler_basis, backup_optimizer=backup_optimizer) elif kak_gate is not None: return TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis, pulse_optimize=pulse_optimize) else: return None
def test_exact_supercontrolled_decompose_random(self, seeds): """Exact decomposition for random supercontrolled basis and random target""" k1 = np.kron(random_unitary(2, seed=seeds[0]).data, random_unitary(2, seed=seeds[1]).data) k2 = np.kron(random_unitary(2, seed=seeds[2]).data, random_unitary(2, seed=seeds[3]).data) basis_unitary = k1 @ Ud(np.pi / 4, 0, 0) @ k2 decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4, seed=seeds[4]).data, decomposer)
def test_euler_basis_selection(self): """Verify decomposition uses euler_basis for 1q gates.""" euler_bases = [ ('U3', ['u3']), ('U1X', ['u1', 'rx']), ('RR', ['r']), ('ZYZ', ['rz', 'ry']), ('ZXZ', ['rz', 'rx']), ('XYX', ['rx', 'ry']), ] kak_gates = [ (CXGate(), 'cx'), (CZGate(), 'cz'), (iSwapGate(), 'iswap'), (RXXGate(np.pi / 2), 'rxx'), ] for basis in product(euler_bases, kak_gates): (euler_basis, oneq_gates), (kak_gate, kak_gate_name) = basis with self.subTest(euler_basis=euler_basis, kak_gate=kak_gate): decomposer = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis) unitary = random_unitary(4) self.check_exact_decomposition(unitary.data, decomposer) decomposition_basis = set(decomposer(unitary).count_ops()) requested_basis = set(oneq_gates + [kak_gate_name]) self.assertTrue(decomposition_basis.issubset(requested_basis))
def evolve_in_real_time(logfile, qc, t, c): # definizione di U3 --- https://qiskit-staging.mybluemix.net/documentation/terra/summary_of_quantum_operations.html H, U = get_matrices(t, c) two_qubit_cnot_decompose = TwoQubitBasisDecomposer(CnotGate()) C = two_qubit_cnot_decompose.__call__(U) i, j = 0, 1 parameter_string = [] for g in C: instruction, q1, q2 = g if (instruction.name == 'u3'): t1, t2, t3 = instruction.params for x in [t1, t2, t3]: parameter_string.append(round(x, 4)) if (q1[0].index == 0): idx = i else: idx = j qc.u3(t1, t2, t3, idx) if (instruction.name == 'cx'): if (q1[0].index == 0): idx_ctrl = i idx_targ = j else: idx_ctrl = j idx_targ = i qc.cx(idx_ctrl, idx_targ) logfile.write("time = %f \n" % (t)) #logfile.write("circuit: \n"+str(qc.draw())+"\n") ##logfile.write(qc.draw()) return qc
def test_exact_supercontrolled_decompose_random(self, seed): """Exact decomposition for random supercontrolled basis and random target (seed={seed})""" # pylint: disable=invalid-name k1 = np.kron(random_unitary(2, seed=seed).data, random_unitary(2, seed=seed + 1).data) k2 = np.kron(random_unitary(2, seed=seed + 2).data, random_unitary(2, seed=seed + 3).data) basis_unitary = k1 @ Ud(np.pi / 4, 0, 0) @ k2 decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4, seed=seed + 4).data, decomposer)
def test_exact_supercontrolled_decompose_random(self, nsamples=10): """Verify exact decomposition for random supercontrolled basis and random target""" for _ in range(nsamples): k1 = np.kron(random_unitary(2).data, random_unitary(2).data) k2 = np.kron(random_unitary(2).data, random_unitary(2).data) basis_unitary = k1 @ Ud(np.pi / 4, 0, 0) @ k2 decomposer = TwoQubitBasisDecomposer(UnitaryGate(basis_unitary)) self.check_exact_decomposition(random_unitary(4).data, decomposer)
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the UnitarySynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with UnitaryGates synthesized to target basis. Raises: TranspilerError: 1. pulse_optimize is True but pulse optimal decomposition is not known for requested basis. 2. pulse_optimize is True and natural_direction is True but a preferred gate direction can't be determined from the coupling map or the relative gate lengths. """ euler_basis = _choose_euler_basis(self._basis_gates) kak_gate = _choose_kak_gate(self._basis_gates) decomposer1q, decomposer2q = None, None if euler_basis is not None: decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer( euler_basis) if kak_gate is not None: decomposer2q = TwoQubitBasisDecomposer( kak_gate, euler_basis=euler_basis, pulse_optimize=self._pulse_optimize) for node in dag.named_nodes(*self._synth_gates): if self._basis_gates and node.name in self._basis_gates: continue synth_dag = None wires = None if len(node.qargs) == 1: if decomposer1q is None: continue synth_dag = circuit_to_dag( decomposer1q._decompose(node.op.to_matrix())) elif len(node.qargs) == 2: if decomposer2q is None: continue synth_dag, wires = self._synth_natural_direction( node, dag, decomposer2q) else: synth_dag = circuit_to_dag( isometry.Isometry(node.op.to_matrix(), 0, 0).definition) dag.substitute_node_with_dag(node, synth_dag, wires=wires) return dag
def run(self, unitary, **options): # Approximation degree is set directly as an attribute on the # instance by the UnitarySynthesis pass here as it's not part of # plugin interface. However if for some reason it's not set assume # it's 1. approximation_degree = getattr(self, "_approximation_degree", 1) basis_gates = options["basis_gates"] coupling_map = options["coupling_map"][0] natural_direction = options["natural_direction"] pulse_optimize = options["pulse_optimize"] gate_lengths = options["gate_lengths"] gate_errors = options["gate_errors"] qubits = options["coupling_map"][1] euler_basis = _choose_euler_basis(basis_gates) kak_gate = _choose_kak_gate(basis_gates) decomposer1q, decomposer2q = None, None if euler_basis is not None: decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer( euler_basis) if kak_gate is not None: decomposer2q = TwoQubitBasisDecomposer( kak_gate, euler_basis=euler_basis, pulse_optimize=pulse_optimize) synth_dag = None wires = None if unitary.shape == (2, 2): if decomposer1q is None: return None synth_dag = circuit_to_dag(decomposer1q._decompose(unitary)) elif unitary.shape == (4, 4): if decomposer2q is None: return None synth_dag, wires = self._synth_natural_direction( unitary, coupling_map, qubits, decomposer2q, gate_lengths, gate_errors, natural_direction, approximation_degree, pulse_optimize, ) else: synth_dag = circuit_to_dag( isometry.Isometry(unitary, 0, 0).definition) return synth_dag, wires
def test_euler_basis_selection(self, euler_bases, kak_gates, seed): """Verify decomposition uses euler_basis for 1q gates.""" (euler_basis, oneq_gates) = euler_bases (kak_gate, kak_gate_name) = kak_gates with self.subTest(euler_basis=euler_basis, kak_gate=kak_gate): decomposer = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis) unitary = random_unitary(4, seed=seed) self.check_exact_decomposition(unitary.data, decomposer) decomposition_basis = set(decomposer(unitary).count_ops()) requested_basis = set(oneq_gates + [kak_gate_name]) self.assertTrue( decomposition_basis.issubset(requested_basis))
def replace_definition_cz(self, dag: DAGCircuit) -> None: """by default custom two qubit gates are defined by CX and 1Qubit Gates this method replaces the definition by a definition consisting of CZ and 1Qubit Gates """ cz_matrix = np.array( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]], dtype=complex) cz_gate = UnitaryGate(cz_matrix) two_qubit_cz_decompose = TwoQubitBasisDecomposer(cz_gate) for node in dag.op_nodes(): gate = node.op if isinstance(gate, UnitaryGate) and gate.num_qubits == 2: gate.definition = two_qubit_cz_decompose(gate.to_matrix()).data
def evolve_dimer(self,qc,i,j,dt): # c=self.B H,U = get_matrices(dt,c) two_qubit_cnot_decompose = TwoQubitBasisDecomposer(CnotGate()) C = two_qubit_cnot_decompose.__call__(U) parameter_string = [] for g in C: instruction,q1,q2 = g if(instruction.name=='u3'): t1,t2,t3 = instruction.params for x in [t1,t2,t3]: parameter_string.append(round(x,4)) if(q1[0].index==0): idx = i else: idx = j qc.u3(t1,t2,t3,idx) if(instruction.name=='cx'): if(q1[0].index==0): idx_ctrl = i; idx_targ = j else: idx_ctrl = j; idx_targ = i qc.cx(idx_ctrl,idx_targ) return qc
def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the UnitarySynthesis pass on `dag`. Args: dag: input dag. Returns: Output dag with UnitaryGates synthesized to target basis. """ euler_basis = _choose_euler_basis(self._basis_gates) kak_gate = _choose_kak_gate(self._basis_gates) decomposer1q, decomposer2q = None, None if euler_basis is not None: decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer( euler_basis) if kak_gate is not None: decomposer2q = TwoQubitBasisDecomposer(kak_gate, euler_basis=euler_basis) for node in dag.named_nodes("unitary"): synth_dag = None if len(node.qargs) == 1: if decomposer1q is None: continue synth_dag = circuit_to_dag( decomposer1q._decompose(node.op.to_matrix())) elif len(node.qargs) == 2: if decomposer2q is None: continue synth_dag = circuit_to_dag( decomposer2q(node.op.to_matrix(), basis_fidelity=self._approximation_degree)) else: synth_dag = circuit_to_dag( isometry.Isometry(node.op.to_matrix(), 0, 0).definition) dag.substitute_node_with_dag(node, synth_dag) return dag
def test_exact_nonsupercontrolled_decompose(self): """Check that the nonsupercontrolled basis throws a warning""" with self.assertWarns(UserWarning, msg="Supposed to warn when basis non-supercontrolled"): TwoQubitBasisDecomposer(UnitaryGate(Ud(np.pi / 4, 0.2, 0.1)))
def _find_decomposer_2q_from_target(self, target, qubits, pulse_optimize): qubits_tuple = tuple(qubits) reverse_tuple = (qubits[1], qubits[0]) if qubits_tuple in self._decomposer_cache: return self._decomposer_cache[qubits_tuple] matching = {} reverse = {} kak_gates = _find_matching_kak_gates(target) euler_basis_gates = _find_matching_euler_bases(target) decomposers_2q = [] # find all decomposers for kak_gate, euler_basis in product(kak_gates, euler_basis_gates): gate_name = None if isinstance(kak_gate, tuple): gate_name = kak_gate[1] kak_gate = kak_gate[0] if isinstance(kak_gate, RZXGate): backup_optimizer = TwoQubitBasisDecomposer( CXGate(), euler_basis=euler_basis, pulse_optimize=pulse_optimize) decomposer = XXDecomposer(euler_basis=euler_basis, backup_optimizer=backup_optimizer) if gate_name is not None: decomposer.gate_name = gate_name decomposers_2q.append(decomposer) elif kak_gate is not None: decomposer = TwoQubitBasisDecomposer( kak_gate, euler_basis=euler_basis, pulse_optimize=pulse_optimize) if gate_name is not None: decomposer.gate_name = gate_name decomposers_2q.append(decomposer) # Find lowest error matching or reverse decomposer and use that for index, decomposer in enumerate(decomposers_2q): gate_name = getattr(decomposer, "gate_name", decomposer.gate.name) props_dict = target[gate_name] if target.instruction_supported(gate_name, qubits_tuple): if props_dict is None or None in props_dict: error = 0.0 else: error = getattr(props_dict[qubits_tuple], "error", 0.0) if error is None: error = 0.0 matching[index] = error # Skip reverse check if we already have matching elif not matching and target.instruction_supported( gate_name, reverse_tuple): if props_dict is None or None in props_dict: error = 0.0 else: error = getattr(props_dict[reverse_tuple], "error", 0.0) if error is None: error = 0.0 reverse[index] = error preferred_direction = None if matching: preferred_direction = [0, 1] min_error_index = min(matching, key=matching.get) decomposer2q = decomposers_2q[min_error_index] elif reverse: preferred_direction = [1, 0] min_error_index = min(reverse, key=reverse.get) decomposer2q = decomposers_2q[min_error_index] # If no matching or reverse direction is found just pick one, if natural direction is # enforced it will fail later else: decomposer2q = decomposers_2q[0] self._decomposer_cache[qubits_tuple] = (decomposer2q, preferred_direction) return (decomposer2q, preferred_direction)