Ejemplo n.º 1
0
 def _circuit_zxz(theta, phi, lam, phase, simplify=True, atol=DEFAULT_ATOL):
     gphase = phase - (phi + lam) / 2
     qr = QuantumRegister(1, "qr")
     circuit = QuantumCircuit(qr)
     if not simplify:
         atol = -1.0
     if abs(theta) < atol:
         tot = _mod_2pi(phi + lam)
         if abs(tot) > atol:
             circuit._append(RZGate(tot), [qr[0]], [])
             gphase += tot / 2
         circuit.global_phase = gphase
         return circuit
     if abs(theta - np.pi) < atol:
         gphase += phi
         lam, phi = lam - phi, 0
     lam = _mod_2pi(lam, atol)
     if abs(lam) > atol:
         gphase += lam / 2
         circuit._append(RZGate(lam), [qr[0]], [])
     circuit._append(RXGate(theta), [qr[0]], [])
     phi = _mod_2pi(phi, atol)
     if abs(phi) > atol:
         gphase += phi / 2
         circuit._append(RZGate(phi), [qr[0]], [])
     circuit.global_phase = gphase
     return circuit
Ejemplo n.º 2
0
 def specialize(self):
     self.a = self.b = (self.a + self.b) / 2
     k2ltheta, k2lphi, k2llambda, k2lphase = _oneq_zyz.angles_and_phase(self.K2l)
     self.global_phase += k2lphase
     self.K1r = self.K1r @ np.asarray(RZGate(k2lphi))
     self.K1l = self.K1l @ np.asarray(RZGate(k2lphi))
     self.K2l = np.asarray(RYGate(k2ltheta)) @ np.asarray(RZGate(k2llambda))
     self.K2r = np.asarray(RZGate(-k2lphi)) @ self.K2r
Ejemplo n.º 3
0
 def specialize(self):
     self.a = self.b = np.pi / 4
     k2ltheta, k2lphi, k2llambda, k2lphase = _oneq_zyz.angles_and_phase(self.K2l)
     k2rtheta, k2rphi, k2rlambda, k2rphase = _oneq_zyz.angles_and_phase(self.K2r)
     self.global_phase += k2lphase + k2rphase
     self.K1r = self.K1r @ np.asarray(RZGate(k2lphi))
     self.K1l = self.K1l @ np.asarray(RZGate(k2rphi))
     self.K2l = np.asarray(RYGate(k2ltheta)) @ np.asarray(RZGate(k2llambda))
     self.K2r = np.asarray(RYGate(k2rtheta)) @ np.asarray(RZGate(k2rlambda))
Ejemplo n.º 4
0
 def _circuit_zxz(theta, phi, lam, phase, simplify=True, atol=DEFAULT_ATOL):
     circuit = QuantumCircuit(1, global_phase=phase)
     if simplify and np.isclose(theta, 0.0, atol=atol):
         circuit.append(RZGate(phi + lam), [0])
         return circuit
     if not simplify or not np.isclose(lam, 0.0, atol=atol):
         circuit.append(RZGate(lam), [0])
     if not simplify or not np.isclose(theta, 0.0, atol=atol):
         circuit.append(RXGate(theta), [0])
     if not simplify or not np.isclose(phi, 0.0, atol=atol):
         circuit.append(RZGate(phi), [0])
     return circuit
Ejemplo n.º 5
0
 def _circuit_zxz(theta, phi, lam, simplify=False, atol=DEFAULT_ATOL):
     if simplify and np.isclose(theta, 0.0, atol=atol):
         circuit = QuantumCircuit(1)
         circuit.append(RZGate(phi + lam), [0])
         return circuit
     circuit = QuantumCircuit(1)
     if not simplify or not np.isclose(lam, 0.0, atol=atol):
         circuit.append(RZGate(lam), [0])
     if not simplify or not np.isclose(theta, 0.0, atol=atol):
         circuit.append(RXGate(theta), [0])
     if not simplify or not np.isclose(phi, 0.0, atol=atol):
         circuit.append(RZGate(phi), [0])
     return circuit
 def _circuit_zxz(theta, phi, lam, phase, simplify=True, atol=DEFAULT_ATOL):
     qr = QuantumRegister(1, 'qr')
     circuit = QuantumCircuit(qr, global_phase=phase)
     if simplify and math.isclose(theta, 0.0, abs_tol=atol):
         circuit._append(RZGate(phi + lam), [qr[0]], [])
         return circuit
     if not simplify or not math.isclose(lam, 0.0, abs_tol=atol):
         circuit._append(RZGate(lam), [qr[0]], [])
     if not simplify or not math.isclose(theta, 0.0, abs_tol=atol):
         circuit._append(RXGate(theta), [qr[0]], [])
     if not simplify or not math.isclose(phi, 0.0, abs_tol=atol):
         circuit._append(RZGate(phi), [qr[0]], [])
     return circuit
    def run(self, dag):

        runs = dag.collect_runs([self.gate])
        runs = _split_runs_on_parameters(runs)

        for group in runs:
            angle = sum([float(node.op.params[0]) for node in group])
            angle = sign(angle) * (abs(angle) % (2 * pi))

            # for angles multiple of 2*pi (numerically close),
            #  the gates act as an identity (up to a global phase).
            if abs(angle) < self.eps:
                dag.remove_op_node(group[0])
            else:
                if self.gate == 'rx':
                    new_op = RXGate(angle)
                elif self.gate == 'rz':
                    new_op = RZGate(angle)

                dag.substitute_node(group[0], new_op,
                                    inplace=True)
            for node in group[1:]:
                dag.remove_op_node(node)

        return dag
Ejemplo n.º 8
0
	def narrowband_noise(time):
		"""
		Apply a single-frequency noise source
		"""
		f = 13.1
		qr = QuantumRegister(1)
		qc = QuantumCircuit(qr, name='narrowband_noise')
		qc.append(RZGate(2 * np.pi * f * time), [qr[0]])
		return qc
Ejemplo n.º 9
0
def _dag(angles, qubits, back=True):
    """ Return a new DAGCircuit with a CZ gate and RZ gates applied (front or back). """
    qarg = QuantumRegister(2)

    dag = DAGCircuit()
    dag.add_qreg(qarg)

    cz_node = dag.apply_operation_back(CZGate(),
                                    [qarg[0], qarg[1]])

    for angle, qubit in zip(angles, qubits):
        if back:
            dag.apply_operation_back(RZGate(angle),
                                    [qarg[qubit]], [])
        else:
            dag.apply_operation_front(RZGate(angle),
                                    [qarg[qubit]], [])

    return dag
Ejemplo n.º 10
0
 def _circuit_zsx(theta,
                  phi,
                  lam,
                  phase,
                  simplify=True,
                  atol=DEFAULT_ATOL):
     # Shift theta and phi so decomposition is
     # RZ(phi+pi).SX.RZ(theta+pi).SX.RZ(lam)
     theta = _mod2pi(theta + np.pi)
     phi = _mod2pi(phi + np.pi)
     circuit = QuantumCircuit(1, global_phase=phase)
     # Check for decomposition into minimimal number required SX gates
     if simplify and np.isclose(abs(theta), np.pi, atol=atol):
         if not np.isclose(_mod2pi(abs(lam + phi + theta)),
                           [0., 2*np.pi], atol=atol).any():
             circuit.append(RZGate(_mod2pi(lam + phi + theta)), [0])
     elif simplify and np.isclose(abs(theta),
                                  [np.pi/2, 3*np.pi/2], atol=atol).any():
         if not np.isclose(_mod2pi(abs(lam + theta)),
                           [0., 2*np.pi], atol=atol).any():
             circuit.append(RZGate(_mod2pi(lam + theta)), [0])
         circuit.append(SXGate(), [0])
         if not np.isclose(_mod2pi(abs(phi + theta)),
                           [0., 2*np.pi], atol=atol).any():
             circuit.append(RZGate(_mod2pi(phi + theta)), [0])
     else:
         if not np.isclose(abs(lam), [0., 2*np.pi], atol=atol).any():
             circuit.append(RZGate(lam), [0])
         circuit.append(SXGate(), [0])
         if not np.isclose(abs(theta), [0., 2*np.pi], atol=atol).any():
             circuit.append(RZGate(theta), [0])
         circuit.append(SXGate(), [0])
         if not np.isclose(abs(phi), [0., 2*np.pi], atol=atol).any():
             circuit.append(RZGate(phi), [0])
     return circuit
