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
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
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))
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
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
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
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
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
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
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()
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)
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
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)
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
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
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
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
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)
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), }
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
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