def synthesize(self, evolution): # get operators and time to evolve operators = evolution.operator time = evolution.time # construct the evolution circuit evolution_circuit = QuantumCircuit(operators[0].num_qubits) first_barrier = False if not isinstance(operators, list): pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operators.to_list()] else: pauli_list = [(op, 1) for op in operators] # if we only evolve a single Pauli we don't need to additionally wrap it wrap = not (len(pauli_list) == 1 and self.reps == 1) for _ in range(self.reps): for op, coeff in pauli_list: # add barriers if first_barrier: if self.insert_barriers: evolution_circuit.barrier() else: first_barrier = True evolution_circuit.compose(self.atomic_evolution( op, coeff * time / self.reps), wrap=wrap, inplace=True) return evolution_circuit
def select_value(circuit: QuantumCircuit, register: QuantumRegister, value: int, target: QuantumRegister, ancillas: QuantumRegister): circuit.barrier() circuit = encode_value(circuit, register, value, ancillas) circuit.cnx(register, target, ancillas) circuit = encode_value_inverse(circuit, register, value, ancillas) return circuit
def as_late_as_possible(circuit: QuantumCircuit, schedule_config: ScheduleConfig) -> Schedule: """ Return the pulse Schedule which implements the input circuit using an "as late as possible" (alap) scheduling policy. Circuit instructions are first each mapped to equivalent pulse Schedules according to the command definition given by the schedule_config. Then, this circuit instruction-equivalent Schedule is appended at the latest time that it can be without allowing unnecessary time between instructions or allowing instructions with common qubits to overlap. This method should improves the outcome fidelity over ASAP scheduling, because we may maximize the time that the qubit remains in the ground state. Args: circuit: The quantum circuit to translate. schedule_config: Backend specific parameters used for building the Schedule. Returns: A schedule corresponding to the input ``circuit`` with pulses occurring as late as possible. """ sched = Schedule(name=circuit.name) # Align channel end times. circuit.barrier() # We schedule in reverse order to get ALAP behaviour. We need to know how far out from t=0 any # qubit will become occupied. We add positive shifts to these times as we go along. # The time is initialized to 0 because all qubits are involved in the final barrier. qubit_available_until = defaultdict(lambda: 0) def update_times(inst_qubits: List[int], shift: int = 0, inst_start_time: int = 0) -> None: """Update the time tracker for all inst_qubits to the given time.""" for q in inst_qubits: qubit_available_until[q] = inst_start_time for q in qubit_available_until.keys(): if q not in inst_qubits: # Uninvolved qubits might be free for the duration of the new instruction qubit_available_until[q] += shift circ_pulse_defs = translate_gates_to_pulse_defs(circuit, schedule_config) for circ_pulse_def in reversed(circ_pulse_defs): inst_sched = circ_pulse_def.schedule # The new instruction should end when one of its qubits becomes occupied inst_start_time = ( min([qubit_available_until[q] for q in circ_pulse_def.qubits]) - getattr(inst_sched, 'duration', 0)) # Barrier has no duration # We have to translate qubit times forward when the inst_start_time is negative shift_amount = max(0, -inst_start_time) inst_start_time = max(inst_start_time, 0) if not isinstance(circ_pulse_def.schedule, Barrier): sched = inst_sched.shift(inst_start_time).insert(shift_amount, sched, name=sched.name) update_times(circ_pulse_def.qubits, shift_amount, inst_start_time) return sched
def select_vertex(circuit : QuantumCircuit, registers : QuantumRegister, value : int, target : QuantumRegister, ancillas : QuantumRegister) -> QuantumCircuit: circuit.barrier() circuit = encode_value(circuit, registers[0], value, reverse=True) controlled = [q for register in registers for q in register] circuit.cnx(controlled, target, ancillas) circuit = encode_value(circuit, registers[0], value, reverse=True) return circuit
def diffusion(circuit: QuantumCircuit, registers: List[QuantumRegister], ancillas: QuantumRegister) -> QuantumCircuit: """Invert all the amplitudes around the means.""" circuit.barrier() # H columns circuit = superposition(circuit, registers) circuit = phase_shift(circuit, registers, ancillas) # H columns circuit = superposition(circuit, registers) return circuit
def oracle(circuit : QuantumCircuit) -> QuantumCircuit: """The oracle to find the edge.""" start, end, ancillas, flags = circuit.qregs circuit = encode_graph(circuit, graph, flags[0]) # Select all the edges that start from 7 circuit = select_vertex(circuit, [start] + [[flags[0]]], 1, flags[1], ancillas) circuit = select_vertex(circuit, [end] + [[flags[0]]], 5, flags[1], ancillas) circuit.barrier() circuit.z(flags[1]) return circuit
def synthesize(self, evolution): # get operators and time to evolve operators = evolution.operator time = evolution.time if not isinstance(operators, list): pauli_list = [(Pauli(op), np.real(coeff)) for op, coeff in operators.to_list()] else: pauli_list = [(op, 1) for op in operators] ops_to_evolve = self._recurse(self.order, time / self.reps, pauli_list) # construct the evolution circuit single_rep = QuantumCircuit(operators[0].num_qubits) first_barrier = False for op, coeff in ops_to_evolve: # add barriers if first_barrier: if self.insert_barriers: single_rep.barrier() else: first_barrier = True single_rep.compose(self.atomic_evolution(op, coeff), wrap=True, inplace=True) evolution_circuit = QuantumCircuit(operators[0].num_qubits) first_barrier = False for _ in range(self.reps): # add barriers if first_barrier: if self.insert_barriers: single_rep.barrier() else: first_barrier = True evolution_circuit.compose(single_rep, inplace=True) return evolution_circuit
def encode_edge(circuit : QuantumCircuit, start : QuantumRegister, start_value : int, end : QuantumRegister, end_value : int, weight : QuantumRegister, weight_value : int, target : QuantumRegister, ancillas : QuantumRegister) -> QuantumCircuit: """Encode all the edges of the graph. |i>|j>|0> -> |i>|j>|A_{ij}>""" circuit.barrier() circuit = encode_value(circuit, start, start_value, ancillas) circuit = encode_value(circuit, end, end_value, ancillas) circuit = encode_value(circuit, weight, weight_value, ancillas) # Simulate the Big C^nNOT controlled = [q for register in [start,end,weight] for q in register] circuit.cnx(controlled,target,ancillas) # Reverse the computation circuit = encode_value(circuit, weight, weight_value, ancillas) circuit = encode_value_inverse(circuit, end, end_value, ancillas) circuit = encode_value_inverse(circuit, start, start_value, ancillas) return circuit
def _build(self) -> None: """Build the circuit.""" if self._data: return _ = self._check_configuration() self._data = [] if self.num_qubits == 0: return circuit = QuantumCircuit(*self.qregs, name=self.name) # use the initial state as starting circuit, if it is set if self._initial_state: if isinstance(self._initial_state, QuantumCircuit): initial = self._initial_state.copy() else: initial = self._initial_state.construct_circuit( "circuit", register=self.qregs[0]) circuit.compose(initial, inplace=True) param_iter = iter(self.ordered_parameters) # build the prepended layers self._build_additional_layers(circuit, "prepended") # main loop to build the entanglement and rotation layers for i in range(self.reps): # insert barrier if specified and there is a preceding layer if self._insert_barriers and (i > 0 or len(self._prepended_blocks) > 0): circuit.barrier() # build the rotation layer self._build_rotation_layer(circuit, param_iter, i) # barrier in between rotation and entanglement layer if self._insert_barriers and len(self._rotation_blocks) > 0: circuit.barrier() # build the entanglement layer self._build_entanglement_layer(circuit, param_iter, i) # add the final rotation layer if not self._skip_final_rotation_layer: if self.insert_barriers and self.reps > 0: circuit.barrier() self._build_rotation_layer(circuit, param_iter, self.reps) # add the appended layers self._build_additional_layers(circuit, "appended") try: block = circuit.to_gate() except QiskitError: block = circuit.to_instruction() self.append(block, self.qubits)
def encode_edge(circuit: QuantumCircuit, start_value: int, end_value: int, weight_value: float, target: QuantumRegister) -> QuantumCircuit: """Encode all the edges of the graph.""" start, end, ancillas, flags = circuit.qregs circuit.barrier() circuit = encode_value(circuit, start, start_value) circuit = encode_value(circuit, end, end_value) # Simulate the Big C^nNOT controlled = [q for register in [start, end] for q in register] circuit.cnx(controlled, target, ancillas) # Reverse the computation circuit = encode_value_inverse(circuit, end, end_value) circuit = encode_value_inverse(circuit, start, start_value) return circuit
def _build(self) -> None: """If not already built, build the circuit.""" if self._is_built: return super()._build() if self.num_qubits == 0: return circuit = QuantumCircuit(*self.qregs, name=self.name) # use the initial state as starting circuit, if it is set if self.initial_state: if isinstance(self.initial_state, QuantumCircuit): initial = self.initial_state.copy() else: initial = self.initial_state.construct_circuit("circuit", register=self.qregs[0]) circuit.compose(initial, inplace=True) param_iter = iter(self.ordered_parameters) # build the prepended layers self._build_additional_layers(circuit, "prepended") # main loop to build the entanglement and rotation layers for i in range(self.reps): # insert barrier if specified and there is a preceding layer if self._insert_barriers and (i > 0 or len(self._prepended_blocks) > 0): circuit.barrier() # build the rotation layer self._build_rotation_layer(circuit, param_iter, i) # barrier in between rotation and entanglement layer if self._insert_barriers and len(self._rotation_blocks) > 0: circuit.barrier() # build the entanglement layer self._build_entanglement_layer(circuit, param_iter, i) # add the final rotation layer if not self._skip_final_rotation_layer: if self.insert_barriers and self.reps > 0: circuit.barrier() self._build_rotation_layer(circuit, param_iter, self.reps) # add the appended layers self._build_additional_layers(circuit, "appended") # cast global phase to float if it has no free parameters if isinstance(circuit.global_phase, ParameterExpression): try: circuit.global_phase = float(circuit.global_phase) except TypeError: # expression contains free parameters pass try: block = circuit.to_gate() except QiskitError: block = circuit.to_instruction() self.append(block, self.qubits)
def tensored_meas_cal( mit_pattern: List[List[int]] = None, qr: Union[int, List["QuantumRegister"]] = None, cr: Union[int, List["ClassicalRegister"]] = None, circlabel: str = "", ) -> Tuple[List["QuantumCircuit"], List[List[int]]]: """ Return a list of calibration circuits Args: mit_pattern: Qubits on which to perform the measurement correction, divided to groups according to tensors. If `None` and `qr` is given then assumed to be performed over the entire `qr` as one group (default `None`). qr: A quantum register (or its size). If `None`, one is created (default `None`). cr: A classical register (or its size). If `None`, one is created (default `None`). circlabel: A string to add to the front of circuit names for unique identification (default ' '). Returns: A list of two QuantumCircuit objects containing the calibration circuits mit_pattern Additional Information: The returned circuits are named circlabel+cal_XXX where XXX is the basis state, e.g., cal_000 and cal_111. Pass the results of these circuits to the TensoredMeasurementFitter constructor. Raises: QiskitError: if both `mit_pattern` and `qr` are None. QiskitError: if a qubit appears more than once in `mit_pattern`. """ # Runtime imports to avoid circular imports causeed by QuantumInstance # getting initialized by imported utils/__init__ which is imported # by qiskit.circuit from qiskit.circuit.quantumregister import QuantumRegister from qiskit.circuit.classicalregister import ClassicalRegister from qiskit.circuit.quantumcircuit import QuantumCircuit from qiskit.circuit.exceptions import QiskitError if mit_pattern is None and qr is None: raise QiskitError("Must give one of mit_pattern or qr") if isinstance(qr, int): qr = QuantumRegister(qr) qubits_in_pattern = [] if mit_pattern is not None: for qubit_list in mit_pattern: for qubit in qubit_list: if qubit in qubits_in_pattern: raise QiskitError( "mit_pattern cannot contain multiple instances of the same qubit" ) qubits_in_pattern.append(qubit) # Create the registers if not already done if qr is None: qr = QuantumRegister(max(qubits_in_pattern) + 1) else: qubits_in_pattern = range(len(qr)) mit_pattern = [qubits_in_pattern] nqubits = len(qubits_in_pattern) # create classical bit registers if cr is None: cr = ClassicalRegister(nqubits) if isinstance(cr, int): cr = ClassicalRegister(cr) qubits_list_sizes = [len(qubit_list) for qubit_list in mit_pattern] nqubits = sum(qubits_list_sizes) size_of_largest_group = max(qubits_list_sizes) largest_labels = count_keys(size_of_largest_group) state_labels = [] for largest_state in largest_labels: basis_state = "" for list_size in qubits_list_sizes: basis_state = largest_state[:list_size] + basis_state state_labels.append(basis_state) cal_circuits = [] for basis_state in state_labels: qc_circuit = QuantumCircuit(qr, cr, name=f"{circlabel}cal_{basis_state}") end_index = nqubits for qubit_list, list_size in zip(mit_pattern, qubits_list_sizes): start_index = end_index - list_size substate = basis_state[start_index:end_index] for qind in range(list_size): if substate[list_size - qind - 1] == "1": qc_circuit.x(qr[qubit_list[qind]]) end_index = start_index qc_circuit.barrier(qr) # add measurements end_index = nqubits for qubit_list, list_size in zip(mit_pattern, qubits_list_sizes): for qind in range(list_size): qc_circuit.measure(qr[qubit_list[qind]], cr[nqubits - (end_index - qind)]) end_index -= list_size cal_circuits.append(qc_circuit) return cal_circuits, mit_pattern