Ejemplo n.º 11
0
 def _circuit_zsx(theta,
                  phi,
                  lam,
                  phase,
                  simplify=True,
                  atol=DEFAULT_ATOL):
     # Shift theta and phi so decomposition is
     # RZ(phi+pi).SX.RZ(theta+pi).SX.RZ(lam)
     theta = _mod2pi(theta + np.pi)
     phi = _mod2pi(phi + np.pi)
     qr = QuantumRegister(1, 'qr')
     circuit = QuantumCircuit(qr, global_phase=phase - np.pi / 2)
     # Check for decomposition into minimimal number required SX gates
     abs_theta = abs(theta)
     if simplify and math.isclose(abs_theta, np.pi, abs_tol=atol):
         lam_phi_theta = _mod2pi(lam + phi + theta)
         abs_lam_phi_theta = _mod2pi(abs(lam + phi + theta))
         if not (math.isclose(abs_lam_phi_theta, 0., abs_tol=atol) or
                 math.isclose(abs_lam_phi_theta, 2*np.pi, abs_tol=atol)):
             circuit._append(RZGate(lam_phi_theta), [qr[0]], [])
             circuit.global_phase += 0.5 * lam_phi_theta
         circuit.global_phase += np.pi / 2
     elif simplify and (math.isclose(abs_theta, np.pi/2, abs_tol=atol) or
                        math.isclose(abs_theta, 3*np.pi/2, abs_tol=atol)):
         lam_theta = _mod2pi(lam + theta)
         abs_lam_theta = _mod2pi(abs(lam + theta))
         if not (math.isclose(abs_lam_theta, 0, abs_tol=atol) or
                 math.isclose(abs_lam_theta, 2*np.pi, abs_tol=atol)):
             circuit._append(RZGate(lam_theta), [qr[0]], [])
             circuit.global_phase += 0.5 * lam_theta
         circuit._append(SXGate(), [qr[0]], [])
         phi_theta = _mod2pi(phi + theta)
         abs_phi_theta = _mod2pi(abs(phi_theta))
         if not (math.isclose(abs_phi_theta, 0, abs_tol=atol) or
                 math.isclose(abs_phi_theta, 2*np.pi, abs_tol=atol)):
             circuit._append(RZGate(phi_theta), [qr[0]], [])
             circuit.global_phase += 0.5 * phi_theta
         if (math.isclose(theta, -np.pi / 2, abs_tol=atol) or
                 math.isclose(theta, 3 * np.pi / 2, abs_tol=atol)):
             circuit.global_phase += np.pi / 2
     else:
         abs_lam = abs(lam)
         if not (math.isclose(abs_lam, 0., abs_tol=atol) or
                 math.isclose(abs_lam, 2*np.pi, abs_tol=atol)):
             circuit._append(RZGate(lam), [qr[0]], [])
             circuit.global_phase += 0.5 * lam
         circuit._append(SXGate(), [qr[0]], [])
         if not (math.isclose(abs_theta, 0., abs_tol=atol) or
                 math.isclose(abs_theta, 2*np.pi, abs_tol=atol)):
             circuit._append(RZGate(theta), [qr[0]], [])
             circuit.global_phase += 0.5 * theta
         circuit._append(SXGate(), [qr[0]], [])
         abs_phi = abs(phi)
         if not (math.isclose(abs_phi, 0., abs_tol=atol) or
                 math.isclose(abs_phi, 2*np.pi, abs_tol=atol)):
             circuit._append(RZGate(phi), [qr[0]], [])
             circuit.global_phase += 0.5 * phi
     return circuit
Ejemplo n.º 12
0
 def __init__(self):
     super().__init__(
         None,
         name="FakeSimpleV2",
         description="A fake simple BackendV2 example",
         online_date=datetime.datetime.utcnow(),
         backend_version="0.0.1",
     )
     self._lam = Parameter("lambda")
     self._target = Target(num_qubits=20)
     self._target.add_instruction(SXGate())
     self._target.add_instruction(XGate())
     self._target.add_instruction(RZGate(self._lam))
     self._target.add_instruction(CXGate())
     self._target.add_instruction(Measure())
     self._runner = QasmSimulatorPy()
