Exemplo n.º 1
0
    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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
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
Exemplo n.º 6
0
    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
Exemplo n.º 7
0
    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
Exemplo n.º 8
0
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
Exemplo n.º 9
0
    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)
Exemplo n.º 10
0
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
Exemplo n.º 11
0
    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)
Exemplo n.º 12
0
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