Ejemplo n.º 13
0
    def _hessian_states(
        self,
        state_op: StateFn,
        meas_op: Optional[OperatorBase] = None,
        target_params: Optional[Union[Tuple[ParameterExpression,
                                            ParameterExpression],
                                      List[Tuple[ParameterExpression,
                                                 ParameterExpression]]]] = None
    ) -> OperatorBase:
        """Generate the operator states whose evaluation returns the Hessian (items).

        Args:
            state_op: The operator representing the quantum state for which we compute the Hessian.
            meas_op: The operator representing the observable for which we compute the gradient.
            target_params: The parameters we are computing the Hessian wrt: ω

        Returns:
            Operators which give the Hessian. If a parameter appears multiple times, one circuit is
            created per parameterized gates to compute the product rule.

        Raises:
            AquaError: If one of the circuits could not be constructed.
            TypeError: If ``operator`` is of unsupported type.
        """
        state_qc = deepcopy(state_op.primitive)
        if isinstance(target_params, list) and isinstance(
                target_params[0], tuple):
            tuples_list = deepcopy(target_params)
            target_params = []
            for tuples in tuples_list:
                if all([
                        param in state_qc._parameter_table.get_keys()
                        for param in tuples
                ]):
                    for param in tuples:
                        if param not in target_params:
                            target_params.append(param)
        elif isinstance(target_params, tuple):
            tuples_list = deepcopy([target_params])
            target_params = []
            for tuples in tuples_list:
                if all([
                        param in state_qc._parameter_table.get_keys()
                        for param in tuples
                ]):
                    for param in tuples:
                        if param not in target_params:
                            target_params.append(param)
        else:
            raise TypeError(
                'Please define in the parameters for which the Hessian is evaluated either '
                'as parameter tuple or a list of parameter tuples')

        qr_add0 = QuantumRegister(1, 'work_qubit0')
        work_q0 = qr_add0[0]
        qr_add1 = QuantumRegister(1, 'work_qubit1')
        work_q1 = qr_add1[0]
        # create a copy of the original circuit with an additional working qubit register
        circuit = state_qc.copy()
        circuit.add_register(qr_add0, qr_add1)
        # Get the circuits needed to compute the Hessian
        hessian_ops = None
        for param_a, param_b in tuples_list:

            if param_a not in state_qc._parameter_table.get_keys() or param_b \
                    not in state_qc._parameter_table.get_keys():
                hessian_op = ~Zero @ One
            else:
                param_gates_a = state_qc._parameter_table[param_a]
                param_gates_b = state_qc._parameter_table[param_b]
                for i, param_occurence_a in enumerate(param_gates_a):
                    coeffs_a, gates_a = self._gate_gradient_dict(
                        param_occurence_a[0])[param_occurence_a[1]]
                    # apply Hadamard on working qubit
                    self.insert_gate(circuit,
                                     param_occurence_a[0],
                                     HGate(),
                                     qubits=[work_q0])
                    self.insert_gate(circuit,
                                     param_occurence_a[0],
                                     HGate(),
                                     qubits=[work_q1])
                    for j, gate_to_insert_a in enumerate(gates_a):

                        coeff_a = coeffs_a[j]
                        hessian_circuit_temp = QuantumCircuit(*circuit.qregs)
                        hessian_circuit_temp.data = circuit.data
                        # Fix working qubit 0 phase
                        sign = np.sign(coeff_a)
                        is_complex = np.iscomplex(coeff_a)
                        if sign == -1:
                            if is_complex:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 SdgGate(),
                                                 qubits=[work_q0])
                            else:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 ZGate(),
                                                 qubits=[work_q0])
                        else:
                            if is_complex:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 SGate(),
                                                 qubits=[work_q0])

                        # Insert controlled, intercepting gate - controlled by |1>
                        if isinstance(param_occurence_a[0], UGate):
                            if param_occurence_a[1] == 0:
                                self.insert_gate(
                                    hessian_circuit_temp, param_occurence_a[0],
                                    RZGate(param_occurence_a[0].params[2]))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 RXGate(np.pi / 2))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 additional_qubits=([work_q0],
                                                                    []))
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 RXGate(-np.pi / 2))
                                self.insert_gate(
                                    hessian_circuit_temp, param_occurence_a[0],
                                    RZGate(-param_occurence_a[0].params[2]))

                            elif param_occurence_a[1] == 1:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 after=True,
                                                 additional_qubits=([work_q0],
                                                                    []))
                            else:
                                self.insert_gate(hessian_circuit_temp,
                                                 param_occurence_a[0],
                                                 gate_to_insert_a,
                                                 additional_qubits=([work_q0],
                                                                    []))
                        else:
                            self.insert_gate(hessian_circuit_temp,
                                             param_occurence_a[0],
                                             gate_to_insert_a,
                                             additional_qubits=([work_q0], []))

                        for m, param_occurence_b in enumerate(param_gates_b):
                            coeffs_b, gates_b = self._gate_gradient_dict(
                                param_occurence_b[0])[param_occurence_b[1]]
                            for n, gate_to_insert_b in enumerate(gates_b):
                                coeff_b = coeffs_b[n]
                                # create a copy of the original circuit with the same registers
                                hessian_circuit = QuantumCircuit(
                                    *hessian_circuit_temp.qregs)
                                hessian_circuit.data = hessian_circuit_temp.data

                                # Fix working qubit 1 phase
                                sign = np.sign(coeff_b)
                                is_complex = np.iscomplex(coeff_b)
                                if sign == -1:
                                    if is_complex:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         SdgGate(),
                                                         qubits=[work_q1])
                                    else:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         ZGate(),
                                                         qubits=[work_q1])
                                else:
                                    if is_complex:
                                        self.insert_gate(hessian_circuit,
                                                         param_occurence_b[0],
                                                         SGate(),
                                                         qubits=[work_q1])

                                # Insert controlled, intercepting gate - controlled by |1>

                                if isinstance(param_occurence_b[0], UGate):
                                    if param_occurence_b[1] == 0:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RZGate(param_occurence_b[0].
                                                   params[2]))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RXGate(np.pi / 2))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            additional_qubits=([work_q1], []))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RXGate(-np.pi / 2))
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            RZGate(-param_occurence_b[0].
                                                   params[2]))

                                    elif param_occurence_b[1] == 1:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            after=True,
                                            additional_qubits=([work_q1], []))
                                    else:
                                        self.insert_gate(
                                            hessian_circuit,
                                            param_occurence_b[0],
                                            gate_to_insert_b,
                                            additional_qubits=([work_q1], []))
                                else:
                                    self.insert_gate(
                                        hessian_circuit,
                                        param_occurence_b[0],
                                        gate_to_insert_b,
                                        additional_qubits=([work_q1], []))

                                hessian_circuit.h(work_q0)
                                hessian_circuit.cz(work_q1, work_q0)
                                hessian_circuit.h(work_q1)

                                term = state_op.coeff * np.sqrt(np.abs(coeff_a) * np.abs(coeff_b)) \
                                                      * CircuitStateFn(hessian_circuit)

                                # Chain Rule Parameter Expression
                                gate_param_a = param_occurence_a[0].params[
                                    param_occurence_a[1]]
                                gate_param_b = param_occurence_b[0].params[
                                    param_occurence_b[1]]

                                if meas_op:
                                    meas = deepcopy(meas_op)
                                    if isinstance(gate_param_a,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        meas *= expr_grad
                                    if isinstance(gate_param_b,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        meas *= expr_grad
                                    term = meas @ term
                                else:
                                    term = ListOp([term],
                                                  combo_fn=partial(
                                                      self._hess_combo_fn,
                                                      state_op=state_op))
                                    if isinstance(gate_param_a,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        term *= expr_grad
                                    if isinstance(gate_param_b,
                                                  ParameterExpression):
                                        expr_grad = DerivativeBase.parameter_expression_grad(
                                            gate_param_a, param_a)
                                        term *= expr_grad

                                if i == 0 and j == 0 and m == 0 and n == 0:
                                    hessian_op = term
                                else:
                                    # Product Rule
                                    hessian_op += term
            # Create a list of Hessian elements w.r.t. the given parameter tuples
            if len(tuples_list) == 1:
                return hessian_op
            else:
                if not hessian_ops:
                    hessian_ops = [hessian_op]
                else:
                    hessian_ops += [hessian_op]
        return ListOp(hessian_ops)
Ejemplo n.º 14
0
    def _gradient_states(
        self,
        state_op: StateFn,
        meas_op: Optional[OperatorBase] = None,
        target_params: Optional[Union[ParameterExpression, ParameterVector,
                                      List[ParameterExpression]]] = None
    ) -> ListOp:
        """Generate the gradient states.

        Args:
            state_op: The operator representing the quantum state for which we compute the gradient.
            meas_op: The operator representing the observable for which we compute the gradient.
            target_params: The parameters we are taking the gradient wrt: ω

        Returns:
            ListOp of StateFns as quantum circuits which are the states w.r.t. which we compute the
            gradient. If a parameter appears multiple times, one circuit is created per
            parameterized gates to compute the product rule.

        Raises:
            AquaError: If one of the circuits could not be constructed.
            TypeError: If the operators is of unsupported type.
        """
        state_qc = deepcopy(state_op.primitive)

        # Define the working qubit to realize the linear combination of unitaries
        qr_work = QuantumRegister(1, 'work_qubit_lin_comb_grad')
        work_q = qr_work[0]

        if not isinstance(target_params, (list, np.ndarray)):
            target_params = [target_params]

        if len(target_params) > 1:
            states = None

        additional_qubits: Tuple[List[Qubit], List[Qubit]] = ([work_q], [])

        for param in target_params:
            if param not in state_qc._parameter_table.get_keys():
                op = ~Zero @ One
            else:
                param_gates = state_qc._parameter_table[param]
                for m, param_occurence in enumerate(param_gates):
                    coeffs, gates = self._gate_gradient_dict(
                        param_occurence[0])[param_occurence[1]]

                    # construct the states
                    for k, gate_to_insert in enumerate(gates):
                        grad_state = QuantumCircuit(*state_qc.qregs, qr_work)
                        grad_state.compose(state_qc, inplace=True)

                        # apply Hadamard on work_q
                        self.insert_gate(grad_state,
                                         param_occurence[0],
                                         HGate(),
                                         qubits=[work_q])

                        # Fix work_q phase
                        coeff_i = coeffs[k]
                        sign = np.sign(coeff_i)
                        is_complex = np.iscomplex(coeff_i)
                        if sign == -1:
                            if is_complex:
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 SdgGate(),
                                                 qubits=[work_q])
                            else:
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 ZGate(),
                                                 qubits=[work_q])
                        else:
                            if is_complex:
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 SGate(),
                                                 qubits=[work_q])

                        # Insert controlled, intercepting gate - controlled by |0>
                        if isinstance(param_occurence[0], UGate):
                            if param_occurence[1] == 0:
                                self.insert_gate(
                                    grad_state, param_occurence[0],
                                    RZGate(param_occurence[0].params[2]))
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 RXGate(np.pi / 2))
                                self.insert_gate(
                                    grad_state,
                                    param_occurence[0],
                                    gate_to_insert,
                                    additional_qubits=additional_qubits)
                                self.insert_gate(grad_state,
                                                 param_occurence[0],
                                                 RXGate(-np.pi / 2))
                                self.insert_gate(
                                    grad_state, param_occurence[0],
                                    RZGate(-param_occurence[0].params[2]))

                            elif param_occurence[1] == 1:
                                self.insert_gate(
                                    grad_state,
                                    param_occurence[0],
                                    gate_to_insert,
                                    after=True,
                                    additional_qubits=additional_qubits)
                            else:
                                self.insert_gate(
                                    grad_state,
                                    param_occurence[0],
                                    gate_to_insert,
                                    additional_qubits=additional_qubits)
                        else:
                            self.insert_gate(
                                grad_state,
                                param_occurence[0],
                                gate_to_insert,
                                additional_qubits=additional_qubits)
                        grad_state.h(work_q)

                        state = np.sqrt(
                            np.abs(coeff_i)) * state_op.coeff * CircuitStateFn(
                                grad_state)
                        # Chain Rule parameter expressions
                        gate_param = param_occurence[0].params[
                            param_occurence[1]]
                        if meas_op:
                            if gate_param == param:
                                state = meas_op @ state
                            else:
                                if isinstance(gate_param, ParameterExpression):
                                    expr_grad = DerivativeBase.parameter_expression_grad(
                                        gate_param, param)
                                    state = (expr_grad * meas_op) @ state
                                else:
                                    state = ~Zero @ One
                        else:
                            if gate_param == param:
                                state = ListOp([state],
                                               combo_fn=partial(
                                                   self._grad_combo_fn,
                                                   state_op=state_op))
                            else:
                                if isinstance(gate_param, ParameterExpression):
                                    expr_grad = DerivativeBase.parameter_expression_grad(
                                        gate_param, param)
                                    state = expr_grad * ListOp(
                                        [state],
                                        combo_fn=partial(self._grad_combo_fn,
                                                         state_op=state_op))
                                else:
                                    state = ~Zero @ One

                        if m == 0 and k == 0:
                            op = state
                        else:
                            # Product Rule
                            op += state
                if len(target_params) > 1:
                    if not states:
                        states = [op]
                    else:
                        states += [op]
                else:
                    return op
        if len(target_params) > 1:
            return ListOp(states)
        else:
            return op
Ejemplo n.º 15
0
from qiskit.circuit import Parameter
from qiskit import QuantumCircuit, QuantumRegister

from basis_library import BasisLibrary

from qiskit.circuit.library.standard_gates import (HGate, ZGate, XGate, YGate,
                                                   RZGate, RXGate, RYGate,
                                                   CXGate, CZGate)

libr = RxzCzLibrary = BasisLibrary()

# H - Gate
q = QuantumRegister(1, 'q')
_def = QuantumCircuit(q, global_phase=pi / 2)

rules = [(RZGate(pi / 2), [q[0]], []), (RXGate(pi / 2), [q[0]], []),
         (RZGate(pi / 2), [q[0]], [])]

for inst, qargs, cargs in rules:
    _def.append(inst, qargs, cargs)

libr.add('h', _def)

# Z - Gate
q = QuantumRegister(1, 'q')
_def = QuantumCircuit(q, global_phase=pi / 2)

rules = [(RZGate(pi), [q[0]], [])]

for inst, qargs, cargs in rules:
    _def.append(inst, qargs, cargs)
Ejemplo n.º 16
0
    def apply_grad_gate(circuit, gate, param_index, grad_gate, grad_coeff, qr_superpos,
                        open_ctrl=False, trim_after_grad_gate=False):
        """Util function to apply a gradient gate for the linear combination of unitaries method.

        Replaces the ``gate`` instance in ``circuit`` with ``grad_gate`` using ``qr_superpos`` as
        superposition qubit. Also adds the appropriate sign-fix gates on the superposition qubit.

        Args:
            circuit (QuantumCircuit): The circuit in which to do the replacements.
            gate (Gate): The gate instance to replace.
            param_index (int): The index of the parameter in ``gate``.
            grad_gate (Gate): A controlled gate encoding the gradient of ``gate``.
            grad_coeff (float): A coefficient to the gradient component. Might not be one if the
                gradient contains multiple summed terms.
            qr_superpos (QuantumRegister): A ``QuantumRegister`` of size 1 contained in ``circuit``
                that is used as control for ``grad_gate``.
            open_ctrl (bool): If True use an open control for ``grad_gate`` instead of closed.
            trim_after_grad_gate (bool): If True remove all gates after the ``grad_gate``. Can
                be used to reduce the circuit depth in e.g. computing an overlap of gradients.

        Returns:
            QuantumCircuit: A copy of the original circuit with the gradient gate added.

        Raises:
            RuntimeError: If ``gate`` is not in ``circuit``.
        """
        # copy the input circuit taking the gates by reference
        out = QuantumCircuit(*circuit.qregs)
        out._data = circuit._data.copy()
        out._parameter_table = ParameterTable({
            param: values.copy() for param, values in circuit._parameter_table.items()
        })

        # get the data index and qubits of the target gate  TODO use built-in
        gate_idx, gate_qubits = None, None
        for i, (op, qarg, _) in enumerate(out._data):
            if op is gate:
                gate_idx, gate_qubits = i, qarg
                break
        if gate_idx is None:
            raise RuntimeError('The specified gate could not be found in the circuit data.')

        # initialize replacement instructions
        replacement = []

        # insert the phase fix before the target gate better documentation
        sign = np.sign(grad_coeff)
        is_complex = np.iscomplex(grad_coeff)

        if sign < 0 and is_complex:
            replacement.append((SdgGate(), qr_superpos[:], []))
        elif sign < 0:
            replacement.append((ZGate(), qr_superpos[:], []))
        elif is_complex:
            replacement.append((SGate(), qr_superpos[:], []))
        # else no additional gate required

        # open control if specified
        if open_ctrl:
            replacement += [(XGate(), qr_superpos[:], [])]

        # compute the replacement
        if isinstance(gate, UGate) and param_index == 0:
            theta = gate.params[2]
            rz_plus, rz_minus = RZGate(theta), RZGate(-theta)
            replacement += [(rz_plus, [qubit], []) for qubit in gate_qubits]
            replacement += [(RXGate(np.pi / 2), [qubit], []) for qubit in gate_qubits]
            replacement.append((grad_gate, qr_superpos[:] + gate_qubits, []))
            replacement += [(RXGate(-np.pi / 2), [qubit], []) for qubit in gate_qubits]
            replacement += [(rz_minus, [qubit], []) for qubit in gate_qubits]

            # update parametertable if necessary
            if isinstance(theta, ParameterExpression):
                out._update_parameter_table(rz_plus)
                out._update_parameter_table(rz_minus)

            if open_ctrl:
                replacement += [(XGate(), qr_superpos[:], [])]

            if not trim_after_grad_gate:
                replacement.append((gate, gate_qubits, []))

        elif isinstance(gate, UGate) and param_index == 1:
            # gradient gate is applied after the original gate in this case
            replacement.append((gate, gate_qubits, []))
            replacement.append((grad_gate, qr_superpos[:] + gate_qubits, []))
            if open_ctrl:
                replacement += [(XGate(), qr_superpos[:], [])]

        else:
            replacement.append((grad_gate, qr_superpos[:] + gate_qubits, []))
            if open_ctrl:
                replacement += [(XGate(), qr_superpos[:], [])]
            if not trim_after_grad_gate:
                replacement.append((gate, gate_qubits, []))

        # replace the parameter we compute the derivative of with the replacement
        # TODO can this be done more efficiently?
        if trim_after_grad_gate:  # remove everything after the gradient gate
            out._data[gate_idx:] = replacement
            # reset parameter table
            table = ParameterTable()
            for op, _, _ in out._data:
                for idx, param_expression in enumerate(op.params):
                    if isinstance(param_expression, ParameterExpression):
                        for param in param_expression.parameters:
                            if param not in table.keys():
                                table[param] = [(op, idx)]
                            else:
                                table[param].append((op, idx))

            out._parameter_table = table

        else:
            out._data[gate_idx:gate_idx + 1] = replacement

        return out
Ejemplo n.º 17
0
def convert_to_target(conf_dict: dict,
                      props_dict: dict = None,
                      defs_dict: dict = None) -> Target:
    """Uses configuration, properties and pulse defaults dicts
    to construct and return Target class.
    """
    name_mapping = {
        "id": IGate(),
        "sx": SXGate(),
        "x": XGate(),
        "cx": CXGate(),
        "rz": RZGate(Parameter("λ")),
        "reset": Reset(),
    }
    custom_gates = {}
    qubit_props = None
    if props_dict:
        qubit_props = qubit_props_from_props(props_dict)
    target = Target(qubit_properties=qubit_props)
    # Parse from properties if it exsits
    if props_dict is not None:
        # Parse instructions
        gates = {}
        for gate in props_dict["gates"]:
            name = gate["gate"]
            if name in name_mapping:
                if name not in gates:
                    gates[name] = {}
            elif name not in custom_gates:
                custom_gate = Gate(name, len(gate["qubits"]), [])
                custom_gates[name] = custom_gate
                gates[name] = {}

            qubits = tuple(gate["qubits"])
            gate_props = {}
            for param in gate["parameters"]:
                if param["name"] == "gate_error":
                    gate_props["error"] = param["value"]
                if param["name"] == "gate_length":
                    gate_props["duration"] = apply_prefix(
                        param["value"], param["unit"])
            gates[name][qubits] = InstructionProperties(**gate_props)
        for gate, props in gates.items():
            if gate in name_mapping:
                inst = name_mapping.get(gate)
            else:
                inst = custom_gates[gate]
            target.add_instruction(inst, props)
        # Create measurement instructions:
        measure_props = {}
        count = 0
        for qubit in props_dict["qubits"]:
            qubit_prop = {}
            for prop in qubit:
                if prop["name"] == "readout_length":
                    qubit_prop["duration"] = apply_prefix(
                        prop["value"], prop["unit"])
                if prop["name"] == "readout_error":
                    qubit_prop["error"] = prop["value"]
            measure_props[(count, )] = InstructionProperties(**qubit_prop)
            count += 1
        target.add_instruction(Measure(), measure_props)
    # Parse from configuration because properties doesn't exist
    else:
        for gate in conf_dict["gates"]:
            name = gate["name"]
            gate_props = {tuple(x): None for x in gate["coupling_map"]}
            if name in name_mapping:
                target.add_instruction(name_mapping[name], gate_props)
            else:
                custom_gate = Gate(name, len(gate["coupling_map"][0]), [])
                target.add_instruction(custom_gate, gate_props)
        measure_props = {(n, ): None for n in range(conf_dict["n_qubits"])}
        target.add_instruction(Measure(), measure_props)
    # parse global configuration properties
    dt = conf_dict.get("dt")
    if dt:
        target.dt = dt * 1e-9
    if "timing_constraints" in conf_dict:
        target.granularity = conf_dict["timing_constraints"].get("granularity")
        target.min_length = conf_dict["timing_constraints"].get("min_length")
        target.pulse_alignment = conf_dict["timing_constraints"].get(
            "pulse_alignment")
        target.aquire_alignment = conf_dict["timing_constraints"].get(
            "acquire_alignment")
    # If pulse defaults exists use that as the source of truth
    if defs_dict is not None:
        # TODO remove the usage of PulseDefaults as it will be deprecated in the future
        pulse_defs = PulseDefaults.from_dict(defs_dict)
        inst_map = pulse_defs.instruction_schedule_map
        for inst in inst_map.instructions:
            for qarg in inst_map.qubits_with_instruction(inst):
                sched = inst_map.get(inst, qarg)
                if inst in target:
                    try:
                        qarg = tuple(qarg)
                    except TypeError:
                        qarg = (qarg, )
                    if inst == "measure":
                        for qubit in qarg:
                            target[inst][(qubit, )].calibration = sched
                    else:
                        target[inst][qarg].calibration = sched
    target.add_instruction(Delay(Parameter("t")),
                           {(bit, ): None
                            for bit in range(target.num_qubits)})
    return target
Ejemplo n.º 18
0
def decompose_xxyy_into_xxyy_xx(a_target, b_target, a_source, b_source,
                                interaction):
    """
    Consumes a target canonical interaction CAN(a_target, b_target) and source interactions
    CAN(a1, b1), CAN(a2), then manufactures a circuit identity of the form

    CAN(a_target, b_target) = (Zr, Zs) CAN(a_source, b_source) (Zu, Zv) CAN(interaction) (Zx, Zy).

    Returns the 6-tuple (r, s, u, v, x, y).
    """

    cplus, cminus = np.cos(a_source + b_source), np.cos(a_source - b_source)
    splus, sminus = np.sin(a_source + b_source), np.sin(a_source - b_source)
    ca, sa = np.cos(interaction), np.sin(interaction)

    uplusv = (1 / 2 * safe_arccos(
        cminus**2 * ca**2 + sminus**2 * sa**2 - np.cos(a_target - b_target)**2,
        2 * cminus * ca * sminus * sa,
    ))
    uminusv = (1 / 2 * safe_arccos(
        cplus**2 * ca**2 + splus**2 * sa**2 - np.cos(a_target + b_target)**2,
        2 * cplus * ca * splus * sa,
    ))

    u, v = (uplusv + uminusv) / 2, (uplusv - uminusv) / 2

    # NOTE: the target matrix is phase-free
    middle_matrix = reduce(
        np.dot,
        [
            RXXGate(2 * a_source).to_matrix() @ RYYGate(
                2 * b_source).to_matrix(),
            np.kron(RZGate(2 * u).to_matrix(),
                    RZGate(2 * v).to_matrix()),
            RXXGate(2 * interaction).to_matrix(),
        ],
    )

    phase_solver = np.array([
        [
            1 / 4,
            1 / 4,
            1 / 4,
            1 / 4,
        ],
        [
            1 / 4,
            -1 / 4,
            -1 / 4,
            1 / 4,
        ],
        [
            1 / 4,
            1 / 4,
            -1 / 4,
            -1 / 4,
        ],
        [
            1 / 4,
            -1 / 4,
            1 / 4,
            -1 / 4,
        ],
    ])
    inner_phases = [
        np.angle(middle_matrix[0, 0]),
        np.angle(middle_matrix[1, 1]),
        np.angle(middle_matrix[1, 2]) + np.pi / 2,
        np.angle(middle_matrix[0, 3]) + np.pi / 2,
    ]
    r, s, x, y = np.dot(phase_solver, inner_phases)

    # If there's a phase discrepancy, need to conjugate by an extra Z/2 (x) Z/2.
    generated_matrix = reduce(
        np.dot,
        [
            np.kron(RZGate(2 * r).to_matrix(),
                    RZGate(2 * s).to_matrix()),
            middle_matrix,
            np.kron(RZGate(2 * x).to_matrix(),
                    RZGate(2 * y).to_matrix()),
        ],
    )
    if (abs(np.angle(generated_matrix[3, 0]) - np.pi / 2) < 0.01
            and a_target > b_target) or (
                abs(np.angle(generated_matrix[3, 0]) + np.pi / 2) < 0.01
                and a_target < b_target):
        x += np.pi / 4
        y += np.pi / 4
        r -= np.pi / 4
        s -= np.pi / 4

    return r, s, u, v, x, y
Ejemplo n.º 19
0
 def fnz(circuit, qr, phi):
     phi = _mod_2pi(phi, atol)
     if abs(phi) > atol:
         circuit._append(RZGate(phi), [qr[0]], [])
         circuit.global_phase += phi / 2
Ejemplo n.º 20
0
from qiskit.qasm import pi

eq_lib = EquivalenceLibrary()

theta = Parameter('theta')
phi = Parameter('phi')
lamda = Parameter('lamda')

u3 = U3Gate(theta, phi, lamda)
u2 = U2Gate(theta, phi)
u1 = U1Gate(theta)
ccx = CCXGate()
        
q = QuantumRegister(1, 'q')
equiv_u3 = QuantumCircuit(q)
equiv_u3.append(RZGate(phi+(pi/2)), [q[0]], [])
equiv_u3.append(HGate(),[q[0]], [] )
equiv_u3.append(RZGate(theta),[q[0]], [])
equiv_u3.append(HGate(), [q[0]], [])
equiv_u3.append(RZGate(lamda-(pi/2)),[q[0]], 0)
eq_lib.add_equivalence(u3, equiv_u3)


q = QuantumRegister(1, 'q')
equiv_u2 = QuantumCircuit(q)
equiv_u2.append(RZGate(theta+(pi/2)), [q[0]], [])
equiv_u2.append(HGate(),[q[0]], [] )
equiv_u2.append(RZGate(pi/2),[q[0]], [])
equiv_u2.append(HGate(), [q[0]], [])
equiv_u2.append(RZGate(phi-(pi/2)),[q[0]], 0)
eq_lib.add_equivalence(u2, equiv_u2)
Ejemplo n.º 21
0
    def __init__(self):
        super().__init__(
            name="FakeMumbaiV2",
            description="A fake BackendV2 example based on IBM Mumbai",
            online_date=datetime.datetime.utcnow(),
            backend_version="0.0.1",
        )
        dt = 0.2222222222222222e-9
        self._target = Target(dt=dt)
        self._phi = Parameter("phi")
        rz_props = {
            (0, ): InstructionProperties(duration=0.0, error=0),
            (1, ): InstructionProperties(duration=0.0, error=0),
            (2, ): InstructionProperties(duration=0.0, error=0),
            (3, ): InstructionProperties(duration=0.0, error=0),
            (4, ): InstructionProperties(duration=0.0, error=0),
            (5, ): InstructionProperties(duration=0.0, error=0),
            (6, ): InstructionProperties(duration=0.0, error=0),
            (7, ): InstructionProperties(duration=0.0, error=0),
            (8, ): InstructionProperties(duration=0.0, error=0),
            (9, ): InstructionProperties(duration=0.0, error=0),
            (10, ): InstructionProperties(duration=0.0, error=0),
            (11, ): InstructionProperties(duration=0.0, error=0),
            (12, ): InstructionProperties(duration=0.0, error=0),
            (13, ): InstructionProperties(duration=0.0, error=0),
            (14, ): InstructionProperties(duration=0.0, error=0),
            (15, ): InstructionProperties(duration=0.0, error=0),
            (16, ): InstructionProperties(duration=0.0, error=0),
            (17, ): InstructionProperties(duration=0.0, error=0),
            (18, ): InstructionProperties(duration=0.0, error=0),
            (19, ): InstructionProperties(duration=0.0, error=0),
            (20, ): InstructionProperties(duration=0.0, error=0),
            (21, ): InstructionProperties(duration=0.0, error=0),
            (22, ): InstructionProperties(duration=0.0, error=0),
            (23, ): InstructionProperties(duration=0.0, error=0),
            (24, ): InstructionProperties(duration=0.0, error=0),
            (25, ): InstructionProperties(duration=0.0, error=0),
            (26, ): InstructionProperties(duration=0.0, error=0),
        }
        self._target.add_instruction(RZGate(self._phi), rz_props)
        x_props = {
            (0, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00020056469709026198),
            (1, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0004387432040599484),
            (2, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002196765027963209),
            (3, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0003065541555566093),
            (4, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002402026686478811),
            (5, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002162777062721698),
            (6, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00021981280474256117),
            (7, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00018585647396926756),
            (8, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00027053333211825124),
            (9, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002603116226593832),
            (10, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00023827406030798066),
            (11, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00024856063217108685),
            (12, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002065075637361354),
            (13, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00024898181450337464),
            (14, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00017758796319636606),
            (15, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00016530893922883836),
            (16, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0003213658218204255),
            (17, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00024068450432012685),
            (18, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00026676441863976344),
            (19, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00017090891698571018),
            (20, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00021057196071004095),
            (21, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00030445404779882887),
            (22, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00019322295843406375),
            (23, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00030966037392287727),
            (24, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00023570754161126),
            (25, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00018367783963229033),
            (26, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00019630609928571516),
        }
        self._target.add_instruction(XGate(), x_props)
        sx_props = {
            (0, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00020056469709026198),
            (1, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0004387432040599484),
            (2, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002196765027963209),
            (3, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0003065541555566093),
            (4, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002402026686478811),
            (5, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002162777062721698),
            (6, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00021981280474256117),
            (7, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00018585647396926756),
            (8, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00027053333211825124),
            (9, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002603116226593832),
            (10, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00023827406030798066),
            (11, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00024856063217108685),
            (12, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0002065075637361354),
            (13, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00024898181450337464),
            (14, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00017758796319636606),
            (15, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00016530893922883836),
            (16, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.0003213658218204255),
            (17, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00024068450432012685),
            (18, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00026676441863976344),
            (19, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00017090891698571018),
            (20, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00021057196071004095),
            (21, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00030445404779882887),
            (22, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00019322295843406375),
            (23, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00030966037392287727),
            (24, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00023570754161126),
            (25, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00018367783963229033),
            (26, ):
            InstructionProperties(duration=3.5555555555555554e-08,
                                  error=0.00019630609928571516),
        }
        self._target.add_instruction(SXGate(), sx_props)
        chunk_size = 16
        cx_props = {
            (0, 1):
            InstructionProperties(duration=101 * chunk_size * dt,
                                  error=0.030671121181161276),
            (4, 1):
            InstructionProperties(duration=70 * chunk_size * dt,
                                  error=0.014041986073052737),
            (4, 7):
            InstructionProperties(duration=74 * chunk_size * dt,
                                  error=0.0052040275323747),
            (10, 7):
            InstructionProperties(duration=92 * chunk_size * dt,
                                  error=0.005625282141655502),
            (10, 12):
            InstructionProperties(duration=84 * chunk_size * dt,
                                  error=0.005771827440726435),
            (15, 12):
            InstructionProperties(duration=84 * chunk_size * dt,
                                  error=0.0050335609425562755),
            (15, 18):
            InstructionProperties(duration=64 * chunk_size * dt,
                                  error=0.0051374141171115495),
            (12, 13):
            InstructionProperties(duration=70 * chunk_size * dt,
                                  error=0.011361175954064051),
            (13, 14):
            InstructionProperties(duration=101 * chunk_size * dt,
                                  error=0.005231334872256355),
            # From FakeMumbai:
            (1, 0):
            InstructionProperties(duration=4.551111111111111e-07,
                                  error=0.030671121181161276),
            (1, 2):
            InstructionProperties(duration=7.395555555555556e-07,
                                  error=0.03420291964205785),
            (1, 4):
            InstructionProperties(duration=3.6266666666666663e-07,
                                  error=0.014041986073052737),
            (2, 1):
            InstructionProperties(duration=7.04e-07,
                                  error=0.03420291964205785),
            (2, 3):
            InstructionProperties(duration=4.266666666666666e-07,
                                  error=0.005618162036535312),
            (3, 2):
            InstructionProperties(duration=3.911111111111111e-07,
                                  error=0.005618162036535312),
            (3, 5):
            InstructionProperties(duration=3.5555555555555553e-07,
                                  error=0.006954580732294352),
            (5, 3):
            InstructionProperties(duration=3.911111111111111e-07,
                                  error=0.006954580732294352),
            (5, 8):
            InstructionProperties(duration=1.3155555555555553e-06,
                                  error=0.021905829471073668),
            (6, 7):
            InstructionProperties(duration=2.4177777777777775e-07,
                                  error=0.011018069718028878),
            (7, 4):
            InstructionProperties(duration=3.7688888888888884e-07,
                                  error=0.0052040275323747),
            (7, 6):
            InstructionProperties(duration=2.7733333333333333e-07,
                                  error=0.011018069718028878),
            (7, 10):
            InstructionProperties(duration=4.337777777777778e-07,
                                  error=0.005625282141655502),
            (8, 5):
            InstructionProperties(duration=1.351111111111111e-06,
                                  error=0.021905829471073668),
            (8, 9):
            InstructionProperties(duration=6.897777777777777e-07,
                                  error=0.011889378687341773),
            (8, 11):
            InstructionProperties(duration=5.902222222222222e-07,
                                  error=0.009523844852027258),
            (9, 8):
            InstructionProperties(duration=6.542222222222222e-07,
                                  error=0.011889378687341773),
            (11, 8):
            InstructionProperties(duration=6.257777777777777e-07,
                                  error=0.009523844852027258),
            (11, 14):
            InstructionProperties(duration=4.053333333333333e-07,
                                  error=0.004685421425282804),
            (12, 10):
            InstructionProperties(duration=3.9822222222222215e-07,
                                  error=0.005771827440726435),
            (12, 15):
            InstructionProperties(duration=4.053333333333333e-07,
                                  error=0.0050335609425562755),
            (13, 12):
            InstructionProperties(duration=5.831111111111111e-07,
                                  error=0.011361175954064051),
            (14, 11):
            InstructionProperties(duration=3.697777777777778e-07,
                                  error=0.004685421425282804),
            (14, 13):
            InstructionProperties(duration=3.5555555555555553e-07,
                                  error=0.005231334872256355),
            (14, 16):
            InstructionProperties(duration=3.484444444444444e-07,
                                  error=0.0051117141032224755),
            (16, 14):
            InstructionProperties(duration=3.1288888888888885e-07,
                                  error=0.0051117141032224755),
            (16, 19):
            InstructionProperties(duration=7.537777777777777e-07,
                                  error=0.013736796355458464),
            (17, 18):
            InstructionProperties(duration=2.488888888888889e-07,
                                  error=0.007267536233537236),
            (18, 15):
            InstructionProperties(duration=3.413333333333333e-07,
                                  error=0.0051374141171115495),
            (18, 17):
            InstructionProperties(duration=2.8444444444444443e-07,
                                  error=0.007267536233537236),
            (18, 21):
            InstructionProperties(duration=4.977777777777778e-07,
                                  error=0.007718304749257138),
            (19, 16):
            InstructionProperties(duration=7.182222222222222e-07,
                                  error=0.013736796355458464),
            (19, 20):
            InstructionProperties(duration=4.266666666666666e-07,
                                  error=0.005757038521092134),
            (19, 22):
            InstructionProperties(duration=3.6266666666666663e-07,
                                  error=0.004661878013991871),
            (20, 19):
            InstructionProperties(duration=3.911111111111111e-07,
                                  error=0.005757038521092134),
            (21, 18):
            InstructionProperties(duration=5.333333333333332e-07,
                                  error=0.007718304749257138),
            (21, 23):
            InstructionProperties(duration=3.911111111111111e-07,
                                  error=0.007542515578725928),
            (22, 19):
            InstructionProperties(duration=3.271111111111111e-07,
                                  error=0.004661878013991871),
            (22, 25):
            InstructionProperties(duration=4.835555555555555e-07,
                                  error=0.005536735115231589),
            (23, 21):
            InstructionProperties(duration=4.266666666666666e-07,
                                  error=0.007542515578725928),
            (23, 24):
            InstructionProperties(duration=6.613333333333332e-07,
                                  error=0.010797784688907186),
            (24, 23):
            InstructionProperties(duration=6.257777777777777e-07,
                                  error=0.010797784688907186),
            (24, 25):
            InstructionProperties(duration=4.337777777777778e-07,
                                  error=0.006127506135155392),
            (25, 22):
            InstructionProperties(duration=4.48e-07,
                                  error=0.005536735115231589),
            (25, 24):
            InstructionProperties(duration=4.693333333333333e-07,
                                  error=0.006127506135155392),
            (25, 26):
            InstructionProperties(duration=3.484444444444444e-07,
                                  error=0.0048451525929122385),
            (26, 25):
            InstructionProperties(duration=3.1288888888888885e-07,
                                  error=0.0048451525929122385),
        }
        self.target.add_instruction(CXGate(), cx_props)
        # Error and duration the same as CX
        rzx_90_props = {
            (0, 1):
            InstructionProperties(duration=101 * chunk_size * dt,
                                  error=0.030671121181161276),
            (4, 1):
            InstructionProperties(duration=70 * chunk_size * dt,
                                  error=0.014041986073052737),
            (4, 7):
            InstructionProperties(duration=74 * chunk_size * dt,
                                  error=0.0052040275323747),
            (10, 7):
            InstructionProperties(duration=92 * chunk_size * dt,
                                  error=0.005625282141655502),
            (10, 12):
            InstructionProperties(duration=84 * chunk_size * dt,
                                  error=0.005771827440726435),
            (15, 12):
            InstructionProperties(duration=84 * chunk_size * dt,
                                  error=0.0050335609425562755),
            (15, 18):
            InstructionProperties(duration=64 * chunk_size * dt,
                                  error=0.0051374141171115495),
            (12, 13):
            InstructionProperties(duration=70 * chunk_size * dt,
                                  error=0.011361175954064051),
            (13, 14):
            InstructionProperties(duration=101 * chunk_size * dt,
                                  error=0.005231334872256355),
        }
        self.target.add_instruction(RZXGate(np.pi / 2),
                                    rzx_90_props,
                                    name="rzx_90")
        rzx_45_props = {
            (0, 1):
            InstructionProperties(duration=52 * chunk_size * dt,
                                  error=0.030671121181161276 / 2),
            (4, 1):
            InstructionProperties(duration=37 * chunk_size * dt,
                                  error=0.014041986073052737 / 2),
            (4, 7):
            InstructionProperties(duration=40 * chunk_size * dt,
                                  error=0.0052040275323747 / 2),
            (10, 7):
            InstructionProperties(duration=46 * chunk_size * dt,
                                  error=0.005625282141655502 / 2),
            (10, 12):
            InstructionProperties(duration=45 * chunk_size * dt,
                                  error=0.005771827440726435 / 2),
            (15, 12):
            InstructionProperties(duration=42 * chunk_size * dt,
                                  error=0.0050335609425562755 / 2),
            (15, 18):
            InstructionProperties(duration=34 * chunk_size * dt,
                                  error=0.0051374141171115495 / 2),
            (12, 13):
            InstructionProperties(duration=37 * chunk_size * dt,
                                  error=0.011361175954064051 / 2),
            (13, 14):
            InstructionProperties(duration=52 * chunk_size * dt,
                                  error=0.005231334872256355 / 2),
        }
        self.target.add_instruction(RZXGate(np.pi / 4),
                                    rzx_45_props,
                                    name="rzx_45")
        rzx_30_props = {
            (0, 1):
            InstructionProperties(duration=37 * chunk_size * dt,
                                  error=0.030671121181161276 / 3),
            (4, 1):
            InstructionProperties(duration=24 * chunk_size * dt,
                                  error=0.014041986073052737 / 3),
            (4, 7):
            InstructionProperties(duration=29 * chunk_size * dt,
                                  error=0.0052040275323747 / 3),
            (10, 7):
            InstructionProperties(duration=32 * chunk_size * dt,
                                  error=0.005625282141655502 / 3),
            (10, 12):
            InstructionProperties(duration=32 * chunk_size * dt,
                                  error=0.005771827440726435 / 3),
            (15, 12):
            InstructionProperties(duration=29 * chunk_size * dt,
                                  error=0.0050335609425562755 / 3),
            (15, 18):
            InstructionProperties(duration=26 * chunk_size * dt,
                                  error=0.0051374141171115495 / 3),
            (12, 13):
            InstructionProperties(duration=24 * chunk_size * dt,
                                  error=0.011361175954064051 / 3),
            (13, 14):
            InstructionProperties(duration=377 * chunk_size * dt,
                                  error=0.005231334872256355 / 3),
        }
        self.target.add_instruction(RZXGate(np.pi / 6),
                                    rzx_30_props,
                                    name="rzx_30")
        reset_props = {(i, ):
                       InstructionProperties(duration=3676.4444444444443)
                       for i in range(27)}
        self._target.add_instruction(Reset(), reset_props)

        meas_props = {
            (0, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.02089999999999992),
            (1, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.020199999999999996),
            (2, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.014100000000000001),
            (3, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.03710000000000002),
            (4, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.015100000000000002),
            (5, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.01869999999999994),
            (6, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.013000000000000012),
            (7, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.02059999999999995),
            (8, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.06099999999999994),
            (9, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.02950000000000008),
            (10, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.040000000000000036),
            (11, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.017299999999999982),
            (12, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.04410000000000003),
            (13, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.017199999999999993),
            (14, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.10119999999999996),
            (15, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.07840000000000003),
            (16, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.014499999999999957),
            (17, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.021299999999999986),
            (18, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.022399999999999975),
            (19, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.01859999999999995),
            (20, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.02859999999999996),
            (21, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.021600000000000064),
            (22, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.030200000000000005),
            (23, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.01970000000000005),
            (24, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.03079999999999994),
            (25, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.04400000000000004),
            (26, ):
            InstructionProperties(duration=3.552e-06,
                                  error=0.026800000000000046),
        }
        self.target.add_instruction(Measure(), meas_props)
        self._qubit_properties = {
            0:
            QubitProperties(t1=0.00015987993124584417,
                            t2=0.00016123516590787283,
                            frequency=5073462814.921423),
            1:
            QubitProperties(t1=0.00017271188343294773,
                            t2=3.653713654834547e-05,
                            frequency=4943844681.620448),
            2:
            QubitProperties(t1=7.179635917914033e-05,
                            t2=0.00012399765778639733,
                            frequency=4668157502.363186),
            3:
            QubitProperties(t1=0.0001124203171256432,
                            t2=0.0001879954854434302,
                            frequency=4887315883.214115),
            4:
            QubitProperties(t1=9.568769051084652e-05,
                            t2=6.9955557231525e-05,
                            frequency=5016355075.77537),
            5:
            QubitProperties(t1=9.361326963775646e-05,
                            t2=0.00012561361411231962,
                            frequency=4950539585.866738),
            6:
            QubitProperties(t1=9.735672898365994e-05,
                            t2=0.00012522003396944046,
                            frequency=4970622491.726983),
            7:
            QubitProperties(t1=0.00012117839009784141,
                            t2=0.0001492370106539427,
                            frequency=4889863864.167805),
            8:
            QubitProperties(t1=8.394707006435891e-05,
                            t2=5.5194256398727296e-05,
                            frequency=4769852625.405966),
            9:
            QubitProperties(t1=0.00012392229685657686,
                            t2=5.97129502818714e-05,
                            frequency=4948868138.885028),
            10:
            QubitProperties(t1=0.00011193014813922708,
                            t2=0.00014091085124119432,
                            frequency=4966294754.357908),
            11:
            QubitProperties(t1=0.000124426408667364,
                            t2=9.561432905002298e-05,
                            frequency=4664636564.282378),
            12:
            QubitProperties(t1=0.00012469120424014884,
                            t2=7.1792446286313e-05,
                            frequency=4741461907.952719),
            13:
            QubitProperties(t1=0.00010010942474357871,
                            t2=9.260751861141544e-05,
                            frequency=4879064835.799635),
            14:
            QubitProperties(t1=0.00010793367069728063,
                            t2=0.00020462601085738193,
                            frequency=4774809501.962878),
            15:
            QubitProperties(t1=0.00010814279470918582,
                            t2=0.00014052616328020083,
                            frequency=4860834948.367331),
            16:
            QubitProperties(t1=9.889617874757627e-05,
                            t2=0.00012160357011388956,
                            frequency=4978318747.333388),
            17:
            QubitProperties(t1=8.435212562619916e-05,
                            t2=4.43587633824445e-05,
                            frequency=5000300619.491221),
            18:
            QubitProperties(t1=0.00011719166507869474,
                            t2=5.461866556148401e-05,
                            frequency=4772460318.985625),
            19:
            QubitProperties(t1=0.00013321880066203932,
                            t2=0.0001704632622810825,
                            frequency=4807707035.998121),
            20:
            QubitProperties(t1=9.14192211953385e-05,
                            t2=0.00014298332288799443,
                            frequency=5045028334.669125),
            21:
            QubitProperties(t1=5.548103716494676e-05,
                            t2=9.328101902519704e-05,
                            frequency=4941029753.792485),
            22:
            QubitProperties(t1=0.00017109481586484562,
                            t2=0.00019209594920551097,
                            frequency=4906801587.246266),
            23:
            QubitProperties(t1=0.00010975552427765991,
                            t2=0.00015616813868639905,
                            frequency=4891601685.652732),
            24:
            QubitProperties(t1=0.0001612962696960434,
                            t2=6.940808472789023e-05,
                            frequency=4664347869.784967),
            25:
            QubitProperties(t1=0.00015414506978323392,
                            t2=8.382170181880107e-05,
                            frequency=4742061753.511209),
            26:
            QubitProperties(t1=0.00011828557676958944,
                            t2=0.00016963640893557827,
                            frequency=4961661099.733828),
        }
Ejemplo n.º 22
0
def convert_to_target(
    configuration: BackendConfiguration,
    properties: BackendProperties = None,
    defaults: PulseDefaults = None,
) -> Target:
    """Uses configuration, properties and pulse defaults
    to construct and return Target class.
    """
    name_mapping = {
        "id": IGate(),
        "sx": SXGate(),
        "x": XGate(),
        "cx": CXGate(),
        "rz": RZGate(Parameter("λ")),
        "reset": Reset(),
    }
    custom_gates = {}
    target = None
    # Parse from properties if it exsits
    if properties is not None:
        qubit_properties = qubit_props_list_from_props(properties=properties)
        target = Target(
            num_qubits=configuration.n_qubits, qubit_properties=qubit_properties
        )
        # Parse instructions
        gates: Dict[str, Any] = {}
        for gate in properties.gates:
            name = gate.gate
            if name in name_mapping:
                if name not in gates:
                    gates[name] = {}
            elif name not in custom_gates:
                custom_gate = Gate(name, len(gate.qubits), [])
                custom_gates[name] = custom_gate
                gates[name] = {}

            qubits = tuple(gate.qubits)
            gate_props = {}
            for param in gate.parameters:
                if param.name == "gate_error":
                    gate_props["error"] = param.value
                if param.name == "gate_length":
                    gate_props["duration"] = apply_prefix(param.value, param.unit)
            gates[name][qubits] = InstructionProperties(**gate_props)
        for gate, props in gates.items():
            if gate in name_mapping:
                inst = name_mapping.get(gate)
            else:
                inst = custom_gates[gate]
            target.add_instruction(inst, props)
        # Create measurement instructions:
        measure_props = {}
        for qubit, _ in enumerate(properties.qubits):
            measure_props[(qubit,)] = InstructionProperties(
                duration=properties.readout_length(qubit),
                error=properties.readout_error(qubit),
            )
        target.add_instruction(Measure(), measure_props)
    # Parse from configuration because properties doesn't exist
    else:
        target = Target(num_qubits=configuration.n_qubits)
        for gate in configuration.gates:
            name = gate.name
            gate_props = (
                {tuple(x): None for x in gate.coupling_map}  # type: ignore[misc]
                if hasattr(gate, "coupling_map")
                else {None: None}
            )
            gate_len = len(gate.coupling_map[0]) if hasattr(gate, "coupling_map") else 0
            if name in name_mapping:
                target.add_instruction(name_mapping[name], gate_props)
            else:
                custom_gate = Gate(name, gate_len, [])
                target.add_instruction(custom_gate, gate_props)
        target.add_instruction(Measure())
    # parse global configuration properties
    if hasattr(configuration, "dt"):
        target.dt = configuration.dt
    if hasattr(configuration, "timing_constraints"):
        target.granularity = configuration.timing_constraints.get("granularity")
        target.min_length = configuration.timing_constraints.get("min_length")
        target.pulse_alignment = configuration.timing_constraints.get("pulse_alignment")
        target.aquire_alignment = configuration.timing_constraints.get(
            "acquire_alignment"
        )
    # If a pulse defaults exists use that as the source of truth
    if defaults is not None:
        inst_map = defaults.instruction_schedule_map
        for inst in inst_map.instructions:
            for qarg in inst_map.qubits_with_instruction(inst):
                sched = inst_map.get(inst, qarg)
                if inst in target:
                    try:
                        qarg = tuple(qarg)
                    except TypeError:
                        qarg = (qarg,)
                    if inst == "measure":
                        for qubit in qarg:
                            target[inst][(qubit,)].calibration = sched
                    else:
                        target[inst][qarg].calibration = sched
    if "delay" not in target:
        target.add_instruction(
            Delay(Parameter("t")), {(bit,): None for bit in range(target.num_qubits)}
        )
    return target
Ejemplo n.º 23
0
    def apply_grad_gate(
        circuit,
        gate,
        param_index,
        grad_gate,
        grad_coeff,
        qr_superpos,
        open_ctrl=False,
        trim_after_grad_gate=False,
    ):
        """Util function to apply a gradient gate for the linear combination of unitaries method.
        Replaces the ``gate`` instance in ``circuit`` with ``grad_gate`` using ``qr_superpos`` as
        superposition qubit. Also adds the appropriate sign-fix gates on the superposition qubit.

        Args:
            circuit (QuantumCircuit): The circuit in which to do the replacements.
            gate (Gate): The gate instance to replace.
            param_index (int): The index of the parameter in ``gate``.
            grad_gate (Gate): A controlled gate encoding the gradient of ``gate``.
            grad_coeff (float): A coefficient to the gradient component. Might not be one if the
                gradient contains multiple summed terms.
            qr_superpos (QuantumRegister): A ``QuantumRegister`` of size 1 contained in ``circuit``
                that is used as control for ``grad_gate``.
            open_ctrl (bool): If True use an open control for ``grad_gate`` instead of closed.
            trim_after_grad_gate (bool): If True remove all gates after the ``grad_gate``. Can
                be used to reduce the circuit depth in e.g. computing an overlap of gradients.

        Returns:
            QuantumCircuit: A copy of the original circuit with the gradient gate added.

        Raises:
            RuntimeError: If ``gate`` is not in ``circuit``.
        """
        qr_superpos_qubits = tuple(qr_superpos)
        # copy the input circuit taking the gates by reference
        out = QuantumCircuit(*circuit.qregs)
        out._data = circuit._data.copy()
        out._parameter_table = ParameterTable({
            param: values.copy()
            for param, values in circuit._parameter_table.items()
        })

        # get the data index and qubits of the target gate  TODO use built-in
        gate_idx, gate_qubits = None, None
        for i, instruction in enumerate(out._data):
            if instruction.operation is gate:
                gate_idx, gate_qubits = i, instruction.qubits
                break
        if gate_idx is None:
            raise RuntimeError(
                "The specified gate could not be found in the circuit data.")

        # initialize replacement instructions
        replacement = []

        # insert the phase fix before the target gate better documentation
        sign = np.sign(grad_coeff)
        is_complex = np.iscomplex(grad_coeff)

        if sign < 0 and is_complex:
            replacement.append(
                CircuitInstruction(SdgGate(), qr_superpos_qubits, ()))
        elif sign < 0:
            replacement.append(
                CircuitInstruction(ZGate(), qr_superpos_qubits, ()))
        elif is_complex:
            replacement.append(
                CircuitInstruction(SGate(), qr_superpos_qubits, ()))
        # else no additional gate required

        # open control if specified
        if open_ctrl:
            replacement += [
                CircuitInstruction(XGate(), qr_superpos_qubits, [])
            ]

        # compute the replacement
        if isinstance(gate, UGate) and param_index == 0:
            theta = gate.params[2]
            rz_plus, rz_minus = RZGate(theta), RZGate(-theta)
            replacement += [
                CircuitInstruction(rz_plus, (qubit, ), ())
                for qubit in gate_qubits
            ]
            replacement += [
                CircuitInstruction(RXGate(np.pi / 2), (qubit, ), ())
                for qubit in gate_qubits
            ]
            replacement.append(
                CircuitInstruction(grad_gate, qr_superpos_qubits + gate_qubits,
                                   []))
            replacement += [
                CircuitInstruction(RXGate(-np.pi / 2), (qubit, ), ())
                for qubit in gate_qubits
            ]
            replacement += [
                CircuitInstruction(rz_minus, (qubit, ), ())
                for qubit in gate_qubits
            ]

            # update parametertable if necessary
            if isinstance(theta, ParameterExpression):
                # This dangerously subverts ParameterTable by abusing the fact that binding will
                # mutate the exact instruction instance, and relies on all instances of `rz_plus`
                # that were added before being the same in memory, which QuantumCircuit usually
                # ensures is not the case.  I'm leaving this as close to its previous form as
                # possible, to avoid introducing further complications, but this whole method
                # accesses internal attributes of `QuantumCircuit` and needs rewriting.
                # - Jake Lishman, 2022-03-02.
                out._update_parameter_table(
                    CircuitInstruction(rz_plus, (gate_qubits[0], ), ()))
                out._update_parameter_table(
                    CircuitInstruction(rz_minus, (gate_qubits[0], ), ()))

            if open_ctrl:
                replacement.append(
                    CircuitInstruction(XGate(), qr_superpos_qubits, ()))

            if not trim_after_grad_gate:
                replacement.append(CircuitInstruction(gate, gate_qubits, ()))

        elif isinstance(gate, UGate) and param_index == 1:
            # gradient gate is applied after the original gate in this case
            replacement.append(CircuitInstruction(gate, gate_qubits, ()))
            replacement.append(
                CircuitInstruction(grad_gate, qr_superpos_qubits + gate_qubits,
                                   ()))
            if open_ctrl:
                replacement.append(
                    CircuitInstruction(XGate(), qr_superpos_qubits, ()))

        else:
            replacement.append(
                CircuitInstruction(grad_gate, qr_superpos_qubits + gate_qubits,
                                   ()))
            if open_ctrl:
                replacement.append(
                    CircuitInstruction(XGate(), qr_superpos_qubits, ()))
            if not trim_after_grad_gate:
                replacement.append(CircuitInstruction(gate, gate_qubits, ()))

        # replace the parameter we compute the derivative of with the replacement
        # TODO can this be done more efficiently?
        if trim_after_grad_gate:  # remove everything after the gradient gate
            out._data[gate_idx:] = replacement
            # reset parameter table
            table = ParameterTable()
            for instruction in out._data:
                for idx, param_expression in enumerate(
                        instruction.operation.params):
                    if isinstance(param_expression, ParameterExpression):
                        for param in param_expression.parameters:
                            if param not in table.keys():
                                table[param] = ParameterReferences(
                                    ((instruction.operation, idx), ))
                            else:
                                table[param].add((instruction.operation, idx))

            out._parameter_table = table

        else:
            out._data[gate_idx:gate_idx + 1] = replacement

        return out